From d7b715b83f968c2062dcee10112085e98ef37f73 Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Thu, 18 Apr 2013 10:38:03 -0700 Subject: [PATCH 001/114] Rename widget 'plugins' to 'pluginListing' For better clarity on its function, rename the 'plugins' widget to 'pluginListing,' as it does not handle the actual plugin logic. --- ui/index.jsp | 2 +- ui/scripts/plugins.js | 4 +--- ui/scripts/ui-custom/{plugins.js => pluginListing.js} | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) rename ui/scripts/ui-custom/{plugins.js => pluginListing.js} (98%) diff --git a/ui/index.jsp b/ui/index.jsp index 46f49f00984..550661e546a 100644 --- a/ui/index.jsp +++ b/ui/index.jsp @@ -1681,7 +1681,7 @@ under the License. - + diff --git a/ui/scripts/plugins.js b/ui/scripts/plugins.js index 5a33d56ef9f..d3e07055299 100644 --- a/ui/scripts/plugins.js +++ b/ui/scripts/plugins.js @@ -51,7 +51,7 @@ cloudStack.sections.plugins = { title: 'label.plugins', - show: cloudStack.uiCustom.plugins + show: cloudStack.uiCustom.pluginListing }; // Load plugins @@ -70,7 +70,5 @@ ui: pluginAPI }); }); - - // Load CSS }); }(jQuery, cloudStack, require)); diff --git a/ui/scripts/ui-custom/plugins.js b/ui/scripts/ui-custom/pluginListing.js similarity index 98% rename from ui/scripts/ui-custom/plugins.js rename to ui/scripts/ui-custom/pluginListing.js index aaf95319da1..3dcce983943 100644 --- a/ui/scripts/ui-custom/plugins.js +++ b/ui/scripts/ui-custom/pluginListing.js @@ -95,7 +95,7 @@ } }; - cloudStack.uiCustom.plugins = function() { + cloudStack.uiCustom.pluginListing = function() { var plugins = cloudStack.plugins; return elems.pluginListing({ From 908115203e6997ad8bea6e273a10865e38726877 Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Thu, 18 Apr 2013 15:13:14 -0700 Subject: [PATCH 002/114] WIP: Service provider module -Add 'add service provider' module to assist with creating a new service provider UI -Add required functionality to append service provider to hardcoded list -Add basic ASA 1000v provider to list (name, id, state) --- .../asa1000vNetworkProvider.js | 25 +++++++++++++ ui/modules/infrastructure/infrastructure.js | 37 +++++++++++++++++++ ui/modules/modules.js | 2 + ui/scripts/system.js | 4 ++ 4 files changed, 68 insertions(+) create mode 100644 ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js create mode 100644 ui/modules/infrastructure/infrastructure.js diff --git a/ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js b/ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js new file mode 100644 index 00000000000..3855daf6724 --- /dev/null +++ b/ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js @@ -0,0 +1,25 @@ +// 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) { + cloudStack.modules.asa1000vNetworkProvider = function(module) { + module.infrastructure.networkServiceProvider({ + id: 'ciscoAsa1000v', + name: 'Cisco ASA 1000v', + state: 'Disabled' + }); + }; +}(jQuery, cloudStack)); \ No newline at end of file diff --git a/ui/modules/infrastructure/infrastructure.js b/ui/modules/infrastructure/infrastructure.js new file mode 100644 index 00000000000..01cc4d7fe77 --- /dev/null +++ b/ui/modules/infrastructure/infrastructure.js @@ -0,0 +1,37 @@ +// 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) { + cloudStack.modules.infrastructure = function(module) { + module.pluginAPI.extend({ + networkServiceProvider: function(args) { + var name = args.name; + var id = args.id; + var state = args.state; + + $(window).bind('cloudStack.system.serviceProviders.makeHarcodedArray', function(event, data) { + var nspHardcodingArray = data.nspHardcodingArray; + + nspHardcodingArray.push({ + id: id, + name: name, + state: state + }); + }); + } + }); + }; +}(jQuery, cloudStack)); \ No newline at end of file diff --git a/ui/modules/modules.js b/ui/modules/modules.js index 490749ff085..f5dd62a0e9e 100644 --- a/ui/modules/modules.js +++ b/ui/modules/modules.js @@ -16,5 +16,7 @@ // under the License. (function($, cloudStack) { cloudStack.modules = [ + 'infrastructure', + 'asa1000vNetworkProvider' ]; }(jQuery, cloudStack)); diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 73bf3fd4160..f8881698de0 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -11666,6 +11666,10 @@ } ]; + $(window).trigger('cloudStack.system.serviceProviders.makeHarcodedArray', { + nspHardcodingArray: nspHardcodingArray + }); + if(selectedZoneObj.networktype == "Basic") { nspHardcodingArray.push( { From d53d06cc2f202d326740d01ffa29e626c9b735d2 Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Thu, 18 Apr 2013 16:26:23 -0700 Subject: [PATCH 003/114] Add basic listView/detailView for network provider --- .../asa1000vNetworkProvider.js | 48 ++++++++++++++++++- ui/modules/infrastructure/infrastructure.js | 9 ++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js b/ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js index 3855daf6724..8c83339c562 100644 --- a/ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js +++ b/ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js @@ -19,7 +19,53 @@ module.infrastructure.networkServiceProvider({ id: 'ciscoAsa1000v', name: 'Cisco ASA 1000v', - state: 'Disabled' + state: 'Disabled', + listView: { + id: 'asa1000vDevices', + fields: { + name: { label: 'label.name' }, + ipaddress: { label: 'label.ip.address' }, + state: { label: 'label.state', indicator: { + 'Enabled': 'on', + 'Disabled': 'off' + }} + }, + dataProvider: function(args) { + args.response.success({ + data: [ + { name: 'device1', ipaddress: '192.168.1.12', state: 'Enabled' }, + { name: 'device2', ipaddress: '192.168.1.13', state: 'Disabled' }, + { name: 'device3', ipaddress: '192.168.1.14', state: 'Enabled' } + ] + }); + } + }, + detailView: { + id: 'asa1000vProvider', + label: 'label.netScaler', + viewAll: { label: 'label.devices', path: '_zone.asa100vDevices' }, + tabs: { + details: { + title: 'label.details', + fields: [ + { + name: { label: 'label.name' } + }, + { + state: { label: 'label.state' } + } + ], + dataProvider: function(args) { + args.response.success({ + data: { + name: 'Cisco ASA 1000v', + state: 'Disabled' + } + }); + } + } + } + } }); }; }(jQuery, cloudStack)); \ No newline at end of file diff --git a/ui/modules/infrastructure/infrastructure.js b/ui/modules/infrastructure/infrastructure.js index 01cc4d7fe77..8292896f052 100644 --- a/ui/modules/infrastructure/infrastructure.js +++ b/ui/modules/infrastructure/infrastructure.js @@ -21,6 +21,15 @@ var name = args.name; var id = args.id; var state = args.state; + var detailView = args.detailView; + var listView = args.listView; + + cloudStack.sections.system.naas.networkProviders.types[id] = detailView; + cloudStack.sections.system.subsections[listView.id] = { + id: listView.id, + title: name, + listView: listView + }; $(window).bind('cloudStack.system.serviceProviders.makeHarcodedArray', function(event, data) { var nspHardcodingArray = data.nspHardcodingArray; From 1c482b5c3bc85e549b457070e5cd901bb181c3f9 Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Tue, 23 Apr 2013 14:40:33 -0700 Subject: [PATCH 004/114] Infrastructure UI plugin API: Add 'resource' method Add new method 'infrastructure.resource' for retrieving resource objects from the infrastructure section. Specify the type as a string (i.e, 'pod' 'cluster' or 'host') and the entire resource object will be returned, including listView, actions, createForm, etc. Updating the data in this resource will automatically update the UI. --- ui/modules/infrastructure/infrastructure.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ui/modules/infrastructure/infrastructure.js b/ui/modules/infrastructure/infrastructure.js index 8292896f052..ad43108259b 100644 --- a/ui/modules/infrastructure/infrastructure.js +++ b/ui/modules/infrastructure/infrastructure.js @@ -40,7 +40,17 @@ state: state }); }); + }, + + resource: function(args) { + var type = args.type; + + if (type) { + return cloudStack.sections.system.subsections[type]; + } else { + return false; + } } }); }; -}(jQuery, cloudStack)); \ No newline at end of file +}(jQuery, cloudStack)); From a9b903d597614adcb8d2c783d718e23f9011767f Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Tue, 23 Apr 2013 14:42:16 -0700 Subject: [PATCH 005/114] Add pod action: Add custom 'appendData' to action For use with plugin API, if 'appendData' is passed in args, always append this data to the end of the API call. Used when plugin adds new attributes that need to be passed via the API. --- ui/scripts/system.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/scripts/system.js b/ui/scripts/system.js index f8881698de0..95690a9b7c7 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -7634,6 +7634,7 @@ action: function(args) { var array1 = []; + var appendData = args.data.append ? args.data.append : {}; array1.push("&zoneId=" + args.data.zoneid); array1.push("&name=" + todb(args.data.podname)); @@ -7647,6 +7648,7 @@ $.ajax({ url: createURL("createPod" + array1.join("")), + data: appendData, dataType: "json", success: function(json) { var item = json.createpodresponse.pod; From d1642a489ce76e055d60b2caf3ccfe4bb136b745 Mon Sep 17 00:00:00 2001 From: Nitin Mehta Date: Thu, 25 Apr 2013 12:41:46 +0530 Subject: [PATCH 006/114] =initial changes --- api/src/com/cloud/event/EventTypes.java | 3 + api/src/com/cloud/network/Network.java | 2 + api/src/com/cloud/network/NetworkProfile.java | 7 + .../com/cloud/storage/VolumeApiService.java | 13 +- api/src/com/cloud/storage/VolumeDetail.java | 16 + api/src/com/cloud/vm/UserVmService.java | 22 +- .../apache/cloudstack/api/ApiConstants.java | 4 + .../admin/offering/CreateDiskOfferingCmd.java | 9 +- .../command/user/network/AddNicDetailCmd.java | 116 ++++++ .../user/network/CreateNetworkCmd.java | 7 + .../user/network/RemoveNicDetailCmd.java | 117 ++++++ .../user/network/UpdateNicDetailCmd.java | 116 ++++++ .../api/command/user/vm/DeployVMCmd.java | 14 +- .../api/command/user/vm/UpdateVMCmd.java | 7 + .../user/volume/AddVolumeDetailCmd.java | 115 ++++++ .../command/user/volume/CreateVolumeCmd.java | 8 +- .../user/volume/ListVolumeDetailCmd.java | 11 + .../user/volume/ListVolumeDetailsCmd.java | 82 ++++ .../user/volume/RemoveVolumeDetailCmd.java | 107 ++++++ .../command/user/volume/UpdateVolumeCmd.java | 121 ++++++ .../user/volume/UpdateVolumeDetailCmd.java | 115 ++++++ .../api/response/DiskOfferingResponse.java | 12 + .../api/response/NetworkResponse.java | 13 +- .../api/response/UserVmResponse.java | 9 + .../api/response/VolumeDetailResponse.java | 82 ++++ .../api/response/VolumeResponse.java | 12 + .../apache/cloudstack/query/QueryService.java | 28 +- .../api/command/test/AddNicDetailCmdTest.java | 62 ++++ .../command/test/AddVolumeDetailCmdTest.java | 62 ++++ .../command/test/RemoveNicDetailCmdTest.java | 62 ++++ .../test/RemoveVolumeDetailCmdTest.java | 63 ++++ .../test/UpdateVolumeDetailCmdTest.java | 65 ++++ .../command/test/updateNicDetailCmdTest.java | 62 ++++ client/tomcatconf/commands.properties.in | 7 + .../src/com/cloud/storage/DiskOfferingVO.java | 12 + .../src/com/cloud/storage/VolumeDetailVO.java | 85 +++++ core/src/com/cloud/storage/VolumeVO.java | 14 +- core/src/com/cloud/vm/VMInstanceVO.java | 11 + .../storage/volume/db/VolumeVO.java | 2 + .../src/com/cloud/api/ApiResponseHelper.java | 1 + .../com/cloud/api/query/QueryManagerImpl.java | 62 ++-- .../query/dao/DiskOfferingJoinDaoImpl.java | 5 +- .../api/query/dao/UserVmJoinDaoImpl.java | 1 + .../api/query/dao/VolumeJoinDaoImpl.java | 1 + .../api/query/vo/DiskOfferingJoinVO.java | 11 + .../com/cloud/api/query/vo/UserVmJoinVO.java | 10 + .../com/cloud/api/query/vo/VolumeJoinVO.java | 10 + .../configuration/ConfigurationManager.java | 4 +- .../ConfigurationManagerImpl.java | 14 +- .../src/com/cloud/network/dao/NetworkVO.java | 12 + .../cloud/server/ManagementServerImpl.java | 8 +- .../com/cloud/storage/VolumeManagerImpl.java | 88 ++++- .../cloud/storage/dao/VolumeDetailsDao.java | 33 ++ .../storage/dao/VolumeDetailsDaoImpl.java | 93 +++++ server/src/com/cloud/vm/NicDetailVO.java | 85 +++++ server/src/com/cloud/vm/NicDetailsVO.java | 11 + .../src/com/cloud/vm/UserVmManagerImpl.java | 47 ++- server/src/com/cloud/vm/dao/NicDetailDao.java | 32 ++ .../com/cloud/vm/dao/NicDetailDaoImpl.java | 98 +++++ server/src/com/cloud/vm/dao/UserVmDao.java | 3 +- .../src/com/cloud/vm/dao/UserVmDaoImpl.java | 3 +- .../com/cloud/vm/MockUserVmManagerImpl.java | 10 +- .../vpc/MockConfigurationManagerImpl.java | 8 +- setup/db/db/schema-410to420.sql | 350 ++++++++++++++++++ 64 files changed, 2555 insertions(+), 120 deletions(-) create mode 100644 api/src/com/cloud/storage/VolumeDetail.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/network/AddNicDetailCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/network/RemoveNicDetailCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/network/UpdateNicDetailCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/volume/AddVolumeDetailCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/volume/ListVolumeDetailCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/volume/ListVolumeDetailsCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/volume/RemoveVolumeDetailCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/volume/UpdateVolumeCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/volume/UpdateVolumeDetailCmd.java create mode 100644 api/src/org/apache/cloudstack/api/response/VolumeDetailResponse.java create mode 100644 api/test/org/apache/cloudstack/api/command/test/AddNicDetailCmdTest.java create mode 100644 api/test/org/apache/cloudstack/api/command/test/AddVolumeDetailCmdTest.java create mode 100644 api/test/org/apache/cloudstack/api/command/test/RemoveNicDetailCmdTest.java create mode 100644 api/test/org/apache/cloudstack/api/command/test/RemoveVolumeDetailCmdTest.java create mode 100644 api/test/org/apache/cloudstack/api/command/test/UpdateVolumeDetailCmdTest.java create mode 100644 api/test/org/apache/cloudstack/api/command/test/updateNicDetailCmdTest.java create mode 100644 core/src/com/cloud/storage/VolumeDetailVO.java create mode 100644 server/src/com/cloud/storage/dao/VolumeDetailsDao.java create mode 100644 server/src/com/cloud/storage/dao/VolumeDetailsDaoImpl.java create mode 100644 server/src/com/cloud/vm/NicDetailVO.java create mode 100644 server/src/com/cloud/vm/NicDetailsVO.java create mode 100644 server/src/com/cloud/vm/dao/NicDetailDao.java create mode 100644 server/src/com/cloud/vm/dao/NicDetailDaoImpl.java diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index 0ee7f402fd7..7737089f99b 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -166,6 +166,9 @@ public class EventTypes { public static final String EVENT_VOLUME_UPLOAD = "VOLUME.UPLOAD"; public static final String EVENT_VOLUME_MIGRATE = "VOLUME.MIGRATE"; public static final String EVENT_VOLUME_RESIZE = "VOLUME.RESIZE"; + public static final String EVENT_VOLUME_DETAIL_UPDATE = "VOLUME.DETAIL.UPDATE"; + public static final String EVENT_VOLUME_DETAIL_ADD = "VOLUME.DETAIL.ADD"; + public static final String EVENT_VOLUME_DETAIL_REMOVE = "VOLUME.DETAIL.REMOVE"; // Domains public static final String EVENT_DOMAIN_CREATE = "DOMAIN.CREATE"; diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index 4472dbacc53..f1b6f87cf8f 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -319,6 +319,8 @@ public interface Network extends ControlledEntity, StateObject, I boolean getSpecifyIpRanges(); + boolean getDisplayNetwork(); + /** * @return */ diff --git a/api/src/com/cloud/network/NetworkProfile.java b/api/src/com/cloud/network/NetworkProfile.java index 2f56645139c..7358b1ac4eb 100644 --- a/api/src/com/cloud/network/NetworkProfile.java +++ b/api/src/com/cloud/network/NetworkProfile.java @@ -52,6 +52,7 @@ public class NetworkProfile implements Network { private boolean restartRequired; private boolean specifyIpRanges; private Long vpcId; + private boolean displayNetwork; public NetworkProfile(Network network) { this.id = network.getId(); @@ -81,6 +82,7 @@ public class NetworkProfile implements Network { this.restartRequired = network.isRestartRequired(); this.specifyIpRanges = network.getSpecifyIpRanges(); this.vpcId = network.getVpcId(); + this.displayNetwork = network.getDisplayNetwork(); } public String getDns1() { @@ -231,6 +233,11 @@ public class NetworkProfile implements Network { return false; } + @Override + public boolean getDisplayNetwork() { + return displayNetwork; + } + @Override public Long getVpcId() { return vpcId; diff --git a/api/src/com/cloud/storage/VolumeApiService.java b/api/src/com/cloud/storage/VolumeApiService.java index 09a07d4be13..1f70c5b4e54 100644 --- a/api/src/com/cloud/storage/VolumeApiService.java +++ b/api/src/com/cloud/storage/VolumeApiService.java @@ -18,12 +18,7 @@ */ package com.cloud.storage; -import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.*; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.PermissionDeniedException; @@ -79,4 +74,10 @@ public interface VolumeApiService { Volume attachVolumeToVM(AttachVolumeCmd command); Volume detachVolumeFromVM(DetachVolumeCmd cmmd); + + void updateVolumeDetails(UpdateVolumeDetailCmd updateVolumeDetailCmd); + + void removeVolumeDetail(RemoveVolumeDetailCmd removeVolumeDetailCmd); + + void addVolumeDetail(AddVolumeDetailCmd addVolumeDetailCmd); } diff --git a/api/src/com/cloud/storage/VolumeDetail.java b/api/src/com/cloud/storage/VolumeDetail.java new file mode 100644 index 00000000000..70173734ed0 --- /dev/null +++ b/api/src/com/cloud/storage/VolumeDetail.java @@ -0,0 +1,16 @@ +package com.cloud.storage; + +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +/** + * Created with IntelliJ IDEA. + * User: nitinmehta + * Date: 24/04/13 + * Time: 5:55 PM + * To change this template use File | Settings | File Templates. + */ +public interface VolumeDetail extends ControlledEntity, InternalIdentity, Identity { + +} diff --git a/api/src/com/cloud/vm/UserVmService.java b/api/src/com/cloud/vm/UserVmService.java index 7e89cd3e618..2ccd19dd221 100755 --- a/api/src/com/cloud/vm/UserVmService.java +++ b/api/src/com/cloud/vm/UserVmService.java @@ -177,7 +177,10 @@ public interface UserVmService { * TODO * @param defaultIp * TODO + * @param displayVm + * - Boolean flag whether to the display the vm to the end user or not * @param affinityGroupIdList + * * @param accountName * - an optional account for the virtual machine. Must be used * with domainId @@ -197,9 +200,9 @@ public interface UserVmService { * @throws InsufficientResourcesException */ UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List securityGroupIdList, Account owner, String hostName, - String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, + String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData, String sshKeyPair, Map requestedIps, - IpAddresses defaultIp, String keyboard, List affinityGroupIdList) + IpAddresses defaultIp, Boolean displayVm, String keyboard, List affinityGroupIdList) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; /** @@ -250,7 +253,10 @@ public interface UserVmService { * TODO * @param defaultIps * TODO + * @param displayVm + * - Boolean flag whether to the display the vm to the end user or not * @param affinityGroupIdList + * * @param accountName * - an optional account for the virtual machine. Must be used * with domainId @@ -270,8 +276,8 @@ public interface UserVmService { * @throws InsufficientResourcesException */ UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, List securityGroupIdList, - Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData, String sshKeyPair, - Map requestedIps, IpAddresses defaultIps, String keyboard, List affinityGroupIdList) + Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData, String sshKeyPair, + Map requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List affinityGroupIdList) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; /** @@ -319,7 +325,10 @@ public interface UserVmService { * TODO * @param defaultIps * TODO + * @param displayVm + * - Boolean flag whether to the display the vm to the end user or not * @param affinityGroupIdList + * * @param accountName * - an optional account for the virtual machine. Must be used * with domainId @@ -340,8 +349,9 @@ public interface UserVmService { */ UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, - HTTPMethod httpmethod, String userData, String sshKeyPair, Map requestedIps, - IpAddresses defaultIps, String keyboard, List affinityGroupIdList) + HTTPMethod httpmethod, String userData, String sshKeyPair, Map requestedIps, + IpAddresses defaultIps, Boolean displayVm, String keyboard, List affinityGroupIdList) + throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; /** diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 1165c7b34f6..8ff4b0b44ac 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -56,7 +56,11 @@ public class ApiConstants { public static final String DISK_OFFERING_ID = "diskofferingid"; public static final String DISK_SIZE = "disksize"; public static final String DISPLAY_NAME = "displayname"; + public static final String DISPLAY_NETWORK = "displaynetwork"; public static final String DISPLAY_TEXT = "displaytext"; + public static final String DISPLAY_VM = "displayvm"; + public static final String DISPLAY_OFFERING = "displayoffering"; + public static final String DISPLAY_VOLUME = "displayvolume"; public static final String DNS1 = "dns1"; public static final String DNS2 = "dns2"; public static final String IP6_DNS1 = "ip6dns1"; diff --git a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java index 68d5dd466a3..aa11599a69e 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java @@ -62,7 +62,10 @@ public class CreateDiskOfferingCmd extends BaseCmd { @Parameter(name=ApiConstants.STORAGE_TYPE, type=CommandType.STRING, description="the storage type of the disk offering. Values are local and shared.") private String storageType = ServiceOffering.StorageType.shared.toString(); - ///////////////////////////////////////////////////// + @Parameter(name=ApiConstants.DISPLAY_OFFERING, type=CommandType.BOOLEAN, description="an optional field, whether to display the offering to the end user or not.") + private Boolean displayOffering; + +///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -94,6 +97,10 @@ public class CreateDiskOfferingCmd extends BaseCmd { return storageType; } + public Boolean getDisplayOffering() { + return displayOffering; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/network/AddNicDetailCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/AddNicDetailCmd.java new file mode 100644 index 00000000000..e5f7a0e80eb --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/network/AddNicDetailCmd.java @@ -0,0 +1,116 @@ +// 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. +package org.apache.cloudstack.api.command.user.network; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.NicResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.cloudstack.api.response.VolumeResponse; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.storage.Volume; +import com.cloud.user.Account; +import com.cloud.user.UserContext; + +@APICommand(name = "addNicDetail", description="Adds detail for the volume.", since="4.2", responseObject=SuccessResponse.class) +public class AddNicDetailCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(AddNicDetailCmd.class.getName()); + private static final String s_name = "addNicDetailresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=NicResponse.class, + required=true, description="the ID of the nic") + private Long id; + + @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, + required=true, description="the name of the field") + private String name; + + @Parameter(name=ApiConstants.VALUE, type=CommandType.STRING, + required=true, description="the value of the field") + private String value; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.Volume; + } + + public Long getInstanceId() { + return getId(); + } + + @Override + public long getEntityOwnerId() { + Volume volume = _responseGenerator.findVolumeById(getId()); + if (volume == null) { + return Account.ACCOUNT_ID_SYSTEM; // bad id given, parent this command to SYSTEM so ERROR events are tracked + } + return volume.getAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_VOLUME_ATTACH; + } + + @Override + public String getEventDescription() { + return "adding detail to the nic: " + getId(); + } + + @Override + public void execute(){ + _networkService.addNicDetail(this); + this.setResponseObject(new SuccessResponse(getCommandName())); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java index fc7bd9fdd3f..8c0f75e0bc5 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java @@ -126,6 +126,9 @@ public class CreateNetworkCmd extends BaseCmd { @Parameter(name=ApiConstants.IP6_CIDR, type=CommandType.STRING, description="the CIDR of IPv6 network, must be at least /64") private String ip6Cidr; + @Parameter(name=ApiConstants.DISPLAY_NETWORK, type=CommandType.BOOLEAN, description="an optional field, whether to the display the network to the end user or not.") + private Boolean displayNetwork; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -189,6 +192,10 @@ public class CreateNetworkCmd extends BaseCmd { return vpcId; } + public Boolean getDisplayNetwork() { + return displayNetwork; + } + public Long getZoneId() { Long physicalNetworkId = getPhysicalNetworkId(); diff --git a/api/src/org/apache/cloudstack/api/command/user/network/RemoveNicDetailCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/RemoveNicDetailCmd.java new file mode 100644 index 00000000000..fe7503f57ee --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/network/RemoveNicDetailCmd.java @@ -0,0 +1,117 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for removeitional 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. +package org.apache.cloudstack.api.command.user.network; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.NicResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.cloudstack.api.response.VolumeResponse; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.storage.Volume; +import com.cloud.user.Account; +import com.cloud.user.UserContext; + +@APICommand(name = "removeNicDetail", description="Removes detail for the volume.", since="4.2", responseObject=SuccessResponse.class) +public class RemoveNicDetailCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(RemoveNicDetailCmd.class.getName()); + private static final String s_name = "removeNicDetailresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=NicResponse.class, + required=true, description="the ID of the nic") + private Long id; + + @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, + required=true, description="the name of the field") + private String name; + + @Parameter(name=ApiConstants.VALUE, type=CommandType.STRING, + required=true, description="the value of the field") + private String value; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.Volume; + } + + public Long getInstanceId() { + return getId(); + } + + @Override + public long getEntityOwnerId() { + Volume volume = _responseGenerator.findVolumeById(getId()); + if (volume == null) { + return Account.ACCOUNT_ID_SYSTEM; // bad id given, parent this command to SYSTEM so ERROR events are tracked + } + return volume.getAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_VOLUME_ATTACH; + } + + @Override + public String getEventDescription() { + return "removing detail to the nic: " + getId(); + } + + @Override + public void execute(){ + UserContext.current().setEventDetails("Nic Id: "+getId()); + _networkService.removeNicDetail(this); + this.setResponseObject(new SuccessResponse(getCommandName())); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/user/network/UpdateNicDetailCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/UpdateNicDetailCmd.java new file mode 100644 index 00000000000..0e263e1bb3f --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/network/UpdateNicDetailCmd.java @@ -0,0 +1,116 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for updateitional 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. +package org.apache.cloudstack.api.command.user.network; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.NicResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.cloudstack.api.response.VolumeResponse; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.storage.Volume; +import com.cloud.user.Account; +import com.cloud.user.UserContext; + +@APICommand(name = "updateNicDetail", description="Updates detail for the nic.", since="4.2", responseObject=SuccessResponse.class) +public class UpdateNicDetailCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(UpdateNicDetailCmd.class.getName()); + private static final String s_name = "updateNicDetailresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=NicResponse.class, + required=true, description="the ID of the nic") + private Long id; + + @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, + required=true, description="the name of the field") + private String name; + + @Parameter(name=ApiConstants.VALUE, type=CommandType.STRING, + required=true, description="the value of the field") + private String value; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.Volume; + } + + public Long getInstanceId() { + return getId(); + } + + @Override + public long getEntityOwnerId() { + Volume volume = _responseGenerator.findVolumeById(getId()); + if (volume == null) { + return Account.ACCOUNT_ID_SYSTEM; // bad id given, parent this command to SYSTEM so ERROR events are tracked + } + return volume.getAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_VOLUME_ATTACH; + } + + @Override + public String getEventDescription() { + return "updating detail to the nic: " + getId(); + } + + @Override + public void execute(){ + _networkService.updateNicDetail(this); + this.setResponseObject(new SuccessResponse(getCommandName())); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java index 3ed08d26be0..b5cf9f9c054 100755 --- a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java @@ -183,6 +183,8 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { + "Mutually exclusive with affinitygroupids parameter") private List affinityGroupNameList; + @Parameter(name=ApiConstants.DISPLAY_VM, type=CommandType.BOOLEAN, since="4.2", description="an optional field, whether to the display the vm to the end user or not.") + private Boolean displayVm; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -219,6 +221,10 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { return HypervisorType.getType(hypervisor); } + public Boolean getDisplayVm() { + return displayVm; + } + public List getSecurityGroupIdList() { if (securityGroupNameList != null && securityGroupIdList != null) { throw new InvalidParameterValueException("securitygroupids parameter is mutually exclusive with securitygroupnames parameter"); @@ -481,18 +487,20 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { throw new InvalidParameterValueException("Can't specify network Ids in Basic zone"); } else { vm = _userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(), owner, name, - displayName, diskOfferingId, size, group, getHypervisor(), this.getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard, getAffinityGroupIdList()); + displayName, diskOfferingId, size, group, getHypervisor(), this.getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, displayVm, keyboard, getAffinityGroupIdList()); } } else { if (zone.isSecurityGroupEnabled()) { vm = _userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, getNetworkIds(), getSecurityGroupIdList(), - owner, name, displayName, diskOfferingId, size, group, getHypervisor(), this.getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard, getAffinityGroupIdList()); + owner, name, displayName, diskOfferingId, size, group, getHypervisor(), this.getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, displayVm, keyboard, getAffinityGroupIdList()); + } else { if (getSecurityGroupIdList() != null && !getSecurityGroupIdList().isEmpty()) { throw new InvalidParameterValueException("Can't create vm with security groups; security group feature is not enabled per zone"); } vm = _userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, getNetworkIds(), owner, name, displayName, - diskOfferingId, size, group, getHypervisor(), this.getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard, getAffinityGroupIdList()); + diskOfferingId, size, group, getHypervisor(), this.getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, displayVm, keyboard, getAffinityGroupIdList()); + } } diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java index bbf9b259201..28602830e02 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java @@ -64,6 +64,8 @@ public class UpdateVMCmd extends BaseCmd{ @Parameter(name=ApiConstants.USER_DATA, type=CommandType.STRING, description="an optional binary data that can be sent to the virtual machine upon a successful deployment. This binary data must be base64 encoded before adding it to the request. Using HTTP GET (via querystring), you can send up to 2KB of data after base64 encoding. Using HTTP POST(via POST body), you can send up to 32K of data after base64 encoding.", length=32768) private String userData; + @Parameter(name=ApiConstants.DISPLAY_VM, type=CommandType.BOOLEAN, description="an optional field, whether to the display the vm to the end user or not.") + private Boolean displayVm; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -89,6 +91,10 @@ public class UpdateVMCmd extends BaseCmd{ return userData; } + public Boolean getDisplayVm() { + return displayVm; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -107,6 +113,7 @@ public class UpdateVMCmd extends BaseCmd{ } @Override + public long getEntityOwnerId() { UserVm userVm = _entityMgr.findById(UserVm.class, getId()); if (userVm != null) { diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/AddVolumeDetailCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/AddVolumeDetailCmd.java new file mode 100644 index 00000000000..e9eff59c0a8 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/volume/AddVolumeDetailCmd.java @@ -0,0 +1,115 @@ +// 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. +package org.apache.cloudstack.api.command.user.volume; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.cloudstack.api.response.VolumeResponse; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.storage.Volume; +import com.cloud.user.Account; +import com.cloud.user.UserContext; + +@APICommand(name = "addVolumeDetail", description="Adds detail for the volume.", responseObject=SuccessResponse.class) +public class AddVolumeDetailCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(AddVolumeDetailCmd.class.getName()); + private static final String s_name = "addVolumeDetailresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=VolumeResponse.class, + required=true, description="the ID of the disk volume") + private Long id; + + @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, + required=true, description="the name of the field") + private String name; + + @Parameter(name=ApiConstants.VALUE, type=CommandType.STRING, + required=true, description="the value of the field") + private String value; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.Volume; + } + + public Long getInstanceId() { + return getId(); + } + + @Override + public long getEntityOwnerId() { + Volume volume = _responseGenerator.findVolumeById(getId()); + if (volume == null) { + return Account.ACCOUNT_ID_SYSTEM; // bad id given, parent this command to SYSTEM so ERROR events are tracked + } + return volume.getAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_VOLUME_DETAIL_ADD; + } + + @Override + public String getEventDescription() { + return "adding detail to the volume: " + getId(); + } + + @Override + public void execute(){ + _volumeService.addVolumeDetail(this); + this.setResponseObject(new SuccessResponse(getCommandName())); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java index 5db06bcd47f..86a494b8848 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java @@ -76,8 +76,10 @@ public class CreateVolumeCmd extends BaseAsyncCreateCmd { description="the ID of the availability zone") private Long zoneId; + @Parameter(name=ApiConstants.DISPLAY_VOLUME, type=CommandType.BOOLEAN, description="an optional field, whether to display the volume to the end user or not.") + private Boolean displayVolume; - ///////////////////////////////////////////////////// +///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -114,6 +116,10 @@ public class CreateVolumeCmd extends BaseAsyncCreateCmd { return projectId; } + public Boolean getDisplayVolume() { + return displayVolume; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumeDetailCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumeDetailCmd.java new file mode 100644 index 00000000000..db53eb4a0b9 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumeDetailCmd.java @@ -0,0 +1,11 @@ +package org.apache.cloudstack.api.command.user.volume; + +/** + * Created with IntelliJ IDEA. + * User: nitinmehta + * Date: 24/04/13 + * Time: 5:18 PM + * To change this template use File | Settings | File Templates. + */ +public class ListVolumeDetailCmd { +} diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumeDetailsCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumeDetailsCmd.java new file mode 100644 index 00000000000..a0424b6957a --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumeDetailsCmd.java @@ -0,0 +1,82 @@ +// 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. +package org.apache.cloudstack.api.command.user.volume; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseListTaggedResourcesCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.*; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; + +import java.util.List; + + +@APICommand(name = "listVolumeDetails", description="Lists all volume details.", responseObject=VolumeDetailResponse.class) +public class ListVolumeDetailsCmd extends BaseListTaggedResourcesCmd { + public static final Logger s_logger = Logger.getLogger(ListVolumesCmd.class.getName()); + + private static final String s_name = "listvolumedetailsresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=VolumeResponse.class, + required=true, description="the ID of the volume") + private Long id; + + @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, description="the name of the volume detail") + private String name; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.Volume; + } + + @Override + public void execute(){ + ListResponse responses = new ListResponse(); + List volumeDetailList = _queryService.searchForVolumeDetails(this); + responses.setResponses(volumeDetailList); + responses.setResponseName(getCommandName()); + this.setResponseObject(responses); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/RemoveVolumeDetailCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/RemoveVolumeDetailCmd.java new file mode 100644 index 00000000000..9e3c1c6284e --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/volume/RemoveVolumeDetailCmd.java @@ -0,0 +1,107 @@ +// 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. +package org.apache.cloudstack.api.command.user.volume; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.cloudstack.api.response.VolumeResponse; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.storage.Volume; +import com.cloud.user.Account; +import com.cloud.user.UserContext; + +@APICommand(name = "removeVolumeDetail", description="Remove a particular detail for the volume.", responseObject=VolumeResponse.class) +public class RemoveVolumeDetailCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(AttachVolumeCmd.class.getName()); + private static final String s_name = "removeVolumeDetailresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=VolumeResponse.class, + required=true, description="the ID of the disk volume") + private Long id; + + @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, + required=true, description="the name of the field") + private String name; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + + public String getName() { + return name; + } + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.Volume; + } + + public Long getInstanceId() { + return getId(); + } + + @Override + public long getEntityOwnerId() { + Volume volume = _responseGenerator.findVolumeById(getId()); + if (volume == null) { + return Account.ACCOUNT_ID_SYSTEM; // bad id given, parent this command to SYSTEM so ERROR events are tracked + } + return volume.getAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_VOLUME_ATTACH; + } + + @Override + public String getEventDescription() { + return "adding detail to the volume: " + getId(); + } + + @Override + public void execute(){ + _volumeService.removeVolumeDetail(this); + this.setResponseObject(new SuccessResponse(getCommandName())); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/UpdateVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/UpdateVolumeCmd.java new file mode 100644 index 00000000000..1f35a432848 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/volume/UpdateVolumeCmd.java @@ -0,0 +1,121 @@ +// 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. +package org.apache.cloudstack.api.command.user.volume; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.cloudstack.api.response.VolumeResponse; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.storage.Volume; +import com.cloud.user.Account; +import com.cloud.user.UserContext; + +@APICommand(name = "updateVolumeDetail", description="Updates the volume.", responseObject=VolumeResponse.class) +public class UpdateVolumeCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(AttachVolumeCmd.class.getName()); + private static final String s_name = "addVolumeDetailresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=VolumeResponse.class, + required=true, description="the ID of the disk volume") + private Long id; + + @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, + required=true, description="the name of the field") + private String name; + + @Parameter(name=ApiConstants.VALUE, type=CommandType.STRING, entityType=UserVmResponse.class, + required=true, description="the value of the field") + private String value; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.Volume; + } + + public Long getInstanceId() { + return getId(); + } + + @Override + public long getEntityOwnerId() { + Volume volume = _responseGenerator.findVolumeById(getId()); + if (volume == null) { + return Account.ACCOUNT_ID_SYSTEM; // bad id given, parent this command to SYSTEM so ERROR events are tracked + } + return volume.getAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_VOLUME_ATTACH; + } + + @Override + public String getEventDescription() { + return "adding detail to the volume: " + getId(); + } + + @Override + public void execute(){ + UserContext.current().setEventDetails("Volume Id: "+getId()); + /*Volume result = _volumeService.attachVolumeToVM(this); + if (result != null) { + VolumeResponse response = _responseGenerator.createVolumeResponse(result); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to attach volume"); + } */ + } +} diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/UpdateVolumeDetailCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/UpdateVolumeDetailCmd.java new file mode 100644 index 00000000000..8a43c6ed70c --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/volume/UpdateVolumeDetailCmd.java @@ -0,0 +1,115 @@ +// 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. +package org.apache.cloudstack.api.command.user.volume; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.cloudstack.api.response.VolumeResponse; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.storage.Volume; +import com.cloud.user.Account; +import com.cloud.user.UserContext; + +@APICommand(name = "updateVolumeDetail", description="Updates the volume detail.", responseObject=VolumeResponse.class) +public class UpdateVolumeDetailCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(AttachVolumeCmd.class.getName()); + private static final String s_name = "updateVolumeDetailresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=VolumeResponse.class, + required=true, description="the ID of the disk volume") + private Long id; + + @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, + required=true, description="the name of the field") + private String name; + + @Parameter(name=ApiConstants.VALUE, type=CommandType.STRING, entityType=UserVmResponse.class, + required=true, description="the value of the field") + private String value; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.Volume; + } + + public Long getInstanceId() { + return getId(); + } + + @Override + public long getEntityOwnerId() { + Volume volume = _responseGenerator.findVolumeById(getId()); + if (volume == null) { + return Account.ACCOUNT_ID_SYSTEM; // bad id given, parent this command to SYSTEM so ERROR events are tracked + } + return volume.getAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_VOLUME_ATTACH; + } + + @Override + public String getEventDescription() { + return "updating detail to the volume: " + getId(); + } + + @Override + public void execute(){ + _volumeService.updateVolumeDetails(this); + this.setResponseObject(new SuccessResponse(getCommandName())); + } +} diff --git a/api/src/org/apache/cloudstack/api/response/DiskOfferingResponse.java b/api/src/org/apache/cloudstack/api/response/DiskOfferingResponse.java index 04c318f8a2f..377e66ec2b1 100644 --- a/api/src/org/apache/cloudstack/api/response/DiskOfferingResponse.java +++ b/api/src/org/apache/cloudstack/api/response/DiskOfferingResponse.java @@ -58,8 +58,20 @@ public class DiskOfferingResponse extends BaseResponse { @SerializedName("storagetype") @Param(description="the storage type for this disk offering") private String storageType; + @SerializedName("displayoffering") @Param(description="whether to display the offering to the end user or not.") + private Boolean displayOffering; + + public Boolean getDisplayOffering() { + return displayOffering; + } + + public void setDisplayOffering(Boolean displayOffering) { + this.displayOffering = displayOffering; + } + public String getId() { return id; + } public void setId(String id) { diff --git a/api/src/org/apache/cloudstack/api/response/NetworkResponse.java b/api/src/org/apache/cloudstack/api/response/NetworkResponse.java index 3f366e2e576..d6847d55846 100644 --- a/api/src/org/apache/cloudstack/api/response/NetworkResponse.java +++ b/api/src/org/apache/cloudstack/api/response/NetworkResponse.java @@ -162,7 +162,18 @@ public class NetworkResponse extends BaseResponse implements ControlledEntityRes @SerializedName(ApiConstants.IP6_CIDR) @Param(description="the cidr of IPv6 network") private String ip6Cidr; - + + @SerializedName(ApiConstants.DISPLAY_NETWORK) @Param(description="an optional field, whether to the display the network to the end user or not.") + private Boolean displayNetwork; + + public Boolean getDisplayNetwork() { + return displayNetwork; + } + + public void setDisplayNetwork(Boolean displayNetwork) { + this.displayNetwork = displayNetwork; + } + public void setId(String id) { this.id = id; } diff --git a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java index da08c94074c..c3bbf8db382 100644 --- a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java +++ b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java @@ -177,6 +177,9 @@ public class UserVmResponse extends BaseResponse implements ControlledEntityResp @Param(description = "list of affinity groups associated with the virtual machine", responseObject = AffinityGroupResponse.class) private Set affinityGroupList; + @SerializedName(ApiConstants.DISPLAY_VM) @Param(description="an optional field whether to the display the vm to the end user or not.") + private Boolean displayVm; + public UserVmResponse(){ securityGroupList = new LinkedHashSet(); nics = new LinkedHashSet(); @@ -196,7 +199,13 @@ public class UserVmResponse extends BaseResponse implements ControlledEntityResp return this.id; } + public Boolean getDisplayVm() { + return displayVm; + } + public void setDisplayVm(Boolean displayVm) { + this.displayVm = displayVm; + } @Override public String getObjectId() { diff --git a/api/src/org/apache/cloudstack/api/response/VolumeDetailResponse.java b/api/src/org/apache/cloudstack/api/response/VolumeDetailResponse.java new file mode 100644 index 00000000000..3a8fab9b300 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/VolumeDetailResponse.java @@ -0,0 +1,82 @@ +// 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. +package org.apache.cloudstack.api.response; + +import java.util.Date; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + +import com.cloud.serializer.Param; +import com.cloud.storage.Volume; +import com.google.gson.annotations.SerializedName; + +@SuppressWarnings("unused") +public class VolumeDetailResponse extends BaseResponse{ + @SerializedName(ApiConstants.VOLUME_ID) + @Param(description = "ID of the volume") + private String id; + + @SerializedName(ApiConstants.NAME) + @Param(description = "name of the volume detail") + private String name; + + + @SerializedName(ApiConstants.VALUE) + @Param(description = "value of the volume detail") + private String value; + + @SerializedName(ApiConstants.DISPLAY_VOLUME) @Param(description="an optional field whether to the display the volume to the end user or not.") + private Boolean displayVm; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getName() { + + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Boolean getDisplayVm() { + return displayVm; + } + + public void setDisplayVm(Boolean displayVm) { + this.displayVm = displayVm; + } +} diff --git a/api/src/org/apache/cloudstack/api/response/VolumeResponse.java b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java index b928fcd90d0..21d7d1a449f 100644 --- a/api/src/org/apache/cloudstack/api/response/VolumeResponse.java +++ b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java @@ -165,6 +165,9 @@ public class VolumeResponse extends BaseResponse implements ControlledViewEntity @SerializedName(ApiConstants.TAGS) @Param(description="the list of resource tags associated with volume", responseObject = ResourceTagResponse.class) private Set tags; + @SerializedName(ApiConstants.DISPLAY_VOLUME) @Param(description="an optional field whether to the display the volume to the end user or not.") + private Boolean displayVm; + public VolumeResponse(){ tags = new LinkedHashSet(); } @@ -324,4 +327,13 @@ public class VolumeResponse extends BaseResponse implements ControlledViewEntity public void addTag(ResourceTagResponse tag){ this.tags.add(tag); } + + public Boolean getDisplayVm() { + return displayVm; + } + + public void setDisplayVm(Boolean displayVm) { + this.displayVm = displayVm; + } + } diff --git a/api/src/org/apache/cloudstack/query/QueryService.java b/api/src/org/apache/cloudstack/query/QueryService.java index 443c5df65b5..e821f3cd335 100644 --- a/api/src/org/apache/cloudstack/query/QueryService.java +++ b/api/src/org/apache/cloudstack/query/QueryService.java @@ -33,30 +33,15 @@ import org.apache.cloudstack.api.command.user.securitygroup.ListSecurityGroupsCm import org.apache.cloudstack.api.command.user.tag.ListTagsCmd; import org.apache.cloudstack.api.command.user.vm.ListVMsCmd; import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd; +import org.apache.cloudstack.api.command.user.volume.ListVolumeDetailsCmd; import org.apache.cloudstack.api.command.user.volume.ListVolumesCmd; import org.apache.cloudstack.api.command.user.zone.ListZonesByCmd; -import org.apache.cloudstack.api.response.AccountResponse; -import org.apache.cloudstack.api.response.AsyncJobResponse; -import org.apache.cloudstack.api.response.DiskOfferingResponse; -import org.apache.cloudstack.api.response.DomainRouterResponse; -import org.apache.cloudstack.api.response.EventResponse; -import org.apache.cloudstack.api.response.HostResponse; -import org.apache.cloudstack.api.response.InstanceGroupResponse; -import org.apache.cloudstack.api.response.ListResponse; -import org.apache.cloudstack.api.response.ProjectAccountResponse; -import org.apache.cloudstack.api.response.ProjectInvitationResponse; -import org.apache.cloudstack.api.response.ProjectResponse; -import org.apache.cloudstack.api.response.ResourceTagResponse; -import org.apache.cloudstack.api.response.SecurityGroupResponse; -import org.apache.cloudstack.api.response.ServiceOfferingResponse; -import org.apache.cloudstack.api.response.StoragePoolResponse; -import org.apache.cloudstack.api.response.UserResponse; -import org.apache.cloudstack.api.response.UserVmResponse; -import org.apache.cloudstack.api.response.VolumeResponse; -import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.cloudstack.api.response.*; import com.cloud.exception.PermissionDeniedException; +import java.util.List; + /** * Service used for list api query. * @@ -101,4 +86,7 @@ public interface QueryService { public ListResponse listAffinityGroups(Long affinityGroupId, String affinityGroupName, String affinityGroupType, Long vmId, Long startIndex, Long pageSize); -} + + public List searchForVolumeDetails(ListVolumeDetailsCmd cmd); + + } diff --git a/api/test/org/apache/cloudstack/api/command/test/AddNicDetailCmdTest.java b/api/test/org/apache/cloudstack/api/command/test/AddNicDetailCmdTest.java new file mode 100644 index 00000000000..6c43fd8bba9 --- /dev/null +++ b/api/test/org/apache/cloudstack/api/command/test/AddNicDetailCmdTest.java @@ -0,0 +1,62 @@ +// 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. +package org.apache.cloudstack.api.command.test; + +import com.cloud.network.NetworkService; +import junit.framework.Assert; +import junit.framework.TestCase; +import org.apache.cloudstack.api.ResponseGenerator; + +import org.apache.cloudstack.api.command.user.network.AddNicDetailCmd; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; +import static org.mockito.Mockito.*; + + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + + +public class AddNicDetailCmdTest extends TestCase{ + + private AddNicDetailCmd addNicDetailCmd; + private ResponseGenerator responseGenerator; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Before + public void setUp() { + + addNicDetailCmd = new AddNicDetailCmd(); + + } + + + @Test + public void testCreateSuccess() { + + NetworkService networkService = Mockito.mock(NetworkService.class); + doNothing().when(networkService).addNicDetail(addNicDetailCmd); + + } + +} diff --git a/api/test/org/apache/cloudstack/api/command/test/AddVolumeDetailCmdTest.java b/api/test/org/apache/cloudstack/api/command/test/AddVolumeDetailCmdTest.java new file mode 100644 index 00000000000..d501439a279 --- /dev/null +++ b/api/test/org/apache/cloudstack/api/command/test/AddVolumeDetailCmdTest.java @@ -0,0 +1,62 @@ +// 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. +package org.apache.cloudstack.api.command.test; + +import com.cloud.storage.VolumeApiService; +import junit.framework.Assert; +import junit.framework.TestCase; +import org.apache.cloudstack.api.ResponseGenerator; + +import org.apache.cloudstack.api.command.user.volume.AddVolumeDetailCmd; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; +import static org.mockito.Mockito.*; + + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + + +public class AddVolumeDetailCmdTest extends TestCase{ + + private AddVolumeDetailCmd addVolumeDetailCmd; + private ResponseGenerator responseGenerator; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Before + public void setUp() { + + addVolumeDetailCmd = new AddVolumeDetailCmd(); + + } + + + @Test + public void testCreateSuccess() { + + VolumeApiService volumeService = Mockito.mock(VolumeApiService.class); + doNothing().when(volumeService).addVolumeDetail(addVolumeDetailCmd); + + } + +} diff --git a/api/test/org/apache/cloudstack/api/command/test/RemoveNicDetailCmdTest.java b/api/test/org/apache/cloudstack/api/command/test/RemoveNicDetailCmdTest.java new file mode 100644 index 00000000000..607255c1a94 --- /dev/null +++ b/api/test/org/apache/cloudstack/api/command/test/RemoveNicDetailCmdTest.java @@ -0,0 +1,62 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for removeitional 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. +package org.apache.cloudstack.api.command.test; + +import com.cloud.network.NetworkService; +import junit.framework.Assert; +import junit.framework.TestCase; +import org.apache.cloudstack.api.ResponseGenerator; + +import org.apache.cloudstack.api.command.user.network.RemoveNicDetailCmd; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; +import static org.mockito.Mockito.*; + + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + + +public class RemoveNicDetailCmdTest extends TestCase{ + + private RemoveNicDetailCmd removeNicDetailCmd; + private ResponseGenerator responseGenerator; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Before + public void setUp() { + + removeNicDetailCmd = new RemoveNicDetailCmd(); + + } + + + @Test + public void testCreateSuccess() { + + NetworkService networkService = Mockito.mock(NetworkService.class); + doNothing().when(networkService).removeNicDetail(removeNicDetailCmd); + + } + +} diff --git a/api/test/org/apache/cloudstack/api/command/test/RemoveVolumeDetailCmdTest.java b/api/test/org/apache/cloudstack/api/command/test/RemoveVolumeDetailCmdTest.java new file mode 100644 index 00000000000..12ae8124482 --- /dev/null +++ b/api/test/org/apache/cloudstack/api/command/test/RemoveVolumeDetailCmdTest.java @@ -0,0 +1,63 @@ +// 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. +package org.apache.cloudstack.api.command.test; + +import com.cloud.storage.VolumeApiService; +import junit.framework.Assert; +import junit.framework.TestCase; +import org.apache.cloudstack.api.ResponseGenerator; + +import org.apache.cloudstack.api.command.user.volume.AddVolumeDetailCmd; +import org.apache.cloudstack.api.command.user.volume.RemoveVolumeDetailCmd; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; +import static org.mockito.Mockito.*; + + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + + +public class RemoveVolumeDetailCmdTest extends TestCase{ + + private RemoveVolumeDetailCmd removeVolumeDetailCmd; + private ResponseGenerator responseGenerator; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Before + public void setUp() { + + removeVolumeDetailCmd = new RemoveVolumeDetailCmd(); + + } + + + @Test + public void testCreateSuccess() { + + VolumeApiService volumeService = Mockito.mock(VolumeApiService.class); + doNothing().when(volumeService).removeVolumeDetail(removeVolumeDetailCmd); + + } + +} diff --git a/api/test/org/apache/cloudstack/api/command/test/UpdateVolumeDetailCmdTest.java b/api/test/org/apache/cloudstack/api/command/test/UpdateVolumeDetailCmdTest.java new file mode 100644 index 00000000000..1a3bada60bf --- /dev/null +++ b/api/test/org/apache/cloudstack/api/command/test/UpdateVolumeDetailCmdTest.java @@ -0,0 +1,65 @@ +// 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. +package org.apache.cloudstack.api.command.test; + +import com.cloud.storage.VolumeApiService; +import junit.framework.Assert; +import junit.framework.TestCase; +import org.apache.cloudstack.api.ResponseGenerator; + +import org.apache.cloudstack.api.command.user.volume.UpdateVolumeDetailCmd; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; +import static org.mockito.Mockito.*; + + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + + +public class UpdateVolumeDetailCmdTest extends TestCase{ + + private UpdateVolumeDetailCmd updateVolumeDetailCmd; + private ResponseGenerator responseGenerator; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Before + public void setUp() { + + updateVolumeDetailCmd = new UpdateVolumeDetailCmd(); + + //Account account = new AccountVO("testaccount", 1L, "networkdomain", (short) 0, "uuid"); + //UserContext.registerContext(1, account, null, true); + + } + + + @Test + public void testCreateSuccess() { + + VolumeApiService volumeService = Mockito.mock(VolumeApiService.class); + doNothing().when(volumeService).updateVolumeDetails(updateVolumeDetailCmd); + + } + +} diff --git a/api/test/org/apache/cloudstack/api/command/test/updateNicDetailCmdTest.java b/api/test/org/apache/cloudstack/api/command/test/updateNicDetailCmdTest.java new file mode 100644 index 00000000000..7143e2c36b4 --- /dev/null +++ b/api/test/org/apache/cloudstack/api/command/test/updateNicDetailCmdTest.java @@ -0,0 +1,62 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for updateitional 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. +package org.apache.cloudstack.api.command.test; + +import com.cloud.network.NetworkService; +import junit.framework.Assert; +import junit.framework.TestCase; +import org.apache.cloudstack.api.ResponseGenerator; + +import org.apache.cloudstack.api.command.user.network.UpdateNicDetailCmd; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; +import static org.mockito.Mockito.*; + + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + + +public class updateNicDetailCmdTest extends TestCase{ + + private UpdateNicDetailCmd updateNicDetailCmd; + private ResponseGenerator responseGenerator; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Before + public void setUp() { + + updateNicDetailCmd = new UpdateNicDetailCmd(); + + } + + + @Test + public void testCreateSuccess() { + + NetworkService networkService = Mockito.mock(NetworkService.class); + doNothing().when(networkService).updateNicDetail(updateNicDetailCmd); + + } + +} diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index b49e1fbf5ff..c4d0fcfa551 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -269,6 +269,10 @@ listVolumes=15 extractVolume=15 migrateVolume=15 resizeVolume=15 +addVolumeDetail=15 +updateVolumeDetail=15 +removeVolumeDetail=15 +listVolumeDetails=15 #### registration command: FIXME -- this really should be something in management server that #### generates a new key for the user and they just have to @@ -339,6 +343,9 @@ updateNetwork=15 addNicToVirtualMachine=15 removeNicFromVirtualMachine=15 updateDefaultNicForVirtualMachine=15 +addNicDetail=15 +updateNicDetail=15 +removeNicDetail=15 #### addIpToNic=15 diff --git a/core/src/com/cloud/storage/DiskOfferingVO.java b/core/src/com/cloud/storage/DiskOfferingVO.java index e4fc21c7c13..909d7fe6325 100755 --- a/core/src/com/cloud/storage/DiskOfferingVO.java +++ b/core/src/com/cloud/storage/DiskOfferingVO.java @@ -100,6 +100,9 @@ public class DiskOfferingVO implements DiskOffering { @Column(name="sort_key") int sortKey; + @Column(name="display_offering") + boolean displayOffering; + public DiskOfferingVO() { this.uuid = UUID.randomUUID().toString(); } @@ -315,4 +318,13 @@ public class DiskOfferingVO implements DiskOffering { public void setRecreatable(boolean recreatable) { this.recreatable = recreatable; } + + + public boolean getDisplayOffering() { + return displayOffering; + } + + public void setDisplayOffering(boolean displayOffering) { + this.displayOffering = displayOffering; + } } diff --git a/core/src/com/cloud/storage/VolumeDetailVO.java b/core/src/com/cloud/storage/VolumeDetailVO.java new file mode 100644 index 00000000000..b0c8c1dbf35 --- /dev/null +++ b/core/src/com/cloud/storage/VolumeDetailVO.java @@ -0,0 +1,85 @@ +// 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. +package com.cloud.storage; + +import org.apache.cloudstack.api.InternalIdentity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name="volume_details") +public class VolumeDetailVO implements InternalIdentity { + @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) + @Column(name="id") + private long id; + + @Column(name="volume_id") + private long volumeId; + + @Column(name="name") + private String name; + + @Column(name="value", length=1024) + private String value; + + public VolumeDetailVO() {} + + public VolumeDetailVO(long volumeId, String name, String value) { + this.volumeId = volumeId; + this.name = name; + this.value = value; + } + + public long getId() { + return id; + } + + public long getVolumeId() { + return volumeId; + } + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + + public void setId(long id) { + this.id = id; + } + + public void setVolumeId(long volumeId) { + this.volumeId = volumeId; + } + + public void setName(String name) { + this.name = name; + } + + public void setValue(String value) { + this.value = value; + } + +} diff --git a/core/src/com/cloud/storage/VolumeVO.java b/core/src/com/cloud/storage/VolumeVO.java index a287c26348b..1699afd320f 100755 --- a/core/src/com/cloud/storage/VolumeVO.java +++ b/core/src/com/cloud/storage/VolumeVO.java @@ -130,7 +130,10 @@ public class VolumeVO implements Volume { @Column(name = "uuid") String uuid; - + + @Column(name="display_volume", updatable=true, nullable=false) + protected boolean displayVolume; + @Transient // @Column(name="reservation") String reservationId; @@ -451,4 +454,13 @@ public class VolumeVO implements Volume { public void setUuid(String uuid) { this.uuid = uuid; } + + + public boolean isDisplayVolume() { + return displayVolume; + } + + public void setDisplayVolume(boolean displayVolume) { + this.displayVolume = displayVolume; + } } diff --git a/core/src/com/cloud/vm/VMInstanceVO.java b/core/src/com/cloud/vm/VMInstanceVO.java index 77e9c0279c9..5f930199548 100644 --- a/core/src/com/cloud/vm/VMInstanceVO.java +++ b/core/src/com/cloud/vm/VMInstanceVO.java @@ -111,6 +111,9 @@ public class VMInstanceVO implements VirtualMachine, FiniteStateObject { this(that.getSize(), that.getVolumeType(), that.getName(), that.getTemplateId()); this.recreatable = that.isRecreatable(); this.state = that.getState(); + this.size = that.getSize(); this.diskOfferingId = that.getDiskOfferingId(); this.poolId = that.getPoolId(); @@ -413,4 +414,5 @@ public class VolumeVO implements Identity, StateObject { public void setDiskType(DiskFormat type) { diskType = type; } + } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 894ec8d0e97..4cf261e6935 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -2394,6 +2394,7 @@ public class ApiResponseHelper implements ResponseGenerator { if (network.getAclType() != null) { response.setAclType(network.getAclType().toString()); } + response.setDisplayNetwork(network.getDisplayNetwork()); response.setState(network.getState().toString()); response.setRestartRequired(network.isRestartRequired()); NetworkVO nw = ApiDBUtils.findNetworkById(network.getRelated()); diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index 6690b24ca69..592757b6461 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -16,12 +16,7 @@ // under the License. package com.cloud.api.query; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import javax.ejb.Local; import javax.inject.Inject; @@ -29,6 +24,8 @@ import javax.inject.Inject; import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.affinity.AffinityGroupVMMapVO; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; +import com.cloud.storage.VolumeDetailVO; +import com.cloud.storage.dao.VolumeDetailsDao; import org.apache.cloudstack.api.command.admin.host.ListHostsCmd; import org.apache.cloudstack.api.command.admin.router.ListRoutersCmd; import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolsCmd; @@ -45,28 +42,12 @@ import org.apache.cloudstack.api.command.user.securitygroup.ListSecurityGroupsCm import org.apache.cloudstack.api.command.user.tag.ListTagsCmd; import org.apache.cloudstack.api.command.user.vm.ListVMsCmd; import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd; +import org.apache.cloudstack.api.command.user.volume.ListVolumeDetailsCmd; import org.apache.cloudstack.api.command.user.volume.ListVolumesCmd; import org.apache.cloudstack.api.command.user.zone.ListZonesByCmd; -import org.apache.cloudstack.api.response.AccountResponse; -import org.apache.cloudstack.api.response.AsyncJobResponse; -import org.apache.cloudstack.api.response.DiskOfferingResponse; -import org.apache.cloudstack.api.response.DomainRouterResponse; -import org.apache.cloudstack.api.response.EventResponse; -import org.apache.cloudstack.api.response.HostResponse; -import org.apache.cloudstack.api.response.InstanceGroupResponse; -import org.apache.cloudstack.api.response.ListResponse; -import org.apache.cloudstack.api.response.ProjectAccountResponse; -import org.apache.cloudstack.api.response.ProjectInvitationResponse; -import org.apache.cloudstack.api.response.ProjectResponse; -import org.apache.cloudstack.api.response.ResourceTagResponse; -import org.apache.cloudstack.api.response.SecurityGroupResponse; -import org.apache.cloudstack.api.response.ServiceOfferingResponse; -import org.apache.cloudstack.api.response.StoragePoolResponse; -import org.apache.cloudstack.api.response.UserResponse; -import org.apache.cloudstack.api.response.UserVmResponse; -import org.apache.cloudstack.api.response.VolumeResponse; -import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.cloudstack.api.response.*; import org.apache.cloudstack.query.QueryService; +import org.apache.commons.collections.map.HashedMap; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -245,6 +226,9 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { @Inject private DomainRouterDao _routerDao; + @Inject + private VolumeDetailsDao _volumeDetailDao; + @Inject private HighAvailabilityManager _haMgr; @@ -1508,6 +1492,34 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { return response; } + @Override + public List searchForVolumeDetails(ListVolumeDetailsCmd cmd){ + + Long id = cmd.getId(); + String name = cmd.getName(); + + List volumeDetailList; + if(name == null){ + volumeDetailList = _volumeDetailDao.findDetails(id); + }else{ + VolumeDetailVO volumeDetail = _volumeDetailDao.findDetail(id, name); + volumeDetailList = new LinkedList(); + volumeDetailList.add(volumeDetail); + } + + List volumeDetailResponseList = new ArrayList(); + for (VolumeDetailVO volumeDetail : volumeDetailList ){ + VolumeDetailResponse volumeDetailResponse = new VolumeDetailResponse(); + volumeDetailResponse.setId(id.toString()); + volumeDetailResponse.setName(volumeDetail.getName()); + volumeDetailResponse.setValue(volumeDetail.getValue()); + volumeDetailResponse.setObjectName("volumedetail"); + volumeDetailResponseList.add(volumeDetailResponse); + } + + return volumeDetailResponseList; + } + private Pair, Integer> searchForVolumesInternal(ListVolumesCmd cmd) { diff --git a/server/src/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java index 43c9d005121..283181f5245 100644 --- a/server/src/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java @@ -68,8 +68,9 @@ public class DiskOfferingJoinDaoImpl extends GenericDaoBase implem userVmResponse.setDomainName(userVm.getDomainName()); userVmResponse.setCreated(userVm.getCreated()); + userVmResponse.setDisplayVm(userVm.isDisplayVm()); if (userVm.getState() != null) { userVmResponse.setState(userVm.getState().toString()); diff --git a/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java index a7a0bf0b435..018745deda1 100644 --- a/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java @@ -195,6 +195,7 @@ public class VolumeJoinDaoImpl extends GenericDaoBase implem } volResponse.setExtractable(isExtractable); + volResponse.setDisplayVm(volume.isDisplayVolume()); // set async job volResponse.setJobId(volume.getJobUuid()); diff --git a/server/src/com/cloud/api/query/vo/DiskOfferingJoinVO.java b/server/src/com/cloud/api/query/vo/DiskOfferingJoinVO.java index 7785beeece3..6d3cdcb7fef 100644 --- a/server/src/com/cloud/api/query/vo/DiskOfferingJoinVO.java +++ b/server/src/com/cloud/api/query/vo/DiskOfferingJoinVO.java @@ -85,6 +85,9 @@ public class DiskOfferingJoinVO extends BaseViewVO implements InternalIdentity, @Column(name="domain_path") private String domainPath = null; + @Column(name="display_offering") + boolean displayOffering; + public DiskOfferingJoinVO() { } @@ -164,6 +167,14 @@ public class DiskOfferingJoinVO extends BaseViewVO implements InternalIdentity, this.customized = customized; } + public boolean isDisplayOffering() { + return displayOffering; + } + + public void setDisplayOffering(boolean displayOffering) { + this.displayOffering = displayOffering; + } + public Date getCreated() { return created; } diff --git a/server/src/com/cloud/api/query/vo/UserVmJoinVO.java b/server/src/com/cloud/api/query/vo/UserVmJoinVO.java index a50906d9e3d..7fdb93ea976 100644 --- a/server/src/com/cloud/api/query/vo/UserVmJoinVO.java +++ b/server/src/com/cloud/api/query/vo/UserVmJoinVO.java @@ -128,6 +128,9 @@ public class UserVmJoinVO extends BaseViewVO implements ControlledViewEntity { @Column(name="limit_cpu_use", updatable=true, nullable=true) private boolean limitCpuUse; + @Column(name="display_vm", updatable=true, nullable=false) + protected boolean displayVm = true; + @Column(name="last_host_id", updatable=true, nullable=true) private Long lastHostId; @@ -780,6 +783,13 @@ public class UserVmJoinVO extends BaseViewVO implements ControlledViewEntity { limitCpuUse = value; } + public boolean isDisplayVm() { + return displayVm; + } + + public void setDisplayVm(boolean displayVm) { + this.displayVm = displayVm; + } public String getDataCenterUuid() { return dataCenterUuid; diff --git a/server/src/com/cloud/api/query/vo/VolumeJoinVO.java b/server/src/com/cloud/api/query/vo/VolumeJoinVO.java index 8a4bfe5c0fa..e5e50b04a63 100644 --- a/server/src/com/cloud/api/query/vo/VolumeJoinVO.java +++ b/server/src/com/cloud/api/query/vo/VolumeJoinVO.java @@ -246,6 +246,9 @@ public class VolumeJoinVO extends BaseViewVO implements ControlledViewEntity { private String tagCustomer; + @Column(name="display_volume", updatable=true, nullable=false) + protected boolean displayVolume; + public VolumeJoinVO() { } @@ -387,6 +390,13 @@ public class VolumeJoinVO extends BaseViewVO implements ControlledViewEntity { } + public boolean isDisplayVolume() { + return displayVolume; + } + + public void setDisplayVolume(boolean displayVolume) { + this.displayVolume = displayVolume; + } @Override public String getAccountUuid() { diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java index 738c5bab35d..ca035afa4b4 100755 --- a/server/src/com/cloud/configuration/ConfigurationManager.java +++ b/server/src/com/cloud/configuration/ConfigurationManager.java @@ -93,9 +93,11 @@ public interface ConfigurationManager extends ConfigurationService, Manager { * @param numGibibytes * @param tags * @param isCustomized + * @param localStorageRequired + * @param isDisplayOfferingEnabled * @return newly created disk offering */ - DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized, boolean localStorageRequired); + DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized, boolean localStorageRequired, boolean isDisplayOfferingEnabled); /** * Creates a new pod diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index d5e405d5395..40cceb74a07 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -1727,7 +1727,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati userNetwork.setBroadcastDomainType(broadcastDomainType); userNetwork.setNetworkDomain(networkDomain); _networkMgr.setupNetwork(systemAccount, offering, userNetwork, plan, null, null, false, - Domain.ROOT_DOMAIN, null, null, null); + Domain.ROOT_DOMAIN, null, null, null, true); } } } @@ -1954,7 +1954,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati @Override @ActionEvent(eventType = EventTypes.EVENT_DISK_OFFERING_CREATE, eventDescription = "creating disk offering") - public DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized, boolean localStorageRequired) { + public DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized, boolean localStorageRequired, boolean isDisplayOfferingEnabled) { long diskSize = 0;// special case for custom disk offerings if (numGibibytes != null && (numGibibytes <= 0)) { throw new InvalidParameterValueException("Please specify a disk size of at least 1 Gb."); @@ -1973,6 +1973,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati tags = cleanupTags(tags); DiskOfferingVO newDiskOffering = new DiskOfferingVO(domainId, name, description, diskSize, tags, isCustomized); newDiskOffering.setUseLocalStorage(localStorageRequired); + newDiskOffering.setDisplayOffering(isDisplayOfferingEnabled); UserContext.current().setEventDetails("Disk offering id=" + newDiskOffering.getId()); DiskOfferingVO offering = _diskOfferingDao.persist(newDiskOffering); if (offering != null) { @@ -1988,6 +1989,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati String name = cmd.getOfferingName(); String description = cmd.getDisplayText(); Long numGibibytes = cmd.getDiskSize(); + boolean isDisplayOfferingEnabled = cmd.getDisplayOffering() != null ? cmd.getDisplayOffering() : true; boolean isCustomized = cmd.isCustomized() != null ? cmd.isCustomized() : false; // false // by // default @@ -2012,7 +2014,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } } - return createDiskOffering(domainId, name, description, numGibibytes, tags, isCustomized, localStorageRequired); + return createDiskOffering(domainId, name, description, numGibibytes, tags, isCustomized, localStorageRequired, isDisplayOfferingEnabled); } @Override @@ -2376,9 +2378,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati @Override @DB - public Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, Long podId, - String startIP, String endIP, String vlanGateway, String vlanNetmask, - String vlanId, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr) { + public Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, Long podId, + String startIP, String endIP, String vlanGateway, String vlanNetmask, + String vlanId, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr) { Network network = _networkModel.getNetwork(networkId); boolean ipv4 = false, ipv6 = false; diff --git a/server/src/com/cloud/network/dao/NetworkVO.java b/server/src/com/cloud/network/dao/NetworkVO.java index 77b40c8a5c9..7e4c6bcaa6b 100644 --- a/server/src/com/cloud/network/dao/NetworkVO.java +++ b/server/src/com/cloud/network/dao/NetworkVO.java @@ -163,6 +163,9 @@ public class NetworkVO implements Network { @Column(name="ip6_cidr") String ip6Cidr; + @Column(name="display_network", updatable=true, nullable=false) + protected boolean displayNetwork = true; + public NetworkVO() { this.uuid = UUID.randomUUID().toString(); } @@ -540,4 +543,13 @@ public class NetworkVO implements Network { public void setIp6Gateway(String ip6Gateway) { this.ip6Gateway = ip6Gateway; } + + @Override() + public boolean getDisplayNetwork() { + return displayNetwork; + } + + public void setDisplayNetwork(boolean displayNetwork) { + this.displayNetwork = displayNetwork; + } } diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 16127a22d95..485790a509d 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -2480,7 +2480,13 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(ListAffinityGroupsCmd.class); cmdList.add(UpdateVMAffinityGroupCmd.class); cmdList.add(ListAffinityGroupTypesCmd.class); - + cmdList.add(AddVolumeDetailCmd.class); + cmdList.add(UpdateVolumeDetailCmd.class); + cmdList.add(RemoveVolumeDetailCmd.class); + cmdList.add(ListVolumeDetailsCmd.class); + cmdList.add(AddNicDetailCmd.class); + cmdList.add(UpdateNicDetailCmd.class); + cmdList.add(RemoveNicDetailCmd.class); return cmdList; } diff --git a/server/src/com/cloud/storage/VolumeManagerImpl.java b/server/src/com/cloud/storage/VolumeManagerImpl.java index e57d393eb2d..73e96f4c8ae 100644 --- a/server/src/com/cloud/storage/VolumeManagerImpl.java +++ b/server/src/com/cloud/storage/VolumeManagerImpl.java @@ -36,14 +36,10 @@ import java.util.concurrent.ExecutionException; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.storage.dao.*; import org.apache.cloudstack.api.BaseCmd; -import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd; import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; +import org.apache.cloudstack.api.command.user.volume.*; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; @@ -122,18 +118,6 @@ import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.Volume.Event; import com.cloud.storage.Volume.Type; -import com.cloud.storage.dao.DiskOfferingDao; -import com.cloud.storage.dao.SnapshotDao; -import com.cloud.storage.dao.SnapshotPolicyDao; -import com.cloud.storage.dao.StoragePoolHostDao; -import com.cloud.storage.dao.StoragePoolWorkDao; -import com.cloud.storage.dao.VMTemplateDao; -import com.cloud.storage.dao.VMTemplateHostDao; -import com.cloud.storage.dao.VMTemplatePoolDao; -import com.cloud.storage.dao.VMTemplateS3Dao; -import com.cloud.storage.dao.VMTemplateSwiftDao; -import com.cloud.storage.dao.VolumeDao; -import com.cloud.storage.dao.VolumeHostDao; import com.cloud.storage.download.DownloadMonitor; import com.cloud.storage.s3.S3Manager; import com.cloud.storage.secondary.SecondaryStorageVmManager; @@ -302,6 +286,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { @Inject ConfigurationDao _configDao; @Inject + VolumeDetailsDao _volDetailDao; + @Inject ManagementServer _msServer; @Inject DataStoreManager dataStoreMgr; @@ -817,6 +803,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { Account caller = UserContext.current().getCaller(); long ownerId = cmd.getEntityOwnerId(); + Boolean displayVolumeEnabled = cmd.getDisplayVolume(); // permission check _accountMgr.checkAccess(caller, null, true, @@ -891,6 +878,10 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { size = diskOffering.getDiskSize(); } + if(displayVolumeEnabled == null){ + displayVolumeEnabled = true; + } + if (!validateVolumeSizeRange(size)) {// convert size from mb to gb // for validation throw new InvalidParameterValueException( @@ -971,6 +962,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { volume.setUpdated(new Date()); volume.setDomainId((caller == null) ? Domain.ROOT_DOMAIN : caller .getDomainId()); + volume.setDisplayVolume(displayVolumeEnabled); if (parentVolume != null) { volume.setTemplateId(parentVolume.getTemplateId()); } else { @@ -1781,6 +1773,66 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { return newVol; } + @Override + @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETAIL_UPDATE, eventDescription = "updating volume detail", async = true) + public void updateVolumeDetails(UpdateVolumeDetailCmd cmd){ + UserContext.current().setEventDetails("Volume Id: "+cmd.getId()); + Account caller = UserContext.current().getCaller(); + Long volumeId = cmd.getId(); + String name = cmd.getName(); + String value = cmd.getValue(); + + VolumeVO volume = _volsDao.findById(volumeId); + _accountMgr.checkAccess(caller, null, true, volume); + VolumeDetailVO volDetail = _volDetailDao.findDetail(volumeId, name); + if(volDetail != null){ + volDetail.setValue(value); + _volDetailDao.update(volDetail.getId(), volDetail); + }else{ + throw new InvalidParameterValueException("This detail doesnt exist for the volume "); + } + + } + + + @Override + @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETAIL_REMOVE, eventDescription = "removing volume detail", async = true) + public void removeVolumeDetail(RemoveVolumeDetailCmd cmd){ + UserContext.current().setEventDetails("Volume Id: "+cmd.getId()); + Account caller = UserContext.current().getCaller(); + Long volumeId = cmd.getId(); + String name = cmd.getName(); + + VolumeVO volume = _volsDao.findById(volumeId); + _accountMgr.checkAccess(caller, null, true, volume); + VolumeDetailVO volDetail = _volDetailDao.findDetail(volumeId, name); + if(volDetail != null){ + _volDetailDao.remove(volDetail.getId()); + }else{ + throw new InvalidParameterValueException("This detail doesnt exist for the volume "); + } + + } + + + @Override + @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETAIL_ADD, eventDescription = "adding volume detail", async = true) + public void addVolumeDetail(AddVolumeDetailCmd cmd){ + + Account caller = UserContext.current().getCaller(); + UserContext.current().setEventDetails("Volume Id: "+ cmd.getId()); + + Long volumeId = cmd.getId(); + String name = cmd.getName(); + String value = cmd.getValue(); + + VolumeVO volume = _volsDao.findById(volumeId); + _accountMgr.checkAccess(caller, null, true, volume); + VolumeDetailVO volDetail = new VolumeDetailVO(volumeId, name, value); + _volDetailDao.persist(volDetail); + } + + @Override @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "detaching volume", async = true) public Volume detachVolumeFromVM(DetachVolumeCmd cmmd) { diff --git a/server/src/com/cloud/storage/dao/VolumeDetailsDao.java b/server/src/com/cloud/storage/dao/VolumeDetailsDao.java new file mode 100644 index 00000000000..37a98d60fbe --- /dev/null +++ b/server/src/com/cloud/storage/dao/VolumeDetailsDao.java @@ -0,0 +1,33 @@ +// 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. +package com.cloud.storage.dao; + +import java.util.List; +import java.util.Map; + +import com.cloud.storage.VolumeDetailVO; +import com.cloud.utils.db.GenericDao; + +public interface VolumeDetailsDao extends GenericDao { + List findDetails(long volumeId); + + void persist(long vmId, Map details); + + VolumeDetailVO findDetail(long vmId, String name); + + void deleteDetails(long vmId); +} diff --git a/server/src/com/cloud/storage/dao/VolumeDetailsDaoImpl.java b/server/src/com/cloud/storage/dao/VolumeDetailsDaoImpl.java new file mode 100644 index 00000000000..d3967ea9dea --- /dev/null +++ b/server/src/com/cloud/storage/dao/VolumeDetailsDaoImpl.java @@ -0,0 +1,93 @@ +// 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. +package com.cloud.storage.dao; + +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; + +import com.cloud.storage.VolumeDetailVO; +import org.springframework.stereotype.Component; + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; + +@Component +@Local(value=VolumeDetailsDao.class) +public class VolumeDetailsDaoImpl extends GenericDaoBase implements VolumeDetailsDao { + protected final SearchBuilder VolumeSearch; + protected final SearchBuilder DetailSearch; + + public VolumeDetailsDaoImpl() { + VolumeSearch = createSearchBuilder(); + VolumeSearch.and("volumeId", VolumeSearch.entity().getVolumeId(), SearchCriteria.Op.EQ); + VolumeSearch.done(); + + DetailSearch = createSearchBuilder(); + DetailSearch.and("volumeId", DetailSearch.entity().getVolumeId(), SearchCriteria.Op.EQ); + DetailSearch.and("name", DetailSearch.entity().getName(), SearchCriteria.Op.EQ); + DetailSearch.done(); + } + + @Override + public void deleteDetails(long volumeId) { + SearchCriteria sc = VolumeSearch.create(); + sc.setParameters("volumeId", volumeId); + + List results = search(sc, null); + for (VolumeDetailVO result : results) { + remove(result.getId()); + } + } + + @Override + public VolumeDetailVO findDetail(long volumeId, String name) { + SearchCriteria sc = DetailSearch.create(); + sc.setParameters("volumeId", volumeId); + sc.setParameters("name", name); + + return findOneBy(sc); + } + + @Override + public List findDetails(long volumeId) { + SearchCriteria sc = VolumeSearch.create(); + sc.setParameters("volumeId", volumeId); + + List results = search(sc, null); + return results; + } + + @Override + public void persist(long volumeId, Map details) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + SearchCriteria sc = VolumeSearch.create(); + sc.setParameters("volumeId", volumeId); + expunge(sc); + + for (Map.Entry detail : details.entrySet()) { + VolumeDetailVO vo = new VolumeDetailVO(volumeId, detail.getKey(), detail.getValue()); + persist(vo); + } + txn.commit(); + } + +} diff --git a/server/src/com/cloud/vm/NicDetailVO.java b/server/src/com/cloud/vm/NicDetailVO.java new file mode 100644 index 00000000000..91499721e80 --- /dev/null +++ b/server/src/com/cloud/vm/NicDetailVO.java @@ -0,0 +1,85 @@ +// 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. +package com.cloud.vm; + +import org.apache.cloudstack.api.InternalIdentity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name="nic_details") +public class NicDetailVO implements InternalIdentity { + @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) + @Column(name="id") + private long id; + + @Column(name="nic_id") + private long nicId; + + @Column(name="name") + private String name; + + @Column(name="value", length=1024) + private String value; + + public NicDetailVO() {} + + public NicDetailVO(long nicId, String name, String value) { + this.nicId = nicId; + this.name = name; + this.value = value; + } + + public long getId() { + return id; + } + + public long getNicId() { + return nicId; + } + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + + public void setId(long id) { + this.id = id; + } + + public void setNicId(long nicId) { + this.nicId = nicId; + } + + public void setName(String name) { + this.name = name; + } + + public void setValue(String value) { + this.value = value; + } + +} diff --git a/server/src/com/cloud/vm/NicDetailsVO.java b/server/src/com/cloud/vm/NicDetailsVO.java new file mode 100644 index 00000000000..f7cc9df22e0 --- /dev/null +++ b/server/src/com/cloud/vm/NicDetailsVO.java @@ -0,0 +1,11 @@ +package com.cloud.vm; + +/** + * Created with IntelliJ IDEA. + * User: nitinmehta + * Date: 15/04/13 + * Time: 5:03 PM + * To change this template use File | Settings | File Templates. + */ +public class NicDetailsVO { +} diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index ebc5757770e..5bc3a166896 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -1572,6 +1572,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use String displayName = cmd.getDisplayName(); String group = cmd.getGroup(); Boolean ha = cmd.getHaEnable(); + Boolean isDisplayVmEnabled = cmd.getDisplayVm(); Long id = cmd.getId(); Long osTypeId = cmd.getOsTypeId(); String userData = cmd.getUserData(); @@ -1605,6 +1606,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use ha = vmInstance.isHaEnabled(); } + if (isDisplayVmEnabled == null) { + isDisplayVmEnabled = vmInstance.isDisplayVm(); + } + UserVmVO vm = _vmDao.findById(id); if (vm == null) { throw new CloudRuntimeException( @@ -1653,7 +1658,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } } - _vmDao.updateVM(id, displayName, ha, osTypeId, userData); + _vmDao.updateVM(id, displayName, ha, osTypeId, userData, isDisplayVmEnabled); if (updateUserdata) { boolean result = updateUserDataInternal(_vmDao.findById(id)); @@ -1945,9 +1950,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use public UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData, String sshKeyPair, - Map requestedIps, IpAddresses defaultIps, String keyboard, + Map requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List affinityGroupIdList) - throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { + throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { Account caller = UserContext.current().getCaller(); List networkList = new ArrayList(); @@ -1997,16 +2002,17 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod, userData, sshKeyPair, hypervisor, - caller, requestedIps, defaultIps, keyboard, affinityGroupIdList); + caller, requestedIps, defaultIps, displayVm, keyboard, affinityGroupIdList); + } @Override public UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, List securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, - Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData, - String sshKeyPair, Map requestedIps, IpAddresses defaultIps, String keyboard, - List affinityGroupIdList) throws InsufficientCapacityException, ConcurrentOperationException, - ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { + Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData, + String sshKeyPair, Map requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, + List affinityGroupIdList) throws InsufficientCapacityException, ConcurrentOperationException, + ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { Account caller = UserContext.current().getCaller(); List networkList = new ArrayList(); @@ -2113,15 +2119,15 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod, userData, sshKeyPair, hypervisor, - caller, requestedIps, defaultIps, keyboard, affinityGroupIdList); + caller, requestedIps, defaultIps, displayVm, keyboard, affinityGroupIdList); } @Override public UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, Account owner, String hostName, - String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, + String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData, String sshKeyPair, Map requestedIps, - IpAddresses defaultIps, String keyboard, List affinityGroupIdList) - throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { + IpAddresses defaultIps, Boolean displayvm, String keyboard, List affinityGroupIdList) + throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { Account caller = UserContext.current().getCaller(); List networkList = new ArrayList(); @@ -2165,7 +2171,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use s_logger.debug("Creating network for account " + owner + " from the network offering id=" +requiredOfferings.get(0).getId() + " as a part of deployVM process"); Network newNetwork = _networkMgr.createGuestNetwork(requiredOfferings.get(0).getId(), owner.getAccountName() + "-network", owner.getAccountName() + "-network", null, null, - null, null, owner, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, null, null); + null, null, owner, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, null, null, true); defaultNetwork = _networkDao.findById(newNetwork.getId()); } else if (virtualNetworks.size() > 1) { throw new InvalidParameterValueException( @@ -2230,7 +2236,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, null, group, httpmethod, userData, sshKeyPair, hypervisor, caller, requestedIps, - defaultIps, keyboard, affinityGroupIdList); + defaultIps, displayvm, keyboard, affinityGroupIdList); } @@ -2243,9 +2249,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use @DB @ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true) protected UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, String hostName, String displayName, Account owner, Long diskOfferingId, - Long diskSize, List networkList, List securityGroupIdList, String group, HTTPMethod httpmethod, + Long diskSize, List networkList, List securityGroupIdList, String group, HTTPMethod httpmethod, String userData, String sshKeyPair, HypervisorType hypervisor, Account caller, Map requestedIps, - IpAddresses defaultIps, String keyboard, List affinityGroupIdList) + IpAddresses defaultIps, Boolean displayvm, String keyboard, List affinityGroupIdList) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, StorageUnavailableException, ResourceAllocationException { _accountMgr.checkAccess(caller, null, true, owner); @@ -2510,6 +2516,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } else { hypervisorType = template.getHypervisorType(); } + Transaction txn = Transaction.currentTxn(); txn.start(); UserVmVO vm = new UserVmVO(id, instanceName, displayName, @@ -2530,6 +2537,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use vm.setIsoId(template.getId()); } + if(displayvm != null){ + vm.setDisplayVm(displayvm); + }else { + vm.setDisplayVm(true); + } + // If hypervisor is vSphere, check for clone type setting. if (hypervisorType.equals(HypervisorType.VMware)) { // retrieve clone flag. @@ -4003,7 +4016,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use requiredOfferings.get(0).getId() + " as a part of deployVM process"); Network newNetwork = _networkMgr.createGuestNetwork(requiredOfferings.get(0).getId(), newAccount.getAccountName() + "-network", newAccount.getAccountName() + "-network", null, null, - null, null, newAccount, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, null, null); + null, null, newAccount, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, null, null, true); // if the network offering has persistent set to true, implement the network if (requiredOfferings.get(0).getIsPersistent()) { DeployDestination dest = new DeployDestination(zone, null, null, null); diff --git a/server/src/com/cloud/vm/dao/NicDetailDao.java b/server/src/com/cloud/vm/dao/NicDetailDao.java new file mode 100644 index 00000000000..ff6802bd376 --- /dev/null +++ b/server/src/com/cloud/vm/dao/NicDetailDao.java @@ -0,0 +1,32 @@ +// 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. +package com.cloud.vm.dao; + +import java.util.Map; + +import com.cloud.utils.db.GenericDao; +import com.cloud.vm.NicDetailVO; + +public interface NicDetailDao extends GenericDao { + Map findDetails(long nicId); + + void persist(long nicId, Map details); + + NicDetailVO findDetail(long nicId, String name); + + void deleteDetails(long nicId); +} diff --git a/server/src/com/cloud/vm/dao/NicDetailDaoImpl.java b/server/src/com/cloud/vm/dao/NicDetailDaoImpl.java new file mode 100644 index 00000000000..519e4e7d3ae --- /dev/null +++ b/server/src/com/cloud/vm/dao/NicDetailDaoImpl.java @@ -0,0 +1,98 @@ +// 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. +package com.cloud.vm.dao; + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.vm.NicDetailVO; +import org.springframework.stereotype.Component; + +import javax.ejb.Local; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +@Local(value = { NicDetailDao.class }) +public class NicDetailDaoImpl extends GenericDaoBase implements NicDetailDao { + protected final SearchBuilder NicSearch; + protected final SearchBuilder DetailSearch; + + public NicDetailDaoImpl() { + NicSearch = createSearchBuilder(); + NicSearch.and("nicId", NicSearch.entity().getNicId(), SearchCriteria.Op.EQ); + NicSearch.done(); + + DetailSearch = createSearchBuilder(); + DetailSearch.and("nicId", DetailSearch.entity().getNicId(), SearchCriteria.Op.EQ); + DetailSearch.and("name", DetailSearch.entity().getName(), SearchCriteria.Op.EQ); + DetailSearch.done(); + } + + @Override + public void deleteDetails(long nicId) { + SearchCriteria sc = NicSearch.create(); + sc.setParameters("nicId", nicId); + + List results = search(sc, null); + for (NicDetailVO result : results) { + remove(result.getId()); + } + } + + @Override + public NicDetailVO findDetail(long nicId, String name) { + SearchCriteria sc = DetailSearch.create(); + sc.setParameters("nicId", nicId); + sc.setParameters("name", name); + + return findOneBy(sc); + } + + @Override + public Map findDetails(long nicId) { + SearchCriteria sc = NicSearch.create(); + sc.setParameters("nicId", nicId); + + List results = search(sc, null); + Map details = new HashMap(results.size()); + for (NicDetailVO result : results) { + details.put(result.getName(), result.getValue()); + } + + return details; + } + + @Override + public void persist(long nicId, Map details) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + SearchCriteria sc = NicSearch.create(); + sc.setParameters("nicId", nicId); + expunge(sc); + + for (Map.Entry detail : details.entrySet()) { + NicDetailVO vo = new NicDetailVO(nicId, detail.getKey(), detail.getValue()); + persist(vo); + } + txn.commit(); + } + + +} diff --git a/server/src/com/cloud/vm/dao/UserVmDao.java b/server/src/com/cloud/vm/dao/UserVmDao.java index 81d13cda2ed..e7cd61bddfe 100755 --- a/server/src/com/cloud/vm/dao/UserVmDao.java +++ b/server/src/com/cloud/vm/dao/UserVmDao.java @@ -38,8 +38,9 @@ public interface UserVmDao extends GenericDao { * @param id vm id. * @param displan name and enable for ha * @param userData updates the userData of the vm + * @param displayVm updates the displayvm attribute signifying whether it has to be displayed to the end user or not. */ - void updateVM(long id, String displayName, boolean enable, Long osTypeId, String userData); + void updateVM(long id, String displayName, boolean enable, Long osTypeId, String userData, boolean displayVm); List findDestroyedVms(Date date); diff --git a/server/src/com/cloud/vm/dao/UserVmDaoImpl.java b/server/src/com/cloud/vm/dao/UserVmDaoImpl.java index c2fd6481875..5e8be1054a9 100755 --- a/server/src/com/cloud/vm/dao/UserVmDaoImpl.java +++ b/server/src/com/cloud/vm/dao/UserVmDaoImpl.java @@ -224,12 +224,13 @@ public class UserVmDaoImpl extends GenericDaoBase implements Use } @Override - public void updateVM(long id, String displayName, boolean enable, Long osTypeId, String userData) { + public void updateVM(long id, String displayName, boolean enable, Long osTypeId, String userData, boolean displayVm) { UserVmVO vo = createForUpdate(); vo.setDisplayName(displayName); vo.setHaEnabled(enable); vo.setGuestOSId(osTypeId); vo.setUserData(userData); + vo.setDisplayVm(displayVm); update(id, vo); } diff --git a/server/test/com/cloud/vm/MockUserVmManagerImpl.java b/server/test/com/cloud/vm/MockUserVmManagerImpl.java index d886fd8697f..46eb6eb15f6 100644 --- a/server/test/com/cloud/vm/MockUserVmManagerImpl.java +++ b/server/test/com/cloud/vm/MockUserVmManagerImpl.java @@ -23,7 +23,10 @@ import java.util.Map; import javax.ejb.Local; import javax.naming.ConfigurationException; + import org.apache.cloudstack.api.BaseCmd.HTTPMethod; + +import com.cloud.hypervisor.Hypervisor; import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd; @@ -339,11 +342,10 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager, return null; } - @Override public UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData, String sshKeyPair, Map requestedIps, - IpAddresses defaultIp, String keyboard, List affinityGroupIdList) + IpAddresses defaultIp, Boolean displayVm, String keyboard, List affinityGroupIdList) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { // TODO Auto-generated method stub @@ -355,7 +357,7 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager, List securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIps, - String keyboard, List affinityGroupIdList) throws InsufficientCapacityException, + Boolean displayVm, String keyboard, List affinityGroupIdList) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { // TODO Auto-generated method stub return null; @@ -365,7 +367,7 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager, public UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData, String sshKeyPair, Map requestedIps, - IpAddresses defaultIps, String keyboard, List affinityGroupIdList) throws InsufficientCapacityException, + IpAddresses defaultIps, Boolean displayVm, String keyboard, List affinityGroupIdList) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { // TODO Auto-generated method stub return null; diff --git a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java index 6cda294fbe7..46568603ec4 100755 --- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -75,13 +75,11 @@ import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.Availability; import com.cloud.offering.ServiceOffering; import com.cloud.offerings.NetworkOfferingVO; -import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.offerings.dao.NetworkOfferingDaoImpl; import com.cloud.org.Grouping.AllocationState; import com.cloud.service.ServiceOfferingVO; import com.cloud.storage.DiskOfferingVO; import com.cloud.user.Account; -import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.vm.VirtualMachine.Type; @@ -511,7 +509,7 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu */ @Override public Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, Long podId, String startIP, String endIP, String vlanGateway, String vlanNetmask, String vlanId, - Account vlanOwner, String startIPv6, String endIPv6, String vlanGatewayv6, String vlanCidrv6) throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException { + Account vlanOwner, String startIPv6, String endIPv6, String vlanGatewayv6, String vlanCidrv6) throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException { // TODO Auto-generated method stub return null; } @@ -598,10 +596,10 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu } /* (non-Javadoc) - * @see com.cloud.configuration.ConfigurationManager#createDiskOffering(java.lang.Long, java.lang.String, java.lang.String, java.lang.Long, java.lang.String, boolean, boolean) + * @see com.cloud.configuration.ConfigurationManager#createDiskOffering(java.lang.Long, java.lang.String, java.lang.String, java.lang.Long, java.lang.String, boolean, boolean, boolean) */ @Override - public DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized, boolean localStorageRequired) { + public DiskOfferingVO createDiskOffering(Long domainId, String name, String description, Long numGibibytes, String tags, boolean isCustomized, boolean localStorageRequired, boolean isDisplayOfferingEnabled) { // TODO Auto-generated method stub return null; } diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index 78444fd5576..2154d1cfeb2 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -243,6 +243,58 @@ ALTER TABLE `cloud`.`external_load_balancer_devices` ADD COLUMN `gslb_site_publi ALTER TABLE `cloud`.`external_load_balancer_devices` ADD COLUMN `gslb_site_privateip` varchar(255) DEFAULT NULL COMMENT 'GSLB service Provider site private ip'; +ALTER TABLE `cloud`.`vm_instance` ADD COLUMN `display_vm` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Should vm instance be displayed to the end user'; + +ALTER TABLE `cloud`.`user_vm_details` ADD COLUMN `display_detail` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Should vm detail instance be displayed to the end user'; + +ALTER TABLE `cloud`.`volumes` ADD COLUMN `display_volume` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Should volume be displayed to the end user'; + +ALTER TABLE `cloud`.`networks` ADD COLUMN `display_network` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Should network be displayed to the end user'; + +ALTER TABLE `cloud`.`nics` ADD COLUMN `display_nic` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Should nic be displayed to the end user'; + +ALTER TABLE `cloud`.`disk_offering` ADD COLUMN `display_offering` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Should disk offering be displayed to the end user'; + +CREATE TABLE `cloud`.`volume_details` ( + `id` bigint unsigned NOT NULL auto_increment, + `volume_id` bigint unsigned NOT NULL COMMENT 'volume id', + `name` varchar(255) NOT NULL, + `value` varchar(1024) NOT NULL, + `display_detail` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Should detail be displayed to the end user', + PRIMARY KEY (`id`), + CONSTRAINT `fk_volume_details__volume_id` FOREIGN KEY `fk_volume_details__volume_id`(`volume_id`) REFERENCES `volumes`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`network_details` ( + `id` bigint unsigned NOT NULL auto_increment, + `network_id` bigint unsigned NOT NULL COMMENT 'network id', + `name` varchar(255) NOT NULL, + `value` varchar(1024) NOT NULL, + `display_detail` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Should detail be displayed to the end user', + PRIMARY KEY (`id`), + CONSTRAINT `fk_network_details__network_id` FOREIGN KEY `fk_network_details__network_id`(`network_id`) REFERENCES `networks`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`nic_details` ( + `id` bigint unsigned NOT NULL auto_increment, + `nic_id` bigint unsigned NOT NULL COMMENT 'nic id', + `name` varchar(255) NOT NULL, + `value` varchar(1024) NOT NULL, + `display_detail` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Should detail be displayed to the end user', + PRIMARY KEY (`id`), + CONSTRAINT `fk_nic_details__nic_id` FOREIGN KEY `fk_nic_details__nic_id`(`nic_id`) REFERENCES `nics`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`disk_offering_details` ( + `id` bigint unsigned NOT NULL auto_increment, + `offering_id` bigint unsigned NOT NULL COMMENT 'offering id', + `name` varchar(255) NOT NULL, + `value` varchar(1024) NOT NULL, + `display_detail` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Should detail be displayed to the end user', + PRIMARY KEY (`id`), + CONSTRAINT `fk_offering_details__offering_id` FOREIGN KEY `fk_offering_details__offering_id`(`offering_id`) REFERENCES `disk_offering`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + CREATE TABLE `cloud`.`global_load_balancing_rules` ( `id` bigint unsigned NOT NULL auto_increment COMMENT 'id', `uuid` varchar(40), @@ -1110,3 +1162,301 @@ CREATE VIEW `cloud`.`account_view` AS and async_job.job_status = 0; alter table `cloud_usage`.`usage_network_offering` add column nic_id bigint(20) unsigned NOT NULL; +DROP VIEW IF EXISTS `cloud`.`disk_offering_view`; +CREATE VIEW `cloud`.`disk_offering_view` AS + select + disk_offering.id, + disk_offering.uuid, + disk_offering.name, + disk_offering.display_text, + disk_offering.disk_size, + disk_offering.created, + disk_offering.tags, + disk_offering.customized, + disk_offering.removed, + disk_offering.use_local_storage, + disk_offering.system_use, + disk_offering.sort_key, + disk_offering.type, + disk_offering.display_offering, + domain.id domain_id, + domain.uuid domain_uuid, + domain.name domain_name, + domain.path domain_path + from + `cloud`.`disk_offering` + left join + `cloud`.`domain` ON disk_offering.domain_id = domain.id; + +DROP VIEW IF EXISTS `cloud`.`user_vm_view`; +CREATE VIEW `cloud`.`user_vm_view` AS + select + vm_instance.id id, + vm_instance.name name, + user_vm.display_name display_name, + user_vm.user_data user_data, + account.id account_id, + account.uuid account_uuid, + account.account_name account_name, + account.type account_type, + domain.id domain_id, + domain.uuid domain_uuid, + domain.name domain_name, + domain.path domain_path, + projects.id project_id, + projects.uuid project_uuid, + projects.name project_name, + instance_group.id instance_group_id, + instance_group.uuid instance_group_uuid, + instance_group.name instance_group_name, + vm_instance.uuid uuid, + vm_instance.last_host_id last_host_id, + vm_instance.vm_type type, + vm_instance.vnc_password vnc_password, + vm_instance.limit_cpu_use limit_cpu_use, + vm_instance.created created, + vm_instance.state state, + vm_instance.removed removed, + vm_instance.ha_enabled ha_enabled, + vm_instance.hypervisor_type hypervisor_type, + vm_instance.instance_name instance_name, + vm_instance.guest_os_id guest_os_id, + vm_instance.display_vm display_vm, + guest_os.uuid guest_os_uuid, + vm_instance.pod_id pod_id, + host_pod_ref.uuid pod_uuid, + vm_instance.private_ip_address private_ip_address, + vm_instance.private_mac_address private_mac_address, + vm_instance.vm_type vm_type, + data_center.id data_center_id, + data_center.uuid data_center_uuid, + data_center.name data_center_name, + data_center.is_security_group_enabled security_group_enabled, + host.id host_id, + host.uuid host_uuid, + host.name host_name, + vm_template.id template_id, + vm_template.uuid template_uuid, + vm_template.name template_name, + vm_template.display_text template_display_text, + vm_template.enable_password password_enabled, + iso.id iso_id, + iso.uuid iso_uuid, + iso.name iso_name, + iso.display_text iso_display_text, + service_offering.id service_offering_id, + disk_offering.uuid service_offering_uuid, + service_offering.cpu cpu, + service_offering.speed speed, + service_offering.ram_size ram_size, + disk_offering.name service_offering_name, + storage_pool.id pool_id, + storage_pool.uuid pool_uuid, + storage_pool.pool_type pool_type, + volumes.id volume_id, + volumes.uuid volume_uuid, + volumes.device_id volume_device_id, + volumes.volume_type volume_type, + security_group.id security_group_id, + security_group.uuid security_group_uuid, + security_group.name security_group_name, + security_group.description security_group_description, + nics.id nic_id, + nics.uuid nic_uuid, + nics.network_id network_id, + nics.ip4_address ip_address, + nics.ip6_address ip6_address, + nics.ip6_gateway ip6_gateway, + nics.ip6_cidr ip6_cidr, + nics.default_nic is_default_nic, + nics.gateway gateway, + nics.netmask netmask, + nics.mac_address mac_address, + nics.broadcast_uri broadcast_uri, + nics.isolation_uri isolation_uri, + vpc.id vpc_id, + vpc.uuid vpc_uuid, + networks.uuid network_uuid, + networks.name network_name, + networks.traffic_type traffic_type, + networks.guest_type guest_type, + user_ip_address.id public_ip_id, + user_ip_address.uuid public_ip_uuid, + user_ip_address.public_ip_address public_ip_address, + ssh_keypairs.keypair_name keypair_name, + resource_tags.id tag_id, + resource_tags.uuid tag_uuid, + resource_tags.key tag_key, + resource_tags.value tag_value, + resource_tags.domain_id tag_domain_id, + resource_tags.account_id tag_account_id, + resource_tags.resource_id tag_resource_id, + resource_tags.resource_uuid tag_resource_uuid, + resource_tags.resource_type tag_resource_type, + resource_tags.customer tag_customer, + async_job.id job_id, + async_job.uuid job_uuid, + async_job.job_status job_status, + async_job.account_id job_account_id + from + `cloud`.`user_vm` + inner join + `cloud`.`vm_instance` ON vm_instance.id = user_vm.id + and vm_instance.removed is NULL + inner join + `cloud`.`account` ON vm_instance.account_id = account.id + inner join + `cloud`.`domain` ON vm_instance.domain_id = domain.id + left join + `cloud`.`guest_os` ON vm_instance.guest_os_id = guest_os.id + left join + `cloud`.`host_pod_ref` ON vm_instance.pod_id = host_pod_ref.id + left join + `cloud`.`projects` ON projects.project_account_id = account.id + left join + `cloud`.`instance_group_vm_map` ON vm_instance.id = instance_group_vm_map.instance_id + left join + `cloud`.`instance_group` ON instance_group_vm_map.group_id = instance_group.id + left join + `cloud`.`data_center` ON vm_instance.data_center_id = data_center.id + left join + `cloud`.`host` ON vm_instance.host_id = host.id + left join + `cloud`.`vm_template` ON vm_instance.vm_template_id = vm_template.id + left join + `cloud`.`vm_template` iso ON iso.id = user_vm.iso_id + left join + `cloud`.`service_offering` ON vm_instance.service_offering_id = service_offering.id + left join + `cloud`.`disk_offering` ON vm_instance.service_offering_id = disk_offering.id + left join + `cloud`.`volumes` ON vm_instance.id = volumes.instance_id + left join + `cloud`.`storage_pool` ON volumes.pool_id = storage_pool.id + left join + `cloud`.`security_group_vm_map` ON vm_instance.id = security_group_vm_map.instance_id + left join + `cloud`.`security_group` ON security_group_vm_map.security_group_id = security_group.id + left join + `cloud`.`nics` ON vm_instance.id = nics.instance_id + left join + `cloud`.`networks` ON nics.network_id = networks.id + left join + `cloud`.`vpc` ON networks.vpc_id = vpc.id + left join + `cloud`.`user_ip_address` ON user_ip_address.vm_id = vm_instance.id + left join + `cloud`.`user_vm_details` ON user_vm_details.vm_id = vm_instance.id + and user_vm_details.name = 'SSH.PublicKey' + left join + `cloud`.`ssh_keypairs` ON ssh_keypairs.public_key = user_vm_details.value + left join + `cloud`.`resource_tags` ON resource_tags.resource_id = vm_instance.id + and resource_tags.resource_type = 'UserVm' + left join + `cloud`.`async_job` ON async_job.instance_id = vm_instance.id + and async_job.instance_type = 'VirtualMachine' + and async_job.job_status = 0; + +DROP VIEW IF EXISTS `cloud`.`volume_view`; +CREATE VIEW `cloud`.`volume_view` AS + select + volumes.id, + volumes.uuid, + volumes.name, + volumes.device_id, + volumes.volume_type, + volumes.size, + volumes.created, + volumes.state, + volumes.attached, + volumes.removed, + volumes.pod_id, + volumes.display_volume, + account.id account_id, + account.uuid account_uuid, + account.account_name account_name, + account.type account_type, + domain.id domain_id, + domain.uuid domain_uuid, + domain.name domain_name, + domain.path domain_path, + projects.id project_id, + projects.uuid project_uuid, + projects.name project_name, + data_center.id data_center_id, + data_center.uuid data_center_uuid, + data_center.name data_center_name, + vm_instance.id vm_id, + vm_instance.uuid vm_uuid, + vm_instance.name vm_name, + vm_instance.state vm_state, + vm_instance.vm_type, + user_vm.display_name vm_display_name, + volume_host_ref.size volume_host_size, + volume_host_ref.created volume_host_created, + volume_host_ref.format, + volume_host_ref.download_pct, + volume_host_ref.download_state, + volume_host_ref.error_str, + disk_offering.id disk_offering_id, + disk_offering.uuid disk_offering_uuid, + disk_offering.name disk_offering_name, + disk_offering.display_text disk_offering_display_text, + disk_offering.use_local_storage, + disk_offering.system_use, + storage_pool.id pool_id, + storage_pool.uuid pool_uuid, + storage_pool.name pool_name, + cluster.hypervisor_type, + vm_template.id template_id, + vm_template.uuid template_uuid, + vm_template.extractable, + vm_template.type template_type, + resource_tags.id tag_id, + resource_tags.uuid tag_uuid, + resource_tags.key tag_key, + resource_tags.value tag_value, + resource_tags.domain_id tag_domain_id, + resource_tags.account_id tag_account_id, + resource_tags.resource_id tag_resource_id, + resource_tags.resource_uuid tag_resource_uuid, + resource_tags.resource_type tag_resource_type, + resource_tags.customer tag_customer, + async_job.id job_id, + async_job.uuid job_uuid, + async_job.job_status job_status, + async_job.account_id job_account_id + from + `cloud`.`volumes` + inner join + `cloud`.`account` ON volumes.account_id = account.id + inner join + `cloud`.`domain` ON volumes.domain_id = domain.id + left join + `cloud`.`projects` ON projects.project_account_id = account.id + left join + `cloud`.`data_center` ON volumes.data_center_id = data_center.id + left join + `cloud`.`vm_instance` ON volumes.instance_id = vm_instance.id + left join + `cloud`.`user_vm` ON user_vm.id = vm_instance.id + left join + `cloud`.`volume_host_ref` ON volumes.id = volume_host_ref.volume_id + and volumes.data_center_id = volume_host_ref.zone_id + left join + `cloud`.`disk_offering` ON volumes.disk_offering_id = disk_offering.id + left join + `cloud`.`storage_pool` ON volumes.pool_id = storage_pool.id + left join + `cloud`.`cluster` ON storage_pool.cluster_id = cluster.id + left join + `cloud`.`vm_template` ON volumes.template_id = vm_template.id + left join + `cloud`.`resource_tags` ON resource_tags.resource_id = volumes.id + and resource_tags.resource_type = 'Volume' + left join + `cloud`.`async_job` ON async_job.instance_id = volumes.id + and async_job.instance_type = 'Volume' + and async_job.job_status = 0; + From 242f5f9cf7f2bb923c746d207be2f57dfd36f2a8 Mon Sep 17 00:00:00 2001 From: Nitin Mehta Date: Sat, 27 Apr 2013 11:08:02 +0530 Subject: [PATCH 007/114] =More changes and marvin test --- api/src/com/cloud/network/NetworkService.java | 11 +- client/tomcatconf/applicationContext.xml.in | 2 + .../com/cloud/api/query/QueryManagerImpl.java | 4 +- .../src/com/cloud/network/NetworkManager.java | 6 +- .../com/cloud/network/NetworkManagerImpl.java | 15 +- .../com/cloud/network/NetworkServiceImpl.java | 66 ++++- .../src/com/cloud/network/vpc/VpcManager.java | 8 +- .../com/cloud/network/vpc/VpcManagerImpl.java | 8 +- server/src/com/cloud/vm/NicDetailsVO.java | 11 - .../com/cloud/vm/dao/NicDetailDaoImpl.java | 4 +- .../cloud/network/MockNetworkManagerImpl.java | 26 +- .../com/cloud/vpc/MockNetworkManagerImpl.java | 24 +- .../com/cloud/vpc/MockVpcManagerImpl.java | 2 +- setup/db/db/schema-410to420.sql | 1 + test/integration/smoke/test_volumedetail.py | 239 ++++++++++++++++++ 15 files changed, 372 insertions(+), 55 deletions(-) delete mode 100644 server/src/com/cloud/vm/NicDetailsVO.java create mode 100644 test/integration/smoke/test_volumedetail.py diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java index 5a6054da23b..f9e6238a697 100755 --- a/api/src/com/cloud/network/NetworkService.java +++ b/api/src/com/cloud/network/NetworkService.java @@ -19,9 +19,7 @@ package com.cloud.network; import java.util.List; import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; -import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; -import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; -import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; +import org.apache.cloudstack.api.command.user.network.*; import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; import com.cloud.exception.ConcurrentOperationException; @@ -165,4 +163,11 @@ public interface NetworkService { /* lists the nic informaton */ List listNics(ListNicsCmd listNicsCmd); + + void removeNicDetail(RemoveNicDetailCmd removeNicDetailCmd); + + void addNicDetail(AddNicDetailCmd cmd); + + void updateNicDetail(UpdateNicDetailCmd cmd); + } diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index d2ea380ddab..09e80b3bc59 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -256,6 +256,7 @@ + @@ -355,6 +356,7 @@ + diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index 592757b6461..a1a4113e074 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -21,6 +21,7 @@ import java.util.*; import javax.ejb.Local; import javax.inject.Inject; +import com.cloud.api.ApiDBUtils; import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.affinity.AffinityGroupVMMapVO; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; @@ -1510,7 +1511,8 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { List volumeDetailResponseList = new ArrayList(); for (VolumeDetailVO volumeDetail : volumeDetailList ){ VolumeDetailResponse volumeDetailResponse = new VolumeDetailResponse(); - volumeDetailResponse.setId(id.toString()); + String uuid = ApiDBUtils.findVolumeById(id).getUuid(); + volumeDetailResponse.setId(uuid); volumeDetailResponse.setName(volumeDetail.getName()); volumeDetailResponse.setValue(volumeDetail.getValue()); volumeDetailResponse.setObjectName("volumedetail"); diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index 4af716ca12a..8a33a95314d 100755 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -99,7 +99,7 @@ public interface NetworkManager { throws ConcurrentOperationException; List setupNetwork(Account owner, NetworkOffering offering, Network predefined, DeploymentPlan plan, String name, String displayText, boolean errorIfAlreadySetup, Long domainId, - ACLType aclType, Boolean subdomainAccess, Long vpcId) throws ConcurrentOperationException; + ACLType aclType, Boolean subdomainAccess, Long vpcId, Boolean isDisplayNetworkEnabled) throws ConcurrentOperationException; void allocate(VirtualMachineProfile vm, List> networks) throws InsufficientCapacityException, ConcurrentOperationException; @@ -127,8 +127,8 @@ public interface NetworkManager { boolean destroyNetwork(long networkId, ReservationContext context); Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, - String vlanId, String networkDomain, Account owner, Long domainId, PhysicalNetwork physicalNetwork, - long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr) + String vlanId, String networkDomain, Account owner, Long domainId, PhysicalNetwork physicalNetwork, + long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr, Boolean displayNetworkEnabled) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException; /** diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 72ccac0ec7d..ea5338949db 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -1091,14 +1091,14 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L public List setupNetwork(Account owner, NetworkOffering offering, DeploymentPlan plan, String name, String displayText, boolean isDefault) throws ConcurrentOperationException { - return setupNetwork(owner, offering, null, plan, name, displayText, false, null, null, null, null); + return setupNetwork(owner, offering, null, plan, name, displayText, false, null, null, null, null, true); } @Override @DB public List setupNetwork(Account owner, NetworkOffering offering, Network predefined, DeploymentPlan plan, String name, String displayText, boolean errorIfAlreadySetup, Long domainId, - ACLType aclType, Boolean subdomainAccess, Long vpcId) throws ConcurrentOperationException { + ACLType aclType, Boolean subdomainAccess, Long vpcId, Boolean isDisplayNetworkEnabled) throws ConcurrentOperationException { Account locked = _accountDao.acquireInLockTable(owner.getId()); if (locked == null) { @@ -1173,6 +1173,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L NetworkVO vo = new NetworkVO(id, network, offering.getId(), guru.getName(), owner.getDomainId(), owner.getId(), related, name, displayText, predefined.getNetworkDomain(), offering.getGuestType(), plan.getDataCenterId(), plan.getPhysicalNetworkId(), aclType, offering.getSpecifyIpRanges(), vpcId); + vo.setDisplayNetwork(isDisplayNetworkEnabled); networks.add(_networksDao.persist(vo, vo.getGuestType() == Network.GuestType.Isolated, finalizeServicesAndProvidersForNetwork(offering, plan.getPhysicalNetworkId()))); @@ -1862,9 +1863,9 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L @Override @DB - public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, - String cidr, String vlanId, String networkDomain, Account owner, Long domainId, - PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr) + public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, + String cidr, String vlanId, String networkDomain, Account owner, Long domainId, + PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr, Boolean isDisplayNetworkEnabled) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId); @@ -2094,7 +2095,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L } List networks = setupNetwork(owner, ntwkOff, userNetwork, plan, name, displayText, true, domainId, - aclType, subdomainAccess, vpcId); + aclType, subdomainAccess, vpcId, isDisplayNetworkEnabled); Network network = null; if (networks == null || networks.isEmpty()) { @@ -2687,7 +2688,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L guestNetwork = createGuestNetwork(requiredOfferings.get(0).getId(), owner.getAccountName() + "-network" , owner.getAccountName() + "-network", null, null, null, null, owner, null, physicalNetwork, zoneId, ACLType.Account, - null, null, null, null); + null, null, null, null, true); if (guestNetwork == null) { s_logger.warn("Failed to create default Virtual network for the account " + accountId + "in zone " + zoneId); throw new CloudRuntimeException("Failed to create a Guest Isolated Networks with SourceNAT " + diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 7653a0816f0..5d62bc3b9cf 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -86,9 +86,7 @@ import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.SecurityChecker; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; -import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; -import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; -import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; +import org.apache.cloudstack.api.command.user.network.*; import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -203,6 +201,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { HostPodDao _hostPodDao; @Inject DataCenterVnetDao _datacneter_vnet; + @Inject + NicDetailDao _nicDetailDao = null; int _cidrLimit; boolean _allowSubdomainNetworkAccess; @@ -817,6 +817,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { String endIPv6 = cmd.getEndIpv6(); String ip6Gateway = cmd.getIp6Gateway(); String ip6Cidr = cmd.getIp6Cidr(); + Boolean isDisplayNetworkEnabled = cmd.getDisplayNetwork(); // Validate network offering NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId); @@ -1098,13 +1099,13 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { throw new InvalidParameterValueException("Network offering can't be used for VPC networks"); } network = _vpcMgr.createVpcGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId, - networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, caller); + networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, caller, isDisplayNetworkEnabled); } else { if (_configMgr.isOfferingForVpc(ntwkOff)){ throw new InvalidParameterValueException("Network offering can be used for VPC networks only"); } network = _networkMgr.createGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId, - networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, ip6Gateway, ip6Cidr); + networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, ip6Gateway, ip6Cidr, isDisplayNetworkEnabled); } if (caller.getType() == Account.ACCOUNT_TYPE_ADMIN && createVlan) { @@ -3347,7 +3348,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { if (privateNetwork == null) { //create Guest network privateNetwork = _networkMgr.createGuestNetwork(ntwkOff.getId(), networkName, displayText, gateway, cidr, vlan, - null, owner, null, pNtwk, pNtwk.getDataCenterId(), ACLType.Account, null, null, null, null); + null, owner, null, pNtwk, pNtwk.getDataCenterId(), ACLType.Account, null, null, null, null, true); s_logger.debug("Created private network " + privateNetwork); } else { s_logger.debug("Private network already exists: " + privateNetwork); @@ -3407,4 +3408,57 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { _accountMgr.checkAccess(caller, null, true, userVm); return _networkMgr.listVmNics(vmId, nicId); } + + @Override + public void addNicDetail(AddNicDetailCmd cmd){ + UserContext.current().setEventDetails("Nic Id: " + cmd.getId()); + Account caller = UserContext.current().getCaller(); + Long nicId = cmd.getId(); + String name = cmd.getName(); + String value = cmd.getValue(); + + NicVO nic = _nicDao.findById(nicId); + + //_accountMgr.checkAccess(caller, null, true, nic); + NicDetailVO nicDetail = new NicDetailVO(nicId, name, value); + _nicDetailDao.persist(nicDetail); + } + + @Override + public void updateNicDetail(UpdateNicDetailCmd cmd){ + UserContext.current().setEventDetails("Nic Id: " + cmd.getId()); + Account caller = UserContext.current().getCaller(); + Long nicId = cmd.getId(); + String name = cmd.getName(); + String value = cmd.getValue(); + + NicVO nic = _nicDao.findById(nicId); + // _accountMgr.checkAccess(caller, null, true, nic); + NicDetailVO nicDetail = _nicDetailDao.findDetail(nicId, name); + if(nicDetail != null){ + nicDetail.setValue(value); + _nicDetailDao.update(nicDetail.getId(), nicDetail); + }else{ + throw new InvalidParameterValueException("This detail doesnt exist for the nic"); + } + + } + + @Override + public void removeNicDetail(RemoveNicDetailCmd cmd){ + Account caller = UserContext.current().getCaller(); + Long nicId = cmd.getId(); + String name = cmd.getName(); + + NicVO nic = _nicDao.findById(nicId); + //_accountMgr.checkAccess(caller, null, true, nic); + NicDetailVO nicDetail = _nicDetailDao.findDetail(nicId, name); + if(nicDetail != null){ + _nicDetailDao.remove(nicDetail.getId()); + }else{ + throw new InvalidParameterValueException("This detail doesnt exist for the nic "); + } + + } + } diff --git a/server/src/com/cloud/network/vpc/VpcManager.java b/server/src/com/cloud/network/vpc/VpcManager.java index 84ab8ef5dd7..3fad1aa1b0d 100644 --- a/server/src/com/cloud/network/vpc/VpcManager.java +++ b/server/src/com/cloud/network/vpc/VpcManager.java @@ -82,6 +82,7 @@ public interface VpcManager extends VpcService{ /** * Creates guest network in the VPC * + * * @param ntwkOffId * @param name * @param displayText @@ -97,14 +98,15 @@ public interface VpcManager extends VpcService{ * @param subdomainAccess * @param vpcId * @param caller + * @param displayNetworkEnabled * @return * @throws ConcurrentOperationException * @throws InsufficientCapacityException * @throws ResourceAllocationException */ - Network createVpcGuestNetwork(long ntwkOffId, String name, String displayText, String gateway, String cidr, - String vlanId, String networkDomain, Account owner, Long domainId, PhysicalNetwork pNtwk, long zoneId, - ACLType aclType, Boolean subdomainAccess, long vpcId, Account caller) + Network createVpcGuestNetwork(long ntwkOffId, String name, String displayText, String gateway, String cidr, + String vlanId, String networkDomain, Account owner, Long domainId, PhysicalNetwork pNtwk, long zoneId, + ACLType aclType, Boolean subdomainAccess, long vpcId, Account caller, Boolean displayNetworkEnabled) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException; diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index 224a6800326..4e171aa5509 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -1938,9 +1938,9 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis @DB @Override - public Network createVpcGuestNetwork(long ntwkOffId, String name, String displayText, String gateway, - String cidr, String vlanId, String networkDomain, Account owner, Long domainId, - PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess, long vpcId, Account caller) + public Network createVpcGuestNetwork(long ntwkOffId, String name, String displayText, String gateway, + String cidr, String vlanId, String networkDomain, Account owner, Long domainId, + PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess, long vpcId, Account caller, Boolean isDisplayNetworkEnabled) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { Vpc vpc = getActiveVpc(vpcId); @@ -1965,7 +1965,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis //2) Create network Network guestNetwork = _ntwkMgr.createGuestNetwork(ntwkOffId, name, displayText, gateway, cidr, vlanId, - networkDomain, owner, domainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, null, null); + networkDomain, owner, domainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, null, null, isDisplayNetworkEnabled); return guestNetwork; } diff --git a/server/src/com/cloud/vm/NicDetailsVO.java b/server/src/com/cloud/vm/NicDetailsVO.java deleted file mode 100644 index f7cc9df22e0..00000000000 --- a/server/src/com/cloud/vm/NicDetailsVO.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.cloud.vm; - -/** - * Created with IntelliJ IDEA. - * User: nitinmehta - * Date: 15/04/13 - * Time: 5:03 PM - * To change this template use File | Settings | File Templates. - */ -public class NicDetailsVO { -} diff --git a/server/src/com/cloud/vm/dao/NicDetailDaoImpl.java b/server/src/com/cloud/vm/dao/NicDetailDaoImpl.java index 519e4e7d3ae..fd110359473 100644 --- a/server/src/com/cloud/vm/dao/NicDetailDaoImpl.java +++ b/server/src/com/cloud/vm/dao/NicDetailDaoImpl.java @@ -16,6 +16,8 @@ // under the License. package com.cloud.vm.dao; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.VolumeDao; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; @@ -29,7 +31,7 @@ import java.util.List; import java.util.Map; @Component -@Local(value = { NicDetailDao.class }) +@Local (value={NicDetailDao.class}) public class NicDetailDaoImpl extends GenericDaoBase implements NicDetailDao { protected final SearchBuilder NicSearch; protected final SearchBuilder DetailSearch; diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index 6a0263ee334..521dccfcdbb 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -45,19 +45,16 @@ import com.cloud.utils.Pair; import com.cloud.utils.component.ManagerBase; import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; -import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.NicVO; import com.cloud.vm.ReservationContext; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.VirtualMachineProfile; -import com.cloud.vm.VirtualMachineProfileImpl; +import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; -import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; -import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; -import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; +import org.apache.cloudstack.api.command.user.network.*; import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; import org.springframework.stereotype.Component; @@ -178,7 +175,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage @Override public List setupNetwork(Account owner, NetworkOffering offering, Network predefined, DeploymentPlan plan, String name, String displayText, boolean errorIfAlreadySetup, Long domainId, - ACLType aclType, Boolean subdomainAccess, Long vpcId) throws ConcurrentOperationException { + ACLType aclType, Boolean subdomainAccess, Long vpcId, Boolean isDisplayNetworkEnabled) throws ConcurrentOperationException { // TODO Auto-generated method stub return null; } @@ -249,7 +246,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage @Override public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner, Long domainId, - PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String gatewayv6, String cidrv6) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { + PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String gatewayv6, String cidrv6, Boolean displayNetworkEnabled) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { // TODO Auto-generated method stub return null; } @@ -862,6 +859,21 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage return null; } + @Override + public void removeNicDetail(RemoveNicDetailCmd removeNicDetailCmd) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void addNicDetail(AddNicDetailCmd addNicDetailCmd) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void updateNicDetail(UpdateNicDetailCmd updateNicDetailCmd) { + //To change body of implemented methods use File | Settings | File Templates. + } + @Override public String allocatePublicIpForGuestNic(Long networkId, DataCenter dc, Pod pod, Account caller, String requestedIp) diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index bfcccf54bf0..1a811a55110 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -49,19 +49,15 @@ import com.cloud.utils.Pair; import com.cloud.utils.component.ManagerBase; import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; -import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.NicVO; import com.cloud.vm.ReservationContext; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.VirtualMachineProfile; -import com.cloud.vm.VirtualMachineProfileImpl; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; -import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; -import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; -import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; +import org.apache.cloudstack.api.command.user.network.*; import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -666,7 +662,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage @Override public List setupNetwork(Account owner, NetworkOffering offering, Network predefined, DeploymentPlan plan, String name, String displayText, boolean errorIfAlreadySetup, Long domainId, - ACLType aclType, Boolean subdomainAccess, Long vpcId) throws ConcurrentOperationException { + ACLType aclType, Boolean subdomainAccess, Long vpcId, Boolean isNetworkDisplayEnabled) throws ConcurrentOperationException { // TODO Auto-generated method stub return null; } @@ -830,8 +826,8 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage */ @Override public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, - String cidr, String vlanId, String networkDomain, Account owner, Long domainId, - PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String gatewayv6, String cidrv6) + String cidr, String vlanId, String networkDomain, Account owner, Long domainId, + PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String gatewayv6, String cidrv6, Boolean displayNetworkEnabled) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { // TODO Auto-generated method stub return null; @@ -1370,8 +1366,20 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage return null; } + @Override + public void removeNicDetail(RemoveNicDetailCmd removeNicDetailCmd) { + //To change body of implemented methods use File | Settings | File Templates. + } + @Override + public void addNicDetail(AddNicDetailCmd addNicDetailCmd) { + //To change body of implemented methods use File | Settings | File Templates. + } + @Override + public void updateNicDetail(UpdateNicDetailCmd updateNicDetailCmd) { + //To change body of implemented methods use File | Settings | File Templates. + } @Override diff --git a/server/test/com/cloud/vpc/MockVpcManagerImpl.java b/server/test/com/cloud/vpc/MockVpcManagerImpl.java index 0f269284127..feda7f398bd 100644 --- a/server/test/com/cloud/vpc/MockVpcManagerImpl.java +++ b/server/test/com/cloud/vpc/MockVpcManagerImpl.java @@ -303,7 +303,7 @@ public class MockVpcManagerImpl extends ManagerBase implements VpcManager { */ @Override public Network createVpcGuestNetwork(long ntwkOffId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner, Long domainId, PhysicalNetwork pNtwk, - long zoneId, ACLType aclType, Boolean subdomainAccess, long vpcId, Account caller) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { + long zoneId, ACLType aclType, Boolean subdomainAccess, long vpcId, Account caller, Boolean displayNetworkEnabled) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { // TODO Auto-generated method stub return null; } diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index 2154d1cfeb2..10781b0909c 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -1387,6 +1387,7 @@ CREATE VIEW `cloud`.`volume_view` AS data_center.id data_center_id, data_center.uuid data_center_uuid, data_center.name data_center_name, + data_center.networktype data_center_type, vm_instance.id vm_id, vm_instance.uuid vm_uuid, vm_instance.name vm_name, diff --git a/test/integration/smoke/test_volumedetail.py b/test/integration/smoke/test_volumedetail.py new file mode 100644 index 00000000000..f734dbb4de6 --- /dev/null +++ b/test/integration/smoke/test_volumedetail.py @@ -0,0 +1,239 @@ +# 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. +""" P1 tests for Scaling up Vm +""" +#Import Local Modules +import marvin +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.remoteSSHClient import remoteSSHClient +from marvin.integration.lib.utils import * +from marvin.integration.lib.base import * +from marvin.integration.lib.common import * +from nose.plugins.attrib import attr +#Import System modules +import time + +_multiprocess_shared_ = True +class Services: + """Test VM Life Cycle Services + """ + + def __init__(self): + self.services = { + + "account": { + "email": "test@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + # Random characters are appended in create account to + # ensure unique username generated each time + "password": "password", + }, + "small": + # Create a small virtual machine instance with disk offering + { + "displayname": "testserver", + "username": "root", # VM creds for SSH + "password": "password", + "ssh_port": 22, + "hypervisor": 'XenServer', + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + }, + "disk_offering": { + "displaytext": "Small", + "name": "Small", + "storagetype": "shared", + "disksize": 1 + }, + "service_offerings": + { + "small": + { + # Small service offering ID to for change VM + # service offering from medium to small + "name": "SmallInstance", + "displaytext": "SmallInstance", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 256, + }, + "big": + { + # Big service offering ID to for change VM + "name": "BigInstance", + "displaytext": "BigInstance", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 512, + } + }, + #Change this + "template": { + "displaytext": "xs", + "name": "xs", + "passwordenabled": False, + }, + "diskdevice": '/dev/xvdd', + # Disk device where ISO is attached to instance + "mount_dir": "/mnt/tmp", + "sleep": 60, + "timeout": 10, + #Migrate VM to hostid + "ostype": 'CentOS 5.6 (64-bit)', + # CentOS 5.3 (64-bit) + } + +class TestVolumeDetail(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cls.api_client = super(TestVolumeDetail, cls).getClsTestClient().getApiClient() + cls.services = Services().services + + # Get Zone, Domain and templates + domain = get_domain(cls.api_client, cls.services) + zone = get_zone(cls.api_client, cls.services) + cls.services['mode'] = zone.networktype + + # Set Zones and disk offerings ?? + + # Create account, service offerings, vm. + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=domain.id + ) + + + cls.disk_offering = DiskOffering.create( + cls.api_client, + cls.services["disk_offering"] + ) + + #create a volume + cls.volume = Volume.create( + cls.api_client, + { "diskname" : "ndm"}, + zoneid=zone.id, + account=cls.account.name, + domainid=cls.account.domainid, + diskofferingid=cls.disk_offering.id + ) + #how does it work ?? + cls._cleanup = [ + cls.volume, + cls.account + ] + + @classmethod + def tearDownClass(cls): + cls.api_client = super(TestVolumeDetail, cls).getClsTestClient().getApiClient() + cleanup_resources(cls.api_client, cls._cleanup) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + + def tearDown(self): + #Clean up, terminate the created ISOs + cleanup_resources(self.apiclient, self.cleanup) + return + + @attr(tags = ["advanced", "xenserver"]) + def test_01_updatevolumedetail(self): + """Test volume detail + """ + # Validate the following + # Scale up the vm and see if it scales to the new svc offering and is finally in running state + + self.debug("Testing ADD volume detail Volume-ID: %s " % ( + self.volume.id + )) + + cmd = addVolumeDetail.addVolumeDetailCmd() + cmd.name = self.volume.id + cmd.value = self.volume.id + cmd.id = self.volume.id + self.apiclient.addVolumeDetail(cmd) + + listVolumeDetailCmd = listVolumeDetails.listVolumeDetailsCmd() + listVolumeDetailCmd.id = self.volume.id + listVolumeDetailResponse = self.api_client.listVirtualMachines(listVolumeDetailCmd) + + self.assertNotEqual(len(listVolumeDetailResponse), 0, "Check if the list API \ + returns a non-empty response") + + volumedetail = listVolumeDetailResponse[0] + + #self.assertEqual(volumedetail.id, self.volume.id, "Check if the Volume returned is the same as the one we asked for") + + + self.assertEqual(volumedetail.name, self.volume.id, "Check if Volume has right name") + + self.assertEqual(volumedetail.value, self.volume.id, "Check if Volume has right value") + + #updatevolumedetail + self.debug("Testing UPDATE volume detail Volume-ID: %s " % ( + self.volume.id + )) + cmd = updateVolumeDetail.updateVolumeDetailCmd() + cmd.name = self.volume.id + cmd.value = self.disk_offering.id + cmd.id = self.volume.id + self.apiclient.addVolumeDetail(cmd) + + listVolumeDetailCmd = listVolumeDetails.listVolumeDetailsCmd() + listVolumeDetailCmd.id = self.volume.id + listVolumeDetailResponse = self.api_client.listVirtualMachines(listVolumeDetailCmd) + + self.assertNotEqual(len(listVolumeDetailResponse), 0, "Check if the list API \ + returns a non-empty response") + + volumedetail = listVolumeDetailResponse[0] + + #self.assertEqual(volumedetail.id, self.volume.id, "Check if the Volume returned is the same as the one we asked for") + + + self.assertEqual(volumedetail.name, self.volume.id, "Check if Volume has right name") + + self.assertEqual(volumedetail.value, self.disk_offering.id, "Check if Volume has right value") + + + #remove detail + self.debug("Testing REMOVE volume detail Volume-ID: %s " % ( + self.volume.id + )) + cmd = removeVolumeDetail.removeVolumeDetailCmd() + cmd.name = self.volume.id + cmd.id = self.volume.id + self.apiclient.removeVolumeDetail(cmd) + + listVolumeDetailCmd = listVolumeDetails.listVolumeDetailsCmd() + listVolumeDetailCmd.id = self.volume.id + listVolumeDetailResponse = self.api_client.listVirtualMachines(listVolumeDetailCmd) + + self.assertEqual(listVolumeDetailResponse, None, "Check if the list API \ + returns a non-empty response") + + + return From 335aca3f549d56b19e39d08f3107b9eb13b8ae52 Mon Sep 17 00:00:00 2001 From: Nitin Mehta Date: Sun, 28 Apr 2013 10:28:31 +0530 Subject: [PATCH 008/114] =changes #2 --- api/src/com/cloud/event/EventTypes.java | 4 + .../com/cloud/storage/VolumeApiService.java | 2 + .../apache/cloudstack/api/ApiConstants.java | 1 + .../command/user/network/AddNicDetailCmd.java | 9 +- .../user/network/ListNicDetailsCmd.java | 77 ++++++ .../user/network/RemoveNicDetailCmd.java | 6 +- .../user/volume/ListVolumeDetailCmd.java | 11 - .../user/volume/ListVolumeDetailsCmd.java | 2 +- .../command/user/volume/UpdateVolumeCmd.java | 31 +-- .../api/response/NicDetailResponse.java | 81 +++++++ .../api/response/VolumeDetailResponse.java | 2 +- .../apache/cloudstack/query/QueryService.java | 4 +- client/tomcatconf/commands.properties.in | 16 +- .../com/cloud/api/query/QueryManagerImpl.java | 36 ++- .../cloud/server/ManagementServerImpl.java | 2 + .../com/cloud/storage/VolumeManagerImpl.java | 20 ++ .../src/com/cloud/vm/UserVmManagerImpl.java | 14 +- server/src/com/cloud/vm/dao/NicDetailDao.java | 3 +- .../com/cloud/vm/dao/NicDetailDaoImpl.java | 11 +- test/integration/smoke/test_nicdetail.py | 224 ++++++++++++++++++ 20 files changed, 494 insertions(+), 62 deletions(-) create mode 100644 api/src/org/apache/cloudstack/api/command/user/network/ListNicDetailsCmd.java delete mode 100644 api/src/org/apache/cloudstack/api/command/user/volume/ListVolumeDetailCmd.java create mode 100644 api/src/org/apache/cloudstack/api/response/NicDetailResponse.java create mode 100644 test/integration/smoke/test_nicdetail.py diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index 7737089f99b..afa441ebdde 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -103,6 +103,10 @@ public class EventTypes { public static final String EVENT_NIC_CREATE = "NIC.CREATE"; public static final String EVENT_NIC_DELETE = "NIC.DELETE"; public static final String EVENT_NIC_UPDATE = "NIC.UPDATE"; + public static final String EVENT_NIC_DETAIL_ADD = "NIC.DETAIL.ADD"; + public static final String EVENT_NIC_DETAIL_UPDATE = "NIC.DETAIL.UPDATE"; + public static final String EVENT_NIC_DETAIL_REMOVE = "NIC.DETAIL.REMOVE"; + // Load Balancers public static final String EVENT_ASSIGN_TO_LOAD_BALANCER_RULE = "LB.ASSIGN.TO.RULE"; diff --git a/api/src/com/cloud/storage/VolumeApiService.java b/api/src/com/cloud/storage/VolumeApiService.java index 1f70c5b4e54..047d1242d7a 100644 --- a/api/src/com/cloud/storage/VolumeApiService.java +++ b/api/src/com/cloud/storage/VolumeApiService.java @@ -80,4 +80,6 @@ public interface VolumeApiService { void removeVolumeDetail(RemoveVolumeDetailCmd removeVolumeDetailCmd); void addVolumeDetail(AddVolumeDetailCmd addVolumeDetailCmd); + + Volume updateVolume(UpdateVolumeCmd updateVolumeCmd); } diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 8ff4b0b44ac..4eca1c46c8f 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -57,6 +57,7 @@ public class ApiConstants { public static final String DISK_SIZE = "disksize"; public static final String DISPLAY_NAME = "displayname"; public static final String DISPLAY_NETWORK = "displaynetwork"; + public static final String DISPLAY_NIC = "displaynic"; public static final String DISPLAY_TEXT = "displaytext"; public static final String DISPLAY_VM = "displayvm"; public static final String DISPLAY_OFFERING = "displayoffering"; diff --git a/api/src/org/apache/cloudstack/api/command/user/network/AddNicDetailCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/AddNicDetailCmd.java index e5f7a0e80eb..230cd7e4163 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/AddNicDetailCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/AddNicDetailCmd.java @@ -91,16 +91,13 @@ public class AddNicDetailCmd extends BaseAsyncCmd { @Override public long getEntityOwnerId() { - Volume volume = _responseGenerator.findVolumeById(getId()); - if (volume == null) { - return Account.ACCOUNT_ID_SYSTEM; // bad id given, parent this command to SYSTEM so ERROR events are tracked - } - return volume.getAccountId(); + Account caller = UserContext.current().getCaller(); + return caller.getAccountId(); } @Override public String getEventType() { - return EventTypes.EVENT_VOLUME_ATTACH; + return EventTypes.EVENT_NIC_CREATE; } @Override diff --git a/api/src/org/apache/cloudstack/api/command/user/network/ListNicDetailsCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/ListNicDetailsCmd.java new file mode 100644 index 00000000000..84f3589efda --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/network/ListNicDetailsCmd.java @@ -0,0 +1,77 @@ +// 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. +package org.apache.cloudstack.api.command.user.network; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseListTaggedResourcesCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.*; +import org.apache.log4j.Logger; + +import java.util.List; + + +@APICommand(name = "listNicDetails", description="Lists all nic details.", responseObject=NicDetailResponse.class) +public class ListNicDetailsCmd extends BaseListTaggedResourcesCmd { + public static final Logger s_logger = Logger.getLogger(ListNicDetailsCmd.class.getName()); + + private static final String s_name = "listnicdetailsresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=NicResponse.class, + required=true, description="the ID of the nic") + private Long id; + + @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, description="the name of the nic detail") + private String name; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + + + @Override + public void execute(){ + ListResponse responses = new ListResponse(); + List nicDetailList = _queryService.searchForNicDetails(this); + responses.setResponses(nicDetailList); + responses.setResponseName(getCommandName()); + this.setResponseObject(responses); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/user/network/RemoveNicDetailCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/RemoveNicDetailCmd.java index fe7503f57ee..abea5152dd2 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/RemoveNicDetailCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/RemoveNicDetailCmd.java @@ -48,11 +48,11 @@ public class RemoveNicDetailCmd extends BaseAsyncCmd { private Long id; @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, - required=true, description="the name of the field") + required=false, description="the name of the field") private String name; @Parameter(name=ApiConstants.VALUE, type=CommandType.STRING, - required=true, description="the value of the field") + required=false, description="the value of the field") private String value; ///////////////////////////////////////////////////// @@ -100,7 +100,7 @@ public class RemoveNicDetailCmd extends BaseAsyncCmd { @Override public String getEventType() { - return EventTypes.EVENT_VOLUME_ATTACH; + return EventTypes.EVENT_NIC_DETAIL_REMOVE; } @Override diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumeDetailCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumeDetailCmd.java deleted file mode 100644 index db53eb4a0b9..00000000000 --- a/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumeDetailCmd.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.apache.cloudstack.api.command.user.volume; - -/** - * Created with IntelliJ IDEA. - * User: nitinmehta - * Date: 24/04/13 - * Time: 5:18 PM - * To change this template use File | Settings | File Templates. - */ -public class ListVolumeDetailCmd { -} diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumeDetailsCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumeDetailsCmd.java index a0424b6957a..fc064cca1d6 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumeDetailsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumeDetailsCmd.java @@ -30,7 +30,7 @@ import java.util.List; @APICommand(name = "listVolumeDetails", description="Lists all volume details.", responseObject=VolumeDetailResponse.class) public class ListVolumeDetailsCmd extends BaseListTaggedResourcesCmd { - public static final Logger s_logger = Logger.getLogger(ListVolumesCmd.class.getName()); + public static final Logger s_logger = Logger.getLogger(ListVolumeDetailsCmd.class.getName()); private static final String s_name = "listvolumedetailsresponse"; diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/UpdateVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/UpdateVolumeCmd.java index 1f35a432848..3453eef9187 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/UpdateVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/UpdateVolumeCmd.java @@ -32,10 +32,10 @@ import com.cloud.storage.Volume; import com.cloud.user.Account; import com.cloud.user.UserContext; -@APICommand(name = "updateVolumeDetail", description="Updates the volume.", responseObject=VolumeResponse.class) +@APICommand(name = "updateVolume", description="Updates the volume.", responseObject=VolumeResponse.class) public class UpdateVolumeCmd extends BaseAsyncCmd { - public static final Logger s_logger = Logger.getLogger(AttachVolumeCmd.class.getName()); - private static final String s_name = "addVolumeDetailresponse"; + public static final Logger s_logger = Logger.getLogger(UpdateVolumeCmd.class.getName()); + private static final String s_name = "addVolumeresponse"; ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// @@ -45,25 +45,16 @@ public class UpdateVolumeCmd extends BaseAsyncCmd { required=true, description="the ID of the disk volume") private Long id; - @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, - required=true, description="the name of the field") - private String name; - - @Parameter(name=ApiConstants.VALUE, type=CommandType.STRING, entityType=UserVmResponse.class, - required=true, description="the value of the field") - private String value; + @Parameter(name=ApiConstants.PATH, type=CommandType.STRING, + required=true, description="the path of the volume") + private String path; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// - - public String getName() { - return name; - } - - public String getValue() { - return value; + public String getPath() { + return path; } public Long getId() { @@ -109,13 +100,13 @@ public class UpdateVolumeCmd extends BaseAsyncCmd { @Override public void execute(){ UserContext.current().setEventDetails("Volume Id: "+getId()); - /*Volume result = _volumeService.attachVolumeToVM(this); + Volume result = _volumeService.updateVolume(this); if (result != null) { VolumeResponse response = _responseGenerator.createVolumeResponse(result); response.setResponseName(getCommandName()); this.setResponseObject(response); } else { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to attach volume"); - } */ + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update volume"); + } } } diff --git a/api/src/org/apache/cloudstack/api/response/NicDetailResponse.java b/api/src/org/apache/cloudstack/api/response/NicDetailResponse.java new file mode 100644 index 00000000000..f8ddf1c8250 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/NicDetailResponse.java @@ -0,0 +1,81 @@ +// 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. +package org.apache.cloudstack.api.response; + +import java.util.Date; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +@SuppressWarnings("unused") +public class NicDetailResponse extends BaseResponse{ + @SerializedName(ApiConstants.ID) + @Param(description = "ID of the nic") + private String id; + + @SerializedName(ApiConstants.NAME) + @Param(description = "name of the nic detail") + private String name; + + + @SerializedName(ApiConstants.VALUE) + @Param(description = "value of the nic detail") + private String value; + + @SerializedName(ApiConstants.DISPLAY_NIC) @Param(description="an optional field whether to the display the nic to the end user or not.") + private Boolean displayNic; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getName() { + + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Boolean getDisplayNic() { + return displayNic; + } + + public void setDisplayNic(Boolean displayNic) { + this.displayNic = displayNic; + } +} diff --git a/api/src/org/apache/cloudstack/api/response/VolumeDetailResponse.java b/api/src/org/apache/cloudstack/api/response/VolumeDetailResponse.java index 3a8fab9b300..04d280d0d9f 100644 --- a/api/src/org/apache/cloudstack/api/response/VolumeDetailResponse.java +++ b/api/src/org/apache/cloudstack/api/response/VolumeDetailResponse.java @@ -31,7 +31,7 @@ import com.google.gson.annotations.SerializedName; @SuppressWarnings("unused") public class VolumeDetailResponse extends BaseResponse{ - @SerializedName(ApiConstants.VOLUME_ID) + @SerializedName(ApiConstants.ID) @Param(description = "ID of the volume") private String id; diff --git a/api/src/org/apache/cloudstack/query/QueryService.java b/api/src/org/apache/cloudstack/query/QueryService.java index e821f3cd335..16c07672a16 100644 --- a/api/src/org/apache/cloudstack/query/QueryService.java +++ b/api/src/org/apache/cloudstack/query/QueryService.java @@ -25,6 +25,7 @@ import org.apache.cloudstack.api.command.user.account.ListAccountsCmd; import org.apache.cloudstack.api.command.user.account.ListProjectAccountsCmd; import org.apache.cloudstack.api.command.user.event.ListEventsCmd; import org.apache.cloudstack.api.command.user.job.ListAsyncJobsCmd; +import org.apache.cloudstack.api.command.user.network.ListNicDetailsCmd; import org.apache.cloudstack.api.command.user.offering.ListDiskOfferingsCmd; import org.apache.cloudstack.api.command.user.offering.ListServiceOfferingsCmd; import org.apache.cloudstack.api.command.user.project.ListProjectInvitationsCmd; @@ -89,4 +90,5 @@ public interface QueryService { public List searchForVolumeDetails(ListVolumeDetailsCmd cmd); - } + List searchForNicDetails(ListNicDetailsCmd ListNicDetailsCmd); +} diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index c4d0fcfa551..9837d2428f1 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -269,10 +269,11 @@ listVolumes=15 extractVolume=15 migrateVolume=15 resizeVolume=15 -addVolumeDetail=15 -updateVolumeDetail=15 -removeVolumeDetail=15 -listVolumeDetails=15 +updateVolume=1 +addVolumeDetail=1 +updateVolumeDetail=1 +removeVolumeDetail=1 +listVolumeDetails=1 #### registration command: FIXME -- this really should be something in management server that #### generates a new key for the user and they just have to @@ -343,9 +344,10 @@ updateNetwork=15 addNicToVirtualMachine=15 removeNicFromVirtualMachine=15 updateDefaultNicForVirtualMachine=15 -addNicDetail=15 -updateNicDetail=15 -removeNicDetail=15 +addNicDetail=1 +updateNicDetail=1 +removeNicDetail=1 +listNicDetails=1 #### addIpToNic=15 diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index a1a4113e074..6f168a4f26d 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -22,6 +22,8 @@ import javax.ejb.Local; import javax.inject.Inject; import com.cloud.api.ApiDBUtils; +import com.cloud.vm.NicDetailVO; +import com.cloud.vm.dao.NicDetailDao; import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.affinity.AffinityGroupVMMapVO; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; @@ -35,6 +37,7 @@ import org.apache.cloudstack.api.command.user.account.ListAccountsCmd; import org.apache.cloudstack.api.command.user.account.ListProjectAccountsCmd; import org.apache.cloudstack.api.command.user.event.ListEventsCmd; import org.apache.cloudstack.api.command.user.job.ListAsyncJobsCmd; +import org.apache.cloudstack.api.command.user.network.ListNicDetailsCmd; import org.apache.cloudstack.api.command.user.offering.ListDiskOfferingsCmd; import org.apache.cloudstack.api.command.user.offering.ListServiceOfferingsCmd; import org.apache.cloudstack.api.command.user.project.ListProjectInvitationsCmd; @@ -48,7 +51,6 @@ import org.apache.cloudstack.api.command.user.volume.ListVolumesCmd; import org.apache.cloudstack.api.command.user.zone.ListZonesByCmd; import org.apache.cloudstack.api.response.*; import org.apache.cloudstack.query.QueryService; -import org.apache.commons.collections.map.HashedMap; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -230,6 +232,9 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { @Inject private VolumeDetailsDao _volumeDetailDao; + @Inject + private NicDetailDao _nicDetailDao; + @Inject private HighAvailabilityManager _haMgr; @@ -1522,6 +1527,35 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { return volumeDetailResponseList; } + @Override + public List searchForNicDetails(ListNicDetailsCmd cmd){ + Long id = cmd.getId(); + String name = cmd.getName(); + + List nicDetailList; + if(name == null){ + nicDetailList = _nicDetailDao.findDetails(id); + }else { + NicDetailVO nicDetail = _nicDetailDao.findDetail(id, name); + nicDetailList = new LinkedList(); + nicDetailList.add(nicDetail); + } + + List nicDetailResponseList = new ArrayList(); + for(NicDetailVO nicDetail : nicDetailList){ + NicDetailResponse nicDetailResponse = new NicDetailResponse(); + //String uuid = ApiDBUtils.findN + nicDetailResponse.setName(nicDetail.getName()); + nicDetailResponse.setValue(nicDetail.getValue()); + nicDetailResponse.setObjectName("nicdetail"); + nicDetailResponseList.add(nicDetailResponse); + } + + return nicDetailResponseList; + + } + + private Pair, Integer> searchForVolumesInternal(ListVolumesCmd cmd) { diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 485790a509d..db3ed222781 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -2424,6 +2424,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(AttachVolumeCmd.class); cmdList.add(CreateVolumeCmd.class); cmdList.add(DeleteVolumeCmd.class); + cmdList.add(UpdateVolumeCmd.class); cmdList.add(DetachVolumeCmd.class); cmdList.add(ExtractVolumeCmd.class); cmdList.add(ListVolumesCmd.class); @@ -2487,6 +2488,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(AddNicDetailCmd.class); cmdList.add(UpdateNicDetailCmd.class); cmdList.add(RemoveNicDetailCmd.class); + cmdList.add(ListNicDetailsCmd.class); return cmdList; } diff --git a/server/src/com/cloud/storage/VolumeManagerImpl.java b/server/src/com/cloud/storage/VolumeManagerImpl.java index 73e96f4c8ae..356f676f6aa 100644 --- a/server/src/com/cloud/storage/VolumeManagerImpl.java +++ b/server/src/com/cloud/storage/VolumeManagerImpl.java @@ -880,6 +880,10 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { if(displayVolumeEnabled == null){ displayVolumeEnabled = true; + } else{ + if(!_accountMgr.isRootAdmin(caller.getType())){ + throw new PermissionDeniedException( "Cannot update parameter displayvolume, only admin permitted "); + } } if (!validateVolumeSizeRange(size)) {// convert size from mb to gb @@ -1773,6 +1777,22 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { return newVol; } + @Override + public Volume updateVolume(UpdateVolumeCmd cmd){ + Long volumeId = cmd.getId(); + String path = cmd.getPath(); + + if(path == null){ + throw new InvalidParameterValueException("Failed to update the volume as path was null"); + } + + VolumeVO volume = ApiDBUtils.findVolumeById(volumeId); + volume.setPath(path); + _volumeDao.update(volumeId, volume); + + return volume; + } + @Override @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETAIL_UPDATE, eventDescription = "updating volume detail", async = true) public void updateVolumeDetails(UpdateVolumeDetailCmd cmd){ diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 5bc3a166896..d0feff80da6 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -1576,6 +1576,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use Long id = cmd.getId(); Long osTypeId = cmd.getOsTypeId(); String userData = cmd.getUserData(); + Account caller = UserContext.current().getCaller(); // Input validation UserVmVO vmInstance = null; @@ -1608,6 +1609,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use if (isDisplayVmEnabled == null) { isDisplayVmEnabled = vmInstance.isDisplayVm(); + } else{ + if(!_accountMgr.isRootAdmin(caller.getType())){ + throw new PermissionDeniedException( "Cannot update parameter displayvm, only admin permitted "); + } } UserVmVO vm = _vmDao.findById(id); @@ -2251,7 +2256,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use protected UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, String hostName, String displayName, Account owner, Long diskOfferingId, Long diskSize, List networkList, List securityGroupIdList, String group, HTTPMethod httpmethod, String userData, String sshKeyPair, HypervisorType hypervisor, Account caller, Map requestedIps, - IpAddresses defaultIps, Boolean displayvm, String keyboard, List affinityGroupIdList) + IpAddresses defaultIps, Boolean isDisplayVmEnabled, String keyboard, List affinityGroupIdList) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, StorageUnavailableException, ResourceAllocationException { _accountMgr.checkAccess(caller, null, true, owner); @@ -2537,8 +2542,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use vm.setIsoId(template.getId()); } - if(displayvm != null){ - vm.setDisplayVm(displayvm); + if(isDisplayVmEnabled != null){ + if(!_accountMgr.isRootAdmin(caller.getType())){ + throw new PermissionDeniedException( "Cannot update parameter displayvm, only admin permitted "); + } + vm.setDisplayVm(isDisplayVmEnabled); }else { vm.setDisplayVm(true); } diff --git a/server/src/com/cloud/vm/dao/NicDetailDao.java b/server/src/com/cloud/vm/dao/NicDetailDao.java index ff6802bd376..6f51ffe7b95 100644 --- a/server/src/com/cloud/vm/dao/NicDetailDao.java +++ b/server/src/com/cloud/vm/dao/NicDetailDao.java @@ -16,13 +16,14 @@ // under the License. package com.cloud.vm.dao; +import java.util.List; import java.util.Map; import com.cloud.utils.db.GenericDao; import com.cloud.vm.NicDetailVO; public interface NicDetailDao extends GenericDao { - Map findDetails(long nicId); + List findDetails(long nicId); void persist(long nicId, Map details); diff --git a/server/src/com/cloud/vm/dao/NicDetailDaoImpl.java b/server/src/com/cloud/vm/dao/NicDetailDaoImpl.java index fd110359473..ae400cfe75b 100644 --- a/server/src/com/cloud/vm/dao/NicDetailDaoImpl.java +++ b/server/src/com/cloud/vm/dao/NicDetailDaoImpl.java @@ -16,8 +16,6 @@ // under the License. package com.cloud.vm.dao; -import com.cloud.storage.dao.SnapshotDao; -import com.cloud.storage.dao.VolumeDao; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; @@ -26,7 +24,6 @@ import com.cloud.vm.NicDetailVO; import org.springframework.stereotype.Component; import javax.ejb.Local; -import java.util.HashMap; import java.util.List; import java.util.Map; @@ -68,17 +65,17 @@ public class NicDetailDaoImpl extends GenericDaoBase implemen } @Override - public Map findDetails(long nicId) { + public List findDetails(long nicId) { SearchCriteria sc = NicSearch.create(); sc.setParameters("nicId", nicId); List results = search(sc, null); - Map details = new HashMap(results.size()); + /*Map details = new HashMap(results.size()); for (NicDetailVO result : results) { details.put(result.getName(), result.getValue()); - } + } */ - return details; + return results; } @Override diff --git a/test/integration/smoke/test_nicdetail.py b/test/integration/smoke/test_nicdetail.py new file mode 100644 index 00000000000..3d8b1d62a47 --- /dev/null +++ b/test/integration/smoke/test_nicdetail.py @@ -0,0 +1,224 @@ +# 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. +""" P1 tests for Scaling up Vm +""" +#Import Local Modules +import marvin +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.remoteSSHClient import remoteSSHClient +from marvin.integration.lib.utils import * +from marvin.integration.lib.base import * +from marvin.integration.lib.common import * +from nose.plugins.attrib import attr +#Import System modules +import time + +_multiprocess_shared_ = True +class Services: + """Test VM Life Cycle Services + """ + + def __init__(self): + self.services = { + + "account": { + "email": "test@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + # Random characters are appended in create account to + # ensure unique username generated each time + "password": "password", + }, + "small": + # Create a small virtual machine instance with disk offering + { + "displayname": "testserver", + "username": "root", # VM creds for SSH + "password": "password", + "ssh_port": 22, + "hypervisor": 'XenServer', + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + }, + "disk_offering": { + "displaytext": "Small", + "name": "Small", + "storagetype": "shared", + "disksize": 1 + }, + "service_offerings": + { + "small": + { + # Small service offering ID to for change VM + # service offering from medium to small + "name": "SmallInstance", + "displaytext": "SmallInstance", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 256, + }, + "big": + { + # Big service offering ID to for change VM + "name": "BigInstance", + "displaytext": "BigInstance", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 512, + } + }, + #Change this + "template": { + "displaytext": "xs", + "name": "xs", + "passwordenabled": False, + }, + "diskdevice": '/dev/xvdd', + # Disk device where ISO is attached to instance + "mount_dir": "/mnt/tmp", + "sleep": 60, + "timeout": 10, + #Migrate VM to hostid + "ostype": 'CentOS 5.6 (64-bit)', + # CentOS 5.3 (64-bit) + } + +class TestNicDetail(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cls.api_client = super(TestNicDetail, cls).getClsTestClient().getApiClient() + cls.services = Services().services + + # Get Zone, Domain and templates + domain = get_domain(cls.api_client, cls.services) + zone = get_zone(cls.api_client, cls.services) + cls.services['mode'] = zone.networktype + + # Set Zone + + # Create account, service offerings, vm. + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=domain.id + ) + + cls.nic = "163738c7-ce3a-481d-ac68-4a8337043415"; + #how does it work + cls._cleanup = [ + cls.account + ] + + @classmethod + def tearDownClass(cls): + cls.api_client = super(TestNicDetail, cls).getClsTestClient().getApiClient() + cleanup_resources(cls.api_client, cls._cleanup) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + + def tearDown(self): + #Clean up, terminate the created ISOs + cleanup_resources(self.apiclient, self.cleanup) + return + + @attr(tags = ["advanced", "xenserver"]) + def test_01_updatenicdetail(self): + """Test nic detail + """ + # Validate the following + # Scale up the vm and see if it scales to the new svc offering and is finally in running state + + self.debug("Testing ADD nic detail Nic-ID: %s " % ( + self.nic + )) + + cmd = addNicDetail.addNicDetailCmd() + cmd.name = self.nic + cmd.value = self.nic + cmd.id = self.nic + self.apiclient.addNicDetail(cmd) + + listNicDetailCmd = listNicDetails.listNicDetailsCmd() + listNicDetailCmd.id = self.nic + listNicDetailResponse = self.api_client.listVirtualMachines(listNicDetailCmd) + + self.assertNotEqual(len(listNicDetailResponse), 0, "Check if the list API \ + returns a non-empty response") + + nicdetail = listNicDetailResponse[0] + + #self.assertEqual(nicdetail.id, self.nic, "Check if the Nic returned is the same as the one we asked for") + + + self.assertEqual(nicdetail.name, self.nic, "Check if Nic has right name") + + self.assertEqual(nicdetail.value, self.nic, "Check if Nic has right value") + + #updatenicdetail + self.debug("Testing UPDATE nic detail Nic-ID: %s " % ( + self.nic + )) + cmd = updateNicDetail.updateNicDetailCmd() + cmd.name = self.nic + cmd.value = self.disk_offering.id + cmd.id = self.nic + self.apiclient.addNicDetail(cmd) + + listNicDetailCmd = listNicDetails.listNicDetailsCmd() + listNicDetailCmd.id = self.nic + listNicDetailResponse = self.api_client.listVirtualMachines(listNicDetailCmd) + + self.assertNotEqual(len(listNicDetailResponse), 0, "Check if the list API \ + returns a non-empty response") + + nicdetail = listNicDetailResponse[0] + + #self.assertEqual(nicdetail.id, self.nic, "Check if the Nic returned is the same as the one we asked for") + + + self.assertEqual(nicdetail.name, self.nic, "Check if Nic has right name") + + self.assertEqual(nicdetail.value, self.disk_offering.id, "Check if Nic has right value") + + + #remove detail + self.debug("Testing REMOVE nic detail Nic-ID: %s " % ( + self.nic + )) + cmd = removeNicDetail.removeNicDetailCmd() + cmd.name = self.nic + cmd.id = self.nic + self.apiclient.removeNicDetail(cmd) + + listNicDetailCmd = listNicDetails.listNicDetailsCmd() + listNicDetailCmd.id = self.nic + listNicDetailResponse = self.api_client.listVirtualMachines(listNicDetailCmd) + + self.assertEqual(listNicDetailResponse, None, "Check if the list API \ + returns a non-empty response") + + + return From c338cb7dd02c20771591fcb2ab8d089e1bb5e855 Mon Sep 17 00:00:00 2001 From: Nitin Mehta Date: Sun, 28 Apr 2013 18:13:22 +0530 Subject: [PATCH 009/114] =updatenetwork changes --- api/src/com/cloud/network/NetworkService.java | 2 +- .../api/command/user/network/UpdateNetworkCmd.java | 9 ++++++++- .../src/com/cloud/network/NetworkManagerImpl.java | 2 +- .../src/com/cloud/network/NetworkServiceImpl.java | 11 +++++++++-- server/src/com/cloud/vm/UserVmManagerImpl.java | 12 +++++++++++- .../com/cloud/network/MockNetworkManagerImpl.java | 3 +-- .../test/com/cloud/vpc/MockNetworkManagerImpl.java | 2 +- setup/db/db/schema-410to420.sql | 14 ++++++++++++-- 8 files changed, 44 insertions(+), 11 deletions(-) diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java index f9e6238a697..b832ccd8199 100755 --- a/api/src/com/cloud/network/NetworkService.java +++ b/api/src/com/cloud/network/NetworkService.java @@ -68,7 +68,7 @@ public interface NetworkService { IpAddress getIp(long id); Network updateGuestNetwork(long networkId, String name, String displayText, Account callerAccount, User callerUser, - String domainSuffix, Long networkOfferingId, Boolean changeCidr, String guestVmCidr); + String domainSuffix, Long networkOfferingId, Boolean changeCidr, String guestVmCidr, Boolean displayNetwork); PhysicalNetwork createPhysicalNetwork(Long zoneId, String vnetRange, String networkSpeed, List isolationMethods, String broadcastDomainRange, Long domainId, List tags, String name); diff --git a/api/src/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java index a61474e69d0..fe381246b28 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java @@ -67,6 +67,9 @@ public class UpdateNetworkCmd extends BaseAsyncCmd { @Parameter(name=ApiConstants.GUEST_VM_CIDR, type=CommandType.STRING, description="CIDR for Guest VMs,Cloudstack allocates IPs to Guest VMs only from this CIDR") private String guestVmCidr; + @Parameter(name=ApiConstants.DISPLAY_NETWORK, type=CommandType.BOOLEAN, description="an optional field, whether to the display the network to the end user or not.") + private Boolean displayNetwork; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -101,6 +104,10 @@ public class UpdateNetworkCmd extends BaseAsyncCmd { private String getGuestVmCidr() { return guestVmCidr; } + + public Boolean getDisplayNetwork() { + return displayNetwork; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -130,7 +137,7 @@ public class UpdateNetworkCmd extends BaseAsyncCmd { } Network result = _networkService.updateGuestNetwork(getId(), getNetworkName(), getDisplayText(), callerAccount, - callerUser, getNetworkDomain(), getNetworkOfferingId(), getChangeCidr(), getGuestVmCidr()); + callerUser, getNetworkDomain(), getNetworkOfferingId(), getChangeCidr(), getGuestVmCidr(), getDisplayNetwork()); if (result != null) { diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index ea5338949db..3bea76dc81e 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -1173,7 +1173,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L NetworkVO vo = new NetworkVO(id, network, offering.getId(), guru.getName(), owner.getDomainId(), owner.getId(), related, name, displayText, predefined.getNetworkDomain(), offering.getGuestType(), plan.getDataCenterId(), plan.getPhysicalNetworkId(), aclType, offering.getSpecifyIpRanges(), vpcId); - vo.setDisplayNetwork(isDisplayNetworkEnabled); + vo.setDisplayNetwork(isDisplayNetworkEnabled == null ? true : isDisplayNetworkEnabled); networks.add(_networksDao.persist(vo, vo.getGuestType() == Network.GuestType.Isolated, finalizeServicesAndProvidersForNetwork(offering, plan.getPhysicalNetworkId()))); diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 5d62bc3b9cf..c3f87f38ed9 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -1711,8 +1711,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { @Override @DB @ActionEvent(eventType = EventTypes.EVENT_NETWORK_UPDATE, eventDescription = "updating network", async = true) - public Network updateGuestNetwork(long networkId, String name, String displayText, Account callerAccount, - User callerUser, String domainSuffix, Long networkOfferingId, Boolean changeCidr, String guestVmCidr) { + public Network updateGuestNetwork(long networkId, String name, String displayText, Account callerAccount, + User callerUser, String domainSuffix, Long networkOfferingId, Boolean changeCidr, String guestVmCidr, Boolean displayNetwork) { boolean restartNetwork = false; // verify input parameters @@ -1756,6 +1756,13 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { network.setDisplayText(displayText); } + if(displayNetwork != null){ + if(!_accountMgr.isRootAdmin(callerAccount.getType())){ + throw new PermissionDeniedException("Only admin allowed to update displaynetwork parameter"); + } + network.setDisplayNetwork(displayNetwork); + } + // network offering and domain suffix can be updated for Isolated networks only in 3.0 if ((networkOfferingId != null || domainSuffix != null) && network.getGuestType() != GuestType.Isolated) { throw new InvalidParameterValueException("NetworkOffering and domain suffix upgrade can be perfomed for Isolated networks only"); diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index d0feff80da6..3e62282e9eb 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -755,6 +755,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use public UserVm upgradeVirtualMachine(UpgradeVMCmd cmd) throws ResourceAllocationException { Long vmId = cmd.getId(); Long svcOffId = cmd.getServiceOfferingId(); + return upgradeStoppedVirtualMachine(vmId, svcOffId); + } + + + private UserVm upgradeStoppedVirtualMachine(Long vmId, Long svcOffId) throws ResourceAllocationException { Account caller = UserContext.current().getCaller(); // Verify input parameters @@ -815,6 +820,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } return _vmDao.findById(vmInstance.getId()); + } @Override @@ -1052,7 +1058,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use @Override @ActionEvent(eventType = EventTypes.EVENT_VM_SCALE, eventDescription = "scaling Vm") public UserVm - upgradeVirtualMachine(ScaleVMCmd cmd) throws InvalidParameterValueException { + upgradeVirtualMachine(ScaleVMCmd cmd) throws InvalidParameterValueException, ResourceAllocationException { Long vmId = cmd.getId(); Long newServiceOfferingId = cmd.getServiceOfferingId(); Account caller = UserContext.current().getCaller(); @@ -1063,6 +1069,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use throw new InvalidParameterValueException("This operation not permitted for this hypervisor of the vm"); } + if(vmInstance.getState().equals(State.Stopped)){ + return upgradeStoppedVirtualMachine(vmId, newServiceOfferingId); + } + _accountMgr.checkAccess(caller, null, true, vmInstance); // Check that the specified service offering ID is valid diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index 521dccfcdbb..3dd060bf018 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -51,7 +51,6 @@ import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.VirtualMachineProfile; -import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; import org.apache.cloudstack.api.command.user.network.*; @@ -563,7 +562,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage */ @Override public Network updateGuestNetwork(long networkId, String name, String displayText, Account callerAccount, - User callerUser, String domainSuffix, Long networkOfferingId, Boolean changeCidr, String guestVmCidr) { + User callerUser, String domainSuffix, Long networkOfferingId, Boolean changeCidr, String guestVmCidr, Boolean displayNetwork) { // TODO Auto-generated method stub return null; } diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index 1a811a55110..7640af08a32 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -286,7 +286,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage */ @Override public Network updateGuestNetwork(long networkId, String name, String displayText, Account callerAccount, - User callerUser, String domainSuffix, Long networkOfferingId, Boolean changeCidr, String guestVmCidr) { + User callerUser, String domainSuffix, Long networkOfferingId, Boolean changeCidr, String guestVmCidr, Boolean displayNetwork) { // TODO Auto-generated method stub return null; } diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index 10781b0909c..1317d303c5c 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -1232,6 +1232,7 @@ CREATE VIEW `cloud`.`user_vm_view` AS data_center.uuid data_center_uuid, data_center.name data_center_name, data_center.is_security_group_enabled security_group_enabled, + data_center.networktype data_center_type, host.id host_id, host.uuid host_uuid, host.name host_name, @@ -1297,7 +1298,12 @@ CREATE VIEW `cloud`.`user_vm_view` AS async_job.id job_id, async_job.uuid job_uuid, async_job.job_status job_status, - async_job.account_id job_account_id + async_job.account_id job_account_id, + affinity_group.id affinity_group_id, + affinity_group.uuid affinity_group_uuid, + affinity_group.name affinity_group_name, + affinity_group.description affinity_group_description + from `cloud`.`user_vm` inner join @@ -1356,7 +1362,11 @@ CREATE VIEW `cloud`.`user_vm_view` AS left join `cloud`.`async_job` ON async_job.instance_id = vm_instance.id and async_job.instance_type = 'VirtualMachine' - and async_job.job_status = 0; + and async_job.job_status = 0 + left join + `cloud`.`affinity_group_vm_map` ON vm_instance.id = affinity_group_vm_map.instance_id + left join + `cloud`.`affinity_group` ON affinity_group_vm_map.affinity_group_id = affinity_group.id; DROP VIEW IF EXISTS `cloud`.`volume_view`; CREATE VIEW `cloud`.`volume_view` AS From eb6ebbb7cacefb3f081cc35a30e78b2fd975c8e7 Mon Sep 17 00:00:00 2001 From: Nitin Mehta Date: Mon, 29 Apr 2013 09:27:07 +0530 Subject: [PATCH 010/114] =remove unwanted file --- api/src/com/cloud/storage/VolumeDetail.java | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 api/src/com/cloud/storage/VolumeDetail.java diff --git a/api/src/com/cloud/storage/VolumeDetail.java b/api/src/com/cloud/storage/VolumeDetail.java deleted file mode 100644 index 70173734ed0..00000000000 --- a/api/src/com/cloud/storage/VolumeDetail.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.cloud.storage; - -import org.apache.cloudstack.acl.ControlledEntity; -import org.apache.cloudstack.api.Identity; -import org.apache.cloudstack.api.InternalIdentity; - -/** - * Created with IntelliJ IDEA. - * User: nitinmehta - * Date: 24/04/13 - * Time: 5:55 PM - * To change this template use File | Settings | File Templates. - */ -public interface VolumeDetail extends ControlledEntity, InternalIdentity, Identity { - -} From 06963409e78ad262868dab4eff6fc34ea79466f5 Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Fri, 3 May 2013 14:07:12 -0700 Subject: [PATCH 011/114] Fix typo --- ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js b/ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js index 8c83339c562..5818c5bed54 100644 --- a/ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js +++ b/ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js @@ -43,7 +43,7 @@ detailView: { id: 'asa1000vProvider', label: 'label.netScaler', - viewAll: { label: 'label.devices', path: '_zone.asa100vDevices' }, + viewAll: { label: 'label.devices', path: '_zone.asa1000vDevices' }, tabs: { details: { title: 'label.details', @@ -68,4 +68,4 @@ } }); }; -}(jQuery, cloudStack)); \ No newline at end of file +}(jQuery, cloudStack)); From ad8f10656c937f87ad858bbd712db5b5a4cc37d3 Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Fri, 3 May 2013 14:12:26 -0700 Subject: [PATCH 012/114] Add sample detail view --- .../asa1000vNetworkProvider.js | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js b/ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js index 5818c5bed54..cae30bfa05f 100644 --- a/ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js +++ b/ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js @@ -38,6 +38,28 @@ { name: 'device3', ipaddress: '192.168.1.14', state: 'Enabled' } ] }); + }, + + detailView: { + tabs: { + details: { + title: 'label.details', + fields: [ + { + name: { label: 'label.name' } + }, + { + ipaddress: { label: 'label.ip.address' }, + state: { label: 'label.state' } + } + ], + dataProvider: function(args) { + args.response.success({ + data: args.context.asa1000vDevices[0] + }); + } + } + } } }, detailView: { From 9a8bf4a66bd08f660eadf6d3707c46044fcac08c Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Mon, 6 May 2013 11:46:24 -0700 Subject: [PATCH 013/114] VNMC: Refactor ASA1000v as a VNMC subdevice -Make new provider 'VNMC' instead of 'ASA1000v' -Add helper function to add new VNMC managed devices to module -Make ASA1000v device listing as a view all link under VNMC --- .../asa1000vNetworkProvider.js | 93 --------------- ui/modules/modules.js | 3 +- ui/modules/vnmcAsa1000v/vnmcAsa1000v.js | 44 +++++++ .../vnmcNetworkProvider.js | 112 ++++++++++++++++++ 4 files changed, 158 insertions(+), 94 deletions(-) delete mode 100644 ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js create mode 100644 ui/modules/vnmcAsa1000v/vnmcAsa1000v.js create mode 100644 ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js diff --git a/ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js b/ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js deleted file mode 100644 index cae30bfa05f..00000000000 --- a/ui/modules/asa1000vNetworkProvider/asa1000vNetworkProvider.js +++ /dev/null @@ -1,93 +0,0 @@ -// 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) { - cloudStack.modules.asa1000vNetworkProvider = function(module) { - module.infrastructure.networkServiceProvider({ - id: 'ciscoAsa1000v', - name: 'Cisco ASA 1000v', - state: 'Disabled', - listView: { - id: 'asa1000vDevices', - fields: { - name: { label: 'label.name' }, - ipaddress: { label: 'label.ip.address' }, - state: { label: 'label.state', indicator: { - 'Enabled': 'on', - 'Disabled': 'off' - }} - }, - dataProvider: function(args) { - args.response.success({ - data: [ - { name: 'device1', ipaddress: '192.168.1.12', state: 'Enabled' }, - { name: 'device2', ipaddress: '192.168.1.13', state: 'Disabled' }, - { name: 'device3', ipaddress: '192.168.1.14', state: 'Enabled' } - ] - }); - }, - - detailView: { - tabs: { - details: { - title: 'label.details', - fields: [ - { - name: { label: 'label.name' } - }, - { - ipaddress: { label: 'label.ip.address' }, - state: { label: 'label.state' } - } - ], - dataProvider: function(args) { - args.response.success({ - data: args.context.asa1000vDevices[0] - }); - } - } - } - } - }, - detailView: { - id: 'asa1000vProvider', - label: 'label.netScaler', - viewAll: { label: 'label.devices', path: '_zone.asa1000vDevices' }, - tabs: { - details: { - title: 'label.details', - fields: [ - { - name: { label: 'label.name' } - }, - { - state: { label: 'label.state' } - } - ], - dataProvider: function(args) { - args.response.success({ - data: { - name: 'Cisco ASA 1000v', - state: 'Disabled' - } - }); - } - } - } - } - }); - }; -}(jQuery, cloudStack)); diff --git a/ui/modules/modules.js b/ui/modules/modules.js index f5dd62a0e9e..d4502a195bc 100644 --- a/ui/modules/modules.js +++ b/ui/modules/modules.js @@ -17,6 +17,7 @@ (function($, cloudStack) { cloudStack.modules = [ 'infrastructure', - 'asa1000vNetworkProvider' + 'vnmcNetworkProvider', + 'vnmcAsa1000v' ]; }(jQuery, cloudStack)); diff --git a/ui/modules/vnmcAsa1000v/vnmcAsa1000v.js b/ui/modules/vnmcAsa1000v/vnmcAsa1000v.js new file mode 100644 index 00000000000..10fe3ef0712 --- /dev/null +++ b/ui/modules/vnmcAsa1000v/vnmcAsa1000v.js @@ -0,0 +1,44 @@ +// 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) { + cloudStack.modules.vnmcAsa1000v = function(module) { + module.vnmcNetworkProvider.addDevice({ + id: 'asa1000v', + title: 'ASA 1000v', + listView: { + id: 'asa1000vDevices', + fields: { + name: { label: 'label.name' }, + ipaddress: { label: 'label.ip.address' }, + state: { label: 'label.state', indicator: { + 'Enabled': 'on', + 'Disabled': 'off' + }} + }, + dataProvider: function(args) { + args.response.success({ + data: [ + { name: 'asadevice1', ipaddress: '192.168.1.12', state: 'Enabled' }, + { name: 'asadevice2', ipaddress: '192.168.1.13', state: 'Disabled' }, + { name: 'asadevice3', ipaddress: '192.168.1.14', state: 'Enabled' } + ] + }); + } + } + }); + }; +}(jQuery, cloudStack)); diff --git a/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js b/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js new file mode 100644 index 00000000000..6add2c59686 --- /dev/null +++ b/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js @@ -0,0 +1,112 @@ +// 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) { + cloudStack.modules.vnmcNetworkProvider = function(module) { + var vnmcDeviceViewAll = window._m = [ + { + label: 'VNMC Devices', + path: '_zone.vnmcDevices' + } + ]; + + var vnmcListView = { + id: 'vnmcDevices', + fields: { + name: { label: 'label.name' }, + ipaddress: { label: 'label.ip.address' }, + state: { label: 'label.state', indicator: { + 'Enabled': 'on', + 'Disabled': 'off' + }} + }, + dataProvider: function(args) { + args.response.success({ + data: [ + { name: 'device1', ipaddress: '192.168.1.12', state: 'Enabled' }, + { name: 'device2', ipaddress: '192.168.1.13', state: 'Disabled' }, + { name: 'device3', ipaddress: '192.168.1.14', state: 'Enabled' } + ] + }); + } + }; + + var vnmcProviderDetailView = vnmcListView.detailView = { + id: 'vnmcProvider', + label: 'VNMC', + viewAll: vnmcDeviceViewAll, + tabs: { + details: { + title: 'label.details', + fields: [ + { + name: { label: 'label.name' } + }, + { + state: { label: 'label.state' } + } + ], + dataProvider: function(args) { + args.response.success({ + data: { + name: 'VNMC Devices', + state: 'Disabled' + } + }); + } + } + } + }; + + var vnmcDeviceDetailView = { + tabs: { + details: { + title: 'label.details', + fields: [ + { + name: { label: 'label.name' } + }, + { + ipaddress: { label: 'label.ip.address' }, + state: { label: 'label.state' } + } + ], + dataProvider: function(args) { + args.response.success({ + data: args.context.vnmcDevices[0] + }); + } + } + } + }; + + module.pluginAPI.extend({ + addDevice: function(device) { + cloudStack.sections.system.subsections[device.id] = device; + vnmcDeviceViewAll.push({ label: device.title, path: '_zone.' + device.id }); + } + }); + + module.infrastructure.networkServiceProvider({ + id: 'vnmc', + name: 'Cisco VNMC', + state: 'Disabled', + listView: vnmcListView, + + detailView: vnmcProviderDetailView + }); + }; +}(jQuery, cloudStack)); From 6323b2e71b0d1295fb91ba8735130973b484cdbe Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Wed, 8 May 2013 12:02:30 -0700 Subject: [PATCH 014/114] CLOUDSTACK-1816: Cisco VNMC ASA1000v - UI - implement Add Cisco VNMC action. --- .../vnmcNetworkProvider.js | 190 +++++++++++++++++- 1 file changed, 182 insertions(+), 8 deletions(-) diff --git a/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js b/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js index 6add2c59686..220a0b9c746 100644 --- a/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js +++ b/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js @@ -33,14 +33,188 @@ 'Disabled': 'off' }} }, - dataProvider: function(args) { - args.response.success({ - data: [ - { name: 'device1', ipaddress: '192.168.1.12', state: 'Enabled' }, - { name: 'device2', ipaddress: '192.168.1.13', state: 'Disabled' }, - { name: 'device3', ipaddress: '192.168.1.14', state: 'Enabled' } - ] - }); + + actions: { + add: { + label: 'Add VNMC device', + + messages: { + /* + confirm: function(args) { + return 'Add VNMC device'; + }, + */ + notification: function(args) { + return 'Add VNMC device'; + } + }, + + createForm: { + title: 'Add VNMC device', + fields: { + hostname: { + label: 'label.host', + validation: { required: true } + }, + username: { + label: 'label.username', + validation: { required: true } + }, + password: { + label: 'label.password', + isPassword: true, + validation: { required: true } + } + } + }, + + action: function(args) { + //debugger; + $.ajax({ + url: createURL('listNetworkServiceProviders'), + data: { + name: 'CiscoVnmc', + physicalnetworkid: args.context.physicalNetworks[0].id + }, + success: function(json){ + //debugger; + var items = json.listnetworkserviceprovidersresponse.networkserviceprovider; + if(items != null && items.length > 0) { + var ciscoVnmcProvider = items[0]; + if(ciscoVnmcProvider.state == 'Enabled') { + addCiscoVnmcResourceFn(); + } + else { + enableCiscoVnmcProviderFn(ciscoVnmcProvider); + } + } + else { + $.ajax({ + url: createURL("addNetworkServiceProvider"), + data: { + name: 'CiscoVnmc', + physicalnetworkid: args.context.physicalNetworks[0].id + }, + success: function(json) { + var jobId = json.addnetworkserviceproviderresponse.jobid; + var addVnmcProviderIntervalID = setInterval(function() { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId="+jobId), + dataType: "json", + success: function(json) { + var result = json.queryasyncjobresultresponse; + //debugger; + if (result.jobstatus == 0) { + return; //Job has not completed + } + else { + clearInterval(addVnmcProviderIntervalID ); + if (result.jobstatus == 1) { + //nspMap["CiscoVnmc"] = json.queryasyncjobresultresponse.jobresult.networkserviceprovider; + var ciscoVnmcProvider = json.queryasyncjobresultresponse.jobresult.networkserviceprovider; + enableCiscoVnmcProviderFn(ciscoVnmcProvider); + } + else if (result.jobstatus == 2) { + args.response.error(_s(result.jobresult.errortext)); + } + } + }, + error: function(XMLHttpResponse) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, g_queryAsyncJobResultInterval); + } + }); + } + } + }); + //debugger; + + var enableCiscoVnmcProviderFn = function(ciscoVnmcProvider){ + $.ajax({ + url: createURL('updateNetworkServiceProvider'), + data: { + id: ciscoVnmcProvider.id, + state: 'Enabled' + }, + success: function(json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + var enableVnmcProviderIntervalID = setInterval(function(){ + $.ajax({ + url: createURL('queryAsyncJobResult'), + data: { + jobid: jid + }, + success: function(json){ + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } + else { + clearInterval(enableVnmcProviderIntervalID); + if (result.jobstatus == 1) { + addCiscoVnmcResourceFn(); + } + else if (result.jobstatus == 2) { + args.response.error(_s(result.jobresult.errortext)); + } + } + } + }); + }, g_queryAsyncJobResultInterval); + } + }); + } + + var addCiscoVnmcResourceFn = function(){ + //debugger; + var data = { + physicalnetworkid: args.context.physicalNetworks[0].id, + hostname: args.data.hostname, + username: args.data.username, + password: args.data.password + }; + + $.ajax({ + url: createURL('addCiscoVnmcResource'), + data: data, + success: function(json) { + //debugger; + var item = json.addciscovnmcresourceresponse.ciscovnmcresource; + args.response.success({data: item}); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + }, + + notification: { + poll: function(args) { + args.complete(); + } + } + } + }, + + dataProvider: function(args) { + $.ajax({ + url: createURL('listCiscoVnmcResources'), + data: { + physicalnetworkid: args.context.physicalNetworks[0].id + }, + success: function(json){ + args.response.success({ + data: [ + { name: 'device1', ipaddress: '192.168.1.12', state: 'Enabled' }, + { name: 'device2', ipaddress: '192.168.1.13', state: 'Disabled' }, + { name: 'device3', ipaddress: '192.168.1.14', state: 'Enabled' } + ] + }); + } + }); } }; From 99f0cdd0d9d8de8f82d8f7ce12f98bce2a8915d8 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Wed, 8 May 2013 14:50:15 -0700 Subject: [PATCH 015/114] CLOUDSTACK-1816: Cisco VNMC ASA1000v - UI - implement Add CiscoASA1000v action. --- ui/modules/vnmcAsa1000v/vnmcAsa1000v.js | 103 +++++++++++++++--- .../vnmcNetworkProvider.js | 7 +- 2 files changed, 89 insertions(+), 21 deletions(-) diff --git a/ui/modules/vnmcAsa1000v/vnmcAsa1000v.js b/ui/modules/vnmcAsa1000v/vnmcAsa1000v.js index 10fe3ef0712..3b92d2dfd0c 100644 --- a/ui/modules/vnmcAsa1000v/vnmcAsa1000v.js +++ b/ui/modules/vnmcAsa1000v/vnmcAsa1000v.js @@ -22,22 +22,95 @@ listView: { id: 'asa1000vDevices', fields: { - name: { label: 'label.name' }, - ipaddress: { label: 'label.ip.address' }, - state: { label: 'label.state', indicator: { - 'Enabled': 'on', - 'Disabled': 'off' - }} + hostname: { label: 'label.host' }, + insideportprofile: { label: 'Inside Port Profile' } }, - dataProvider: function(args) { - args.response.success({ - data: [ - { name: 'asadevice1', ipaddress: '192.168.1.12', state: 'Enabled' }, - { name: 'asadevice2', ipaddress: '192.168.1.13', state: 'Disabled' }, - { name: 'asadevice3', ipaddress: '192.168.1.14', state: 'Enabled' } - ] - }); - } + dataProvider: function(args) { + $.ajax({ + url: createURL('listCiscoAsa1000vResources'), + data: { + physicalnetworkid: args.context.physicalNetworks[0].id + }, + success: function(json){ + var items = json.listCiscoAsa1000vResources["null"]; //waiting for Koushik to fix object name to be "CiscoAsa1000vResource" instead of "null" + //var items = json.listCiscoAsa1000vResources.CiscoAsa1000vResource; + args.response.success({ data: items }); + } + }); + }, + + actions: { + add: { + label: 'Add CiscoASA1000v', + messages: { + notification: function(args) { + return 'Add CiscoASA1000v'; + } + }, + createForm: { + title: 'Add CiscoASA1000v', + fields: { + hostname: { + label: 'label.host', + validation: { required: true } + }, + insideportprofile: { + label: 'Inside Port Profile', + validation: { required: true }, + defaultValue: 'in-asa' + }, + clusterid: { + label: 'label.cluster', + validation: { required: true }, + select: function(args){ + $.ajax({ + url: createURL('listClusters'), + data: { + zoneid: args.context.zones[0].id + }, + success: function(json) { + var objs = json.listclustersresponse.cluster; + var items = []; + if(objs != null) { + for(var i = 0; i < objs.length; i++){ + items.push({id: objs[i].id, description: objs[i].name}); + } + } + args.response.success({data: items}); + } + }); + } + } + } + }, + action: function(args) { + var data = { + physicalnetworkid: args.context.physicalNetworks[0].id, + hostname: args.data.hostname, + insideportprofile: args.data.insideportprofile, + clusterid: args.data.clusterid + }; + + $.ajax({ + url: createURL('addCiscoAsa1000vResource'), + data: data, + success: function(json){ + var item = json.addCiscoAsa1000vResource.CiscoAsa1000vResource; + args.response.success({data: item}); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + + }, + notification: { + poll: function(args) { + args.complete(); + } + } + } + } } }); }; diff --git a/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js b/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js index 220a0b9c746..135cefac62c 100644 --- a/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js +++ b/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js @@ -38,12 +38,7 @@ add: { label: 'Add VNMC device', - messages: { - /* - confirm: function(args) { - return 'Add VNMC device'; - }, - */ + messages: { notification: function(args) { return 'Add VNMC device'; } From 6dff20e2129fac2d7f370d9297821bbde32cc92d Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Wed, 8 May 2013 15:40:46 -0700 Subject: [PATCH 016/114] CLOUDSTACK-1816: Cisco VNMC ASA1000v - UI - implement Delete CiscoASA1000v action. --- ui/modules/vnmcAsa1000v/vnmcAsa1000v.js | 82 +++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 6 deletions(-) diff --git a/ui/modules/vnmcAsa1000v/vnmcAsa1000v.js b/ui/modules/vnmcAsa1000v/vnmcAsa1000v.js index 3b92d2dfd0c..6a29c707551 100644 --- a/ui/modules/vnmcAsa1000v/vnmcAsa1000v.js +++ b/ui/modules/vnmcAsa1000v/vnmcAsa1000v.js @@ -41,14 +41,14 @@ actions: { add: { - label: 'Add CiscoASA1000v', + label: 'Add CiscoASA1000v Resource', messages: { notification: function(args) { - return 'Add CiscoASA1000v'; + return 'Add CiscoASA1000v Resource'; } }, createForm: { - title: 'Add CiscoASA1000v', + title: 'Add CiscoASA1000v Resource', fields: { hostname: { label: 'label.host', @@ -56,8 +56,7 @@ }, insideportprofile: { label: 'Inside Port Profile', - validation: { required: true }, - defaultValue: 'in-asa' + validation: { required: true } }, clusterid: { label: 'label.cluster', @@ -110,7 +109,78 @@ } } } - } + }, + + detailView: { + name: 'CiscoASA1000v details', + actions: { + remove: { + label: 'delete CiscoASA1000v', + messages: { + confirm: function(args) { + return 'Please confirm you want to delete CiscoASA1000v'; + }, + notification: function(args) { + return 'delete CiscoASA1000v'; + } + }, + action: function(args) { + debugger; + $.ajax({ + url: createURL('deleteCiscoAsa1000vResource'), + data: { + resourceid: args.context.asa1000vDevices[0].resourceid + }, + success: function(json) { + args.response.success(); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + notification: { + poll: function(args) { + args.complete(); + } + } + } + }, + + tabs: { + details: { + title: 'label.details', + + fields: [ + { + hostname: { + label: 'label.host' + } + }, + { + insideportprofile: { label: 'Inside Port Profile' }, + RESOURCE_NAME: { label: 'Resource Name' }, + resourceid: { label: 'Resource ID' } + } + ], + + dataProvider: function(args) { + debugger; + $.ajax({ + url: createURL('listCiscoAsa1000vResources'), + data: { + resourceid: args.context.asa1000vDevices[0].resourceid + }, + success: function(json) { + var item = json.listCiscoAsa1000vResources["null"][0]; //waiting for Koushik to fix object name to be "CiscoAsa1000vResource" instead of "null" + //var item = json.listCiscoAsa1000vResources.CiscoAsa1000vResource[0]; + args.response.success({ data: item }); + } + }); + } + } + } + } } }); }; From 6ef615e40dd56f57813f0fec78ad2bd9e394b8c7 Mon Sep 17 00:00:00 2001 From: Mice Xia Date: Thu, 9 May 2013 11:03:43 +0800 Subject: [PATCH 017/114] fix bug CLOUDSTACK-2341 remove network from VM is not removing PF/LB/static nat rules for the VM --- .../com/cloud/network/rules/RulesManager.java | 3 ++ .../cloud/network/rules/RulesManagerImpl.java | 38 ++++++++++++++ .../src/com/cloud/vm/UserVmManagerImpl.java | 6 +++ .../cloud/vm/VirtualMachineManagerImpl.java | 50 ++++++++++++++----- .../cloud/network/MockRulesManagerImpl.java | 8 +++ 5 files changed, 92 insertions(+), 13 deletions(-) diff --git a/server/src/com/cloud/network/rules/RulesManager.java b/server/src/com/cloud/network/rules/RulesManager.java index 4b83e04eb28..cede987280d 100644 --- a/server/src/com/cloud/network/rules/RulesManager.java +++ b/server/src/com/cloud/network/rules/RulesManager.java @@ -24,6 +24,7 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.IpAddress; import com.cloud.user.Account; import com.cloud.uservm.UserVm; +import com.cloud.vm.Nic; import com.cloud.vm.VirtualMachine; /** @@ -87,4 +88,6 @@ public interface RulesManager extends RulesService { */ boolean applyStaticNatForNetwork(long networkId, boolean continueOnError, Account caller, boolean forRevoke); + List listAssociatedRulesForGuestNic(Nic nic); + } diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java index 23556354e3a..c9b47b44bab 100755 --- a/server/src/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java @@ -50,8 +50,11 @@ import com.cloud.network.dao.FirewallRulesCidrsDao; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.LoadBalancerVMMapDao; +import com.cloud.network.dao.LoadBalancerVMMapVO; import com.cloud.network.rules.FirewallRule.FirewallRuleType; import com.cloud.network.rules.FirewallRule.Purpose; +import com.cloud.network.rules.FirewallRule.TrafficType; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.vpc.VpcManager; import com.cloud.offering.NetworkOffering; @@ -77,6 +80,7 @@ import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.Ip; +import com.cloud.utils.net.NetUtils; import com.cloud.vm.Nic; import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.UserVmVO; @@ -132,6 +136,8 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules VpcManager _vpcMgr; @Inject NicSecondaryIpDao _nicSecondaryDao; + @Inject + LoadBalancerVMMapDao _loadBalancerVMMapDao; @Override public void checkIpAndUserVm(IpAddress ipAddress, UserVm userVm, Account caller) { @@ -1467,4 +1473,36 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules protected void removePFRule(PortForwardingRuleVO rule) { _portForwardingDao.remove(rule.getId()); } + + @Override + public List listAssociatedRulesForGuestNic(Nic nic){ + List result = new ArrayList(); + // add PF rules + result.addAll(_portForwardingDao.listByDestIpAddr(nic.getIp4Address())); + // add static NAT rules + List staticNatRules = _firewallDao.listStaticNatByVmId(nic.getInstanceId()); + for(FirewallRuleVO rule : staticNatRules){ + if(rule.getNetworkId() == nic.getNetworkId()) + result.add(rule); + } + List staticNatIps = _ipAddressDao.listStaticNatPublicIps(nic.getNetworkId()); + for(IpAddress ip : staticNatIps){ + if(ip.getVmIp() != null && ip.getVmIp().equals(nic.getIp4Address())){ + VMInstanceVO vm = _vmInstanceDao.findById(nic.getInstanceId()); + // generate a static Nat rule on the fly because staticNATrule does not persist into db anymore + // FIX ME + FirewallRuleVO staticNatRule = new FirewallRuleVO(null, ip.getId(), 0, 65535, NetUtils.ALL_PROTO.toString(), + nic.getNetworkId(), vm.getAccountId(), vm.getDomainId(), Purpose.StaticNat, null, null, null, null, null); + result.add(staticNatRule); + } + } + // add LB rules + List lbMapList = _loadBalancerVMMapDao.listByInstanceId(nic.getInstanceId()); + for(LoadBalancerVMMapVO lb : lbMapList){ + FirewallRuleVO lbRule = _firewallDao.findById(lb.getLoadBalancerId()); + if(lbRule.getNetworkId() == nic.getNetworkId()) + result.add(lbRule); + } + return result; + } } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index bc25bedde45..644f5ed773f 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -831,6 +831,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use if(network == null) { throw new InvalidParameterValueException("unable to find a network with id " + networkId); } + List allNics = _nicDao.listByVmId(vmInstance.getId()); + for(NicVO nic : allNics){ + if(nic.getNetworkId() == network.getId()) + throw new CloudRuntimeException("A NIC already exists for VM:" + vmInstance.getInstanceName() + " in network: " + network.getUuid()); + } + NicProfile profile = new NicProfile(null, null); if(ipAddress != null) { profile = new NicProfile(ipAddress, null); diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index afffbec436b..521b5e0c582 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -24,7 +24,6 @@ import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -37,40 +36,56 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.capacity.CapacityManager; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; -import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; - -import com.cloud.dc.*; -import com.cloud.agent.api.*; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.AgentManager.OnError; import com.cloud.agent.Listener; +import com.cloud.agent.api.AgentControlAnswer; +import com.cloud.agent.api.AgentControlCommand; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.CheckVirtualMachineAnswer; +import com.cloud.agent.api.CheckVirtualMachineCommand; +import com.cloud.agent.api.ClusterSyncAnswer; +import com.cloud.agent.api.ClusterSyncCommand; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.MigrateAnswer; +import com.cloud.agent.api.MigrateCommand; +import com.cloud.agent.api.PingRoutingCommand; +import com.cloud.agent.api.PrepareForMigrationAnswer; +import com.cloud.agent.api.PrepareForMigrationCommand; +import com.cloud.agent.api.RebootAnswer; +import com.cloud.agent.api.RebootCommand; +import com.cloud.agent.api.ScaleVmCommand; +import com.cloud.agent.api.StartAnswer; +import com.cloud.agent.api.StartCommand; +import com.cloud.agent.api.StartupCommand; +import com.cloud.agent.api.StartupRoutingCommand; import com.cloud.agent.api.StartupRoutingCommand.VmState; +import com.cloud.agent.api.StopAnswer; +import com.cloud.agent.api.StopCommand; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; -import com.cloud.agent.api.to.StorageFilerTO; -import com.cloud.agent.api.to.VolumeTO; import com.cloud.agent.manager.Commands; import com.cloud.agent.manager.allocator.HostAllocator; import com.cloud.alert.AlertManager; +import com.cloud.capacity.CapacityManager; import com.cloud.cluster.ClusterManager; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.dc.dao.ClusterDao; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.ClusterDetailsVO; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; -import com.cloud.consoleproxy.ConsoleProxyManager; +import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; import com.cloud.deploy.DataCenterDeployment; @@ -109,6 +124,7 @@ import com.cloud.network.NetworkManager; import com.cloud.network.NetworkModel; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; +import com.cloud.network.rules.RulesManager; import com.cloud.offering.ServiceOffering; import com.cloud.org.Cluster; import com.cloud.resource.ResourceManager; @@ -126,9 +142,9 @@ import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.GuestOSCategoryDao; import com.cloud.storage.dao.GuestOSDao; +import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VolumeDao; -import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.storage.snapshot.SnapshotManager; import com.cloud.user.Account; import com.cloud.user.AccountManager; @@ -154,12 +170,12 @@ import com.cloud.vm.VirtualMachine.Event; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.VMInstanceDao; import com.cloud.vm.snapshot.VMSnapshot; import com.cloud.vm.snapshot.VMSnapshotManager; import com.cloud.vm.snapshot.VMSnapshotVO; import com.cloud.vm.snapshot.dao.VMSnapshotDao; -import com.cloud.vm.dao.UserVmDetailsDao; @Local(value = VirtualMachineManager.class) public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMachineManager, Listener { @@ -235,6 +251,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac protected VolumeDataFactory volFactory; @Inject protected ResourceLimitService _resourceLimitMgr; + @Inject + protected RulesManager rulesMgr; protected List _planners; public List getPlanners() { @@ -2845,6 +2863,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac s_logger.warn("Failed to remove nic from " + vm + " in " + network + ", nic is default."); throw new CloudRuntimeException("Failed to remove nic from " + vm + " in " + network + ", nic is default."); } + + // if specified nic is associated with PF/LB/Static NAT + if(rulesMgr.listAssociatedRulesForGuestNic(nic).size() > 0){ + throw new CloudRuntimeException("Failed to remove nic from " + vm + " in " + network + + ", nic has associated Port forwarding or Load balancer or Static NAT rules."); + } NicProfile nicProfile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), _networkModel.getNetworkRate(network.getId(), vm.getId()), diff --git a/server/test/com/cloud/network/MockRulesManagerImpl.java b/server/test/com/cloud/network/MockRulesManagerImpl.java index 200fd2c7462..82a3e9346e3 100644 --- a/server/test/com/cloud/network/MockRulesManagerImpl.java +++ b/server/test/com/cloud/network/MockRulesManagerImpl.java @@ -28,6 +28,7 @@ import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.PortForwardingRuleVO; import com.cloud.network.rules.RulesManager; @@ -40,6 +41,7 @@ import com.cloud.utils.Pair; import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.net.Ip; +import com.cloud.vm.Nic; import com.cloud.vm.VirtualMachine; @Local(value = {RulesManager.class, RulesService.class}) @@ -310,4 +312,10 @@ public class MockRulesManagerImpl extends ManagerBase implements RulesManager, R return null; } + @Override + public List listAssociatedRulesForGuestNic(Nic nic) { + // TODO Auto-generated method stub + return null; + } + } From 600f140df67e8521e118691f92b460d55e7ec656 Mon Sep 17 00:00:00 2001 From: Mice Xia Date: Thu, 9 May 2013 14:27:13 +0800 Subject: [PATCH 018/114] fix CLOUDSTACK-2277 Add approriate message for the user informing about the absence of vm-tools when adding nics to vm on vmware --- .../vmware/resource/VmwareResource.java | 18 ++++++++++++++++++ server/src/com/cloud/vm/UserVmManagerImpl.java | 4 ++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 030eff0148a..d87da64040b 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -237,6 +237,7 @@ import com.vmware.vim25.ClusterDasConfigInfo; import com.vmware.vim25.ComputeResourceSummary; import com.vmware.vim25.DatastoreSummary; import com.vmware.vim25.DynamicProperty; +import com.vmware.vim25.GuestInfo; import com.vmware.vim25.HostCapability; import com.vmware.vim25.HostFirewallInfo; import com.vmware.vim25.HostFirewallRuleset; @@ -1326,6 +1327,12 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa throw new Exception(msg); } + if(!isVMWareToolsInstalled(vmMo)){ + String errMsg = "vmware tools is not installed or not running, cannot add nic to vm " + vmName; + s_logger.debug(errMsg); + return new PlugNicAnswer(cmd, false, "Unable to execute PlugNicCommand due to " + errMsg); + } + // TODO need a way to specify the control of NIC device type VirtualEthernetCardType nicDeviceType = VirtualEthernetCardType.E1000; @@ -1400,6 +1407,12 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa throw new Exception(msg); } + if(!isVMWareToolsInstalled(vmMo)){ + String errMsg = "vmware tools not installed or not running, cannot remove nic from vm " + vmName; + s_logger.debug(errMsg); + return new UnPlugNicAnswer(cmd, false, "Unable to execute unPlugNicCommand due to " + errMsg); + } + VirtualDevice nic = findVirtualNicDevice(vmMo, cmd.getNic().getMac()); if ( nic == null ) { return new UnPlugNicAnswer(cmd, true, "success"); @@ -5237,4 +5250,9 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa // TODO Auto-generated method stub } + + private boolean isVMWareToolsInstalled(VirtualMachineMO vmMo) throws Exception{ + GuestInfo guestInfo = vmMo.getVmGuestInfo(); + return (guestInfo != null && guestInfo.getGuestState() != null && guestInfo.getGuestState().equalsIgnoreCase("running")); + } } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 644f5ed773f..eee8503b3f5 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -4248,7 +4248,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use _agentMgr.send(dest.getHost().getId(),cmds); PlugNicAnswer plugNicAnswer = cmds.getAnswer(PlugNicAnswer.class); if (!(plugNicAnswer != null && plugNicAnswer.getResult())) { - s_logger.warn("Unable to plug nic for " + vmVO); + s_logger.warn("Unable to plug nic for " + vmVO + " due to: " + " due to: " + plugNicAnswer.getDetails()); return false; } } catch (OperationTimedoutException e) { @@ -4276,7 +4276,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use _agentMgr.send(dest.getHost().getId(),cmds); UnPlugNicAnswer unplugNicAnswer = cmds.getAnswer(UnPlugNicAnswer.class); if (!(unplugNicAnswer != null && unplugNicAnswer.getResult())) { - s_logger.warn("Unable to unplug nic for " + vmVO); + s_logger.warn("Unable to unplug nic for " + vmVO + " due to: " + unplugNicAnswer.getDetails()); return false; } } catch (OperationTimedoutException e) { From 2e1877af33a49d4d18d3e024abca16b3d72dbf4e Mon Sep 17 00:00:00 2001 From: Milamber Date: Thu, 9 May 2013 10:46:05 +0100 Subject: [PATCH 019/114] CLOUDSTACK-2413 - Display the Name of compute offering in dialog box Change Service Offering (was Description field before) --- ui/scripts/instances.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js index e5d7d14569b..c76d843ed6e 100644 --- a/ui/scripts/instances.js +++ b/ui/scripts/instances.js @@ -934,7 +934,7 @@ var serviceofferings = json.listserviceofferingsresponse.serviceoffering; var items = []; $(serviceofferings).each(function() { - items.push({id: this.id, description: this.displaytext}); + items.push({id: this.id, description: this.name}); }); args.response.success({data: items}); } From 2e2106002865cff8eb06b5c3a42bfd6f0f6848fb Mon Sep 17 00:00:00 2001 From: Rajesh Battala Date: Wed, 8 May 2013 18:46:51 +0530 Subject: [PATCH 020/114] CLOUDSTACK-869 nTier Apps 2.0 : Support NetScalar as external LB provider --- .../com/cloud/network/vpc/VpcOffering.java | 1 + .../network/element/NetscalerElement.java | 34 ++- server/pom.xml | 4 +- .../com/cloud/network/NetworkServiceImpl.java | 6 +- .../guru/ExternalGuestNetworkGuru.java | 40 +-- .../com/cloud/network/vpc/VpcManagerImpl.java | 32 ++- server/test/com/cloud/vpc/VpcTest.java | 269 ++++++++++++++++++ .../CreateNetworkOfferingTest.java | 43 +++ 8 files changed, 406 insertions(+), 23 deletions(-) create mode 100644 server/test/com/cloud/vpc/VpcTest.java diff --git a/api/src/com/cloud/network/vpc/VpcOffering.java b/api/src/com/cloud/network/vpc/VpcOffering.java index 3961d0aaba7..3ec81e693af 100644 --- a/api/src/com/cloud/network/vpc/VpcOffering.java +++ b/api/src/com/cloud/network/vpc/VpcOffering.java @@ -26,6 +26,7 @@ public interface VpcOffering extends InternalIdentity, Identity { } public static final String defaultVPCOfferingName = "Default VPC offering"; + public static final String defaultVPCNSOfferingName = "Default VPC offering with Netscaler"; /** * diff --git a/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java b/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java index 7bd9c2ec8b3..b8144301810 100644 --- a/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java +++ b/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java @@ -61,6 +61,9 @@ import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.LbStickinessMethod; import com.cloud.network.rules.LbStickinessMethod.StickinessMethodType; import com.cloud.network.rules.StaticNat; +import com.cloud.network.vpc.PrivateGateway; +import com.cloud.network.vpc.StaticRouteProfile; +import com.cloud.network.vpc.Vpc; import com.cloud.offering.NetworkOffering; import com.cloud.utils.NumbersUtil; import com.cloud.utils.db.DB; @@ -85,7 +88,7 @@ import java.util.*; @Local(value = {NetworkElement.class, StaticNatServiceProvider.class, LoadBalancingServiceProvider.class, GslbServiceProvider.class}) public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl implements LoadBalancingServiceProvider, NetscalerLoadBalancerElementService, ExternalLoadBalancerDeviceManager, IpDeployer, StaticNatServiceProvider, - GslbServiceProvider { + GslbServiceProvider, VpcProvider { private static final Logger s_logger = Logger.getLogger(NetscalerElement.class); public static final AutoScaleCounterType AutoScaleCounterSnmp = new AutoScaleCounterType("snmp"); @@ -957,4 +960,33 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl } return null; } + + @Override + public boolean implementVpc(Vpc vpc, DeployDestination dest, ReservationContext context) + throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { + return true; + } + + @Override + public boolean shutdownVpc(Vpc vpc, ReservationContext context) throws ConcurrentOperationException, + ResourceUnavailableException { + return true; + } + + @Override + public boolean createPrivateGateway(PrivateGateway gateway) throws ConcurrentOperationException, + ResourceUnavailableException { + return true; + } + + @Override + public boolean deletePrivateGateway(PrivateGateway privateGateway) throws ConcurrentOperationException, + ResourceUnavailableException { + return true; + } + + @Override + public boolean applyStaticRoutes(Vpc vpc, List routes) throws ResourceUnavailableException { + return true; + } } diff --git a/server/pom.xml b/server/pom.xml index 808dd3eee0a..004d9c8e068 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -154,7 +154,9 @@ com/cloud/network/vpn/RemoteAccessVpnTest.java com/cloud/network/security/SecurityGroupManagerImpl2Test.java com/cloud/network/security/SecurityGroupManagerImpl2Test.java - com/cloud/vpc/* + com/cloud/vpc/VpcTestConfiguration.java + com/cloud/vpc/VpcApiUnitTest.java + com/cloud/vpc/VpcManagerTest.java diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 5e8be92fdb5..f44688c7594 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -1121,7 +1121,11 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { // validate if CIDR specified overlaps with any of the CIDR's allocated for isolated networks and shared networks in the zone checkSharedNetworkCidrOverlap(zoneId, pNtwk.getId(), cidr); } else { - throw new InvalidParameterValueException("Cannot specify CIDR when using network offering with external devices!"); + // if the guest network is for the VPC, if any External Provider are supported in VPC + // cidr will not be null as it is generated from the super cidr of vpc. + // if cidr is not null and network is not part of vpc then throw the exception + if (vpcId == null) + throw new InvalidParameterValueException("Cannot specify CIDR when using network offering with external devices!"); } } diff --git a/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java b/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java index b1606db71b1..fe9e01f558d 100644 --- a/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java +++ b/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java @@ -118,7 +118,7 @@ public class ExternalGuestNetworkGuru extends GuestNetworkGuru { if (Boolean.parseBoolean(_configDao.getValue(Config.OvsTunnelNetwork.key()))) { return null; } - + if (!_networkModel.networkIsConfiguredForExternalNetworking(config.getDataCenterId(), config.getId())) { return super.implement(config, offering, dest, context); } @@ -145,25 +145,31 @@ public class ExternalGuestNetworkGuru extends GuestNetworkGuru { implemented.setBroadcastUri(config.getBroadcastUri()); } - // Determine the offset from the lowest vlan tag - int offset = getVlanOffset(config.getPhysicalNetworkId(), vlanTag); - // Determine the new gateway and CIDR String[] oldCidr = config.getCidr().split("/"); String oldCidrAddress = oldCidr[0]; - int cidrSize = getGloballyConfiguredCidrSize(); - - // If the offset has more bits than there is room for, return null - long bitsInOffset = 32 - Integer.numberOfLeadingZeros(offset); - if (bitsInOffset > (cidrSize - 8)) { - throw new CloudRuntimeException("The offset " + offset + " needs " + bitsInOffset + " bits, but only have " + (cidrSize - 8) + " bits to work with."); + int cidrSize = Integer.parseInt(oldCidr[1]); + long newCidrAddress = (NetUtils.ip2Long(oldCidrAddress)); + // if the implementing network is for vpc, no need to generate newcidr, use the cidr that came from super cidr + if (config.getVpcId() != null) { + implemented.setGateway(config.getGateway()); + implemented.setCidr(config.getCidr()); + implemented.setState(State.Implemented); + } else { + // Determine the offset from the lowest vlan tag + int offset = getVlanOffset(config.getPhysicalNetworkId(), vlanTag); + cidrSize = getGloballyConfiguredCidrSize(); + // If the offset has more bits than there is room for, return null + long bitsInOffset = 32 - Integer.numberOfLeadingZeros(offset); + if (bitsInOffset > (cidrSize - 8)) { + throw new CloudRuntimeException("The offset " + offset + " needs " + bitsInOffset + " bits, but only have " + (cidrSize - 8) + " bits to work with."); + } + newCidrAddress = (NetUtils.ip2Long(oldCidrAddress) & 0xff000000) | (offset << (32 - cidrSize)); + implemented.setGateway(NetUtils.long2Ip(newCidrAddress + 1)); + implemented.setCidr(NetUtils.long2Ip(newCidrAddress) + "/" + cidrSize); + implemented.setState(State.Implemented); } - long newCidrAddress = (NetUtils.ip2Long(oldCidrAddress) & 0xff000000) | (offset << (32 - cidrSize)); - implemented.setGateway(NetUtils.long2Ip(newCidrAddress + 1)); - implemented.setCidr(NetUtils.long2Ip(newCidrAddress) + "/" + cidrSize); - implemented.setState(State.Implemented); - // Mask the Ipv4 address of all nics that use this network with the new guest VLAN offset List nicsInNetwork = _nicDao.listByNetworkId(config.getId()); for (NicVO nic : nicsInNetwork) { @@ -172,8 +178,8 @@ public class ExternalGuestNetworkGuru extends GuestNetworkGuru { nic.setIp4Address(NetUtils.long2Ip(newCidrAddress | ipMask)); _nicDao.persist(nic); } - } - + } + // Mask the destination address of all port forwarding rules in this network with the new guest VLAN offset List pfRulesInNetwork = _pfRulesDao.listByNetwork(config.getId()); for (PortForwardingRuleVO pfRule : pfRulesInNetwork) { diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index a7f06e988dd..9be22084e11 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -184,8 +184,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("VpcChecker")); private List vpcElements = null; private final List nonSupportedServices = Arrays.asList(Service.SecurityGroup, Service.Firewall); - private final List supportedProviders = Arrays.asList(Provider.VPCVirtualRouter, Provider.NiciraNvp); - + private final List supportedProviders = Arrays.asList(Provider.VPCVirtualRouter, Provider.NiciraNvp, Provider.Netscaler); int _cleanupInterval; int _maxNetworks; SearchBuilder IpAddressSearch; @@ -215,7 +214,27 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis createVpcOffering(VpcOffering.defaultVPCOfferingName, VpcOffering.defaultVPCOfferingName, svcProviderMap, true, State.Enabled); } - + + //configure default vpc offering with Netscaler as LB Provider + if (_vpcOffDao.findByUniqueName(VpcOffering.defaultVPCNSOfferingName ) == null) { + s_logger.debug("Creating default VPC offering with Netscaler as LB Provider" + VpcOffering.defaultVPCNSOfferingName); + Map> svcProviderMap = new HashMap>(); + Set defaultProviders = new HashSet(); + defaultProviders.add(Provider.VPCVirtualRouter); + for (Service svc : getSupportedServices()) { + if (svc == Service.Lb) { + Set lbProviders = new HashSet(); + lbProviders.add(Provider.Netscaler); + lbProviders.add(Provider.VPCVirtualRouter); + svcProviderMap.put(svc, lbProviders); + } else { + svcProviderMap.put(svc, defaultProviders); + } + } + createVpcOffering(VpcOffering.defaultVPCNSOfferingName, VpcOffering.defaultVPCNSOfferingName, + svcProviderMap, false, State.Enabled); + } + txn.commit(); Map configs = _configDao.getConfiguration(params); @@ -1084,6 +1103,12 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis if (guestNtwkOff.isConserveMode()) { throw new InvalidParameterValueException("Only networks with conserve mode Off can belong to VPC"); } + + //5) If Netscaler is LB provider make sure it is in dedicated mode + if ( providers.contains(Provider.Netscaler) && !guestNtwkOff.getDedicatedLB() ) { + throw new InvalidParameterValueException("Netscaler only with Dedicated LB can belong to VPC"); + } + return ; } @DB @@ -1155,6 +1180,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis if (vpcElements == null) { vpcElements = new ArrayList(); vpcElements.add((VpcProvider)_ntwkModel.getElementImplementingProvider(Provider.VPCVirtualRouter.getName())); + vpcElements.add((VpcProvider)_ntwkModel.getElementImplementingProvider(Provider.Netscaler.getName())); } if (vpcElements == null) { diff --git a/server/test/com/cloud/vpc/VpcTest.java b/server/test/com/cloud/vpc/VpcTest.java new file mode 100644 index 00000000000..52e837ec5ca --- /dev/null +++ b/server/test/com/cloud/vpc/VpcTest.java @@ -0,0 +1,269 @@ +// 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. + +package com.cloud.vpc; + +import com.cloud.configuration.ConfigurationManager; +import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.VlanDao; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkModel; +import com.cloud.network.NetworkService; +import com.cloud.network.dao.FirewallRulesDao; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.Site2SiteVpnGatewayDao; +import com.cloud.network.vpc.*; +import com.cloud.network.vpc.dao.PrivateIpDao; +import com.cloud.network.vpc.dao.StaticRouteDao; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.network.vpc.dao.VpcGatewayDao; +import com.cloud.network.vpc.dao.VpcOfferingDao; +import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; +import com.cloud.network.vpc.dao.VpcServiceMapDao; +import com.cloud.network.vpn.Site2SiteVpnManager; +import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; +import com.cloud.server.ConfigurationServer; +import com.cloud.tags.dao.ResourceTagDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.ResourceLimitService; +import com.cloud.user.UserContext; +import com.cloud.utils.component.ComponentContext; +import com.cloud.vm.dao.DomainRouterDao; + +import junit.framework.TestCase; +import org.apache.cloudstack.api.command.user.network.CreateNetworkACLCmd; +import org.apache.cloudstack.api.command.user.vpc.CreateVPCCmd; +import org.apache.cloudstack.test.utils.SpringUtils; +import org.apache.log4j.Logger; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.filter.TypeFilter; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; + +import javax.inject.Inject; +import java.io.IOException; +import java.util.UUID; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(loader = AnnotationConfigContextLoader.class) +public class VpcTest extends TestCase { + + @Inject + VpcService _vpcService; + + @Inject + AccountManager _accountMgr; + + @Inject + VpcManager _vpcMgr; + + @Inject + VpcDao _vpcDao; + + @Inject + VpcOfferingDao _vpcOfferinDao; + + private VpcVO vpc; + private static final Logger s_logger = Logger.getLogger(VpcTest.class); + + @Before + public void setUp() { + ComponentContext.initComponentsLifeCycle(); + Account account = new AccountVO("testaccount", 1, "testdomain", (short) 0, UUID.randomUUID().toString()); + UserContext.registerContext(1, account, null, true); + vpc = new VpcVO(1, "myvpc", "myvpc", 2, 1, 1, "10.0.1.0/16", "mydomain"); + } + + @Test + public void testCreateVpc() throws Exception { + Mockito.when( + _vpcMgr.createVpc(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString(), + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenReturn(vpc); + Mockito.when(_vpcOfferinDao.persist(Mockito.any(VpcOfferingVO.class))).thenReturn( + new VpcOfferingVO("test", "test", 1L)); + Vpc vpc1 = _vpcMgr.createVpc(1, 1, 1, "myVpc", "my Vpc", "10.0.0.0/16", "test"); + assertNotNull("Vpc is created", vpc1); + } + + @Configuration + @ComponentScan(basePackageClasses = { VpcManager.class }, includeFilters = { @ComponentScan.Filter(value = VpcTestConfiguration.Library.class, type = FilterType.CUSTOM) }, useDefaultFilters = false) + public static class VpcTestConfiguration extends SpringUtils.CloudStackTestConfiguration { + + @Bean + public AccountManager accountManager() { + return Mockito.mock(AccountManager.class); + } + + @Bean + public NetworkManager networkManager() { + return Mockito.mock(NetworkManager.class); + } + + @Bean + public NetworkModel networkModel() { + return Mockito.mock(NetworkModel.class); + } + + @Bean + public VpcManager vpcManager() { + return Mockito.mock(VpcManager.class); + } + + @Bean + public ResourceTagDao resourceTagDao() { + return Mockito.mock(ResourceTagDao.class); + } + + @Bean + public VpcDao VpcDao() { + return Mockito.mock(VpcDao.class); + } + + @Bean + public VpcOfferingDao vpcOfferingDao() { + return Mockito.mock(VpcOfferingDao.class); + } + + @Bean + public VpcOfferingServiceMapDao vpcOfferingServiceMapDao() { + return Mockito.mock(VpcOfferingServiceMapDao.class); + } + + @Bean + public ConfigurationDao configurationDao() { + return Mockito.mock(ConfigurationDao.class); + } + + @Bean + public ConfigurationManager configurationManager() { + return Mockito.mock(ConfigurationManager.class); + } + + @Bean + public NetworkDao networkDao() { + return Mockito.mock(NetworkDao.class); + } + + @Bean + public NetworkACLManager networkACLManager() { + return Mockito.mock(NetworkACLManager.class); + } + + @Bean + public IPAddressDao ipAddressDao() { + return Mockito.mock(IPAddressDao.class); + } + + @Bean + public DomainRouterDao domainRouterDao() { + return Mockito.mock(DomainRouterDao.class); + } + + @Bean + public VpcGatewayDao vpcGatewayDao() { + return Mockito.mock(VpcGatewayDao.class); + } + + @Bean + public PrivateIpDao privateIpDao() { + return Mockito.mock(PrivateIpDao.class); + } + + @Bean + public StaticRouteDao staticRouteDao() { + return Mockito.mock(StaticRouteDao.class); + } + + @Bean + public NetworkOfferingServiceMapDao networkOfferingServiceMapDao() { + return Mockito.mock(NetworkOfferingServiceMapDao.class); + } + + @Bean + public PhysicalNetworkDao physicalNetworkDao() { + return Mockito.mock(PhysicalNetworkDao.class); + } + + @Bean + public FirewallRulesDao firewallRulesDao() { + return Mockito.mock(FirewallRulesDao.class); + } + + @Bean + public Site2SiteVpnGatewayDao site2SiteVpnGatewayDao() { + return Mockito.mock(Site2SiteVpnGatewayDao.class); + } + + @Bean + public Site2SiteVpnManager site2SiteVpnManager() { + return Mockito.mock(Site2SiteVpnManager.class); + } + + @Bean + public VlanDao vlanDao() { + return Mockito.mock(VlanDao.class); + } + + @Bean + public ResourceLimitService resourceLimitService() { + return Mockito.mock(ResourceLimitService.class); + } + + @Bean + public VpcServiceMapDao vpcServiceMapDao() { + return Mockito.mock(VpcServiceMapDao.class); + } + + @Bean + public NetworkService networkService() { + return Mockito.mock(NetworkService.class); + } + + @Bean + public DataCenterDao dataCenterDao() { + return Mockito.mock(DataCenterDao.class); + } + + @Bean + public ConfigurationServer configurationServer() { + return Mockito.mock(ConfigurationServer.class); + } + + public static class Library implements TypeFilter { + @Override + public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { + mdr.getClassMetadata().getClassName(); + ComponentScan cs = VpcTestConfiguration.class.getAnnotation(ComponentScan.class); + return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + } + } + } + +} diff --git a/server/test/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java b/server/test/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java index cbb6c00e397..7946c1aa740 100644 --- a/server/test/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java +++ b/server/test/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java @@ -41,6 +41,7 @@ import com.cloud.network.Network; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.Networks.TrafficType; +import com.cloud.network.vpc.VpcManager; import com.cloud.offering.NetworkOffering.Availability; import com.cloud.offerings.NetworkOfferingServiceMapVO; import com.cloud.offerings.NetworkOfferingVO; @@ -72,6 +73,9 @@ public class CreateNetworkOfferingTest extends TestCase{ @Inject AccountManager accountMgr; + @Inject + VpcManager vpcMgr; + @Before public void setUp() { ComponentContext.initComponentsLifeCycle(); @@ -180,4 +184,43 @@ public class CreateNetworkOfferingTest extends TestCase{ assertNotNull("Isolated network offering with specifyIpRanges=true and with no sourceNatService, failed to create", off); } + + @Test + public void createVpcNtwkOff() { + Map> serviceProviderMap = new HashMap>(); + Set vrProvider = new HashSet(); + vrProvider.add(Provider.VPCVirtualRouter); + serviceProviderMap.put(Network.Service.Dhcp , vrProvider); + serviceProviderMap.put(Network.Service.Dns , vrProvider); + serviceProviderMap.put(Network.Service.Lb , vrProvider); + serviceProviderMap.put(Network.Service.SourceNat , vrProvider); + serviceProviderMap.put(Network.Service.Gateway , vrProvider); + serviceProviderMap.put(Network.Service.Lb , vrProvider); + NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, + Availability.Optional, 200, serviceProviderMap, false, Network.GuestType.Isolated, false, + null, false, null, false, false); + // System.out.println("Creating Vpc Network Offering"); + assertNotNull("Vpc Isolated network offering with Vpc provider ", off); + } + + @Test + public void createVpcNtwkOffWithNetscaler() { + Map> serviceProviderMap = new HashMap>(); + Set vrProvider = new HashSet(); + Set lbProvider = new HashSet(); + vrProvider.add(Provider.VPCVirtualRouter); + lbProvider.add(Provider.Netscaler); + serviceProviderMap.put(Network.Service.Dhcp, vrProvider); + serviceProviderMap.put(Network.Service.Dns, vrProvider); + serviceProviderMap.put(Network.Service.Lb, vrProvider); + serviceProviderMap.put(Network.Service.SourceNat, vrProvider); + serviceProviderMap.put(Network.Service.Gateway, vrProvider); + serviceProviderMap.put(Network.Service.Lb, lbProvider); + NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, + Availability.Optional, 200, serviceProviderMap, false, Network.GuestType.Isolated, false, null, false, + null, false, false); + // System.out.println("Creating Vpc Network Offering"); + assertNotNull("Vpc Isolated network offering with Vpc and Netscaler provider ", off); + } + } From bde9ad3c13397758cce0b69414c0a70904947d11 Mon Sep 17 00:00:00 2001 From: Koushik Das Date: Thu, 9 May 2013 15:49:36 +0530 Subject: [PATCH 021/114] CLOUDSTACK-2408: Object name is Null with list VNMC/List ASA API response Setting object name correctly in response --- .../ListCiscoAsa1000vResourcesCmd.java | 1 + .../commands/ListCiscoVnmcResourcesCmd.java | 15 ++++--- .../CiscoAsa1000vResourceResponse.java | 45 +++++++++++-------- .../response/CiscoVnmcResourceResponse.java | 42 ++++++++++------- 4 files changed, 62 insertions(+), 41 deletions(-) diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoAsa1000vResourcesCmd.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoAsa1000vResourcesCmd.java index 509d39fb5f9..7a4db69e7e2 100755 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoAsa1000vResourcesCmd.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoAsa1000vResourcesCmd.java @@ -89,6 +89,7 @@ public class ListCiscoAsa1000vResourcesCmd extends BaseListCmd { if (ciscoAsa1000vDevices != null && !ciscoAsa1000vDevices.isEmpty()) { for (CiscoAsa1000vDevice ciscoAsa1000vDeviceVO : ciscoAsa1000vDevices) { CiscoAsa1000vResourceResponse ciscoAsa1000vResourceResponse = _ciscoAsa1000vService.createCiscoAsa1000vResourceResponse(ciscoAsa1000vDeviceVO); + ciscoAsa1000vResourceResponse.setObjectName("asa1000v"); ciscoAsa1000vResourcesResponse.add(ciscoAsa1000vResourceResponse); } } diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoVnmcResourcesCmd.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoVnmcResourcesCmd.java index ab553ee94ac..b15c4e1c43e 100644 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoVnmcResourcesCmd.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoVnmcResourcesCmd.java @@ -77,18 +77,19 @@ public class ListCiscoVnmcResourcesCmd extends BaseListCmd { @Override public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { try { - List CiscoVnmcResources = _ciscoVnmcElementService.listCiscoVnmcResources(this); + List ciscoVnmcResources = _ciscoVnmcElementService.listCiscoVnmcResources(this); ListResponse response = new ListResponse(); - List CiscoVnmcResourcesResponse = new ArrayList(); + List ciscoVnmcResourcesResponse = new ArrayList(); - if (CiscoVnmcResources != null && !CiscoVnmcResources.isEmpty()) { - for (CiscoVnmcController CiscoVnmcResourceVO : CiscoVnmcResources) { - CiscoVnmcResourceResponse CiscoVnmcResourceResponse = _ciscoVnmcElementService.createCiscoVnmcResourceResponse(CiscoVnmcResourceVO); - CiscoVnmcResourcesResponse.add(CiscoVnmcResourceResponse); + if (ciscoVnmcResources != null && !ciscoVnmcResources.isEmpty()) { + for (CiscoVnmcController ciscoVnmcResourceVO : ciscoVnmcResources) { + CiscoVnmcResourceResponse ciscoVnmcResourceResponse = _ciscoVnmcElementService.createCiscoVnmcResourceResponse(ciscoVnmcResourceVO); + ciscoVnmcResourceResponse.setObjectName("vnmc"); + ciscoVnmcResourcesResponse.add(ciscoVnmcResourceResponse); } } - response.setResponses(CiscoVnmcResourcesResponse); + response.setResponses(ciscoVnmcResourcesResponse); response.setResponseName(getCommandName()); this.setResponseObject(response); } catch (InvalidParameterValueException invalidParamExcp) { diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoAsa1000vResourceResponse.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoAsa1000vResourceResponse.java index 9cd87da66a1..f857b352b4a 100755 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoAsa1000vResourceResponse.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoAsa1000vResourceResponse.java @@ -29,60 +29,69 @@ import com.google.gson.annotations.SerializedName; @EntityReference(value = CiscoAsa1000vDevice.class) public class CiscoAsa1000vResourceResponse extends BaseResponse { - public static final String RESOURCE_NAME = "resourcename"; - @SerializedName(ApiConstants.RESOURCE_ID) @Parameter(description="resource id of the Cisco ASA 1000v appliance") + @SerializedName(ApiConstants.RESOURCE_ID) + @Parameter(description="resource id of the Cisco ASA 1000v appliance") private String id; @SerializedName(ApiConstants.PHYSICAL_NETWORK_ID) @Parameter(description="the physical network to which this ASA 1000v belongs to", entityType = PhysicalNetworkResponse.class) - private Long physicalNetworkId ; - - public Long getPhysicalNetworkId() { - return physicalNetworkId; - } + private Long physicalNetworkId; @SerializedName(ApiConstants.HOST_NAME) @Parameter(description="management ip address of ASA 1000v") private String managementIp; - public String getManagementIp() { - return managementIp; - } - @SerializedName(ApiConstants.ASA_INSIDE_PORT_PROFILE) - @Parameter(description="management ip address of ASA 1000v") + @Parameter(description="port profile associated with inside interface of ASA 1000v") private String inPortProfile; - public String getInPortProfile() { - return inPortProfile; - } - @SerializedName(ApiConstants.NETWORK_ID) @Parameter(description="the guest network to which ASA 1000v is associated", entityType = NetworkResponse.class) private Long guestNetworkId; - public Long getGuestNetworkId() { - return guestNetworkId; + public String getId() { + return id; } public void setId(String ciscoAsa1000vResourceId) { this.id = ciscoAsa1000vResourceId; } + public Long getPhysicalNetworkId() { + return physicalNetworkId; + } + public void setPhysicalNetworkId(Long physicalNetworkId) { this.physicalNetworkId = physicalNetworkId; } + public String getManagementIp() { + return managementIp; + } + public void setManagementIp(String managementIp) { this.managementIp = managementIp; } + public String getInPortProfile() { + return inPortProfile; + } + public void setInPortProfile(String inPortProfile) { this.inPortProfile = inPortProfile; } + public Long getGuestNetworkId() { + return guestNetworkId; + } + public void setGuestNetworkId(Long guestNetworkId) { this.guestNetworkId = guestNetworkId; } + + @Override + public String getObjectId() { + return this.getId(); + } } diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoVnmcResourceResponse.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoVnmcResourceResponse.java index f5c9b727f8f..92a766d1bbf 100644 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoVnmcResourceResponse.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoVnmcResourceResponse.java @@ -25,6 +25,7 @@ import org.apache.cloudstack.api.response.PhysicalNetworkResponse; import com.cloud.network.cisco.CiscoVnmcController; import com.google.gson.annotations.SerializedName; + @EntityReference(value = CiscoVnmcController.class) public class CiscoVnmcResourceResponse extends BaseResponse { public static final String RESOURCE_NAME = "resourcename"; @@ -33,43 +34,52 @@ public class CiscoVnmcResourceResponse extends BaseResponse { @Parameter(description="resource id of the Cisco VNMC controller") private String id; - @SerializedName(ApiConstants.PHYSICAL_NETWORK_ID) + @SerializedName(ApiConstants.PHYSICAL_NETWORK_ID) @Parameter(description="the physical network to which this VNMC belongs to", entityType = PhysicalNetworkResponse.class) private Long physicalNetworkId; - public Long getPhysicalNetworkId() { - return physicalNetworkId; - } - - public String getProviderName() { - return providerName; - } - - public String getResourceName() { - return resourceName; - } - - @SerializedName(ApiConstants.PROVIDER) @Parameter(description="name of the provider") + @SerializedName(ApiConstants.PROVIDER) + @Parameter(description="name of the provider") private String providerName; - @SerializedName(RESOURCE_NAME) + @SerializedName(RESOURCE_NAME) @Parameter(description="Cisco VNMC resource name") private String resourceName; + public String getId() { + return id; + } + public void setId(String ciscoVnmcResourceId) { this.id = ciscoVnmcResourceId; } + public Long getPhysicalNetworkId() { + return physicalNetworkId; + } + public void setPhysicalNetworkId(Long physicalNetworkId) { this.physicalNetworkId = physicalNetworkId; } + public String getProviderName() { + return providerName; + } + public void setProviderName(String providerName) { this.providerName = providerName; } + public String getResourceName() { + return resourceName; + } + public void setResourceName(String resourceName) { this.resourceName = resourceName; - } + } + @Override + public String getObjectId() { + return this.getId(); + } } From 8f9a42e0af7424517c7853197a781c0c81addad1 Mon Sep 17 00:00:00 2001 From: Koushik Das Date: Thu, 9 May 2013 15:58:59 +0530 Subject: [PATCH 022/114] CLOUDSTACK-2408: Object name is Null with list VNMC/List ASA API response Made the object name consistent between list and add api responses --- .../com/cloud/api/commands/ListCiscoAsa1000vResourcesCmd.java | 2 +- .../src/com/cloud/api/commands/ListCiscoVnmcResourcesCmd.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoAsa1000vResourcesCmd.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoAsa1000vResourcesCmd.java index 7a4db69e7e2..88ea2709325 100755 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoAsa1000vResourcesCmd.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoAsa1000vResourcesCmd.java @@ -89,7 +89,7 @@ public class ListCiscoAsa1000vResourcesCmd extends BaseListCmd { if (ciscoAsa1000vDevices != null && !ciscoAsa1000vDevices.isEmpty()) { for (CiscoAsa1000vDevice ciscoAsa1000vDeviceVO : ciscoAsa1000vDevices) { CiscoAsa1000vResourceResponse ciscoAsa1000vResourceResponse = _ciscoAsa1000vService.createCiscoAsa1000vResourceResponse(ciscoAsa1000vDeviceVO); - ciscoAsa1000vResourceResponse.setObjectName("asa1000v"); + ciscoAsa1000vResourceResponse.setObjectName("CiscoAsa1000vResource"); ciscoAsa1000vResourcesResponse.add(ciscoAsa1000vResourceResponse); } } diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoVnmcResourcesCmd.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoVnmcResourcesCmd.java index b15c4e1c43e..73128ecec2b 100644 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoVnmcResourcesCmd.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoVnmcResourcesCmd.java @@ -84,7 +84,7 @@ public class ListCiscoVnmcResourcesCmd extends BaseListCmd { if (ciscoVnmcResources != null && !ciscoVnmcResources.isEmpty()) { for (CiscoVnmcController ciscoVnmcResourceVO : ciscoVnmcResources) { CiscoVnmcResourceResponse ciscoVnmcResourceResponse = _ciscoVnmcElementService.createCiscoVnmcResourceResponse(ciscoVnmcResourceVO); - ciscoVnmcResourceResponse.setObjectName("vnmc"); + ciscoVnmcResourceResponse.setObjectName("CiscoVnmcResource"); ciscoVnmcResourcesResponse.add(ciscoVnmcResourceResponse); } } From c9bb5356bde4dcd40ebaea0e6ed0b36560f86267 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Thu, 9 May 2013 11:37:30 -0700 Subject: [PATCH 023/114] CLOUDSTACK-1816: Cisco VNMC ASA1000v - UI - CiscoVNMC - populate listView. --- .../vnmcNetworkProvider.js | 35 ++++++------------- 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js b/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js index 135cefac62c..c4c371cbc4f 100644 --- a/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js +++ b/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js @@ -26,12 +26,8 @@ var vnmcListView = { id: 'vnmcDevices', fields: { - name: { label: 'label.name' }, - ipaddress: { label: 'label.ip.address' }, - state: { label: 'label.state', indicator: { - 'Enabled': 'on', - 'Disabled': 'off' - }} + resourcename: { label: 'Resource Name' }, + provider: { label: 'Provider' } }, actions: { @@ -63,16 +59,14 @@ } }, - action: function(args) { - //debugger; + action: function(args) { $.ajax({ url: createURL('listNetworkServiceProviders'), data: { name: 'CiscoVnmc', physicalnetworkid: args.context.physicalNetworks[0].id }, - success: function(json){ - //debugger; + success: function(json){ var items = json.listnetworkserviceprovidersresponse.networkserviceprovider; if(items != null && items.length > 0) { var ciscoVnmcProvider = items[0]; @@ -97,8 +91,7 @@ url: createURL("queryAsyncJobResult&jobId="+jobId), dataType: "json", success: function(json) { - var result = json.queryasyncjobresultresponse; - //debugger; + var result = json.queryasyncjobresultresponse; if (result.jobstatus == 0) { return; //Job has not completed } @@ -124,8 +117,7 @@ } } }); - //debugger; - + var enableCiscoVnmcProviderFn = function(ciscoVnmcProvider){ $.ajax({ url: createURL('updateNetworkServiceProvider'), @@ -162,8 +154,7 @@ }); } - var addCiscoVnmcResourceFn = function(){ - //debugger; + var addCiscoVnmcResourceFn = function(){ var data = { physicalnetworkid: args.context.physicalNetworks[0].id, hostname: args.data.hostname, @@ -174,9 +165,8 @@ $.ajax({ url: createURL('addCiscoVnmcResource'), data: data, - success: function(json) { - //debugger; - var item = json.addciscovnmcresourceresponse.ciscovnmcresource; + success: function(json) { + var item = json.addCiscoVnmcResource.CiscoVnmcResource; args.response.success({data: item}); }, error: function(data) { @@ -201,12 +191,9 @@ physicalnetworkid: args.context.physicalNetworks[0].id }, success: function(json){ + var items = json.listCiscoVnmcResources["null"]; //change it after API is fixed. args.response.success({ - data: [ - { name: 'device1', ipaddress: '192.168.1.12', state: 'Enabled' }, - { name: 'device2', ipaddress: '192.168.1.13', state: 'Disabled' }, - { name: 'device3', ipaddress: '192.168.1.14', state: 'Enabled' } - ] + data: items }); } }); From 2660a6b7a7f226ab757d2175222db62571813120 Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Thu, 9 May 2013 11:05:54 -0700 Subject: [PATCH 024/114] CLOUDSTACK-747: Internal LB between VPC tiers support Squashed commit of the following: commit def0861d5a12202260cb6672c12d77075a0de26e Author: Alena Prokharchyk Date: Thu May 9 10:53:09 2013 -0700 Inernallb: added internalLbVm to the list of network elements for nonoss build commit 56d94fc074db52ef00ace1703081a342dfb63db0 Merge: d828c15 8f9a42e Author: Alena Prokharchyk Date: Thu May 9 09:51:36 2013 -0700 Merge branch 'master' into internallb1 Conflicts: plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java server/src/com/cloud/network/vpc/VpcManagerImpl.java commit d828c154fd05fbfeb9c142b27e3d26e7dd755c77 Author: Alena Prokharchyk Date: Wed May 8 14:58:22 2013 -0700 internallb: Fixed nonoss build commit 1b8a6986a6fd1808ba7285589f9a007b52feb7e5 Merge: 9e74fa9 738d35a Author: Alena Prokharchyk Date: Wed May 8 13:20:07 2013 -0700 Merge branch 'master' into internallb1 Conflicts: api/src/com/cloud/async/AsyncJob.java api/src/com/cloud/network/NetworkModel.java api/src/com/cloud/network/rules/LoadBalancerContainer.java api/src/org/apache/cloudstack/api/BaseCmd.java api/src/org/apache/cloudstack/api/ResponseGenerator.java api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerContainer.java client/tomcatconf/commands.properties.in engine/schema/src/com/cloud/network/dao/LoadBalancerDaoImpl.java server/src/com/cloud/api/ApiResponseHelper.java server/src/com/cloud/network/NetworkManagerImpl.java server/src/com/cloud/network/NetworkModelImpl.java server/src/com/cloud/network/NetworkServiceImpl.java server/src/com/cloud/server/ManagementServerImpl.java server/test/com/cloud/network/MockNetworkModelImpl.java server/test/com/cloud/vpc/MockNetworkManagerImpl.java server/test/com/cloud/vpc/MockNetworkModelImpl.java server/test/resources/appLoadBalancer.xml setup/db/db/schema-410to420.sql test/integration/component/test_multiple_ip_ranges.py test/integration/smoke/test_guest_vlan_range.py tools/marvin/marvin/integration/lib/base.py commit 9e74fa94067997f0ae6d469f3564df602dd274a6 Author: Prasanna Santhanam Date: Thu May 9 00:11:40 2013 +0530 marvin changes for internallbvm provider - changed the simulator context to load the internallb bean - fixed deployDataCenter to use the additional provider by default - fixed the sandbox script and the setup script for simulator checkin tests Signed-off-by: Prasanna Santhanam commit 0a2d49301b170171ebe8d6646236854f488d06ba Author: Jessica Wang Date: Tue May 7 15:50:41 2013 -0700 Internal LB - UI - zone wizard - advanced zone - enable internal LB element, enable internal LB provider. commit 43e1667f90b01e2b4095009b997b3b2665087fb4 Author: Alena Prokharchyk Date: Tue May 7 13:26:53 2013 -0700 Moved all DAOs and VOs to the cloud-engine-schema project commit 2fd94c8bbe24da86e6bd004ee8165e08038a3e1d Author: Radhika PC Date: Tue May 7 18:26:08 2013 +0530 CLOUDSTACK-893 api commit 12b64d6c00940a4b5c4aa059f2c36ae7cc1b79bd Author: Prasanna Santhanam Date: Tue May 7 17:06:15 2013 +0530 Fixing the gmaven configuration for marvin/pom.xml For the marvin checkin test custom properties had a typo when run for the *nix environment. Signed-off-by: Prasanna Santhanam commit 1e4274dd9f55a6eea7121d50e361babcafe70725 Author: Prasanna Santhanam Date: Tue May 7 15:28:43 2013 +0530 Renaming TesDedicateVlanRange -> TestDedicateVlanRange Signed-off-by: Prasanna Santhanam commit 9264ac526f854c980afb669631177c99e4bbbed7 Author: Prasanna Santhanam Date: Tue May 7 15:28:20 2013 +0530 Adding isolation method to the zone creation of marvin Signed-off-by: Prasanna Santhanam commit 3a0dc67de0285fffa7739b25286df71f92470ddf Author: Prasanna Santhanam Date: Tue May 7 15:27:26 2013 +0530 adding ACL for dedicateGuestVlanRange set of APIs Signed-off-by: Prasanna Santhanam commit 79f6e11368d4b6227e9055bb58cce8e5b9872cfe Author: Prasanna Santhanam Date: Tue May 7 15:26:48 2013 +0530 add debug logs when access checkers fail to find API When the access checkers fail for api discovery, we fail silently. instead record a debug message. Signed-off-by: Prasanna Santhanam commit 92cb7d3e0f3ef052104f698e005ab8dd243f9885 Author: Hugo Trippaers Date: Tue May 7 11:44:23 2013 +0200 commit e0d8f01ecd92a1a7b74558d02a28be3b2f20a10d enabled all tests. Fix AWSAPI build by removing broken tests and excluding failing tests. commit 4a391464c7359689915c4230dfa07d728acfb752 Author: Hugo Trippaers Date: Tue May 7 10:57:23 2013 +0200 commit e0d8f01ecd92a1a7b74558d02a28be3b2f20a10d enabled all tests, but the tests in vmware-base are horribly broken and will not compile with the current CloudStack. Removing the tests to fix the nonoss build and they are so broken they should be rewritten from scratch anyway. commit 2ca03a851360c733ddacbe6a5490b6812dfc6bec Author: Prasanna Santhanam Date: Tue May 7 13:51:34 2013 +0530 moving test data to top level dictionary Signed-off-by: Prasanna Santhanam commit ceaa4e1b0d77ccb811a7e1f56ae212034b3f4a90 Author: Prasanna Santhanam Date: Tue May 7 13:50:56 2013 +0530 Adding tracelogs to the API discovery service Signed-off-by: Prasanna Santhanam commit a3f5f01c7e78e045fdc1302ab484282b0d43e014 Author: Prasanna Santhanam Date: Tue May 7 13:50:12 2013 +0530 dedicateGuestVlanRange is admin only API Adding ACL for the dedicateGuestVlanRange API. Signed-off-by: Prasanna Santhanam commit 1c4c80fe91c7aeec0689fa9a06ae80d2bdf1b0c0 Author: Hugo Trippaers Date: Tue May 7 09:58:16 2013 +0200 Recent pom switcharoo caused the client to lose the dependecy on console-proxy, which it needs to include the systemvm commit 8103f3c386a8f57c520388ea73965a4cb7f15b91 Author: Radhika PC Date: Tue May 7 11:30:17 2013 +0530 CLOUDSTACK-893 first cut commit 67d0411d739417aae4910251e86981e6d1340da0 Author: Dave Cahill Date: Fri Apr 19 17:31:44 2013 +0900 Add docs for MidoNet networking plugin [CLOUDSTACK-996] Signed-off-by: Dave Cahill commit c745e6d28e63ef1cacdf18a98ce47d162d260978 Author: Alex Huang Date: Mon May 6 16:34:03 2013 -0700 Fixed up the simulator to run with windows paths in cygwin commit be91c037021ad17f16b22599acbdd46062a665a8 Author: Alex Huang Date: Mon May 6 10:34:22 2013 -0700 Moved over the VLAN daos commit dcc09f8472d4c94cebae5b430b7eb983037a9935 Author: Alex Huang Date: Mon May 6 06:31:47 2013 -0700 Missing file and updated .gitignore commit e9953cd1a8b1247ce569d22ffa820f51d072c841 Author: Alex Huang Date: Mon May 6 06:29:59 2013 -0700 Fixed up unit testing to use only an in class TestConfiguration commit 67275714035ea2a55c11ee7acf1e915598670845 Author: Alex Huang Date: Thu May 2 15:20:49 2013 -0700 Fixed an incorrect unit test for affinity group. Removed some useless pom.xml. commit d015fb352023a5d2ec07b4d66612836e0a928679 Author: Alex Huang Date: Thu May 2 06:50:38 2013 -0700 Moved most of the VOs and DAOs from server package into engine-schema as well commit 77547a58df5f529031516273015bb770717c5b88 Author: Alex Huang Date: Wed May 1 15:15:57 2013 -0700 Removed files that are no longer used and further separated out the files in the core project commit 345f3d34828a9b573971104cbb6132a777a58ed4 Author: Alex Huang Date: Wed May 1 05:46:15 2013 -0700 Moved agent commands to core and out of api commit e91ca00571ddf078150165a33cd3cbcee5564fe2 Author: Alex Huang Date: Tue Apr 30 19:06:20 2013 -0700 Removed framework-api which is completely useless. Changed framework-ipc to reference gson itself. Move VOs into engine-schema. commit f64564e49001ee0f52120a10665979887fd0ebd1 Author: Dennis Lawler Date: Mon Apr 29 15:10:09 2013 -0700 Removing filterwin2k option Signed-off-by: Chiradeep Vittal commit 944a7ea5d6e6728903074ec18754ce2041aaf7a3 Author: Wei Zhou Date: Mon May 6 20:57:02 2013 +0100 CLOUDSTACK-2319: fix "unable to add egress rules" in SecurityGroup Signed-off-by: Chip Childers commit ff7f8ba3623927b6cef2deb0069e7f839d933fd5 Author: Wei Zhou Date: Mon May 6 20:56:06 2013 +0100 CLOUDSTACK-2322: update network.gateway to fix deployVm error on SharedNetwork after ipv6 support Signed-off-by: Chip Childers commit a153373c7eade440c707bfaeeb9831f8179ab51a Author: Alena Prokharchyk Date: Mon May 6 11:45:19 2013 -0700 CLOUDSTACK-129: added new API - listNetworkIsolationMethods - for displaying isolation methods supported by the cloudStack commit 46f59cd49effc43ffea610cc5b7cab90f601b011 Author: Prasanna Santhanam Date: Mon May 6 20:39:36 2013 +0530 Fixed the incorrect assertion in noncontiguous_vlan test The assertion fails if the VLAN is found in which case find returns a positive number. So here the assertion should infact assert < 0 result. Signed-off-by: Prasanna Santhanam commit bd1dcc10b381b33ab5503f42075999365197168b Author: Prasanna Santhanam Date: Mon May 6 19:53:42 2013 +0530 Affinity Groups requires multiple storage pools Fixing the affinity group test which would fail to find the appropriate storage pool to satisfy the anti-affinity group of the second VM Signed-off-by: Prasanna Santhanam commit 7f853cdb8f8074408205f38c5e63c2dce187b40b Author: Prasanna Santhanam Date: Mon May 6 19:16:15 2013 +0530 fixing double calls to VM deploy This fixes regression introduced in commit 2f40a90c that made duplicate calls to deployVirtualMachine. Signed-off-by: Prasanna Santhanam commit 646e810fcf0f2c0c3fac02a37eb4301fd913b008 Author: Prasanna Santhanam Date: Mon May 6 18:51:53 2013 +0530 fixing wildcard imports Signed-off-by: Prasanna Santhanam commit b29b6e8525ed367cb6f481c7eb116abe1fb847a2 Author: Hugo Trippaers Date: Fri May 3 14:03:53 2013 +0200 BigSwitch should only respond if it is the actual provider on the network. This fixes an NPE during the release call. commit 6fcc9b009b5609756fd5195847557b56f9642ecd Author: Hugo Trippaers Date: Thu May 2 17:38:27 2013 +0200 Prevent Nicira NVP tags from exceeding the 40 character limit. commit d8e61a1c0a02cef67377f1fd1f638d77652edecf Author: Sanjay Tripathi Date: Thu May 2 13:45:39 2013 +0530 CLOUDSTACK-2188 : Parsing error with Download Monitor while checking the health of downloaded templates Signed-off-by: Sateesh Chodapuneedi commit 5b6e1140f90b4625d02b9a0bb035342139c1b6f4 Author: Sebastien Goasguen Date: Mon May 6 05:35:58 2013 -0400 CLOUDSTACK-2339: Adding libcloud example commit 7be62d2374ef5910728627b583ac33498ad7fdce Author: Sebastien Goasguen Date: Mon May 6 05:35:19 2013 -0400 CLOUDSTACK-2338: Adding example of how to sign api requests in python commit 156fd689026ca23e583fa32e5013183e13086a57 Author: Talluri Date: Fri May 3 23:11:56 2013 +0530 CLOUDSTACK-2323: fix test scripts to conform with library changes Signed-off-by: Prasanna Santhanam commit 33ff5e91079b262562b17701d5266bcfd2674ffd Author: sanjeevneelarapu Date: Tue Apr 30 20:09:46 2013 +0530 CLOUDSTACK-702: Tests for Multiple IP Ranges 1.Deleting IP Range from the existing CIDR 2.Add non-contiguous guest IP range in new CIDR 3.Add overlapped guest IP range in existing CIDR Signed-off-by: sanjeevneelarapu Signed-off-by: Prasanna Santhanam commit 33059d1f66fdc7d925f6b087a97912b8bc4598d5 Author: Pranav Saxena Date: Mon May 6 14:08:40 2013 +0530 scaleUp VM response change corresponding UI changes commit 92e18d81060a9e766e1cfce3f41bbd6ddd6d5ff5 Author: Pranav Saxena Date: Mon May 6 13:45:32 2013 +0530 CLOUDSTACK-2337:Resize button available for root/domain admin and normal users commit d5cd3f7e006d688d052f7fe797180753dae989e7 Author: Likitha Shetty Date: Wed May 1 13:47:26 2013 +0530 Dedicate guest vlan range to account commit 12c79c8377d45df2ccec217bbcb9023840a2c064 Author: Pranav Saxena Date: Sun May 5 12:02:32 2013 +0530 scale up virtual machine response change in the backend commit 94bac276228fb2ede08de063e1b789d917c8425f Author: Rohit Yadav Date: Sun May 5 09:58:04 2013 +0530 appliance: Upgrade systemvm appliance from rc1 to Debian7 GA Signed-off-by: Rohit Yadav commit c598bb0038750c18223115026774c56de1366696 Author: Isaac Chiang Date: Sun May 5 01:57:35 2013 +0530 CLOUDSTACK-2076:Listview widget infinte scrolling error commit d0615ea9a1560b7330066544f5ddf4d5c2713f70 Author: Pranav Saxena Date: Sun May 5 01:15:14 2013 +0530 CLOUDSTACK-2274:Detail view loading problem when deleting a zone commit 733b513c3ac10dadf33f187d29651494197678b4 Author: Isaac Chiang Date: Sat May 4 13:41:02 2013 +0530 CLOUDSTACK-2160:Refresh button functionality for security groups and statistics tab commit 418d75d7a4dd4f9785846e3ecbe9f0135d751fe3 Author: Marcus Sorensen Date: Fri May 3 14:09:52 2013 -0600 Summary: Release old DHCP entries Detail: Refresh dnsmasq with updated entries live, no outage BUG-ID: CLOUDSTACK-2299 Submitted-by: Dennis Lawler Signed-off-by: Marcus Sorensen 1367611792 -0600 commit b3dce6457739c0f737ed8f2f61ad108bfee13eba Author: Kelven Yang Date: Tue May 7 10:57:19 2013 -0700 fix unitest commit b17885f0f68affe060a95e3f264b9ac5e3a98a4b Author: Alena Prokharchyk Date: Tue May 7 09:55:47 2013 -0700 InternalLb: some fixes to the unittest commit 1cff609347eed3fb3a5e2e3a76b2f36404ea0b81 Merge: 053e184 a3a5c13 Author: Alena Prokharchyk Date: Fri May 3 11:23:08 2013 -0700 Merge branch 'master' into internallb1 Conflicts: server/src/com/cloud/network/NetworkModelImpl.java server/src/com/cloud/network/NetworkServiceImpl.java server/src/com/cloud/server/ManagementServerImpl.java server/test/com/cloud/network/MockNetworkManagerImpl.java server/test/com/cloud/vpc/MockNetworkManagerImpl.java commit 053e18454d105e9785768123259bacc48383bcea Author: Alena Prokharchyk Date: Fri May 3 11:07:07 2013 -0700 InternalLB: marvin integration test for internal lb feature commit 2e8e2f98f59eecfc37a2645bd353de7f592d8149 Author: Alena Prokharchyk Date: Wed May 1 13:53:20 2013 -0700 InternalLB: don't allow to upgrade the network from the network offering with internal LB to the offering with public LB, and vice versa commit c773d204c8e3b4715b3466f732bdff3100f58cfe Author: Chiradeep Vittal Date: Wed May 1 13:21:52 2013 -0700 Internal LB: if we detect that we are inside an internal lb vm, call out to the ilb script to perform LB configuration Signed-off-by: Chiradeep Vittal commit 8c8845bf77f1258e54998f509df6163df82ce24e Merge: 7e95545 471ca30 Author: Alena Prokharchyk Date: Wed May 1 10:14:06 2013 -0700 Merge branch 'master' into internallb1 commit 7e9554596f3d0e1d68ada880c2c17c01a526b0f5 Author: Alena Prokharchyk Date: Wed May 1 10:01:16 2013 -0700 InternalLb: boot args parameters cleanup for the internal lb vm commit b7cf8700749893abcac1d3a3d20ec32c4cb5d37f Author: Alena Prokharchyk Date: Tue Apr 30 10:31:28 2013 -0700 InternalLb: more unittests for internal lb element commit 63bb98ebe2fa8279138f8b32aa4264b547726224 Author: Chiradeep Vittal Date: Mon Apr 29 18:29:25 2013 -0700 allow ssh on eth1 Signed-off-by: Chiradeep Vittal commit ca1c313c2901a2ce1e7e6e3ce3a566bbf4c817b4 Author: Alena Prokharchyk Date: Mon Apr 29 17:58:45 2013 -0700 InternalLb: DB upgrade - update existing physical networks with InternalLbVm provider commit ed50caa01c12320c4fa5ff7d4e0818840a6c764d Author: Alena Prokharchyk Date: Mon Apr 29 17:48:36 2013 -0700 InternalLbVM: handle the scenario when sourceIpAddress is not passed when create internal Lb rule commit 4c22c911a9ca5d7e05e9eaf0e971cbe56345fa52 Author: Chiradeep Vittal Date: Mon Apr 29 15:56:00 2013 -0700 backend support for Internal LB Signed-off-by: Chiradeep Vittal commit 7b24a7640c53e5b5ab4493de309b43714f4646c6 Merge: 440e848 a0dbf89 Author: Alena Prokharchyk Date: Mon Apr 29 15:49:48 2013 -0700 Merge branch 'master' into internallb1 Conflicts: server/src/com/cloud/api/ApiResponseHelper.java server/src/com/cloud/api/query/QueryManagerImpl.java server/src/com/cloud/configuration/ConfigurationManagerImpl.java server/src/com/cloud/network/NetworkManagerImpl.java server/src/com/cloud/network/firewall/FirewallManagerImpl.java setup/db/db/schema-410to420.sql commit 440e8484d66e3e0366b6d61f930fa13a07d0ce5f Author: Alena Prokharchyk Date: Mon Apr 29 13:27:06 2013 -0700 InternalLB: unittests for InternalLoadBalancerVMManager commit 63babe4b7e8baa1027ac66a7d0b505caafc36d5e Author: Alena Prokharchyk Date: Fri Apr 26 13:44:01 2013 -0700 InternalLb: 1) Added unittests for InternalLoadBalancerVMService 2) Added unittests for InternalLoadBalancerElementService commit 4f9c47ce54915f9c9eb8042936f3a1b19553399d Author: Alena Prokharchyk Date: Thu Apr 25 14:46:42 2013 -0700 InternalLb: create internal lb vm specific service offering commit 408ee59d1fe64ce5d6a5e57b76e25cc505fda5dc Author: Alena Prokharchyk Date: Wed Apr 24 17:08:08 2013 -0700 Internallb: new set of Web services APIs for managing Internal LB VMs commit 7680e1cc10b4e48be78668b31ba1af44d1528a67 Author: Alena Prokharchyk Date: Wed Apr 24 17:08:08 2013 -0700 Internallb: 1) InternalLb and PublicLb can't be enabled on the same network offering 2) Can have internalLb only on VPC tier commit d73ca7ef73ce8f16cd355e48a96c0fc35b037fed Author: Alena Prokharchyk Date: Wed Apr 24 13:02:32 2013 -0700 InternalLb: 1) fixed the bug when the guest nic on internal lb vm wasnt set to be default 2) Don't send the rules to the internal lb vm if its in Stopped state commit ca2fc30655eace01857181ac50789a6632f51d29 Merge: 8057567 04a2b2d Author: Alena Prokharchyk Date: Tue Apr 23 16:56:11 2013 -0700 Merge branch 'master' into internallb1 Conflicts: server/src/com/cloud/network/vpc/VpcManagerImpl.java server/src/com/cloud/server/ManagementServerImpl.java setup/db/db/schema-410to420.sql commit 8057567aaab5000b2f6d3aec8ace65631092adc1 Author: Alena Prokharchyk Date: Tue Apr 23 13:15:36 2013 -0700 Internallb: more unittests for ApplicationLoadBalancerService commit 35c0273b857073a7018fb1a59a33f43f6f112a9c Author: Alena Prokharchyk Date: Fri Apr 19 16:17:45 2013 -0700 InternalLb: unittests for ApplicationLoadBalancerService commit 69b23f700348a56f97bc2118166799332a47b3a5 Author: Alena Prokharchyk Date: Thu Apr 18 14:01:10 2013 -0700 InternalLb: create/configure/listInternalLoadBalancerElement - fixes to the API response commit a3321ce617eab795288ab75357345d45794db93d Author: Alena Prokharchyk Date: Thu Apr 18 13:31:16 2013 -0700 Internal LB : renamed the classes responsible for managing internal lb elements. Now the names are InternalLoadBalancerVMManager, InternalLoadBalancerVMService and InternalLoadBalancerVMManagerImpl commit 2baf7c365c4847ae49cd90ee25d4e3d7d346464d Author: Alena Prokharchyk Date: Thu Apr 18 10:02:17 2013 -0700 Internallb: verify requested IP for LB rule (if specified) against guest network cidr commit 0cfe96bd00a79ccb9ddebed760c6dde257599074 Merge: 501f2ff 11162f5 Author: Alena Prokharchyk Date: Wed Apr 17 15:41:51 2013 -0700 Merge branch 'master' into internallb1 Conflicts: api/src/com/cloud/network/IpAddress.java server/src/com/cloud/network/NetworkServiceImpl.java setup/db/db/schema-410to420.sql commit 501f2ffa0b07e80c17e4d6f7a73721d034c8e46a Author: Alena Prokharchyk Date: Tue Apr 16 17:03:50 2013 -0700 InternalLb: validate source ip network as a part of LB rule creation commit 4d9a7dfd85f010918749dfe3166d75fe4db68d90 Author: Alena Prokharchyk Date: Tue Apr 16 16:03:32 2013 -0700 InternalLB: in VPC, restrict public LB to one tier only. Internal LB can be supported on multiple tiers commit 8689bf9eb38a416997d5ae4d326c51b57b57553e Author: Alena Prokharchyk Date: Tue Apr 16 15:59:56 2013 -0700 Internal LB: added internal lb vm to the list of supported providers in VPC default offering commit b7709b89ff94a7c1eeb0e6dff0eca6220a0aed25 Author: Alena Prokharchyk Date: Tue Apr 16 11:04:22 2013 -0700 Internal Lb: added 2 boolean fields - internal_lb and public_lb - to the network offering. Define if internal or public LB service is supported. In the current release it's either one or another; in the future releases we might support both on the same network commit 014689e45eeaedd9b695ec20dfb2db631f433e14 Merge: b3b16ba 90e8158 Author: Alena Prokharchyk Date: Tue Apr 16 09:55:45 2013 -0700 Merge branch 'master' into internallb1 Conflicts: api/src/com/cloud/network/Network.java plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java server/src/com/cloud/network/NetworkManagerImpl.java server/src/com/cloud/network/NetworkServiceImpl.java server/test/com/cloud/network/MockNetworkManagerImpl.java server/test/com/cloud/vpc/MockNetworkManagerImpl.java setup/db/db/schema-410to420.sql commit b3b16bae48976c027e3439f2e0a84cfb2cb72166 Author: Alena Prokharchyk Date: Mon Apr 15 17:00:31 2013 -0700 InternalLB: allow to specify more than one provider for the LB service when create network offering as diff providers can support internal and public LB for the same network commit a4fc1d7d65191da6a49bce9fa0a64ce6e46ac85d Author: Alena Prokharchyk Date: Mon Apr 15 13:45:25 2013 -0700 Internal LB: 1) Added network_offering_details DB table and corresponding VO/DAO objects. Change createNetworkOffering web services api to accept the map of key/value pairs as details. 2) Allow to have multiple providers for the same service for the network to support the case when LB service can have separate providers for Internal LB and Public LB commit 4530cebf2bef515f86fa29b3798d51e81089f92f Author: Alena Prokharchyk Date: Mon Apr 15 10:06:10 2013 -0700 InternalLbVm: support for start/stop Internal lb vm commit ae69f0ae5612834b8bc911bd074cfb050c0b164c Author: Alena Prokharchyk Date: Fri Apr 12 17:25:02 2013 -0700 InternalLb: fixed prepare() in InternalLbElement - have to prepare nics of User vms only commit 888a83c22111f3792850e6bb6235d30a93408d1d Author: Alena Prokharchyk Date: Fri Apr 12 15:58:27 2013 -0700 InternalLb: Start/deploy internal LB vms for the existing LB rules as a part of network implement commit 3b41d5bee1ac04d3e9cf837a2be4398b7597d1a0 Merge: bb73531 4b1a9f1 Author: Alena Prokharchyk Date: Fri Apr 12 15:32:40 2013 -0700 Merge branch 'master' into internallb1 Conflicts: server/src/com/cloud/network/NetworkModelImpl.java server/src/com/cloud/server/ManagementServerImpl.java commit bb73531fed72cc81012624fd3bae5ec22d23daa2 Author: Alena Prokharchyk Date: Fri Apr 12 15:13:55 2013 -0700 Internal Lb: list internal lb vms as a part of listRouters response. Introduced new parameter - role (can be virtual_router or internal_lb_vm) commit c113ea184b575ccae5d2be411c5bbc345473e35e Author: Alena Prokharchyk Date: Fri Apr 12 12:00:09 2013 -0700 Add Internal Lb Provider/Element as a part of adding a physical network commit 78c9db79dae3bc38699050b05baae32fd02204f6 Author: Alena Prokharchyk Date: Fri Apr 12 10:05:28 2013 -0700 InternalLbVm: destroy the internal lb vm when the last rule for the ip is being revoked commit af6201257b28a0d9177330c8c76b0ec979725870 Author: Alena Prokharchyk Date: Thu Apr 11 16:55:37 2013 -0700 Internal LB: fixed some bugs in internal lb vm startup process commit 1db240c2b668e6cbbea4e09979c34d84fe54a624 Author: Alena Prokharchyk Date: Thu Apr 11 14:23:55 2013 -0700 InternalLb: fixed searchCriteria constructor in ApplicationLoadBalancerDaoImpl commit 3795048fcc68ef23c24d82c9064946dfc082b1b6 Merge: f4c2b53 5f8a278 Author: Alena Prokharchyk Date: Thu Apr 11 14:09:31 2013 -0700 Merge branch 'master' into internallb1 Conflicts: api/src/com/cloud/async/AsyncJob.java api/src/org/apache/cloudstack/api/ApiConstants.java api/src/org/apache/cloudstack/api/BaseCmd.java api/src/org/apache/cloudstack/api/ResponseGenerator.java client/tomcatconf/commands.properties.in server/src/com/cloud/api/ApiDBUtils.java server/src/com/cloud/api/ApiResponseHelper.java server/src/com/cloud/server/ManagementServerImpl.java setup/db/db/schema-410to420.sql commit f4c2b53c218b2d11d510b9acc6baeb0d62042e5c Author: Alena Prokharchyk Date: Thu Apr 11 13:46:47 2013 -0700 InternalLB: modified InternalLbElement to start the Internal Lb vm for each ip address (if not already started) commit 76a4b1cf81610d931d6098ca94fa509c9ba2e274 Author: Alena Prokharchyk Date: Thu Apr 11 11:41:47 2013 -0700 InternalLB: added logic for acquiring guest ip address for the Internal LB rule commit 915e39fbaa9a6b6898e2aa13cbf8ef60a7b9d70e Author: Alena Prokharchyk Date: Thu Apr 11 10:19:18 2013 -0700 Removed unused methods doing ipAllocation from GuestNetworkGuru and NetworkServiceImpl. The correct method is located in NetworkModelImpl commit 3f2a62c7f62d23da23f65ff3842049243ef268e3 Merge: 20beb7a a0b5ebc Author: Alena Prokharchyk Date: Wed Apr 10 17:16:07 2013 -0700 Merge branch 'master' into internallb1 commit 20beb7a16c1a592cd7500148ea8988fe119d34fb Author: Alena Prokharchyk Date: Wed Apr 10 15:28:12 2013 -0700 Internal LB: applyLoadBalancerRules - put not null check for sourceIpAddressId (can be null when Schema is not Public) commit 87e5f5b9a6b006893ee30662fc06ea430e7b70dc Author: Alena Prokharchyk Date: Wed Apr 10 15:17:58 2013 -0700 Internal LB: intermediate checkin - added InternalLBAppliance manager and managerImpl commit 53b9c0d142bd2b99dd00c17987dcf5dc54e3ef56 Author: Alena Prokharchyk Date: Tue Apr 9 17:55:10 2013 -0700 Internal LB: added @Since to API docs for Internal LB related commands commit 867b305ea852dcbe224645dc4e5ffb950d8db8f7 Author: Alena Prokharchyk Date: Tue Apr 9 17:51:19 2013 -0700 Internal LB: Made InternalLbElement to extend the ip deployer as the LB service implements IPDeployerRequester commit 7b9af2809410132db451e48b7b829bf019512a92 Author: Alena Prokharchyk Date: Tue Apr 9 15:45:30 2013 -0700 InternalLb: new set of Web Services APIs to add InternalLB as a network element to the cloudStack (the element is packaged as an independent plugin). New APIs: 1) configureInternalLoadBalancerElement 2) createInternalLoadBalancerElement 3) listInternalLoadBalancerElements commit 039e303d4aec5618cc3914ee1a581d2f7b926e1c Author: Alena Prokharchyk Date: Tue Apr 9 14:01:11 2013 -0700 InternalLB: Modified pluggable service VirtualRouterElementService to accept only VirtualRouter and VpcVirtualRouter as a VirtualRouterProvider type when add/configure elements. Other VirtualRouterProviderTypes are are taken care by elb/internal lb plugins. commit f0018b451281bf02964dbe71d704c9a931783cae Author: Alena Prokharchyk Date: Tue Apr 9 12:56:42 2013 -0700 Internal LB: 1)Added InternalLoadBalancerManager and corresponding Impl 2)Add InternalLbVm as a default CS provider. DB upgrade is covered as well commit e344cf250af6a67a17f082f1c646e6ef5ce9a0a7 Author: Alena Prokharchyk Date: Mon Apr 8 16:57:47 2013 -0700 InternalLB - removed unused code from LoadBalancerDao commit 3588f468482e43181802730ed5a059897eb85458 Author: Alena Prokharchyk Date: Mon Apr 8 16:23:03 2013 -0700 Internal LB - added network-element plugin for internal lb service commit 76325e61681c7e191308b27514ba69e523cf12bd Author: Alena Prokharchyk Date: Mon Apr 8 13:58:08 2013 -0700 Internal Lb: 1) When network has both kinds of LB rules - Public and Internal - never send them in the same set to the provider 2) Added extra checks on the provider side to validate if the schema - Public or Internal - is supported. commit 56c2fe1d376c407a248fba789dd67ff36493a0ed Author: Alena Prokharchyk Date: Mon Apr 8 12:34:59 2013 -0700 InternalLB: 1) Added new capability for the LB service - LbSchemes. Can take 2 values - Internal and Public. 2) F5 and Netscaler LB providers - changes all LB related methods to accept LoadBalancingRule instead of ? extends FirewallRule. commit 34bcb2d026e1951f7b115d71830c69e1ad5ed89a Author: Alena Prokharchyk Date: Mon Apr 8 12:11:11 2013 -0700 InternalLB: implemented list/delete/create web services API commands that will be used for Internal LB creation commit 9ab31e11f7ebd431f9ebdf9d8582f5c126b14928 Author: Alena Prokharchyk Date: Fri Apr 5 15:59:55 2013 -0700 InternalLB: change LoadBalancingRule - reference sourceIpAddress of th load balancer by its value, not DB id commit 08f855d4e4b3888b3b4a163ce73c0e444b91e6b7 Author: Alena Prokharchyk Date: Thu Apr 4 09:26:21 2013 -0700 InternalLB: 1) Added new set of Interfaces - including the new VO - for the internal load balancer 2) DB change - added source_ip_address/source_ip_address_network_id/scheme (Internal/Public) fields to the load_balancer table --- api/src/com/cloud/async/AsyncJob.java | 2 + api/src/com/cloud/event/EventTypes.java | 24 +- api/src/com/cloud/network/IpAddress.java | 3 + api/src/com/cloud/network/Network.java | 19 +- api/src/com/cloud/network/NetworkModel.java | 7 + .../VirtualNetworkApplianceService.java | 2 + .../cloud/network/VirtualRouterProvider.java | 3 +- .../cloud/network/lb/LoadBalancingRule.java | 83 +- .../network/lb/LoadBalancingRulesService.java | 16 +- .../cloud/network/router/VirtualRouter.java | 2 +- .../com/cloud/network/rules/LoadBalancer.java | 10 +- .../network/rules/LoadBalancerContainer.java | 33 + .../com/cloud/offering/NetworkOffering.java | 11 + .../com/cloud/offering/ServiceOffering.java | 1 + api/src/com/cloud/vm/VirtualMachine.java | 3 +- .../apache/cloudstack/api/ApiConstants.java | 6 + .../org/apache/cloudstack/api/BaseCmd.java | 7 + .../cloudstack/api/ResponseGenerator.java | 44 +- ...nfigureInternalLoadBalancerElementCmd.java | 114 +++ .../CreateInternalLoadBalancerElementCmd.java | 116 +++ .../internallb/ListInternalLBVMsCmd.java | 151 +++ .../ListInternalLoadBalancerElementsCmd.java | 99 ++ .../internallb/StartInternalLBVMCmd.java | 120 +++ .../admin/internallb/StopInternalLBVMCmd.java | 123 +++ .../network/CreateNetworkOfferingCmd.java | 15 +- .../router/CreateVirtualRouterElementCmd.java | 21 +- .../command/admin/router/ListRoutersCmd.java | 7 +- .../command/admin/router/StartRouterCmd.java | 10 +- .../command/admin/router/StopRouterCmd.java | 11 +- .../CreateApplicationLoadBalancerCmd.java | 218 ++++ .../CreateLoadBalancerRuleCmd.java | 6 +- .../DeleteApplicationLoadBalancerCmd.java | 116 +++ .../ListApplicationLoadBalancersCmd.java | 131 +++ ...plicationLoadBalancerInstanceResponse.java | 63 ++ .../ApplicationLoadBalancerResponse.java | 142 +++ .../ApplicationLoadBalancerRuleResponse.java | 51 + .../api/response/DomainRouterResponse.java | 13 +- .../InternalLoadBalancerElementResponse.java | 51 + .../api/response/NetworkOfferingResponse.java | 9 + .../VirtualRouterProviderResponse.java | 1 + .../InternalLoadBalancerElementService.java | 56 ++ .../lb/ApplicationLoadBalancerContainer.java | 28 + .../lb/ApplicationLoadBalancerRule.java | 24 + .../lb/ApplicationLoadBalancerService.java | 42 + .../lb/InternalLoadBalancerVMService.java | 34 + .../apache/cloudstack/query/QueryService.java | 3 + client/pom.xml | 5 + client/tomcatconf/applicationContext.xml.in | 9 +- client/tomcatconf/commands.properties.in | 16 + client/tomcatconf/componentContext.xml.in | 2 + .../tomcatconf/nonossComponentContext.xml.in | 2 + .../simulatorComponentContext.xml.in | 1 + .../cloud/network/dao/FirewallRulesDao.java | 1 - .../com/cloud/network/dao/IPAddressVO.java | 9 +- .../cloud/network/dao/LoadBalancerDao.java | 10 +- .../network/dao/LoadBalancerDaoImpl.java | 74 +- .../com/cloud/network/dao/LoadBalancerVO.java | 18 + .../network/dao/NetworkServiceMapDao.java | 1 + .../network/dao/NetworkServiceMapDaoImpl.java | 9 + .../src/com/cloud/network/dao/NetworkVO.java | 3 - .../cloud/network/rules/FirewallRuleVO.java | 2 - .../offerings/NetworkOfferingDetailsVO.java | 90 ++ .../cloud/offerings/NetworkOfferingVO.java | 44 +- .../offerings/dao/NetworkOfferingDao.java | 4 + .../offerings/dao/NetworkOfferingDaoImpl.java | 24 + .../dao/NetworkOfferingDetailsDao.java | 31 + .../dao/NetworkOfferingDetailsDaoImpl.java | 79 ++ .../cloud/upgrade/dao/Upgrade410to420.java | 95 +- .../schema/src/com/cloud/vm/dao/NicDao.java | 2 +- .../src/com/cloud/vm/dao/NicDaoImpl.java | 2 +- .../lb/ApplicationLoadBalancerRuleVO.java | 133 +++ .../dao/ApplicationLoadBalancerRuleDao.java | 35 + .../ApplicationLoadBalancerRuleDaoImpl.java | 115 +++ .../config/etc/init.d/cloud-early-config | 26 + .../debian/config/etc/iptables/iptables-ilbvm | 33 + .../debian/config/opt/cloud/bin/ilb.sh | 211 ++++ .../config/opt/cloud/bin/patchsystemvm.sh | 23 + .../config/opt/cloud/bin/vpc_loadbalancer.sh | 23 + .../element/ElasticLoadBalancerElement.java | 22 +- .../lb/ElasticLoadBalancerManager.java | 4 +- .../lb/ElasticLoadBalancerManagerImpl.java | 32 +- .../F5ExternalLoadBalancerElement.java | 87 +- .../internal-loadbalancer/pom.xml | 50 + .../element/InternalLoadBalancerElement.java | 548 ++++++++++ .../lb/InternalLoadBalancerVMManager.java | 90 ++ .../lb/InternalLoadBalancerVMManagerImpl.java | 951 ++++++++++++++++++ .../ElementChildTestConfiguration.java | 124 +++ .../InternalLbElementServiceTest.java | 190 ++++ .../InternalLbElementTest.java | 226 +++++ .../InternalLBVMManagerTest.java | 388 +++++++ .../InternalLBVMServiceTest.java | 291 ++++++ .../LbChildTestConfiguration.java | 170 ++++ .../test/resources/lb_element.xml | 46 + .../test/resources/lb_mgr.xml | 46 + .../test/resources/lb_svc.xml | 46 + .../network/element/NetscalerElement.java | 108 +- plugins/pom.xml | 1 + server/src/com/cloud/api/ApiDBUtils.java | 10 +- .../src/com/cloud/api/ApiResponseHelper.java | 108 +- .../com/cloud/api/query/QueryManagerImpl.java | 45 +- .../query/dao/DomainRouterJoinDaoImpl.java | 9 +- .../api/query/vo/DomainRouterJoinVO.java | 17 +- .../src/com/cloud/configuration/Config.java | 5 +- .../configuration/ConfigurationManager.java | 10 +- .../ConfigurationManagerImpl.java | 123 ++- .../ExternalLoadBalancerDeviceManager.java | 6 +- ...ExternalLoadBalancerDeviceManagerImpl.java | 33 +- .../ExternalLoadBalancerUsageManagerImpl.java | 34 +- .../src/com/cloud/network/NetworkManager.java | 3 +- .../com/cloud/network/NetworkManagerImpl.java | 103 +- .../com/cloud/network/NetworkModelImpl.java | 57 +- .../com/cloud/network/NetworkServiceImpl.java | 68 +- .../network/element/VirtualRouterElement.java | 56 +- .../network/firewall/FirewallManagerImpl.java | 77 +- .../cloud/network/guru/GuestNetworkGuru.java | 43 +- .../network/lb/LBHealthCheckManager.java | 4 +- .../network/lb/LBHealthCheckManagerImpl.java | 9 +- .../network/lb/LoadBalancingRulesManager.java | 24 +- .../lb/LoadBalancingRulesManagerImpl.java | 410 +++++--- .../VirtualNetworkApplianceManager.java | 4 + .../VirtualNetworkApplianceManagerImpl.java | 59 +- ...VpcVirtualNetworkApplianceManagerImpl.java | 2 +- .../com/cloud/network/vpc/VpcManagerImpl.java | 14 +- .../cloud/server/ConfigurationServerImpl.java | 14 +- .../cloud/server/ManagementServerImpl.java | 580 ++++++++--- .../ApplicationLoadBalancerManagerImpl.java | 524 ++++++++++ .../cloud/network/MockNetworkManagerImpl.java | 27 +- .../cloud/network/MockNetworkModelImpl.java | 17 + .../vpc/MockConfigurationManagerImpl.java | 2 +- .../com/cloud/vpc/MockNetworkManagerImpl.java | 56 +- .../com/cloud/vpc/MockNetworkModelImpl.java | 17 + ...MockVpcVirtualNetworkApplianceManager.java | 14 +- .../vpc/dao/MockNetworkOfferingDaoImpl.java | 12 +- .../vpc/dao/MockNetworkServiceMapDaoImpl.java | 6 + .../lb/ApplicationLoadBalancerTest.java | 292 ++++++ .../cloudstack/lb/ChildTestConfiguration.java | 103 ++ .../CreateNetworkOfferingTest.java | 21 +- server/test/resources/appLoadBalancer.xml | 43 + setup/db/db/schema-40to410.sql | 4 +- setup/db/db/schema-410to420.sql | 45 +- setup/dev/advanced.cfg | 4 + .../component/test_multiple_ip_ranges.py | 1 + .../smoke/test_guest_vlan_range.py | 15 + test/integration/smoke/test_internal_lb.py | 250 +++++ tools/apidoc/gen_toc.py | 1 + tools/marvin/marvin/deployDataCenter.py | 12 + .../marvin/sandbox/advanced/advanced_env.py | 5 + .../marvin/sandbox/advanced/sandbox.cfg | 209 ++++ ui/scripts/zoneWizard.js | 104 ++ 149 files changed, 9497 insertions(+), 817 deletions(-) create mode 100644 api/src/com/cloud/network/rules/LoadBalancerContainer.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/internallb/ConfigureInternalLoadBalancerElementCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/internallb/CreateInternalLoadBalancerElementCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/internallb/ListInternalLBVMsCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/internallb/ListInternalLoadBalancerElementsCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/internallb/StartInternalLBVMCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/internallb/StopInternalLBVMCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateApplicationLoadBalancerCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/loadbalancer/DeleteApplicationLoadBalancerCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/loadbalancer/ListApplicationLoadBalancersCmd.java create mode 100644 api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerInstanceResponse.java create mode 100644 api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerResponse.java create mode 100644 api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerRuleResponse.java create mode 100644 api/src/org/apache/cloudstack/api/response/InternalLoadBalancerElementResponse.java create mode 100644 api/src/org/apache/cloudstack/network/element/InternalLoadBalancerElementService.java create mode 100644 api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerContainer.java create mode 100644 api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerRule.java create mode 100644 api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerService.java create mode 100644 api/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMService.java create mode 100644 engine/schema/src/com/cloud/offerings/NetworkOfferingDetailsVO.java create mode 100644 engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDao.java create mode 100644 engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDaoImpl.java create mode 100644 engine/schema/src/org/apache/cloudstack/lb/ApplicationLoadBalancerRuleVO.java create mode 100644 engine/schema/src/org/apache/cloudstack/lb/dao/ApplicationLoadBalancerRuleDao.java create mode 100644 engine/schema/src/org/apache/cloudstack/lb/dao/ApplicationLoadBalancerRuleDaoImpl.java create mode 100755 patches/systemvm/debian/config/etc/iptables/iptables-ilbvm create mode 100755 patches/systemvm/debian/config/opt/cloud/bin/ilb.sh create mode 100644 plugins/network-elements/internal-loadbalancer/pom.xml create mode 100644 plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java create mode 100644 plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManager.java create mode 100644 plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java create mode 100644 plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/ElementChildTestConfiguration.java create mode 100644 plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/InternalLbElementServiceTest.java create mode 100644 plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/InternalLbElementTest.java create mode 100644 plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/InternalLBVMManagerTest.java create mode 100644 plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/InternalLBVMServiceTest.java create mode 100644 plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/LbChildTestConfiguration.java create mode 100644 plugins/network-elements/internal-loadbalancer/test/resources/lb_element.xml create mode 100644 plugins/network-elements/internal-loadbalancer/test/resources/lb_mgr.xml create mode 100644 plugins/network-elements/internal-loadbalancer/test/resources/lb_svc.xml create mode 100644 server/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerManagerImpl.java create mode 100644 server/test/org/apache/cloudstack/lb/ApplicationLoadBalancerTest.java create mode 100644 server/test/org/apache/cloudstack/lb/ChildTestConfiguration.java create mode 100644 server/test/resources/appLoadBalancer.xml create mode 100644 test/integration/smoke/test_internal_lb.py create mode 100644 tools/marvin/marvin/sandbox/advanced/sandbox.cfg diff --git a/api/src/com/cloud/async/AsyncJob.java b/api/src/com/cloud/async/AsyncJob.java index d384a7ad920..ccdc40620b7 100644 --- a/api/src/com/cloud/async/AsyncJob.java +++ b/api/src/com/cloud/async/AsyncJob.java @@ -50,7 +50,9 @@ public interface AsyncJob extends Identity, InternalIdentity { AutoScaleVmProfile, AutoScaleVmGroup, GlobalLoadBalancerRule, + LoadBalancerRule, AffinityGroup, + InternalLbVm, DedicatedGuestVlanRange } diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index 26c40abb4fb..45a904e426c 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -16,6 +16,9 @@ // under the License. package com.cloud.event; +import java.util.HashMap; +import java.util.Map; + import com.cloud.configuration.Configuration; import com.cloud.dc.DataCenter; import com.cloud.dc.Pod; @@ -23,8 +26,18 @@ import com.cloud.dc.StorageNetworkIpRange; import com.cloud.dc.Vlan; import com.cloud.domain.Domain; import com.cloud.host.Host; -import com.cloud.network.*; -import com.cloud.network.as.*; +import com.cloud.network.GuestVlan; +import com.cloud.network.Network; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.PhysicalNetworkTrafficType; +import com.cloud.network.PublicIpAddress; +import com.cloud.network.RemoteAccessVpn; +import com.cloud.network.as.AutoScaleCounter; +import com.cloud.network.as.AutoScalePolicy; +import com.cloud.network.as.AutoScaleVmGroup; +import com.cloud.network.as.AutoScaleVmProfile; +import com.cloud.network.as.Condition; import com.cloud.network.router.VirtualRouter; import com.cloud.network.rules.LoadBalancer; import com.cloud.network.rules.StaticNat; @@ -43,9 +56,6 @@ import com.cloud.user.Account; import com.cloud.user.User; import com.cloud.vm.VirtualMachine; -import java.util.HashMap; -import java.util.Map; - public class EventTypes { //map of Event and corresponding entity for which Event is applicable @@ -389,11 +399,15 @@ public class EventTypes { public static final String EVENT_AFFINITY_GROUP_ASSIGN = "AG.ASSIGN"; public static final String EVENT_AFFINITY_GROUP_REMOVE = "AG.REMOVE"; public static final String EVENT_VM_AFFINITY_GROUP_UPDATE = "VM.AG.UPDATE"; + + public static final String EVENT_INTERNAL_LB_VM_START = "INTERNALLBVM.START"; + public static final String EVENT_INTERNAL_LB_VM_STOP = "INTERNALLBVM.STOP"; // Dedicated guest vlan range public static final String EVENT_GUEST_VLAN_RANGE_DEDICATE = "GUESTVLANRANGE.DEDICATE"; public static final String EVENT_DEDICATED_GUEST_VLAN_RANGE_RELEASE = "GUESTVLANRANGE.RELEASE"; + static { // TODO: need a way to force author adding event types to declare the entity details as well, with out braking diff --git a/api/src/com/cloud/network/IpAddress.java b/api/src/com/cloud/network/IpAddress.java index 71c9b4e0bf3..c48e8b97ca8 100644 --- a/api/src/com/cloud/network/IpAddress.java +++ b/api/src/com/cloud/network/IpAddress.java @@ -81,4 +81,7 @@ public interface IpAddress extends ControlledEntity, Identity, InternalIdentity Long getVpcId(); String getVmIp(); + + Long getNetworkId(); + } diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index 4472dbacc53..fa062c6a694 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -16,18 +16,19 @@ // under the License. package com.cloud.network; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.Mode; import com.cloud.network.Networks.TrafficType; import com.cloud.utils.fsm.StateMachine2; import com.cloud.utils.fsm.StateObject; -import org.apache.cloudstack.acl.ControlledEntity; -import org.apache.cloudstack.api.Identity; -import org.apache.cloudstack.api.InternalIdentity; - -import java.net.URI; -import java.util.ArrayList; -import java.util.List; /** * owned by an account. @@ -50,7 +51,7 @@ public interface Network extends ControlledEntity, StateObject, I Capability.MultipleIps, Capability.TrafficStatistics, Capability.SupportedTrafficDirection, Capability.SupportedEgressProtocols); public static final Service Lb = new Service("Lb", Capability.SupportedLBAlgorithms, Capability.SupportedLBIsolation, Capability.SupportedProtocols, Capability.TrafficStatistics, Capability.LoadBalancingSupportedIps, - Capability.SupportedStickinessMethods, Capability.ElasticLb); + Capability.SupportedStickinessMethods, Capability.ElasticLb, Capability.LbSchemes); public static final Service UserData = new Service("UserData"); public static final Service SourceNat = new Service("SourceNat", Capability.SupportedSourceNatTypes, Capability.RedundantRouter); public static final Service StaticNat = new Service("StaticNat", Capability.ElasticIp); @@ -124,6 +125,7 @@ public interface Network extends ControlledEntity, StateObject, I public static final Provider None = new Provider("None", false); // NiciraNvp is not an "External" provider, otherwise we get in trouble with NetworkServiceImpl.providersConfiguredForExternalNetworking public static final Provider NiciraNvp = new Provider("NiciraNvp", false); + public static final Provider InternalLbVm = new Provider("InternalLbVm", false); public static final Provider CiscoVnmc = new Provider("CiscoVnmc", true); private String name; @@ -177,6 +179,7 @@ public interface Network extends ControlledEntity, StateObject, I public static final Capability SupportedTrafficDirection = new Capability("SupportedTrafficDirection"); public static final Capability SupportedEgressProtocols = new Capability("SupportedEgressProtocols"); public static final Capability HealthCheckPolicy = new Capability("HealthCheckPolicy"); + public static final Capability LbSchemes = new Capability("LbSchemes"); private String name; diff --git a/api/src/com/cloud/network/NetworkModel.java b/api/src/com/cloud/network/NetworkModel.java index 555a09fc53e..f84a8b0c76a 100644 --- a/api/src/com/cloud/network/NetworkModel.java +++ b/api/src/com/cloud/network/NetworkModel.java @@ -33,6 +33,7 @@ import com.cloud.network.Networks.TrafficType; import com.cloud.network.element.NetworkElement; import com.cloud.network.element.UserDataServiceProvider; import com.cloud.offering.NetworkOffering; +import com.cloud.offering.NetworkOffering.Detail; import com.cloud.user.Account; import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; @@ -264,5 +265,11 @@ public interface NetworkModel { Nic getPlaceholderNicForRouter(Network network, Long podId); + IpAddress getPublicIpAddress(String ipAddress, long zoneId); + + List getUsedIpsInNetwork(Network network); + + Map getNtwkOffDetails(long offId); + Networks.IsolationType[] listNetworkIsolationMethods(); } \ No newline at end of file diff --git a/api/src/com/cloud/network/VirtualNetworkApplianceService.java b/api/src/com/cloud/network/VirtualNetworkApplianceService.java index 250ecb24e91..58eead2af07 100644 --- a/api/src/com/cloud/network/VirtualNetworkApplianceService.java +++ b/api/src/com/cloud/network/VirtualNetworkApplianceService.java @@ -63,5 +63,7 @@ public interface VirtualNetworkApplianceService { VirtualRouter startRouter(long id) throws ResourceUnavailableException, InsufficientCapacityException, ConcurrentOperationException; VirtualRouter destroyRouter(long routerId, Account caller, Long callerUserId) throws ResourceUnavailableException, ConcurrentOperationException; + + VirtualRouter findRouter(long routerId); } diff --git a/api/src/com/cloud/network/VirtualRouterProvider.java b/api/src/com/cloud/network/VirtualRouterProvider.java index ed6a2741ba0..f67686e6b08 100644 --- a/api/src/com/cloud/network/VirtualRouterProvider.java +++ b/api/src/com/cloud/network/VirtualRouterProvider.java @@ -23,7 +23,8 @@ public interface VirtualRouterProvider extends InternalIdentity, Identity { public enum VirtualRouterProviderType { VirtualRouter, ElasticLoadBalancerVm, - VPCVirtualRouter + VPCVirtualRouter, + InternalLbVm } public VirtualRouterProviderType getType(); diff --git a/api/src/com/cloud/network/lb/LoadBalancingRule.java b/api/src/com/cloud/network/lb/LoadBalancingRule.java index 3e11e8c7c2c..4b37782a8c7 100644 --- a/api/src/com/cloud/network/lb/LoadBalancingRule.java +++ b/api/src/com/cloud/network/lb/LoadBalancingRule.java @@ -25,111 +25,83 @@ import com.cloud.network.as.Condition; import com.cloud.network.as.Counter; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.LoadBalancer; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.utils.Pair; +import com.cloud.utils.net.Ip; -public class LoadBalancingRule implements FirewallRule, LoadBalancer { +public class LoadBalancingRule { private LoadBalancer lb; + private Ip sourceIp; private List destinations; private List stickinessPolicies; private LbAutoScaleVmGroup autoScaleVmGroup; private List healthCheckPolicies; public LoadBalancingRule(LoadBalancer lb, List destinations, - List stickinessPolicies, List healthCheckPolicies) { + List stickinessPolicies, List healthCheckPolicies, Ip sourceIp) { this.lb = lb; this.destinations = destinations; this.stickinessPolicies = stickinessPolicies; this.healthCheckPolicies = healthCheckPolicies; + this.sourceIp = sourceIp; } - @Override public long getId() { return lb.getId(); } - @Override - public long getAccountId() { - return lb.getAccountId(); - } - - @Override - public long getDomainId() { - return lb.getDomainId(); - } - - @Override public String getName() { return lb.getName(); } - @Override public String getDescription() { return lb.getDescription(); } - @Override public int getDefaultPortStart() { return lb.getDefaultPortStart(); } - @Override public int getDefaultPortEnd() { return lb.getDefaultPortEnd(); } - @Override public String getAlgorithm() { return lb.getAlgorithm(); } - @Override public String getUuid() { return lb.getUuid(); } - @Override public String getXid() { return lb.getXid(); } - @Override - public Long getSourceIpAddressId() { - return lb.getSourceIpAddressId(); - } - - @Override public Integer getSourcePortStart() { return lb.getSourcePortStart(); } - @Override public Integer getSourcePortEnd() { return lb.getSourcePortEnd(); } - @Override public String getProtocol() { return lb.getProtocol(); } - @Override - public Purpose getPurpose() { - return Purpose.LoadBalancing; + public FirewallRule.Purpose getPurpose() { + return FirewallRule.Purpose.LoadBalancing; } - @Override - public State getState() { + public FirewallRule.State getState() { return lb.getState(); } - @Override public long getNetworkId() { return lb.getNetworkId(); } - public LoadBalancer getLb() { - return lb; - } public void setDestinations(List destinations) { this.destinations = destinations; @@ -287,36 +259,6 @@ public class LoadBalancingRule implements FirewallRule, LoadBalancer { } } - @Override - public Integer getIcmpCode() { - return null; - } - - @Override - public Integer getIcmpType() { - return null; - } - - @Override - public List getSourceCidrList() { - return null; - } - - @Override - public Long getRelated() { - return null; - } - - @Override - public TrafficType getTrafficType() { - return null; - } - - @Override - public FirewallRuleType getType() { - return FirewallRuleType.User; - } - public LbAutoScaleVmGroup getAutoScaleVmGroup() { return autoScaleVmGroup; } @@ -473,4 +415,11 @@ public class LoadBalancingRule implements FirewallRule, LoadBalancer { } } + public Ip getSourceIp() { + return sourceIp; + } + + public Scheme getScheme() { + return lb.getScheme(); + } } diff --git a/api/src/com/cloud/network/lb/LoadBalancingRulesService.java b/api/src/com/cloud/network/lb/LoadBalancingRulesService.java index ed39bedaa6f..5fc41e34c34 100644 --- a/api/src/com/cloud/network/lb/LoadBalancingRulesService.java +++ b/api/src/com/cloud/network/lb/LoadBalancingRulesService.java @@ -17,10 +17,10 @@ package com.cloud.network.lb; import java.util.List; +import java.util.Map; import org.apache.cloudstack.api.command.user.loadbalancer.CreateLBHealthCheckPolicyCmd; import org.apache.cloudstack.api.command.user.loadbalancer.CreateLBStickinessPolicyCmd; -import org.apache.cloudstack.api.command.user.loadbalancer.CreateLoadBalancerRuleCmd; import org.apache.cloudstack.api.command.user.loadbalancer.ListLBHealthCheckPoliciesCmd; import org.apache.cloudstack.api.command.user.loadbalancer.ListLBStickinessPoliciesCmd; import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerRuleInstancesCmd; @@ -30,12 +30,13 @@ import org.apache.cloudstack.api.command.user.loadbalancer.UpdateLoadBalancerRul import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceUnavailableException; -import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; import com.cloud.network.rules.HealthCheckPolicy; import com.cloud.network.rules.LoadBalancer; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.rules.StickinessPolicy; import com.cloud.uservm.UserVm; import com.cloud.utils.Pair; +import com.cloud.utils.net.Ip; public interface LoadBalancingRulesService { @@ -49,7 +50,9 @@ public interface LoadBalancingRulesService { * @return the newly created LoadBalancerVO if successful, null otherwise * @throws InsufficientAddressCapacityException */ - LoadBalancer createLoadBalancerRule(CreateLoadBalancerRuleCmd lb, boolean openFirewall) throws NetworkRuleConflictException, InsufficientAddressCapacityException; + LoadBalancer createPublicLoadBalancerRule(String xId, String name, String description, + int srcPortStart, int srcPortEnd, int defPortStart, int defPortEnd, Long ipAddrId, String protocol, String algorithm, + long networkId, long lbOwnerId, boolean openFirewall) throws NetworkRuleConflictException, InsufficientAddressCapacityException; LoadBalancer updateLoadBalancerRule(UpdateLoadBalancerRuleCmd cmd); @@ -134,8 +137,9 @@ public interface LoadBalancingRulesService { List searchForLBHealthCheckPolicies(ListLBHealthCheckPoliciesCmd cmd); - List listByNetworkId(long networkId); - LoadBalancer findById(long LoadBalancer); - public void updateLBHealthChecks() throws ResourceUnavailableException; + + public void updateLBHealthChecks(Scheme scheme) throws ResourceUnavailableException; + + Map getLbInstances(long lbId); } diff --git a/api/src/com/cloud/network/router/VirtualRouter.java b/api/src/com/cloud/network/router/VirtualRouter.java index d7239dd3452..2311f489918 100755 --- a/api/src/com/cloud/network/router/VirtualRouter.java +++ b/api/src/com/cloud/network/router/VirtualRouter.java @@ -23,7 +23,7 @@ import com.cloud.vm.VirtualMachine; */ public interface VirtualRouter extends VirtualMachine { public enum Role { - VIRTUAL_ROUTER, LB + VIRTUAL_ROUTER, LB, INTERNAL_LB_VM } Role getRole(); boolean getIsRedundantRouter(); diff --git a/api/src/com/cloud/network/rules/LoadBalancer.java b/api/src/com/cloud/network/rules/LoadBalancer.java index ab6085aceb7..e6dadcaee97 100644 --- a/api/src/com/cloud/network/rules/LoadBalancer.java +++ b/api/src/com/cloud/network/rules/LoadBalancer.java @@ -19,16 +19,10 @@ package com.cloud.network.rules; /** * Definition for a LoadBalancer */ -public interface LoadBalancer extends FirewallRule { - - String getName(); - - String getDescription(); - +public interface LoadBalancer extends FirewallRule, LoadBalancerContainer { + int getDefaultPortStart(); int getDefaultPortEnd(); - String getAlgorithm(); - } diff --git a/api/src/com/cloud/network/rules/LoadBalancerContainer.java b/api/src/com/cloud/network/rules/LoadBalancerContainer.java new file mode 100644 index 00000000000..9d5ea595c9d --- /dev/null +++ b/api/src/com/cloud/network/rules/LoadBalancerContainer.java @@ -0,0 +1,33 @@ +// 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. +package com.cloud.network.rules; + +public interface LoadBalancerContainer { + + public enum Scheme { + Public, Internal; + } + + String getName(); + + String getDescription(); + + String getAlgorithm(); + + Scheme getScheme(); + +} diff --git a/api/src/com/cloud/offering/NetworkOffering.java b/api/src/com/cloud/offering/NetworkOffering.java index 6f0b9937854..72e2a2bbbab 100644 --- a/api/src/com/cloud/offering/NetworkOffering.java +++ b/api/src/com/cloud/offering/NetworkOffering.java @@ -16,6 +16,8 @@ // under the License. package com.cloud.offering; +import java.util.Map; + import org.apache.cloudstack.acl.InfrastructureEntity; import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; @@ -38,6 +40,11 @@ public interface NetworkOffering extends InfrastructureEntity, InternalIdentity, Disabled, Enabled } + + public enum Detail { + InternalLbProvider, + PublicLbProvider + } public final static String SystemPublicNetwork = "System-Public-Network"; public final static String SystemControlNetwork = "System-Control-Network"; @@ -116,5 +123,9 @@ public interface NetworkOffering extends InfrastructureEntity, InternalIdentity, boolean isInline(); boolean getIsPersistent(); + + boolean getInternalLb(); + + boolean getPublicLb(); } diff --git a/api/src/com/cloud/offering/ServiceOffering.java b/api/src/com/cloud/offering/ServiceOffering.java index d6c215f42f0..165369c5e9b 100755 --- a/api/src/com/cloud/offering/ServiceOffering.java +++ b/api/src/com/cloud/offering/ServiceOffering.java @@ -30,6 +30,7 @@ public interface ServiceOffering extends InfrastructureEntity, InternalIdentity, public static final String ssvmDefaultOffUniqueName = "Cloud.com-SecondaryStorage"; public static final String routerDefaultOffUniqueName = "Cloud.Com-SoftwareRouter"; public static final String elbVmDefaultOffUniqueName = "Cloud.Com-ElasticLBVm"; + public static final String internalLbVmDefaultOffUniqueName = "Cloud.Com-InternalLBVm"; public enum StorageType { local, diff --git a/api/src/com/cloud/vm/VirtualMachine.java b/api/src/com/cloud/vm/VirtualMachine.java index 8f807d450c7..ce9add62469 100755 --- a/api/src/com/cloud/vm/VirtualMachine.java +++ b/api/src/com/cloud/vm/VirtualMachine.java @@ -186,6 +186,7 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I SecondaryStorageVm, ElasticIpVm, ElasticLoadBalancerVm, + InternalLoadBalancerVm, /* * UserBareMetal is only used for selecting VirtualMachineGuru, there is no @@ -196,7 +197,7 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I public static boolean isSystemVM(VirtualMachine.Type vmtype) { if (DomainRouter.equals(vmtype) || ConsoleProxy.equals(vmtype) - || SecondaryStorageVm.equals(vmtype)) { + || SecondaryStorageVm.equals(vmtype) || InternalLoadBalancerVm.equals(vmtype)) { return true; } return false; diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index d57fe058d93..c76506afc10 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -480,6 +480,12 @@ public class ApiConstants { public static final String HEALTHCHECK_HEALTHY_THRESHOLD = "healthythreshold"; public static final String HEALTHCHECK_UNHEALTHY_THRESHOLD = "unhealthythreshold"; public static final String HEALTHCHECK_PINGPATH = "pingpath"; + public static final String SOURCE_PORT = "sourceport"; + public static final String INSTANCE_PORT = "instanceport"; + public static final String SOURCE_IP = "sourceipaddress"; + public static final String SOURCE_IP_NETWORK_ID = "sourceipaddressnetworkid"; + public static final String SCHEME = "scheme"; + public static final String PROVIDER_TYPE = "providertype"; public static final String AFFINITY_GROUP_IDS = "affinitygroupids"; public static final String AFFINITY_GROUP_NAMES = "affinitygroupnames"; public static final String ASA_INSIDE_PORT_PROFILE = "insideportprofile"; diff --git a/api/src/org/apache/cloudstack/api/BaseCmd.java b/api/src/org/apache/cloudstack/api/BaseCmd.java index 48d18d029fb..8d66a8327f0 100644 --- a/api/src/org/apache/cloudstack/api/BaseCmd.java +++ b/api/src/org/apache/cloudstack/api/BaseCmd.java @@ -28,6 +28,9 @@ import java.util.regex.Pattern; import javax.inject.Inject; import org.apache.cloudstack.affinity.AffinityGroupService; +import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; +import org.apache.cloudstack.network.lb.ApplicationLoadBalancerService; +import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService; import org.apache.cloudstack.query.QueryService; import org.apache.cloudstack.usage.UsageService; import org.apache.log4j.Logger; @@ -139,7 +142,11 @@ public abstract class BaseCmd { @Inject public VMSnapshotService _vmSnapshotService; @Inject public DataStoreProviderApiService dataStoreProviderApiService; @Inject public VpcProvisioningService _vpcProvSvc; + @Inject public ApplicationLoadBalancerService _newLbSvc; + @Inject public ApplicationLoadBalancerService _appLbService; @Inject public AffinityGroupService _affinityGroupService; + @Inject public InternalLoadBalancerElementService _internalLbElementSvc; + @Inject public InternalLoadBalancerVMService _internalLbSvc; @Inject public NetworkModel _ntwkModel; public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException; diff --git a/api/src/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/org/apache/cloudstack/api/ResponseGenerator.java index 3433003cbed..ab8f99583a8 100644 --- a/api/src/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/org/apache/cloudstack/api/ResponseGenerator.java @@ -19,14 +19,15 @@ package org.apache.cloudstack.api; import java.text.DecimalFormat; import java.util.EnumSet; import java.util.List; +import java.util.Map; -import com.cloud.vm.NicSecondaryIp; import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.ApiConstants.HostDetails; import org.apache.cloudstack.api.ApiConstants.VMDetails; import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd; import org.apache.cloudstack.api.response.AccountResponse; +import org.apache.cloudstack.api.response.ApplicationLoadBalancerResponse; import org.apache.cloudstack.api.response.AsyncJobResponse; import org.apache.cloudstack.api.response.AutoScalePolicyResponse; import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse; @@ -44,11 +45,15 @@ import org.apache.cloudstack.api.response.EventResponse; import org.apache.cloudstack.api.response.ExtractResponse; import org.apache.cloudstack.api.response.FirewallResponse; import org.apache.cloudstack.api.response.FirewallRuleResponse; +import org.apache.cloudstack.api.response.GlobalLoadBalancerResponse; import org.apache.cloudstack.api.response.GuestOSResponse; +import org.apache.cloudstack.api.response.GuestVlanRangeResponse; +import org.apache.cloudstack.api.response.HostForMigrationResponse; import org.apache.cloudstack.api.response.HostResponse; import org.apache.cloudstack.api.response.HypervisorCapabilitiesResponse; import org.apache.cloudstack.api.response.IPAddressResponse; import org.apache.cloudstack.api.response.InstanceGroupResponse; +import org.apache.cloudstack.api.response.InternalLoadBalancerElementResponse; import org.apache.cloudstack.api.response.IpForwardingRuleResponse; import org.apache.cloudstack.api.response.IsolationMethodResponse; import org.apache.cloudstack.api.response.LBHealthCheckResponse; @@ -84,6 +89,7 @@ import org.apache.cloudstack.api.response.SnapshotResponse; import org.apache.cloudstack.api.response.SnapshotScheduleResponse; import org.apache.cloudstack.api.response.StaticRouteResponse; import org.apache.cloudstack.api.response.StorageNetworkIpRangeResponse; +import org.apache.cloudstack.api.response.StoragePoolForMigrationResponse; import org.apache.cloudstack.api.response.StoragePoolResponse; import org.apache.cloudstack.api.response.SwiftResponse; import org.apache.cloudstack.api.response.SystemVmInstanceResponse; @@ -103,6 +109,7 @@ import org.apache.cloudstack.api.response.VpcOfferingResponse; import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.api.response.VpnUsersResponse; import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule; import org.apache.cloudstack.region.Region; import org.apache.cloudstack.usage.Usage; @@ -119,10 +126,25 @@ import com.cloud.domain.Domain; import com.cloud.event.Event; import com.cloud.host.Host; import com.cloud.hypervisor.HypervisorCapabilities; -import com.cloud.network.*; +import com.cloud.network.GuestVlan; +import com.cloud.network.IpAddress; +import com.cloud.network.Network; import com.cloud.network.Network.Service; import com.cloud.network.Networks.IsolationType; -import com.cloud.network.as.*; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.PhysicalNetworkTrafficType; +import com.cloud.network.RemoteAccessVpn; +import com.cloud.network.Site2SiteCustomerGateway; +import com.cloud.network.Site2SiteVpnConnection; +import com.cloud.network.Site2SiteVpnGateway; +import com.cloud.network.VirtualRouterProvider; +import com.cloud.network.VpnUser; +import com.cloud.network.as.AutoScalePolicy; +import com.cloud.network.as.AutoScaleVmGroup; +import com.cloud.network.as.AutoScaleVmProfile; +import com.cloud.network.as.Condition; +import com.cloud.network.as.Counter; import com.cloud.network.router.VirtualRouter; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.HealthCheckPolicy; @@ -145,7 +167,12 @@ import com.cloud.projects.ProjectAccount; import com.cloud.projects.ProjectInvitation; import com.cloud.region.ha.GlobalLoadBalancerRule; import com.cloud.server.ResourceTag; -import com.cloud.storage.*; +import com.cloud.storage.GuestOS; +import com.cloud.storage.S3; +import com.cloud.storage.Snapshot; +import com.cloud.storage.StoragePool; +import com.cloud.storage.Swift; +import com.cloud.storage.Volume; import com.cloud.storage.snapshot.SnapshotPolicy; import com.cloud.storage.snapshot.SnapshotSchedule; import com.cloud.template.VirtualMachineTemplate; @@ -153,11 +180,12 @@ import com.cloud.user.Account; import com.cloud.user.User; import com.cloud.user.UserAccount; import com.cloud.uservm.UserVm; +import com.cloud.utils.net.Ip; import com.cloud.vm.InstanceGroup; import com.cloud.vm.Nic; -import com.cloud.vm.snapshot.VMSnapshot; +import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.VirtualMachine; -import org.apache.cloudstack.api.response.*; +import com.cloud.vm.snapshot.VMSnapshot; public interface ResponseGenerator { UserResponse createUserResponse(UserAccount user); @@ -397,9 +425,13 @@ public interface ResponseGenerator { NicSecondaryIpResponse createSecondaryIPToNicResponse(NicSecondaryIp result); public NicResponse createNicResponse(Nic result); + ApplicationLoadBalancerResponse createLoadBalancerContainerReponse(ApplicationLoadBalancerRule lb, Map lbInstances); + AffinityGroupResponse createAffinityGroupResponse(AffinityGroup group); Long getAffinityGroupId(String name, long entityOwnerId); + InternalLoadBalancerElementResponse createInternalLbElementResponse(VirtualRouterProvider result); + IsolationMethodResponse createIsolationMethodResponse(IsolationType method); } diff --git a/api/src/org/apache/cloudstack/api/command/admin/internallb/ConfigureInternalLoadBalancerElementCmd.java b/api/src/org/apache/cloudstack/api/command/admin/internallb/ConfigureInternalLoadBalancerElementCmd.java new file mode 100644 index 00000000000..7c3d1e95e57 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/internallb/ConfigureInternalLoadBalancerElementCmd.java @@ -0,0 +1,114 @@ +// 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. + +package org.apache.cloudstack.api.command.admin.internallb; + +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.InternalLoadBalancerElementResponse; +import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; +import org.apache.log4j.Logger; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.VirtualRouterProvider; +import com.cloud.user.Account; +import com.cloud.user.UserContext; + +@APICommand(name = "configureInternalLoadBalancerElement", responseObject=InternalLoadBalancerElementResponse.class, + description="Configures an Internal Load Balancer element.", since="4.2.0") +public class ConfigureInternalLoadBalancerElementCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(ConfigureInternalLoadBalancerElementCmd.class.getName()); + private static final String s_name = "configureinternalloadbalancerelementresponse"; + + @Inject + private List _service; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType = InternalLoadBalancerElementResponse.class, + required=true, description="the ID of the internal lb provider") + private Long id; + + @Parameter(name=ApiConstants.ENABLED, type=CommandType.BOOLEAN, required=true, description="Enables/Disables the Internal Load Balancer element") + private Boolean enabled; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + + public Long getId() { + return id; + } + + public Boolean getEnabled() { + return enabled; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public String getEventType() { + return EventTypes.EVENT_NETWORK_ELEMENT_CONFIGURE; + } + + @Override + public String getEventDescription() { + return "configuring internal load balancer element: " + id; + } + + @Override + public void execute() throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException{ + s_logger.debug("hello alena"); + UserContext.current().setEventDetails("Internal load balancer element: " + id); + s_logger.debug("hello alena"); + VirtualRouterProvider result = _service.get(0).configureInternalLoadBalancerElement(getId(), getEnabled()); + s_logger.debug("hello alena"); + if (result != null){ + InternalLoadBalancerElementResponse routerResponse = _responseGenerator.createInternalLbElementResponse(result); + routerResponse.setResponseName(getCommandName()); + this.setResponseObject(routerResponse); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to configure the internal load balancer element"); + } + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/internallb/CreateInternalLoadBalancerElementCmd.java b/api/src/org/apache/cloudstack/api/command/admin/internallb/CreateInternalLoadBalancerElementCmd.java new file mode 100644 index 00000000000..2902f7ae18a --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/internallb/CreateInternalLoadBalancerElementCmd.java @@ -0,0 +1,116 @@ +// 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. +package org.apache.cloudstack.api.command.admin.internallb; + +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCreateCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.InternalLoadBalancerElementResponse; +import org.apache.cloudstack.api.response.ProviderResponse; +import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; +import org.apache.log4j.Logger; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.network.VirtualRouterProvider; +import com.cloud.user.Account; +import com.cloud.user.UserContext; + +@APICommand(name = "createInternalLoadBalancerElement", responseObject=InternalLoadBalancerElementResponse.class, description="Create an Internal Load Balancer element.",since="4.2.0") +public class CreateInternalLoadBalancerElementCmd extends BaseAsyncCreateCmd { + public static final Logger s_logger = Logger.getLogger(CreateInternalLoadBalancerElementCmd.class.getName()); + private static final String s_name = "createinternalloadbalancerelementresponse"; + + @Inject + private List _service; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.NETWORK_SERVICE_PROVIDER_ID, type=CommandType.UUID, entityType = ProviderResponse.class, required=true, description="the network service provider ID of the internal load balancer element") + private Long nspId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public void setNspId(Long nspId) { + this.nspId = nspId; + } + + public Long getNspId() { + return nspId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute(){ + UserContext.current().setEventDetails("Virtual router element Id: "+getEntityId()); + VirtualRouterProvider result = _service.get(0).getInternalLoadBalancerElement(getEntityId()); + if (result != null) { + InternalLoadBalancerElementResponse response = _responseGenerator.createInternalLbElementResponse(result); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + }else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add Virtual Router entity to physical network"); + } + } + + @Override + public void create() throws ResourceAllocationException { + VirtualRouterProvider result = _service.get(0).addInternalLoadBalancerElement(getNspId()); + if (result != null) { + setEntityId(result.getId()); + setEntityUuid(result.getUuid()); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add Internal Load Balancer entity to physical network"); + } + } + + @Override + public String getEventType() { + return EventTypes.EVENT_SERVICE_PROVIDER_CREATE; + } + + @Override + public String getEventDescription() { + return "Adding physical network element Internal Load Balancer: " + getEntityId(); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/internallb/ListInternalLBVMsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/internallb/ListInternalLBVMsCmd.java new file mode 100644 index 00000000000..e314b3245c7 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/internallb/ListInternalLBVMsCmd.java @@ -0,0 +1,151 @@ +// 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. +package org.apache.cloudstack.api.command.admin.internallb; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.DomainRouterResponse; +import org.apache.cloudstack.api.response.HostResponse; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.NetworkResponse; +import org.apache.cloudstack.api.response.PodResponse; +import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.cloudstack.api.response.VpcResponse; +import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.network.router.VirtualRouter.Role; + +@APICommand(name = "listInternalLoadBalancerVMs", description="List internal LB VMs.", responseObject=DomainRouterResponse.class) +public class ListInternalLBVMsCmd extends BaseListProjectAndAccountResourcesCmd { + public static final Logger s_logger = Logger.getLogger(ListInternalLBVMsCmd.class.getName()); + + private static final String s_name = "listinternallbvmssresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.HOST_ID, type=CommandType.UUID, entityType=HostResponse.class, + description="the host ID of the Internal LB VM") + private Long hostId; + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=UserVmResponse.class, + description="the ID of the Internal LB VM") + private Long id; + + @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, description="the name of the Internal LB VM") + private String routerName; + + @Parameter(name=ApiConstants.POD_ID, type=CommandType.UUID, entityType=PodResponse.class, + description="the Pod ID of the Internal LB VM") + private Long podId; + + @Parameter(name=ApiConstants.STATE, type=CommandType.STRING, description="the state of the Internal LB VM") + private String state; + + @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType=ZoneResponse.class, + description="the Zone ID of the Internal LB VM") + private Long zoneId; + + @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.UUID, entityType=NetworkResponse.class, + description="list by network id") + private Long networkId; + + @Parameter(name=ApiConstants.VPC_ID, type=CommandType.UUID, entityType=VpcResponse.class, + description="List Internal LB VMs by VPC") + private Long vpcId; + + @Parameter(name=ApiConstants.FOR_VPC, type=CommandType.BOOLEAN, description="if true is passed for this parameter, list only VPC Internal LB VMs") + private Boolean forVpc; + + @Parameter(name=ApiConstants.ZONE_TYPE, type=CommandType.STRING, description="the network type of the zone that the virtual machine belongs to") + private String zoneType; + + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getHostId() { + return hostId; + } + + public Long getId() { + return id; + } + + public String getRouterName() { + return routerName; + } + + public Long getPodId() { + return podId; + } + + public String getState() { + return state; + } + + public Long getZoneId() { + return zoneId; + } + + public Long getNetworkId() { + return networkId; + } + + public Long getVpcId() { + return vpcId; + } + + public Boolean getForVpc() { + return forVpc; + } + + public String getRole() { + return Role.INTERNAL_LB_VM.toString(); + } + + public String getZoneType() { + return zoneType; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.DomainRouter; + } + + @Override + public void execute(){ + ListResponse response = _queryService.searchForInternalLbVms(this); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/internallb/ListInternalLoadBalancerElementsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/internallb/ListInternalLoadBalancerElementsCmd.java new file mode 100644 index 00000000000..18536191995 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/internallb/ListInternalLoadBalancerElementsCmd.java @@ -0,0 +1,99 @@ +// 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. +package org.apache.cloudstack.api.command.admin.internallb; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.InternalLoadBalancerElementResponse; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.ProviderResponse; +import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; +import org.apache.log4j.Logger; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.VirtualRouterProvider; + +@APICommand(name = "listInternalLoadBalancerElements", description="Lists all available Internal Load Balancer elements.", + responseObject=InternalLoadBalancerElementResponse.class, since="4.2.0") +public class ListInternalLoadBalancerElementsCmd extends BaseListCmd { + public static final Logger s_logger = Logger.getLogger(ListInternalLoadBalancerElementsCmd.class.getName()); + private static final String _name = "listinternalloadbalancerelementsresponse"; + + @Inject + private InternalLoadBalancerElementService _service; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType = InternalLoadBalancerElementResponse.class, + description="list internal load balancer elements by id") + private Long id; + + @Parameter(name=ApiConstants.NSP_ID, type=CommandType.UUID, entityType = ProviderResponse.class, + description="list internal load balancer elements by network service provider id") + private Long nspId; + + @Parameter(name=ApiConstants.ENABLED, type=CommandType.BOOLEAN, description="list internal load balancer elements by enabled state") + private Boolean enabled; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + public Long getNspId() { + return nspId; + } + + public Boolean getEnabled() { + return enabled; + } + + @Override + public String getCommandName() { + return _name; + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { + List providers = _service.searchForInternalLoadBalancerElements(getId(), getNspId(), getEnabled()); + ListResponse response = new ListResponse(); + List providerResponses = new ArrayList(); + for (VirtualRouterProvider provider : providers) { + InternalLoadBalancerElementResponse providerResponse = _responseGenerator.createInternalLbElementResponse(provider); + providerResponses.add(providerResponse); + } + response.setResponses(providerResponses); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/internallb/StartInternalLBVMCmd.java b/api/src/org/apache/cloudstack/api/command/admin/internallb/StartInternalLBVMCmd.java new file mode 100644 index 00000000000..31d132b5c9c --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/internallb/StartInternalLBVMCmd.java @@ -0,0 +1,120 @@ +// 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. +package org.apache.cloudstack.api.command.admin.internallb; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.DomainRouterResponse; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.router.VirtualRouter; +import com.cloud.network.router.VirtualRouter.Role; +import com.cloud.user.UserContext; + +@APICommand(name = "startInternalLoadBalancerVM", responseObject=DomainRouterResponse.class, description="Starts an existing internal lb vm.") +public class StartInternalLBVMCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(StartInternalLBVMCmd.class.getName()); + private static final String s_name = "startinternallbvmresponse"; + + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=DomainRouterResponse.class, + required=true, description="the ID of the internal lb vm") + private Long id; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + public static String getResultObjectName() { + return "router"; + } + + @Override + public long getEntityOwnerId() { + VirtualRouter router = _entityMgr.findById(VirtualRouter.class, getId()); + if (router != null && router.getRole() == Role.INTERNAL_LB_VM) { + return router.getAccountId(); + } else { + throw new InvalidParameterValueException("Unable to find internal lb vm by id"); + } + } + + @Override + public String getEventType() { + return EventTypes.EVENT_INTERNAL_LB_VM_START; + } + + @Override + public String getEventDescription() { + return "starting internal lb vm: " + getId(); + } + + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.InternalLbVm; + } + + public Long getInstanceId() { + return getId(); + } + + @Override + public void execute() throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException{ + UserContext.current().setEventDetails("Internal Lb Vm Id: "+getId()); + VirtualRouter result = null; + VirtualRouter router = _routerService.findRouter(getId()); + if (router == null || router.getRole() != Role.INTERNAL_LB_VM) { + throw new InvalidParameterValueException("Can't find internal lb vm by id"); + } else { + result = _internalLbSvc.startInternalLbVm(getId(), UserContext.current().getCaller(), UserContext.current().getCallerUserId()); + } + + if (result != null){ + DomainRouterResponse routerResponse = _responseGenerator.createDomainRouterResponse(result); + routerResponse.setResponseName(getCommandName()); + this.setResponseObject(routerResponse); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to start internal lb vm"); + } + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/internallb/StopInternalLBVMCmd.java b/api/src/org/apache/cloudstack/api/command/admin/internallb/StopInternalLBVMCmd.java new file mode 100644 index 00000000000..f40db49b417 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/internallb/StopInternalLBVMCmd.java @@ -0,0 +1,123 @@ +// 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. +package org.apache.cloudstack.api.command.admin.internallb; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.DomainRouterResponse; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.router.VirtualRouter; +import com.cloud.network.router.VirtualRouter.Role; +import com.cloud.user.UserContext; + +@APICommand(name = "stopInternalLoadBalancerVM", description = "Stops an Internal LB vm.", responseObject = DomainRouterResponse.class) +public class StopInternalLBVMCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(StopInternalLBVMCmd.class.getName()); + private static final String s_name = "stopinternallbvmresponse"; + + // /////////////////////////////////////////////////// + // ////////////// API parameters ///////////////////// + // /////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = DomainRouterResponse.class, + required = true, description = "the ID of the internal lb vm") + private Long id; + + @Parameter(name = ApiConstants.FORCED, type = CommandType.BOOLEAN, required = false, description = "Force stop the VM. The caller knows the VM is stopped.") + private Boolean forced; + + // /////////////////////////////////////////////////// + // ///////////////// Accessors /////////////////////// + // /////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + // /////////////////////////////////////////////////// + // ///////////// API Implementation/////////////////// + // /////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + VirtualRouter vm = _entityMgr.findById(VirtualRouter.class, getId()); + if (vm != null && vm.getRole() == Role.INTERNAL_LB_VM) { + return vm.getAccountId(); + } else { + throw new InvalidParameterValueException("Unable to find internal lb vm by id"); + } + } + + @Override + public String getEventType() { + return EventTypes.EVENT_INTERNAL_LB_VM_STOP; + } + + @Override + public String getEventDescription() { + return "stopping internal lb vm: " + getId(); + } + + @Override + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.InternalLbVm; + } + + @Override + public Long getInstanceId() { + return getId(); + } + + public boolean isForced() { + return (forced != null) ? forced : false; + } + + @Override + public void execute() throws ConcurrentOperationException, ResourceUnavailableException { + UserContext.current().setEventDetails("Internal lb vm Id: "+getId()); + VirtualRouter result = null; + VirtualRouter vm = _routerService.findRouter(getId()); + if (vm == null || vm.getRole() != Role.INTERNAL_LB_VM) { + throw new InvalidParameterValueException("Can't find internal lb vm by id"); + } else { + result = _internalLbSvc.stopInternalLbVm(getId(), isForced(), UserContext.current().getCaller(), UserContext.current().getCallerUserId()); + } + + if (result != null) { + DomainRouterResponse response = _responseGenerator.createDomainRouterResponse(result); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to stop internal lb vm"); + } + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java index b48bf9e763e..6410715727c 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java @@ -31,7 +31,6 @@ import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.NetworkOfferingResponse; import org.apache.cloudstack.api.response.ServiceOfferingResponse; - import org.apache.log4j.Logger; import com.cloud.exception.InvalidParameterValueException; @@ -95,6 +94,10 @@ public class CreateNetworkOfferingCmd extends BaseCmd { @Parameter(name=ApiConstants.IS_PERSISTENT, type=CommandType.BOOLEAN, description="true if network offering supports persistent networks; defaulted to false if not specified") private Boolean isPersistent; + + @Parameter(name=ApiConstants.DETAILS, type=CommandType.MAP, since="4.2.0", description="Template details in key/value pairs." + + " Supported keys are internallbprovider/publiclbprovider with service provider as a value") + protected Map details; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -215,6 +218,16 @@ public class CreateNetworkOfferingCmd extends BaseCmd { return capabilityMap; } + + public Map getDetails() { + if (details == null || details.isEmpty()) { + return null; + } + + Collection paramsCollection = details.values(); + Map params = (Map) (paramsCollection.toArray())[0]; + return params; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/admin/router/CreateVirtualRouterElementCmd.java b/api/src/org/apache/cloudstack/api/command/admin/router/CreateVirtualRouterElementCmd.java index 39fac136233..b3fca5addf1 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/router/CreateVirtualRouterElementCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/router/CreateVirtualRouterElementCmd.java @@ -31,6 +31,7 @@ import org.apache.cloudstack.api.response.VirtualRouterProviderResponse; import org.apache.log4j.Logger; import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceAllocationException; import com.cloud.network.VirtualRouterProvider; import com.cloud.network.VirtualRouterProvider.VirtualRouterProviderType; @@ -52,6 +53,9 @@ public class CreateVirtualRouterElementCmd extends BaseAsyncCreateCmd { @Parameter(name=ApiConstants.NETWORK_SERVICE_PROVIDER_ID, type=CommandType.UUID, entityType = ProviderResponse.class, required=true, description="the network service provider ID of the virtual router element") private Long nspId; + + @Parameter(name=ApiConstants.PROVIDER_TYPE, type=CommandType.UUID, entityType = ProviderResponse.class, description="The provider type. Supported types are VirtualRouter (default) and VPCVirtualRouter") + private String providerType; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -61,16 +65,27 @@ public class CreateVirtualRouterElementCmd extends BaseAsyncCreateCmd { this.nspId = nspId; } - - public Long getNspId() { return nspId; } + + public VirtualRouterProviderType getProviderType() { + if (providerType != null) { + if (providerType.equalsIgnoreCase(VirtualRouterProviderType.VirtualRouter.toString())) { + return VirtualRouterProviderType.VirtualRouter; + } else if (providerType.equalsIgnoreCase(VirtualRouterProviderType.VPCVirtualRouter.toString())) { + return VirtualRouterProviderType.VPCVirtualRouter; + } else throw new InvalidParameterValueException("Invalid providerType specified"); + } + return VirtualRouterProviderType.VirtualRouter; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// + + @Override public String getCommandName() { return s_name; @@ -96,7 +111,7 @@ public class CreateVirtualRouterElementCmd extends BaseAsyncCreateCmd { @Override public void create() throws ResourceAllocationException { - VirtualRouterProvider result = _service.get(0).addElement(getNspId(), VirtualRouterProviderType.VirtualRouter); + VirtualRouterProvider result = _service.get(0).addElement(getNspId(), getProviderType()); if (result != null) { setEntityId(result.getId()); setEntityUuid(result.getUuid()); diff --git a/api/src/org/apache/cloudstack/api/command/admin/router/ListRoutersCmd.java b/api/src/org/apache/cloudstack/api/command/admin/router/ListRoutersCmd.java index 9fbc9401532..78c3554ae73 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/router/ListRoutersCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/router/ListRoutersCmd.java @@ -31,6 +31,7 @@ import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.log4j.Logger; import com.cloud.async.AsyncJob; +import com.cloud.network.router.VirtualRouter.Role; @APICommand(name = "listRouters", description="List routers.", responseObject=DomainRouterResponse.class) public class ListRoutersCmd extends BaseListProjectAndAccountResourcesCmd { @@ -77,7 +78,7 @@ public class ListRoutersCmd extends BaseListProjectAndAccountResourcesCmd { @Parameter(name=ApiConstants.FOR_VPC, type=CommandType.BOOLEAN, description="if true is passed for this parameter, list only VPC routers") private Boolean forVpc; - + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -121,6 +122,10 @@ public class ListRoutersCmd extends BaseListProjectAndAccountResourcesCmd { public Boolean getForVpc() { return forVpc; } + + public String getRole() { + return Role.VIRTUAL_ROUTER.toString(); + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/admin/router/StartRouterCmd.java b/api/src/org/apache/cloudstack/api/command/admin/router/StartRouterCmd.java index 1d3930b6b63..ad0461e0eb7 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/router/StartRouterCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/router/StartRouterCmd.java @@ -29,8 +29,10 @@ import com.cloud.async.AsyncJob; import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.router.VirtualRouter; +import com.cloud.network.router.VirtualRouter.Role; import com.cloud.user.Account; import com.cloud.user.UserContext; @@ -100,7 +102,13 @@ public class StartRouterCmd extends BaseAsyncCmd { @Override public void execute() throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException{ UserContext.current().setEventDetails("Router Id: "+getId()); - VirtualRouter result = _routerService.startRouter(id); + VirtualRouter result = null; + VirtualRouter router = _routerService.findRouter(getId()); + if (router == null || router.getRole() != Role.VIRTUAL_ROUTER) { + throw new InvalidParameterValueException("Can't find router by id"); + } else { + result = _routerService.startRouter(getId()); + } if (result != null){ DomainRouterResponse routerResponse = _responseGenerator.createDomainRouterResponse(result); routerResponse.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/admin/router/StopRouterCmd.java b/api/src/org/apache/cloudstack/api/command/admin/router/StopRouterCmd.java index 60dd9386c75..94473cf9ffc 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/router/StopRouterCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/router/StopRouterCmd.java @@ -28,8 +28,10 @@ import org.apache.log4j.Logger; import com.cloud.async.AsyncJob; import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.router.VirtualRouter; +import com.cloud.network.router.VirtualRouter.Role; import com.cloud.user.Account; import com.cloud.user.UserContext; @@ -103,7 +105,14 @@ public class StopRouterCmd extends BaseAsyncCmd { @Override public void execute() throws ConcurrentOperationException, ResourceUnavailableException { UserContext.current().setEventDetails("Router Id: "+getId()); - VirtualRouter result = _routerService.stopRouter(getId(), isForced()); + VirtualRouter result = null; + VirtualRouter router = _routerService.findRouter(getId()); + if (router == null || router.getRole() != Role.VIRTUAL_ROUTER) { + throw new InvalidParameterValueException("Can't find router by id"); + } else { + result = _routerService.stopRouter(getId(), isForced()); + } + if (result != null) { DomainRouterResponse response = _responseGenerator.createDomainRouterResponse(result); response.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateApplicationLoadBalancerCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateApplicationLoadBalancerCmd.java new file mode 100644 index 00000000000..17ae959aa6e --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateApplicationLoadBalancerCmd.java @@ -0,0 +1,218 @@ +// 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. +package org.apache.cloudstack.api.command.user.loadbalancer; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCreateCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ApplicationLoadBalancerResponse; +import org.apache.cloudstack.api.response.NetworkResponse; +import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapcityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Network; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.user.UserContext; +import com.cloud.utils.net.NetUtils; + +@APICommand(name = "createLoadBalancer", description="Creates a Load Balancer", responseObject=ApplicationLoadBalancerResponse.class, since="4.2.0") +public class CreateApplicationLoadBalancerCmd extends BaseAsyncCreateCmd { + public static final Logger s_logger = Logger.getLogger(CreateApplicationLoadBalancerCmd.class.getName()); + + private static final String s_name = "createloadbalancerresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, required=true, description="name of the Load Balancer") + private String loadBalancerName; + + @Parameter(name=ApiConstants.DESCRIPTION, type=CommandType.STRING, description="the description of the Load Balancer", length=4096) + private String description; + + @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.UUID, required=true, entityType = NetworkResponse.class, + description="The guest network the Load Balancer will be created for") + private Long networkId; + + @Parameter(name=ApiConstants.SOURCE_PORT, type=CommandType.INTEGER, required=true, description="the source port the network traffic will be load balanced from") + private Integer sourcePort; + + @Parameter(name=ApiConstants.ALGORITHM, type=CommandType.STRING, required=true, description="load balancer algorithm (source, roundrobin, leastconn)") + private String algorithm; + + @Parameter(name=ApiConstants.INSTANCE_PORT, type=CommandType.INTEGER, required=true, description="the TCP port of the virtual machine where the network traffic will be load balanced to") + private Integer instancePort; + + @Parameter(name=ApiConstants.SOURCE_IP, type=CommandType.STRING, description="the source ip address the network traffic will be load balanced from") + private String sourceIp; + + @Parameter(name=ApiConstants.SOURCE_IP_NETWORK_ID, type=CommandType.UUID, entityType = NetworkResponse.class, required=true, + description="the network id of the source ip address") + private Long sourceIpNetworkId; + + @Parameter(name=ApiConstants.SCHEME, type=CommandType.STRING, required=true, description="the load balancer scheme. Supported value in this release is Internal") + private String scheme; + + + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public String getAlgorithm() { + return algorithm; + } + + public String getDescription() { + return description; + } + + public String getLoadBalancerName() { + return loadBalancerName; + } + + public Integer getPrivatePort() { + return instancePort; + } + + public long getNetworkId() { + return networkId; + } + + public String getName() { + return loadBalancerName; + } + + public Integer getSourcePort() { + return sourcePort.intValue(); + } + + public String getProtocol() { + return NetUtils.TCP_PROTO; + } + + public long getAccountId() { + //get account info from the network object + Network ntwk = _networkService.getNetwork(networkId); + if (ntwk == null) { + throw new InvalidParameterValueException("Invalid network id specified"); + } + + return ntwk.getAccountId(); + + } + + public int getInstancePort() { + return instancePort.intValue(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_LOAD_BALANCER_CREATE; + } + + @Override + public String getEventDescription() { + return "creating load balancer: " + getName() + " account: " + getAccountId(); + + } + + @Override + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.LoadBalancerRule; + } + + public String getSourceIp() { + return sourceIp; + } + + public long getSourceIpNetworkId() { + return sourceIpNetworkId; + } + + public Scheme getScheme() { + if (scheme.equalsIgnoreCase(Scheme.Internal.toString())) { + return Scheme.Internal; + } else { + throw new InvalidParameterValueException("Invalid value for scheme. Supported value is Internal"); + } + } + + @Override + public long getEntityOwnerId() { + return getAccountId(); + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + @Override + public String getCommandName() { + return s_name; + } + + @Override + public void execute() throws ResourceAllocationException, ResourceUnavailableException { + ApplicationLoadBalancerRule rule = null; + try { + UserContext.current().setEventDetails("Load Balancer Id: " + getEntityId()); + // State might be different after the rule is applied, so get new object here + rule = _entityMgr.findById(ApplicationLoadBalancerRule.class, getEntityId()); + ApplicationLoadBalancerResponse lbResponse = _responseGenerator.createLoadBalancerContainerReponse(rule, _lbService.getLbInstances(getEntityId())); + setResponseObject(lbResponse); + lbResponse.setResponseName(getCommandName()); + } catch (Exception ex) { + s_logger.warn("Failed to create Load Balancer due to exception ", ex); + } finally { + if (rule == null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create Load Balancer"); + } + } + } + + @Override + public void create() { + try { + + ApplicationLoadBalancerRule result = _appLbService.createApplicationLoadBalancer(getName(), getDescription(), getScheme(), + getSourceIpNetworkId(), getSourceIp(), getSourcePort(), getInstancePort(), getAlgorithm(), getNetworkId(), getEntityOwnerId()); + this.setEntityId(result.getId()); + this.setEntityUuid(result.getUuid()); + }catch (NetworkRuleConflictException e) { + s_logger.warn("Exception: ", e); + throw new ServerApiException(ApiErrorCode.NETWORK_RULE_CONFLICT_ERROR, e.getMessage()); + } catch (InsufficientAddressCapacityException e) { + s_logger.warn("Exception: ", e); + throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, e.getMessage()); + } catch (InsufficientVirtualNetworkCapcityException e) { + s_logger.warn("Exception: ", e); + throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, e.getMessage()); + } + } +} + diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java index 5f1d97b2803..f6cc1f130bd 100644 --- a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java @@ -148,7 +148,7 @@ public class CreateLoadBalancerRuleCmd extends BaseAsyncCreateCmd /*implements } - public Long getNetworkId() { + public long getNetworkId() { if (networkId != null) { return networkId; } @@ -278,7 +278,9 @@ public class CreateLoadBalancerRuleCmd extends BaseAsyncCreateCmd /*implements throw new InvalidParameterValueException("Parameter cidrList is deprecated; if you need to open firewall rule for the specific cidr, please refer to createFirewallRule command"); } try { - LoadBalancer result = _lbService.createLoadBalancerRule(this, getOpenFirewall()); + LoadBalancer result = _lbService.createPublicLoadBalancerRule(getXid(), getName(), getDescription(), + getSourcePortStart(), getSourcePortEnd(), getDefaultPortStart(), getDefaultPortEnd(), getSourceIpAddressId(), getProtocol(), getAlgorithm(), + getNetworkId(), getEntityOwnerId(), getOpenFirewall()); this.setEntityId(result.getId()); this.setEntityUuid(result.getUuid()); } catch (NetworkRuleConflictException e) { diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/DeleteApplicationLoadBalancerCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/DeleteApplicationLoadBalancerCmd.java new file mode 100644 index 00000000000..bc6cd09526c --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/DeleteApplicationLoadBalancerCmd.java @@ -0,0 +1,116 @@ +// 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. +package org.apache.cloudstack.api.command.user.loadbalancer; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.FirewallRuleResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.user.UserContext; + +@APICommand(name = "deleteLoadBalancer", description="Deletes a load balancer", responseObject=SuccessResponse.class, since="4.2.0") +public class DeleteApplicationLoadBalancerCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(DeleteApplicationLoadBalancerCmd.class.getName()); + private static final String s_name = "deleteloadbalancerresponse"; + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType = FirewallRuleResponse.class, + required=true, description="the ID of the Load Balancer") + private Long id; + + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + ApplicationLoadBalancerRule lb = _entityMgr.findById(ApplicationLoadBalancerRule.class, getId()); + if (lb != null) { + return lb.getAccountId(); + } else { + throw new InvalidParameterValueException("Can't find load balancer by id specified"); + } + } + + @Override + public String getEventType() { + return EventTypes.EVENT_LOAD_BALANCER_DELETE; + } + + @Override + public String getEventDescription() { + return "deleting load balancer: " + getId(); + } + + @Override + public void execute(){ + UserContext.current().setEventDetails("Load balancer Id: " + getId()); + boolean result = _appLbService.deleteApplicationLoadBalancer(getId()); + + if (result) { + SuccessResponse response = new SuccessResponse(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete load balancer"); + } + } + + @Override + public String getSyncObjType() { + return BaseAsyncCmd.networkSyncObject; + } + + @Override + public Long getSyncObjId() { + ApplicationLoadBalancerRule lb = _appLbService.getApplicationLoadBalancer(id); + if(lb == null){ + throw new InvalidParameterValueException("Unable to find load balancer by id "); + } + return lb.getNetworkId(); + } + + @Override + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.FirewallRule; + } +} diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/ListApplicationLoadBalancersCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/ListApplicationLoadBalancersCmd.java new file mode 100644 index 00000000000..8e5df31ed29 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/ListApplicationLoadBalancersCmd.java @@ -0,0 +1,131 @@ +// 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. +package org.apache.cloudstack.api.command.user.loadbalancer; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseListTaggedResourcesCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.ApplicationLoadBalancerResponse; +import org.apache.cloudstack.api.response.FirewallRuleResponse; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.NetworkResponse; +import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule; +import org.apache.log4j.Logger; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.utils.Pair; + +@APICommand(name = "listLoadBalancers", description = "Lists Load Balancers", responseObject = ApplicationLoadBalancerResponse.class, since="4.2.0") +public class ListApplicationLoadBalancersCmd extends BaseListTaggedResourcesCmd { + public static final Logger s_logger = Logger.getLogger(ListApplicationLoadBalancersCmd.class.getName()); + + private static final String s_name = "listloadbalancerssresponse"; + + // /////////////////////////////////////////////////// + // ////////////// API parameters ///////////////////// + // /////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = FirewallRuleResponse.class, + description = "the ID of the Load Balancer") + private Long id; + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "the name of the Load Balancer") + private String loadBalancerName; + + @Parameter(name = ApiConstants.SOURCE_IP, type = CommandType.STRING, description = "the source ip address of the Load Balancer") + private String sourceIp; + + @Parameter(name=ApiConstants.SOURCE_IP_NETWORK_ID, type=CommandType.UUID, entityType = NetworkResponse.class, + description="the network id of the source ip address") + private Long sourceIpNetworkId; + + @Parameter(name = ApiConstants.SCHEME, type = CommandType.STRING, description = "the scheme of the Load Balancer. Supported value is Internal in the current release") + private String scheme; + + @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.UUID, entityType = NetworkResponse.class, + description="the network id of the Load Balancer") + private Long networkId; + + + // /////////////////////////////////////////////////// + // ///////////////// Accessors /////////////////////// + // /////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + public String getLoadBalancerRuleName() { + return loadBalancerName; + } + + public String getLoadBalancerName() { + return loadBalancerName; + } + + public String getSourceIp() { + return sourceIp; + } + + public Long getSourceIpNetworkId() { + return sourceIpNetworkId; + } + + @Override + public String getCommandName() { + return s_name; + } + + public Scheme getScheme() { + if (scheme != null) { + if (scheme.equalsIgnoreCase(Scheme.Internal.toString())) { + return Scheme.Internal; + } else { + throw new InvalidParameterValueException("Invalid value for scheme. Supported value is Internal"); + } + } + return null; + } + + public Long getNetworkId() { + return networkId; + } + // /////////////////////////////////////////////////// + // ///////////// API Implementation/////////////////// + // /////////////////////////////////////////////////// + + @Override + public void execute() { + Pair, Integer> loadBalancers = _appLbService.listApplicationLoadBalancers(this); + ListResponse response = new ListResponse(); + List lbResponses = new ArrayList(); + for (ApplicationLoadBalancerRule loadBalancer : loadBalancers.first()) { + ApplicationLoadBalancerResponse lbResponse = _responseGenerator.createLoadBalancerContainerReponse(loadBalancer, _lbService.getLbInstances(loadBalancer.getId())); + lbResponse.setObjectName("loadbalancer"); + lbResponses.add(lbResponse); + } + response.setResponses(lbResponses, loadBalancers.second()); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } + +} diff --git a/api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerInstanceResponse.java b/api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerInstanceResponse.java new file mode 100644 index 00000000000..2d6614d217b --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerInstanceResponse.java @@ -0,0 +1,63 @@ +// 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. +package org.apache.cloudstack.api.response; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +/** + * + * Load Balancer instance is the User Vm instance participating in the Load Balancer + * + */ + +@SuppressWarnings("unused") +public class ApplicationLoadBalancerInstanceResponse extends BaseResponse{ + + @SerializedName(ApiConstants.ID) @Param(description = "the instance ID") + private String id; + + @SerializedName(ApiConstants.NAME) @Param(description = "the name of the instance") + private String name; + + @SerializedName(ApiConstants.STATE) @Param(description="the state of the instance") + private String state; + + @SerializedName(ApiConstants.IP_ADDRESS) + @Param(description="the ip address of the instance") + private String ipAddress; + + + public void setId(String id) { + this.id = id; + } + + public void setName(String name) { + this.name = name; + } + + public void setState(String state) { + this.state = state; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } +} diff --git a/api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerResponse.java b/api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerResponse.java new file mode 100644 index 00000000000..de9bce6c658 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerResponse.java @@ -0,0 +1,142 @@ +// 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. + +package org.apache.cloudstack.api.response; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +@SuppressWarnings("unused") +public class ApplicationLoadBalancerResponse extends BaseResponse implements ControlledEntityResponse{ + @SerializedName(ApiConstants.ID) @Param(description = "the Load Balancer ID") + private String id; + + @SerializedName(ApiConstants.NAME) @Param(description = "the name of the Load Balancer") + private String name; + + @SerializedName(ApiConstants.DESCRIPTION) @Param(description = "the description of the Load Balancer") + private String description; + + @SerializedName(ApiConstants.ALGORITHM) @Param(description = "the load balancer algorithm (source, roundrobin, leastconn)") + private String algorithm; + + @SerializedName(ApiConstants.NETWORK_ID) @Param(description="Load Balancer network id") + private String networkId; + + @SerializedName(ApiConstants.SOURCE_IP) @Param(description="Load Balancer source ip") + private String sourceIp; + + @SerializedName(ApiConstants.SOURCE_IP_NETWORK_ID) @Param(description="Load Balancer source ip network id") + private String sourceIpNetworkId; + + @SerializedName(ApiConstants.ACCOUNT) + @Param(description = "the account of the Load Balancer") + private String accountName; + + @SerializedName(ApiConstants.PROJECT_ID) @Param(description="the project id of the Load Balancer") + private String projectId; + + @SerializedName(ApiConstants.PROJECT) @Param(description="the project name of the Load Balancer") + private String projectName; + + @SerializedName(ApiConstants.DOMAIN_ID) + @Param(description = "the domain ID of the Load Balancer") + private String domainId; + + @SerializedName(ApiConstants.DOMAIN) + @Param(description = "the domain of the Load Balancer") + private String domainName; + + @SerializedName("loadbalancerrule") @Param(description="the list of rules associated with the Load Balancer", responseObject = ApplicationLoadBalancerRuleResponse.class) + private List lbRules; + + @SerializedName("loadbalancerinstance") @Param(description="the list of instances associated with the Load Balancer", responseObject = ApplicationLoadBalancerInstanceResponse.class) + private List lbInstances; + + @SerializedName(ApiConstants.TAGS) @Param(description="the list of resource tags associated with the Load Balancer", responseObject = ResourceTagResponse.class) + private List tags; + + public void setAccountName(String accountName) { + this.accountName = accountName; + } + + @Override + public void setDomainId(String domainId) { + this.domainId = domainId; + } + + public void setDomainName(String domainName) { + this.domainName = domainName; + } + + @Override + public void setProjectId(String projectId) { + this.projectId = projectId; + } + + @Override + public void setProjectName(String projectName) { + this.projectName = projectName; + } + + public void setTags(List tags) { + this.tags = tags; + } + + public void setId(String id) { + this.id = id; + } + + public void setName(String name) { + this.name = name; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setAlgorithm(String algorithm) { + this.algorithm = algorithm; + } + + public void setNetworkId(String networkId) { + this.networkId = networkId; + } + + public void setSourceIp(String sourceIp) { + this.sourceIp = sourceIp; + } + + public void setSourceIpNetworkId(String sourceIpNetworkId) { + this.sourceIpNetworkId = sourceIpNetworkId; + } + + public void setLbRules(List lbRules) { + this.lbRules = lbRules; + } + + public void setLbInstances(List lbInstances) { + this.lbInstances = lbInstances; + } +} diff --git a/api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerRuleResponse.java b/api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerRuleResponse.java new file mode 100644 index 00000000000..ffc64d5ca46 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerRuleResponse.java @@ -0,0 +1,51 @@ +// 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. + +package org.apache.cloudstack.api.response; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +/** + * Subobject of the load balancer container response + */ +@SuppressWarnings("unused") +public class ApplicationLoadBalancerRuleResponse extends BaseResponse{ + @SerializedName(ApiConstants.SOURCE_PORT) @Param(description = "source port of the load balancer rule") + private Integer sourcePort; + + @SerializedName(ApiConstants.INSTANCE_PORT) @Param(description = "instance port of the load balancer rule") + private Integer instancePort; + + @SerializedName(ApiConstants.STATE) @Param(description = "the state of the load balancer rule") + private String state; + + public void setSourcePort(Integer sourcePort) { + this.sourcePort = sourcePort; + } + + public void setInstancePort(Integer instancePort) { + this.instancePort = instancePort; + } + + public void setState(String state) { + this.state = state; + } +} diff --git a/api/src/org/apache/cloudstack/api/response/DomainRouterResponse.java b/api/src/org/apache/cloudstack/api/response/DomainRouterResponse.java index 79c8596a8d1..852d98815a3 100644 --- a/api/src/org/apache/cloudstack/api/response/DomainRouterResponse.java +++ b/api/src/org/apache/cloudstack/api/response/DomainRouterResponse.java @@ -153,8 +153,11 @@ public class DomainRouterResponse extends BaseResponse implements ControlledView @SerializedName("scriptsversion") @Param(description="the version of scripts") private String scriptsVersion; - @SerializedName(ApiConstants.VPC_ID) @Param(description="VPC the network belongs to") + @SerializedName(ApiConstants.VPC_ID) @Param(description="VPC the router belongs to") private String vpcId; + + @SerializedName(ApiConstants.ROLE) @Param(description="role of the domain router") + private String role; @SerializedName("nic") @Param(description="the list of nics associated with the router", responseObject = NicResponse.class, since="4.0") @@ -164,15 +167,11 @@ public class DomainRouterResponse extends BaseResponse implements ControlledView nics = new LinkedHashSet(); } - - @Override public String getObjectId() { return this.getId(); } - - public String getId() { return id; } @@ -372,4 +371,8 @@ public class DomainRouterResponse extends BaseResponse implements ControlledView public void setIp6Dns2(String ip6Dns2) { this.ip6Dns2 = ip6Dns2; } + + public void setRole(String role) { + this.role = role; + } } diff --git a/api/src/org/apache/cloudstack/api/response/InternalLoadBalancerElementResponse.java b/api/src/org/apache/cloudstack/api/response/InternalLoadBalancerElementResponse.java new file mode 100644 index 00000000000..b7e8634ee8f --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/InternalLoadBalancerElementResponse.java @@ -0,0 +1,51 @@ +// 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. +package org.apache.cloudstack.api.response; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + +import com.cloud.network.VirtualRouterProvider; +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +@EntityReference(value=VirtualRouterProvider.class) +@SuppressWarnings("unused") +public class InternalLoadBalancerElementResponse extends BaseResponse { + @SerializedName(ApiConstants.ID) @Param(description="the id of the internal load balancer element") + private String id; + + @SerializedName(ApiConstants.NSP_ID) @Param(description="the physical network service provider id of the element") + private String nspId; + + @SerializedName(ApiConstants.ENABLED) @Param(description="Enabled/Disabled the element") + private Boolean enabled; + + + public void setId(String id) { + this.id = id; + } + + public void setNspId(String nspId) { + this.nspId = nspId; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } +} diff --git a/api/src/org/apache/cloudstack/api/response/NetworkOfferingResponse.java b/api/src/org/apache/cloudstack/api/response/NetworkOfferingResponse.java index b1dcd423117..7a7e371e180 100644 --- a/api/src/org/apache/cloudstack/api/response/NetworkOfferingResponse.java +++ b/api/src/org/apache/cloudstack/api/response/NetworkOfferingResponse.java @@ -18,6 +18,7 @@ package org.apache.cloudstack.api.response; import java.util.Date; import java.util.List; +import java.util.Map; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; @@ -83,6 +84,10 @@ public class NetworkOfferingResponse extends BaseResponse { @SerializedName(ApiConstants.IS_PERSISTENT) @Param(description="true if network offering supports persistent networks, false otherwise") private Boolean isPersistent; + + @SerializedName(ApiConstants.DETAILS) @Param(description="additional key/value details tied with network offering", since="4.2.0") + private Map details; + public void setId(String id) { this.id = id; @@ -156,5 +161,9 @@ public class NetworkOfferingResponse extends BaseResponse { public void setIsPersistent(Boolean isPersistent) { this.isPersistent = isPersistent; } + + public void setDetails(Map details) { + this.details = details; + } } diff --git a/api/src/org/apache/cloudstack/api/response/VirtualRouterProviderResponse.java b/api/src/org/apache/cloudstack/api/response/VirtualRouterProviderResponse.java index 92d9a1d0cc1..de355bd0c25 100644 --- a/api/src/org/apache/cloudstack/api/response/VirtualRouterProviderResponse.java +++ b/api/src/org/apache/cloudstack/api/response/VirtualRouterProviderResponse.java @@ -25,6 +25,7 @@ import com.cloud.serializer.Param; import com.google.gson.annotations.SerializedName; @EntityReference(value=VirtualRouterProvider.class) +@SuppressWarnings("unused") public class VirtualRouterProviderResponse extends BaseResponse implements ControlledEntityResponse { @SerializedName(ApiConstants.ID) @Param(description="the id of the router") private String id; diff --git a/api/src/org/apache/cloudstack/network/element/InternalLoadBalancerElementService.java b/api/src/org/apache/cloudstack/network/element/InternalLoadBalancerElementService.java new file mode 100644 index 00000000000..33a0c64058e --- /dev/null +++ b/api/src/org/apache/cloudstack/network/element/InternalLoadBalancerElementService.java @@ -0,0 +1,56 @@ +// 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. +package org.apache.cloudstack.network.element; + +import java.util.List; + + +import com.cloud.network.VirtualRouterProvider; +import com.cloud.utils.component.PluggableService; + +public interface InternalLoadBalancerElementService extends PluggableService{ + /** + * Configures existing Internal Load Balancer Element (enables or disables it) + * @param id + * @param enable + * @return + */ + VirtualRouterProvider configureInternalLoadBalancerElement(long id, boolean enable); + + /** + * Adds Internal Load Balancer element to the Network Service Provider + * @param ntwkSvcProviderId + * @return + */ + VirtualRouterProvider addInternalLoadBalancerElement(long ntwkSvcProviderId); + + /** + * Retrieves existing Internal Load Balancer element + * @param id + * @return + */ + VirtualRouterProvider getInternalLoadBalancerElement(long id); + + /** + * Searches for existing Internal Load Balancer elements based on parameters passed to the call + * @param id + * @param ntwkSvsProviderId + * @param enabled + * @return + */ + List searchForInternalLoadBalancerElements(Long id, Long ntwkSvsProviderId, Boolean enabled); +} diff --git a/api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerContainer.java b/api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerContainer.java new file mode 100644 index 00000000000..df94d3d4338 --- /dev/null +++ b/api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerContainer.java @@ -0,0 +1,28 @@ +// 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. +package org.apache.cloudstack.network.lb; + +import com.cloud.network.rules.LoadBalancerContainer; +import com.cloud.utils.net.Ip; + +public interface ApplicationLoadBalancerContainer extends LoadBalancerContainer{ + + public Long getSourceIpNetworkId(); + + public Ip getSourceIp(); + +} diff --git a/api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerRule.java b/api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerRule.java new file mode 100644 index 00000000000..f4acb734c8b --- /dev/null +++ b/api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerRule.java @@ -0,0 +1,24 @@ +// 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. + +package org.apache.cloudstack.network.lb; + +import com.cloud.network.rules.LoadBalancer; + +public interface ApplicationLoadBalancerRule extends ApplicationLoadBalancerContainer, LoadBalancer{ + int getInstancePort(); +} diff --git a/api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerService.java b/api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerService.java new file mode 100644 index 00000000000..b2ac358555b --- /dev/null +++ b/api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerService.java @@ -0,0 +1,42 @@ +// 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. + +package org.apache.cloudstack.network.lb; + +import java.util.List; + +import org.apache.cloudstack.api.command.user.loadbalancer.ListApplicationLoadBalancersCmd; + +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapcityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.utils.Pair; + +public interface ApplicationLoadBalancerService { + + ApplicationLoadBalancerRule createApplicationLoadBalancer(String name, String description, Scheme scheme, long sourceIpNetworkId, String sourceIp, + int sourcePort, int instancePort, String algorithm, long networkId, long lbOwnerId) throws InsufficientAddressCapacityException, + NetworkRuleConflictException, InsufficientVirtualNetworkCapcityException; + + boolean deleteApplicationLoadBalancer(long id); + + Pair, Integer> listApplicationLoadBalancers(ListApplicationLoadBalancersCmd cmd); + + ApplicationLoadBalancerRule getApplicationLoadBalancer(long ruleId); + +} diff --git a/api/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMService.java b/api/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMService.java new file mode 100644 index 00000000000..91cd88d91c1 --- /dev/null +++ b/api/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMService.java @@ -0,0 +1,34 @@ +// 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. +package org.apache.cloudstack.network.lb; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.exception.StorageUnavailableException; +import com.cloud.network.router.VirtualRouter; +import com.cloud.user.Account; + +public interface InternalLoadBalancerVMService { + + VirtualRouter startInternalLbVm(long internalLbVmId, Account caller, long callerUserId) + throws StorageUnavailableException, InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException; + + VirtualRouter stopInternalLbVm(long vmId, boolean forced, Account caller, long callerUserId) + throws ConcurrentOperationException, ResourceUnavailableException; + +} diff --git a/api/src/org/apache/cloudstack/query/QueryService.java b/api/src/org/apache/cloudstack/query/QueryService.java index 443c5df65b5..2f50d63828c 100644 --- a/api/src/org/apache/cloudstack/query/QueryService.java +++ b/api/src/org/apache/cloudstack/query/QueryService.java @@ -18,6 +18,7 @@ package org.apache.cloudstack.query; import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.command.admin.host.ListHostsCmd; +import org.apache.cloudstack.api.command.admin.internallb.ListInternalLBVMsCmd; import org.apache.cloudstack.api.command.admin.router.ListRoutersCmd; import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolsCmd; import org.apache.cloudstack.api.command.admin.user.ListUsersCmd; @@ -101,4 +102,6 @@ public interface QueryService { public ListResponse listAffinityGroups(Long affinityGroupId, String affinityGroupName, String affinityGroupType, Long vmId, Long startIndex, Long pageSize); + + ListResponse searchForInternalLbVms(ListInternalLBVMsCmd cmd); } diff --git a/client/pom.xml b/client/pom.xml index 147959bd7f0..197ba27975c 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -85,6 +85,11 @@ cloud-plugin-network-midonet ${project.version} + + org.apache.cloudstack + cloud-plugin-network-internallb + ${project.version} + org.apache.cloudstack cloud-plugin-hypervisor-xen diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 36f232c737c..67c8ccf9355 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -363,6 +363,9 @@ + + + diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index 687c3c16c75..cdc19929c19 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -577,6 +577,17 @@ revertToVMSnapshot=15 #### Baremetal commands addBaremetalHost=1 +#### New Load Balancer commands +createLoadBalancer=15 +listLoadBalancers=15 +deleteLoadBalancer=15 + +#Internal Load Balancer Element commands +configureInternalLoadBalancerElement=1 +createInternalLoadBalancerElement=1 +listInternalLoadBalancerElements=1 + + #### Affinity group commands createAffinityGroup=15 deleteAffinityGroup=15 @@ -594,5 +605,10 @@ addCiscoAsa1000vResource=1 deleteCiscoAsa1000vResource=1 listCiscoAsa1000vResources=1 +#### Internal LB VM commands +stopInternalLoadBalancerVM=1 +startInternalLoadBalancerVM=1 +listInternalLoadBalancerVMs=1 + ### Network Isolation methods listing listNetworkIsolationMethods=1 diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index 7a469816f82..8a45e5fea85 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -198,6 +198,7 @@ + @@ -241,6 +242,7 @@ + + + 4.0.0 + cloud-plugin-network-internallb + Apache CloudStack Plugin - Network Internal Load Balancer + + org.apache.cloudstack + cloudstack-plugins + 4.2.0-SNAPSHOT + ../../pom.xml + + + install + src + test + + + resources + + **/*.xml + + + + + + test/resources + + %regex[.*[0-9]*To[0-9]*.*Test.*] + + + + + diff --git a/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java new file mode 100644 index 00000000000..4b9308b6606 --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java @@ -0,0 +1,548 @@ +// 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. + +package org.apache.cloudstack.network.element; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.ejb.Local; +import javax.inject.Inject; + +import org.apache.cloudstack.api.command.admin.internallb.ConfigureInternalLoadBalancerElementCmd; +import org.apache.cloudstack.api.command.admin.internallb.CreateInternalLoadBalancerElementCmd; +import org.apache.cloudstack.api.command.admin.internallb.ListInternalLoadBalancerElementsCmd; +import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; +import org.apache.cloudstack.network.lb.InternalLoadBalancerVMManager; +import org.apache.log4j.Logger; + +import com.cloud.agent.api.to.LoadBalancerTO; +import com.cloud.configuration.ConfigurationManager; +import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.deploy.DeployDestination; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Network; +import com.cloud.network.Network.Capability; +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.network.NetworkModel; +import com.cloud.network.Networks.TrafficType; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.PublicIpAddress; +import com.cloud.network.VirtualRouterProvider; +import com.cloud.network.VirtualRouterProvider.VirtualRouterProviderType; +import com.cloud.network.dao.NetworkServiceMapDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.VirtualRouterProviderDao; +import com.cloud.network.element.IpDeployer; +import com.cloud.network.element.LoadBalancingServiceProvider; +import com.cloud.network.element.NetworkElement; +import com.cloud.network.element.VirtualRouterElement; +import com.cloud.network.element.VirtualRouterProviderVO; +import com.cloud.network.lb.LoadBalancingRule; +import com.cloud.network.router.VirtualRouter; +import com.cloud.network.router.VirtualRouter.Role; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.LoadBalancerContainer; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.offering.NetworkOffering; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.User; +import com.cloud.utils.component.AdapterBase; +import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.utils.db.SearchCriteria2; +import com.cloud.utils.db.SearchCriteriaService; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; +import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.NicProfile; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.dao.DomainRouterDao; + +@Local(value = {NetworkElement.class}) +public class InternalLoadBalancerElement extends AdapterBase implements LoadBalancingServiceProvider, InternalLoadBalancerElementService, IpDeployer{ + private static final Logger s_logger = Logger.getLogger(InternalLoadBalancerElement.class); + protected static final Map> capabilities = setCapabilities(); + private static InternalLoadBalancerElement internalLbElement = null; + + @Inject NetworkModel _ntwkModel; + @Inject NetworkServiceMapDao _ntwkSrvcDao; + @Inject DomainRouterDao _routerDao; + @Inject VirtualRouterProviderDao _vrProviderDao; + @Inject PhysicalNetworkServiceProviderDao _pNtwkSvcProviderDao; + @Inject InternalLoadBalancerVMManager _internalLbMgr; + @Inject ConfigurationManager _configMgr; + @Inject AccountManager _accountMgr; + @Inject ApplicationLoadBalancerRuleDao _appLbDao; + + protected InternalLoadBalancerElement() { + } + + + public static InternalLoadBalancerElement getInstance() { + if ( internalLbElement == null) { + internalLbElement = new InternalLoadBalancerElement(); + } + return internalLbElement; + } + + + private boolean canHandle(Network config, Scheme lbScheme) { + //works in Advance zone only + DataCenter dc = _configMgr.getZone(config.getDataCenterId()); + if (dc.getNetworkType() != NetworkType.Advanced) { + s_logger.trace("Not hanling zone of network type " + dc.getNetworkType()); + return false; + } + if (config.getGuestType() != Network.GuestType.Isolated || config.getTrafficType() != TrafficType.Guest) { + s_logger.trace("Not handling network with Type " + config.getGuestType() + " and traffic type " + config.getTrafficType()); + return false; + } + + Map lbCaps = this.getCapabilities().get(Service.Lb); + if (!lbCaps.isEmpty()) { + String schemeCaps = lbCaps.get(Capability.LbSchemes); + if (schemeCaps != null && lbScheme != null) { + if (!schemeCaps.contains(lbScheme.toString())) { + s_logger.debug("Scheme " + lbScheme.toString() + " is not supported by the provider " + this.getName()); + return false; + } + } + } + + if (!_ntwkModel.isProviderSupportServiceInNetwork(config.getId(), Service.Lb, getProvider())) { + s_logger.trace("Element " + getProvider().getName() + " doesn't support service " + Service.Lb + + " in the network " + config); + return false; + } + return true; + } + + + @Override + public Map> getCapabilities() { + return capabilities; + } + + + @Override + public Provider getProvider() { + return Provider.InternalLbVm; + } + + + @Override + public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) + throws ConcurrentOperationException, ResourceUnavailableException, + InsufficientCapacityException { + + if (!canHandle(network, null)) { + s_logger.trace("No need to implement " + this.getName()); + return true; + } + + //1) Get all the Ips from the network having LB rules assigned + List ips = _appLbDao.listLbIpsBySourceIpNetworkIdAndScheme(network.getId(), Scheme.Internal); + + //2) Start those vms + for (String ip : ips) { + Ip sourceIp = new Ip(ip); + List internalLbVms; + try { + internalLbVms = _internalLbMgr.deployInternalLbVm(network, sourceIp, dest, _accountMgr.getAccount(network.getAccountId()), null); + } catch (InsufficientCapacityException e) { + s_logger.warn("Failed to deploy element " + this.getName() + " for ip " + sourceIp + " due to:", e); + return false; + } catch (ConcurrentOperationException e) { + s_logger.warn("Failed to deploy element " + this.getName() + " for ip " + sourceIp + " due to:", e); + return false; + } + + if (internalLbVms == null || internalLbVms.isEmpty()) { + throw new ResourceUnavailableException("Can't deploy " + this.getName() + " to handle LB rules", + DataCenter.class, network.getDataCenterId()); + } + } + + return true; + } + + + @Override + public boolean prepare(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, + ResourceUnavailableException, InsufficientCapacityException { + + if (!canHandle(network, null)) { + s_logger.trace("No need to prepare " + this.getName()); + return true; + } + + if (vm.getType() == VirtualMachine.Type.User) { + //1) Get all the Ips from the network having LB rules assigned + List ips = _appLbDao.listLbIpsBySourceIpNetworkIdAndScheme(network.getId(), Scheme.Internal); + + //2) Start those vms + for (String ip : ips) { + Ip sourceIp = new Ip(ip); + List internalLbVms; + try { + internalLbVms = _internalLbMgr.deployInternalLbVm(network, sourceIp, dest, _accountMgr.getAccount(network.getAccountId()), null); + } catch (InsufficientCapacityException e) { + s_logger.warn("Failed to deploy element " + this.getName() + " for ip " + sourceIp + " due to:", e); + return false; + } catch (ConcurrentOperationException e) { + s_logger.warn("Failed to deploy element " + this.getName() + " for ip " + sourceIp + " due to:", e); + return false; + } + + if (internalLbVms == null || internalLbVms.isEmpty()) { + throw new ResourceUnavailableException("Can't deploy " + this.getName() + " to handle LB rules", + DataCenter.class, network.getDataCenterId()); + } + } + } + + return true; + } + + @Override + public boolean release(Network network, NicProfile nic, VirtualMachineProfile vm, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { + return true; + } + + + @Override + public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { + List internalLbVms = _routerDao.listByNetworkAndRole(network.getId(), Role.INTERNAL_LB_VM); + if (internalLbVms == null || internalLbVms.isEmpty()) { + return true; + } + boolean result = true; + for (VirtualRouter internalLbVm : internalLbVms) { + result = result && _internalLbMgr.destroyInternalLbVm(internalLbVm.getId(), + context.getAccount(), context.getCaller().getId()); + if (cleanup) { + if (!result) { + s_logger.warn("Failed to stop internal lb element " + internalLbVm + ", but would try to process clean up anyway."); + } + result = (_internalLbMgr.destroyInternalLbVm(internalLbVm.getId(), + context.getAccount(), context.getCaller().getId())); + if (!result) { + s_logger.warn("Failed to clean up internal lb element " + internalLbVm); + } + } + } + return result; + } + + + @Override + public boolean destroy(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { + List internalLbVms = _routerDao.listByNetworkAndRole(network.getId(), Role.INTERNAL_LB_VM); + if (internalLbVms == null || internalLbVms.isEmpty()) { + return true; + } + boolean result = true; + for (VirtualRouter internalLbVm : internalLbVms) { + result = result && (_internalLbMgr.destroyInternalLbVm(internalLbVm.getId(), + context.getAccount(), context.getCaller().getId())); + } + return result; + } + + + @Override + public boolean isReady(PhysicalNetworkServiceProvider provider) { + VirtualRouterProviderVO element = _vrProviderDao.findByNspIdAndType(provider.getId(), + VirtualRouterProviderType.InternalLbVm); + if (element == null) { + return false; + } + return element.isEnabled(); + } + + + @Override + public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) + throws ConcurrentOperationException, ResourceUnavailableException { + VirtualRouterProviderVO element = _vrProviderDao.findByNspIdAndType(provider.getId(), + VirtualRouterProviderType.InternalLbVm); + if (element == null) { + return true; + } + long elementId = element.getId(); + List internalLbVms = _routerDao.listByElementId(elementId); + boolean result = true; + for (DomainRouterVO internalLbVm : internalLbVms) { + result = result && (_internalLbMgr.destroyInternalLbVm(internalLbVm.getId(), + context.getAccount(), context.getCaller().getId())); + } + _vrProviderDao.remove(elementId); + + return result; + } + + + @Override + public boolean canEnableIndividualServices() { + return true; + } + + + @Override + public boolean verifyServicesCombination(Set services) { + return true; + } + + + @Override + public IpDeployer getIpDeployer(Network network) { + return this; + } + + + @Override + public boolean applyLBRules(Network network, List rules) throws ResourceUnavailableException { + //1) Get Internal LB VMs to destroy + Set vmsToDestroy = getVmsToDestroy(rules); + + //2) Get rules to apply + Map> rulesToApply = getLbRulesToApply(rules); + s_logger.debug("Applying " + rulesToApply.size() + " on element " + this.getName()); + + + for (Ip sourceIp : rulesToApply.keySet()) { + if (vmsToDestroy.contains(sourceIp)) { + //2.1 Destroy internal lb vm + List vms = _internalLbMgr.findInternalLbVms(network.getId(), sourceIp); + if (vms.size() > 0) { + //only one internal lb per IP exists + try { + s_logger.debug("Destroying internal lb vm for ip " + sourceIp.addr() + " as all the rules for this vm are in Revoke state"); + return _internalLbMgr.destroyInternalLbVm(vms.get(0).getId(), _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM), + _accountMgr.getUserIncludingRemoved(User.UID_SYSTEM).getId()); + } catch (ConcurrentOperationException e) { + s_logger.warn("Failed to apply lb rule(s) for ip " + sourceIp.addr() + " on the element " + this.getName() + " due to:", e); + return false; + } + } + } else { + //2.2 Start Internal LB vm per IP address + List internalLbVms; + try { + DeployDestination dest = new DeployDestination(_configMgr.getZone(network.getDataCenterId()), null, null, null); + internalLbVms = _internalLbMgr.deployInternalLbVm(network, sourceIp, dest, _accountMgr.getAccount(network.getAccountId()), null); + } catch (InsufficientCapacityException e) { + s_logger.warn("Failed to apply lb rule(s) for ip " + sourceIp.addr() + "on the element " + this.getName() + " due to:", e); + return false; + } catch (ConcurrentOperationException e) { + s_logger.warn("Failed to apply lb rule(s) for ip " + sourceIp.addr() + "on the element " + this.getName() + " due to:", e); + return false; + } + + if (internalLbVms == null || internalLbVms.isEmpty()) { + throw new ResourceUnavailableException("Can't find/deploy internal lb vm to handle LB rules", + DataCenter.class, network.getDataCenterId()); + } + + //2.3 Apply Internal LB rules on the VM + if (!_internalLbMgr.applyLoadBalancingRules(network, rulesToApply.get(sourceIp), internalLbVms)) { + throw new CloudRuntimeException("Failed to apply load balancing rules for ip " + sourceIp.addr() + + " in network " + network.getId() + " on element " + this.getName()); + } + } + } + + return true; + } + + + protected Map> getLbRulesToApply(List rules) { + //Group rules by the source ip address as NetworkManager always passes the entire network lb config to the element + Map> rulesToApply = groupBySourceIp(rules); + + return rulesToApply; + } + + + protected Set getVmsToDestroy(List rules) { + //1) Group rules by the source ip address as NetworkManager always passes the entire network lb config to the element + Map> groupedRules = groupBySourceIp(rules); + + //2) Count rules in revoke state + Set vmsToDestroy = new HashSet(); + + for (Ip sourceIp : groupedRules.keySet()) { + List rulesToCheck = groupedRules.get(sourceIp); + int revoke = 0; + for (LoadBalancingRule ruleToCheck : rulesToCheck) { + if (ruleToCheck.getState() == FirewallRule.State.Revoke){ + revoke++; + } + } + + if (revoke == rulesToCheck.size()) { + s_logger.debug("Have to destroy internal lb vm for source ip " + sourceIp); + vmsToDestroy.add(sourceIp); + } + } + return vmsToDestroy; + } + + + protected Map> groupBySourceIp(List rules) { + Map> groupedRules = new HashMap>(); + for (LoadBalancingRule rule : rules) { + Ip sourceIp = rule.getSourceIp(); + if (!groupedRules.containsKey(sourceIp)) { + groupedRules.put(sourceIp, null); + } + + List rulesToApply = groupedRules.get(sourceIp); + if (rulesToApply == null) { + rulesToApply = new ArrayList(); + } + rulesToApply.add(rule); + groupedRules.put(sourceIp, rulesToApply); + } + return groupedRules; + } + + @Override + public boolean validateLBRule(Network network, LoadBalancingRule rule) { + List rules = new ArrayList(); + rules.add(rule); + if (canHandle(network, rule.getScheme())) { + List routers = _routerDao.listByNetworkAndRole(network.getId(), Role.INTERNAL_LB_VM); + if (routers == null || routers.isEmpty()) { + return true; + } + return VirtualRouterElement.validateHAProxyLBRule(rule); + } + return true; + } + + @Override + public List updateHealthChecks(Network network, List lbrules) { + return null; + } + + private static Map> setCapabilities() { + Map> capabilities = new HashMap>(); + + // Set capabilities for LB service + Map lbCapabilities = new HashMap(); + lbCapabilities.put(Capability.SupportedLBAlgorithms, "roundrobin,leastconn,source"); + lbCapabilities.put(Capability.SupportedLBIsolation, "dedicated"); + lbCapabilities.put(Capability.SupportedProtocols, "tcp, udp"); + lbCapabilities.put(Capability.SupportedStickinessMethods, VirtualRouterElement.getHAProxyStickinessCapability()); + lbCapabilities.put(Capability.LbSchemes, LoadBalancerContainer.Scheme.Internal.toString()); + + capabilities.put(Service.Lb, lbCapabilities); + return capabilities; + } + + @Override + public List> getCommands() { + List> cmdList = new ArrayList>(); + cmdList.add(CreateInternalLoadBalancerElementCmd.class); + cmdList.add(ConfigureInternalLoadBalancerElementCmd.class); + cmdList.add(ListInternalLoadBalancerElementsCmd.class); + return cmdList; + } + + @Override + public VirtualRouterProvider configureInternalLoadBalancerElement(long id, boolean enable) { + VirtualRouterProviderVO element = _vrProviderDao.findById(id); + if (element == null || element.getType() != VirtualRouterProviderType.InternalLbVm) { + throw new InvalidParameterValueException("Can't find " + this.getName() + " element with network service provider id " + id + + " to be used as a provider for " + this.getName()); + } + + element.setEnabled(enable); + element = _vrProviderDao.persist(element); + + return element; + } + + @Override + public VirtualRouterProvider addInternalLoadBalancerElement(long ntwkSvcProviderId) { + VirtualRouterProviderVO element = _vrProviderDao.findByNspIdAndType(ntwkSvcProviderId, VirtualRouterProviderType.InternalLbVm); + if (element != null) { + s_logger.debug("There is already an " + this.getName() + " with service provider id " + ntwkSvcProviderId); + return null; + } + + PhysicalNetworkServiceProvider provider = _pNtwkSvcProviderDao.findById(ntwkSvcProviderId); + if (provider == null || !provider.getProviderName().equalsIgnoreCase(this.getName())) { + throw new InvalidParameterValueException("Invalid network service provider is specified"); + } + + element = new VirtualRouterProviderVO(ntwkSvcProviderId, VirtualRouterProviderType.InternalLbVm); + element = _vrProviderDao.persist(element); + return element; + } + + + @Override + public VirtualRouterProvider getInternalLoadBalancerElement(long id) { + VirtualRouterProvider provider = _vrProviderDao.findById(id); + if (provider == null || provider.getType() != VirtualRouterProviderType.InternalLbVm) { + throw new InvalidParameterValueException("Unable to find " + this.getName() + " by id"); + } + return provider; + } + + @Override + public List searchForInternalLoadBalancerElements(Long id, Long ntwkSvsProviderId, Boolean enabled) { + + SearchCriteriaService sc = SearchCriteria2.create(VirtualRouterProviderVO.class); + if (id != null) { + sc.addAnd(sc.getEntity().getId(), Op.EQ, id); + } + if (ntwkSvsProviderId != null) { + sc.addAnd(sc.getEntity().getNspId(), Op.EQ, ntwkSvsProviderId); + } + if (enabled != null) { + sc.addAnd(sc.getEntity().isEnabled(), Op.EQ, enabled); + } + + //return only Internal LB elements + sc.addAnd(sc.getEntity().getType(), Op.EQ, VirtualRouterProvider.VirtualRouterProviderType.InternalLbVm); + + return sc.list(); + } + + @Override + public boolean applyIps(Network network, List ipAddress, Set services) throws ResourceUnavailableException { + //do nothing here; this element just has to extend the ip deployer + //as the LB service implements IPDeployerRequester + return true; + } + +} diff --git a/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManager.java b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManager.java new file mode 100644 index 00000000000..9faca562bfb --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManager.java @@ -0,0 +1,90 @@ +// 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. +package org.apache.cloudstack.network.lb; + +import java.util.List; +import java.util.Map; + +import com.cloud.deploy.DeployDestination; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Network; +import com.cloud.network.lb.LoadBalancingRule; +import com.cloud.network.router.VirtualRouter; +import com.cloud.user.Account; +import com.cloud.utils.component.Manager; +import com.cloud.utils.net.Ip; +import com.cloud.vm.VirtualMachineProfile.Param; + +public interface InternalLoadBalancerVMManager extends Manager, InternalLoadBalancerVMService{ + //RAM/CPU for the system offering used by Internal LB VMs + public static final int DEFAULT_INTERNALLB_VM_RAMSIZE = 128; // 128 MB + public static final int DEFAULT_INTERNALLB_VM_CPU_MHZ = 256; // 256 MHz + + /** + * Destroys Internal LB vm instance + * @param vmId + * @param caller + * @param callerUserId + * @return + * @throws ResourceUnavailableException + * @throws ConcurrentOperationException + */ + boolean destroyInternalLbVm(long vmId, Account caller, Long callerUserId) + throws ResourceUnavailableException, ConcurrentOperationException; + + + /** + * Deploys internal lb vm + * @param guestNetwork + * @param requestedGuestIp + * @param dest + * @param owner + * @param params + * @return + * @throws InsufficientCapacityException + * @throws ConcurrentOperationException + * @throws ResourceUnavailableException + */ + List deployInternalLbVm(Network guestNetwork, Ip requestedGuestIp, DeployDestination dest, Account owner, + Map params) throws InsufficientCapacityException, + ConcurrentOperationException, ResourceUnavailableException; + + + + /** + * + * @param network + * @param rules + * @param internalLbVms + * @return + * @throws ResourceUnavailableException + */ + boolean applyLoadBalancingRules(Network network, List rules, List internalLbVms) + throws ResourceUnavailableException; + + + /** + * Returns existing Internal Load Balancer elements based on guestNetworkId (required) and requestedIp (optional) + * @param guestNetworkId + * @param requestedGuestIp + * @return + */ + List findInternalLbVms(long guestNetworkId, Ip requestedGuestIp); + +} diff --git a/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java new file mode 100644 index 00000000000..fe32a7ba26f --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java @@ -0,0 +1,951 @@ +// 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. +package org.apache.cloudstack.network.lb; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.lb.ApplicationLoadBalancerRuleVO; +import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.AgentManager.OnError; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.GetDomRVersionAnswer; +import com.cloud.agent.api.GetDomRVersionCmd; +import com.cloud.agent.api.StopAnswer; +import com.cloud.agent.api.check.CheckSshAnswer; +import com.cloud.agent.api.check.CheckSshCommand; +import com.cloud.agent.api.routing.LoadBalancerConfigCommand; +import com.cloud.agent.api.routing.NetworkElementCommand; +import com.cloud.agent.api.to.LoadBalancerTO; +import com.cloud.agent.api.to.NicTO; +import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.agent.manager.Commands; +import com.cloud.configuration.Config; +import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.deploy.DataCenterDeployment; +import com.cloud.deploy.DeployDestination; +import com.cloud.deploy.DeploymentPlan; +import com.cloud.exception.AgentUnavailableException; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InsufficientServerCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.OperationTimedoutException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.exception.StorageUnavailableException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.Network; +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkModel; +import com.cloud.network.Networks.TrafficType; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.VirtualRouterProvider; +import com.cloud.network.VirtualRouterProvider.VirtualRouterProviderType; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.VirtualRouterProviderDao; +import com.cloud.network.lb.LoadBalancingRule; +import com.cloud.network.lb.LoadBalancingRule.LbDestination; +import com.cloud.network.lb.LoadBalancingRule.LbHealthCheckPolicy; +import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; +import com.cloud.network.lb.LoadBalancingRulesManager; +import com.cloud.network.router.VirtualRouter; +import com.cloud.network.router.VirtualRouter.RedundantState; +import com.cloud.network.router.VirtualRouter.Role; +import com.cloud.network.rules.FirewallRule; +import com.cloud.offering.NetworkOffering; +import com.cloud.offering.ServiceOffering; +import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.resource.ResourceManager; +import com.cloud.server.ConfigurationServer; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.User; +import com.cloud.utils.Pair; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.db.DB; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; +import com.cloud.utils.net.NetUtils; +import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.Nic; +import com.cloud.vm.NicProfile; +import com.cloud.vm.NicVO; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.State; +import com.cloud.vm.VirtualMachineGuru; +import com.cloud.vm.VirtualMachineManager; +import com.cloud.vm.VirtualMachineName; +import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.VirtualMachineProfile.Param; +import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.NicDao; + +@Component +@Local(value = { InternalLoadBalancerVMManager.class, InternalLoadBalancerVMService.class}) +public class InternalLoadBalancerVMManagerImpl extends ManagerBase implements + InternalLoadBalancerVMManager, VirtualMachineGuru { + private static final Logger s_logger = Logger + .getLogger(InternalLoadBalancerVMManagerImpl.class); + static final private String _internalLbVmNamePrefix = "b"; + + private String _instance; + private String _mgmtHost; + private String _mgmtCidr; + private long _internalLbVmOfferingId; + + @Inject VirtualMachineManager _itMgr; + @Inject DomainRouterDao _internalLbVmDao; + @Inject ConfigurationDao _configDao; + @Inject AgentManager _agentMgr; + @Inject DataCenterDao _dcDao; + @Inject VirtualRouterProviderDao _vrProviderDao; + @Inject ApplicationLoadBalancerRuleDao _lbDao; + @Inject NetworkModel _ntwkModel; + @Inject LoadBalancingRulesManager _lbMgr; + @Inject NicDao _nicDao; + @Inject AccountManager _accountMgr; + @Inject NetworkDao _networkDao; + @Inject NetworkManager _ntwkMgr; + @Inject ServiceOfferingDao _serviceOfferingDao; + @Inject PhysicalNetworkServiceProviderDao _physicalProviderDao; + @Inject NetworkOfferingDao _networkOfferingDao; + @Inject VMTemplateDao _templateDao; + @Inject ResourceManager _resourceMgr; + @Inject ConfigurationServer _configServer; + + @Override + public DomainRouterVO findByName(String name) { + if (!VirtualMachineName.isValidSystemVmName(name, _instance, _internalLbVmNamePrefix)) { + return null; + } + + return _internalLbVmDao.findById(VirtualMachineName.getRouterId(name)); + } + + @Override + public DomainRouterVO findById(long id) { + return _internalLbVmDao.findById(id); + } + + @Override + public DomainRouterVO persist(DomainRouterVO vm) { + DomainRouterVO virtualRouter = _internalLbVmDao.persist(vm); + return virtualRouter; + } + + @Override + public boolean finalizeVirtualMachineProfile(VirtualMachineProfile profile, + DeployDestination dest, ReservationContext context) { + + //Internal LB vm starts up with 2 Nics + //Nic #1 - Guest Nic with IP address that would act as the LB entry point + //Nic #2 - Control/Management Nic + + StringBuilder buf = profile.getBootArgsBuilder(); + buf.append(" template=domP"); + buf.append(" name=").append(profile.getHostName()); + + if (Boolean.valueOf(_configDao.getValue("system.vm.random.password"))) { + buf.append(" vmpassword=").append(_configDao.getValue("system.vm.password")); + } + + NicProfile controlNic = null; + Network guestNetwork = null; + + for (NicProfile nic : profile.getNics()) { + int deviceId = nic.getDeviceId(); + buf.append(" eth").append(deviceId).append("ip=").append(nic.getIp4Address()); + buf.append(" eth").append(deviceId).append("mask=").append(nic.getNetmask()); + + if (nic.isDefaultNic()) { + buf.append(" gateway=").append(nic.getGateway()); + buf.append(" dns1=").append(nic.getGateway()); + } + + if (nic.getTrafficType() == TrafficType.Guest) { + guestNetwork = _ntwkModel.getNetwork(nic.getNetworkId()); + } else if (nic.getTrafficType() == TrafficType.Management) { + buf.append(" localgw=").append(dest.getPod().getGateway()); + } else if (nic.getTrafficType() == TrafficType.Control) { + controlNic = nic; + // Internal LB control command is sent over management server in VMware + if (dest.getHost().getHypervisorType() == HypervisorType.VMware) { + if (s_logger.isInfoEnabled()) { + s_logger.info("Check if we need to add management server explicit route to Internal LB. pod cidr: " + + dest.getPod().getCidrAddress() + "/" + dest.getPod().getCidrSize() + + ", pod gateway: " + dest.getPod().getGateway() + ", management host: " + _mgmtHost); + } + + if (s_logger.isInfoEnabled()) { + s_logger.info("Add management server explicit route to Internal LB."); + } + + + buf.append(" mgmtcidr=").append(_mgmtCidr); + buf.append(" localgw=").append(dest.getPod().getGateway()); + } + } + } + + if (controlNic == null) { + throw new CloudRuntimeException("Didn't start a control port"); + } + + if (guestNetwork != null) { + String domain = guestNetwork.getNetworkDomain(); + if (domain != null) { + buf.append(" domain=" + domain); + } + } + + String type = "ilbvm"; + buf.append(" type=" + type); + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Boot Args for " + profile + ": " + buf.toString()); + } + + return true; + } + + @Override + public boolean finalizeDeployment(Commands cmds, VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException { + DomainRouterVO internalLbVm = profile.getVirtualMachine(); + + List nics = profile.getNics(); + for (NicProfile nic : nics) { + if (nic.getTrafficType() == TrafficType.Control) { + internalLbVm.setPrivateIpAddress(nic.getIp4Address()); + internalLbVm.setPrivateMacAddress(nic.getMacAddress()); + } + } + _internalLbVmDao.update(internalLbVm.getId(), internalLbVm); + + finalizeCommandsOnStart(cmds, profile); + return true; + } + + @Override + public boolean finalizeStart(VirtualMachineProfile profile, long hostId, Commands cmds, ReservationContext context) { + DomainRouterVO internalLbVm = profile.getVirtualMachine(); + + boolean result = true; + + Answer answer = cmds.getAnswer("checkSsh"); + if (answer != null && answer instanceof CheckSshAnswer) { + CheckSshAnswer sshAnswer = (CheckSshAnswer) answer; + if (sshAnswer == null || !sshAnswer.getResult()) { + s_logger.warn("Unable to ssh to the internal LB VM: " + sshAnswer.getDetails()); + result = false; + } + } else { + result = false; + } + if (result == false) { + return result; + } + + //Get guest network info + List guestNetworks = new ArrayList(); + List internalLbVmNics = _nicDao.listByVmId(profile.getId()); + for (Nic internalLbVmNic : internalLbVmNics) { + Network network = _ntwkModel.getNetwork(internalLbVmNic.getNetworkId()); + if (network.getTrafficType() == TrafficType.Guest) { + guestNetworks.add(network); + } + } + + answer = cmds.getAnswer("getDomRVersion"); + if (answer != null && answer instanceof GetDomRVersionAnswer) { + GetDomRVersionAnswer versionAnswer = (GetDomRVersionAnswer)answer; + if (answer == null || !answer.getResult()) { + s_logger.warn("Unable to get the template/scripts version of internal LB VM " + internalLbVm.getInstanceName() + + " due to: " + versionAnswer.getDetails()); + result = false; + } else { + internalLbVm.setTemplateVersion(versionAnswer.getTemplateVersion()); + internalLbVm.setScriptsVersion(versionAnswer.getScriptsVersion()); + internalLbVm = _internalLbVmDao.persist(internalLbVm, guestNetworks); + } + } else { + result = false; + } + + return result; + } + + @Override + public boolean finalizeCommandsOnStart(Commands cmds, VirtualMachineProfile profile) { + DomainRouterVO internalLbVm = profile.getVirtualMachine(); + NicProfile controlNic = getNicProfileByTrafficType(profile, TrafficType.Control); + + if (controlNic == null) { + s_logger.error("Control network doesn't exist for the internal LB vm " + internalLbVm); + return false; + } + + finalizeSshAndVersionOnStart(cmds, profile, internalLbVm, controlNic); + + // restart network if restartNetwork = false is not specified in profile parameters + boolean reprogramGuestNtwk = true; + if (profile.getParameter(Param.ReProgramGuestNetworks) != null + && (Boolean) profile.getParameter(Param.ReProgramGuestNetworks) == false) { + reprogramGuestNtwk = false; + } + + VirtualRouterProvider lbProvider = _vrProviderDao.findById(internalLbVm.getElementId()); + if (lbProvider == null) { + throw new CloudRuntimeException("Cannot find related element " + VirtualRouterProviderType.InternalLbVm + " of vm: " + internalLbVm.getHostName()); + } + + Provider provider = Network.Provider.getProvider(lbProvider.getType().toString()); + if (provider == null) { + throw new CloudRuntimeException("Cannot find related provider of provider: " + lbProvider.getType().toString()); + } + + if (reprogramGuestNtwk) { + NicProfile guestNic = getNicProfileByTrafficType(profile, TrafficType.Guest); + finalizeLbRulesForIp(cmds, internalLbVm, provider, new Ip(guestNic.getIp4Address()), guestNic.getNetworkId()); + } + + return true; + } + + @Override + public void finalizeStop(VirtualMachineProfile profile, StopAnswer answer) { + } + + @Override + public void finalizeExpunge(DomainRouterVO vm) { + } + + @Override + public Long convertToId(String vmName) { + if (!VirtualMachineName.isValidSystemVmName(vmName, _instance, _internalLbVmNamePrefix)) { + return null; + } + + return VirtualMachineName.getRouterId(vmName); + } + + @Override + public boolean plugNic(Network network, NicTO nic, VirtualMachineTO vm, ReservationContext context, DeployDestination dest) throws ConcurrentOperationException, ResourceUnavailableException, + InsufficientCapacityException { + //not supported + throw new UnsupportedOperationException("Plug nic is not supported for vm of type " + vm.getType()); + } + + @Override + public boolean unplugNic(Network network, NicTO nic, VirtualMachineTO vm, ReservationContext context, DeployDestination dest) throws ConcurrentOperationException, ResourceUnavailableException { + //not supported + throw new UnsupportedOperationException("Unplug nic is not supported for vm of type " + vm.getType()); + } + + @Override + public void prepareStop(VirtualMachineProfile profile) { + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + final Map configs = _configDao.getConfiguration("AgentManager", params); + _instance = configs.get("instance.name"); + if (_instance == null) { + _instance = "DEFAULT"; + } + + _mgmtHost = configs.get("host"); + _mgmtCidr = _configDao.getValue(Config.ManagementNetwork.key()); + + String offIdStr = configs.get(Config.InternalLbVmServiceOfferingId.key()); + if (offIdStr != null && !offIdStr.isEmpty()) { + _internalLbVmOfferingId = Long.parseLong(offIdStr); + } else { + boolean useLocalStorage = Boolean.parseBoolean(configs.get(Config.SystemVMUseLocalStorage.key())); + ServiceOfferingVO newOff = new ServiceOfferingVO("System Offering For Internal LB VM", 1, InternalLoadBalancerVMManager.DEFAULT_INTERNALLB_VM_RAMSIZE, InternalLoadBalancerVMManager.DEFAULT_INTERNALLB_VM_CPU_MHZ, null, + null, true, null, useLocalStorage, true, null, true, VirtualMachine.Type.InternalLoadBalancerVm, true); + newOff.setUniqueName(ServiceOffering.internalLbVmDefaultOffUniqueName); + newOff = _serviceOfferingDao.persistSystemServiceOffering(newOff); + _internalLbVmOfferingId = newOff.getId(); + } + + _itMgr.registerGuru(VirtualMachine.Type.InternalLoadBalancerVm, this); + + if (s_logger.isInfoEnabled()) { + s_logger.info(getName() + " has been configured"); + } + + return true; + } + + @Override + public String getName() { + return _name; + } + + protected NicProfile getNicProfileByTrafficType(VirtualMachineProfile profile, TrafficType trafficType) { + for (NicProfile nic : profile.getNics()) { + if (nic.getTrafficType() == trafficType && nic.getIp4Address() != null) { + return nic; + } + } + return null; + } + + protected void finalizeSshAndVersionOnStart(Commands cmds, VirtualMachineProfile profile, DomainRouterVO router, NicProfile controlNic) { + cmds.addCommand("checkSsh", new CheckSshCommand(profile.getInstanceName(), controlNic.getIp4Address(), 3922)); + + // Update internal lb vm template/scripts version + final GetDomRVersionCmd command = new GetDomRVersionCmd(); + command.setAccessDetail(NetworkElementCommand.ROUTER_IP, controlNic.getIp4Address()); + command.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); + cmds.addCommand("getDomRVersion", command); + } + + + protected void finalizeLbRulesForIp(Commands cmds, DomainRouterVO internalLbVm, Provider provider, Ip sourceIp, long guestNtwkId) { + s_logger.debug("Resending load balancing rules as a part of start for " + internalLbVm); + List lbs = _lbDao.listBySrcIpSrcNtwkId(sourceIp, guestNtwkId); + List lbRules = new ArrayList(); + if (_ntwkModel.isProviderSupportServiceInNetwork(guestNtwkId, Service.Lb, provider)) { + // Re-apply load balancing rules + for (ApplicationLoadBalancerRuleVO lb : lbs) { + List dstList = _lbMgr.getExistingDestinations(lb.getId()); + List policyList = _lbMgr.getStickinessPolicies(lb.getId()); + List hcPolicyList = _lbMgr.getHealthCheckPolicies(lb.getId()); + LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList, sourceIp); + lbRules.add(loadBalancing); + } + } + + s_logger.debug("Found " + lbRules.size() + " load balancing rule(s) to apply as a part of Intenrnal LB vm" + internalLbVm + " start."); + if (!lbRules.isEmpty()) { + createApplyLoadBalancingRulesCommands(lbRules, internalLbVm, cmds, guestNtwkId); + } + } + + private void createApplyLoadBalancingRulesCommands(List rules, VirtualRouter internalLbVm, Commands cmds, long guestNetworkId) { + + LoadBalancerTO[] lbs = new LoadBalancerTO[rules.size()]; + int i = 0; + boolean inline = false; + for (LoadBalancingRule rule : rules) { + boolean revoked = (rule.getState().equals(FirewallRule.State.Revoke)); + String protocol = rule.getProtocol(); + String algorithm = rule.getAlgorithm(); + String uuid = rule.getUuid(); + + String srcIp = rule.getSourceIp().addr(); + int srcPort = rule.getSourcePortStart(); + List destinations = rule.getDestinations(); + List stickinessPolicies = rule.getStickinessPolicies(); + LoadBalancerTO lb = new LoadBalancerTO(uuid, srcIp, srcPort, protocol, algorithm, revoked, false, inline, destinations, stickinessPolicies); + lbs[i++] = lb; + } + + Network guestNetwork = _ntwkModel.getNetwork(guestNetworkId); + Nic guestNic = _nicDao.findByNtwkIdAndInstanceId(guestNetwork.getId(), internalLbVm.getId()); + NicProfile guestNicProfile = new NicProfile(guestNic, guestNetwork, guestNic.getBroadcastUri(), guestNic.getIsolationUri(), + _ntwkModel.getNetworkRate(guestNetwork.getId(), internalLbVm.getId()), + _ntwkModel.isSecurityGroupSupportedInNetwork(guestNetwork), + _ntwkModel.getNetworkTag(internalLbVm.getHypervisorType(), guestNetwork)); + + LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lbs, guestNic.getIp4Address(), + guestNic.getIp4Address(), internalLbVm.getPrivateIpAddress(), + _itMgr.toNicTO(guestNicProfile, internalLbVm.getHypervisorType()), internalLbVm.getVpcId()); + + cmd.lbStatsVisibility = _configDao.getValue(Config.NetworkLBHaproxyStatsVisbility.key()); + cmd.lbStatsUri = _configDao.getValue(Config.NetworkLBHaproxyStatsUri.key()); + cmd.lbStatsAuth = _configDao.getValue(Config.NetworkLBHaproxyStatsAuth.key()); + cmd.lbStatsPort = _configDao.getValue(Config.NetworkLBHaproxyStatsPort.key()); + + cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, getInternalLbControlIp(internalLbVm.getId())); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, guestNic.getIp4Address()); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, internalLbVm.getInstanceName()); + DataCenterVO dcVo = _dcDao.findById(internalLbVm.getDataCenterId()); + cmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString()); + cmds.addCommand(cmd); + } + + + protected String getInternalLbControlIp(long internalLbVmId) { + String controlIpAddress = null; + List nics = _nicDao.listByVmId(internalLbVmId); + for (NicVO nic : nics) { + Network ntwk = _ntwkModel.getNetwork(nic.getNetworkId()); + if (ntwk.getTrafficType() == TrafficType.Control) { + controlIpAddress = nic.getIp4Address(); + } + } + + if(controlIpAddress == null) { + s_logger.warn("Unable to find Internal LB control ip in its attached NICs!. Internal LB vm: " + internalLbVmId); + DomainRouterVO internalLbVm = _internalLbVmDao.findById(internalLbVmId); + return internalLbVm.getPrivateIpAddress(); + } + + return controlIpAddress; + } + + @Override + public boolean destroyInternalLbVm(long vmId, Account caller, Long callerUserId) + throws ResourceUnavailableException, ConcurrentOperationException { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Attempting to destroy Internal LB vm " + vmId); + } + + DomainRouterVO internalLbVm = _internalLbVmDao.findById(vmId); + if (internalLbVm == null) { + return true; + } + + _accountMgr.checkAccess(caller, null, true, internalLbVm); + + return _itMgr.expunge(internalLbVm, _accountMgr.getActiveUser(callerUserId), caller); + } + + + @Override + public VirtualRouter stopInternalLbVm(long vmId, boolean forced, Account caller, long callerUserId) throws ConcurrentOperationException, + ResourceUnavailableException { + DomainRouterVO internalLbVm = _internalLbVmDao.findById(vmId); + if (internalLbVm == null || internalLbVm.getRole() != Role.INTERNAL_LB_VM) { + throw new InvalidParameterValueException("Can't find internal lb vm by id specified"); + } + + return stopInternalLbVm(internalLbVm, forced, caller, callerUserId); + } + + protected VirtualRouter stopInternalLbVm(DomainRouterVO internalLbVm, boolean forced, Account caller, long callerUserId) throws ResourceUnavailableException, ConcurrentOperationException { + s_logger.debug("Stopping internal lb vm " + internalLbVm); + try { + if (_itMgr.advanceStop((DomainRouterVO) internalLbVm, forced, _accountMgr.getActiveUser(callerUserId), caller)) { + return _internalLbVmDao.findById(internalLbVm.getId()); + } else { + return null; + } + } catch (OperationTimedoutException e) { + throw new CloudRuntimeException("Unable to stop " + internalLbVm, e); + } + } + + + @Override + public List deployInternalLbVm(Network guestNetwork, Ip requestedGuestIp, DeployDestination dest, + Account owner, Map params) throws InsufficientCapacityException, + ConcurrentOperationException, ResourceUnavailableException { + + List internalLbVms = findOrDeployInternalLbVm(guestNetwork, requestedGuestIp, dest, owner, params); + + return startInternalLbVms(params, internalLbVms); + } + + protected List startInternalLbVms(Map params, List internalLbVms) + throws StorageUnavailableException, InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { + List runningInternalLbVms = null; + + if (internalLbVms != null) { + runningInternalLbVms = new ArrayList(); + } else { + s_logger.debug("Have no internal lb vms to start"); + return null; + } + + for (DomainRouterVO internalLbVm : internalLbVms) { + if (internalLbVm.getState() != VirtualMachine.State.Running) { + internalLbVm = startInternalLbVm(internalLbVm, _accountMgr.getSystemAccount(), User.UID_SYSTEM, params); + } + + if (internalLbVm != null) { + runningInternalLbVms.add(internalLbVm); + } + } + return runningInternalLbVms; + } + + + + @DB + protected List findOrDeployInternalLbVm(Network guestNetwork, Ip requestedGuestIp, DeployDestination dest, + Account owner, Map params) throws ConcurrentOperationException, + InsufficientCapacityException, ResourceUnavailableException { + + List internalLbVms = new ArrayList(); + Network lock = _networkDao.acquireInLockTable(guestNetwork.getId(), _ntwkMgr.getNetworkLockTimeout()); + if (lock == null) { + throw new ConcurrentOperationException("Unable to lock network " + guestNetwork.getId()); + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Lock is acquired for network id " + lock.getId() + " as a part of internal lb startup in " + dest); + } + + long internalLbProviderId = getInternalLbProviderId(guestNetwork); + + try { + assert guestNetwork.getState() == Network.State.Implemented || guestNetwork.getState() == Network.State.Setup || + guestNetwork.getState() == Network.State.Implementing : "Network is not yet fully implemented: " + + guestNetwork; + assert guestNetwork.getTrafficType() == TrafficType.Guest; + + //deploy internal lb vm + Pair> planAndInternalLbVms = getDeploymentPlanAndInternalLbVms(dest, guestNetwork.getId(), requestedGuestIp); + internalLbVms = planAndInternalLbVms.second(); + DeploymentPlan plan = planAndInternalLbVms.first(); + + if (internalLbVms.size() > 0) { + s_logger.debug("Found " + internalLbVms.size() + " internal lb vms for the requested IP " + requestedGuestIp.addr()); + return internalLbVms; + } + + List> networks = createInternalLbVmNetworks(guestNetwork, plan, requestedGuestIp); + //Pass startVm=false as we are holding the network lock that needs to be released at the end of vm allocation + DomainRouterVO internalLbVm = deployInternalLbVm(owner, dest, plan, params, internalLbProviderId, _internalLbVmOfferingId, guestNetwork.getVpcId(), + networks, false); + if (internalLbVm != null) { + _internalLbVmDao.addRouterToGuestNetwork(internalLbVm, guestNetwork); + internalLbVms.add(internalLbVm); + } + } finally { + if (lock != null) { + _networkDao.releaseFromLockTable(lock.getId()); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Lock is released for network id " + lock.getId() + " as a part of internal lb vm startup in " + dest); + } + } + } + return internalLbVms; + } + + protected long getInternalLbProviderId(Network guestNetwork) { + VirtualRouterProviderType type = VirtualRouterProviderType.InternalLbVm; + long physicalNetworkId = _ntwkModel.getPhysicalNetworkId(guestNetwork); + + PhysicalNetworkServiceProvider provider = _physicalProviderDao.findByServiceProvider(physicalNetworkId, type.toString()); + if (provider == null) { + throw new CloudRuntimeException("Cannot find service provider " + type.toString() + " in physical network " + physicalNetworkId); + } + + VirtualRouterProvider internalLbProvider = _vrProviderDao.findByNspIdAndType(provider.getId(), type); + if (internalLbProvider == null) { + throw new CloudRuntimeException("Cannot find provider " + type.toString() + " as service provider " + provider.getId()); + } + + return internalLbProvider.getId(); + } + + protected List> createInternalLbVmNetworks(Network guestNetwork, DeploymentPlan plan, Ip guestIp) throws ConcurrentOperationException, + InsufficientAddressCapacityException { + + //Form networks + List> networks = new ArrayList>(3); + + //1) Guest network - default + if (guestNetwork != null) { + s_logger.debug("Adding nic for Internal LB in Guest network " + guestNetwork); + NicProfile guestNic = new NicProfile(); + if (guestIp != null) { + guestNic.setIp4Address(guestIp.addr()); + } else { + guestNic.setIp4Address(_ntwkMgr.acquireGuestIpAddress(guestNetwork, null)); + } + guestNic.setGateway(guestNetwork.getGateway()); + guestNic.setBroadcastUri(guestNetwork.getBroadcastUri()); + guestNic.setBroadcastType(guestNetwork.getBroadcastDomainType()); + guestNic.setIsolationUri(guestNetwork.getBroadcastUri()); + guestNic.setMode(guestNetwork.getMode()); + String gatewayCidr = guestNetwork.getCidr(); + guestNic.setNetmask(NetUtils.getCidrNetmask(gatewayCidr)); + guestNic.setDefaultNic(true); + networks.add(new Pair((NetworkVO) guestNetwork, guestNic)); + } + + //2) Control network + s_logger.debug("Adding nic for Internal LB vm in Control network "); + List offerings = _ntwkModel.getSystemAccountNetworkOfferings(NetworkOffering.SystemControlNetwork); + NetworkOffering controlOffering = offerings.get(0); + NetworkVO controlConfig = _ntwkMgr.setupNetwork(_accountMgr.getSystemAccount(), controlOffering, plan, null, null, false).get(0); + networks.add(new Pair(controlConfig, null)); + + return networks; + } + + + protected Pair> getDeploymentPlanAndInternalLbVms(DeployDestination dest, long guestNetworkId, Ip requestedGuestIp) { + long dcId = dest.getDataCenter().getId(); + DeploymentPlan plan = new DataCenterDeployment(dcId); + List internalLbVms = findInternalLbVms(guestNetworkId, requestedGuestIp); + + return new Pair>(plan, internalLbVms); + + } + + @Override + public List findInternalLbVms(long guestNetworkId, Ip requestedGuestIp) { + List internalLbVms = _internalLbVmDao.listByNetworkAndRole(guestNetworkId, Role.INTERNAL_LB_VM); + if (requestedGuestIp != null && !internalLbVms.isEmpty()) { + Iterator it = internalLbVms.iterator(); + while (it.hasNext()) { + DomainRouterVO vm = it.next(); + Nic nic = _nicDao.findByNtwkIdAndInstanceId(guestNetworkId, vm.getId()); + if (!nic.getIp4Address().equalsIgnoreCase(requestedGuestIp.addr())) { + it.remove(); + } + } + } + return internalLbVms; + } + + + protected DomainRouterVO deployInternalLbVm(Account owner, DeployDestination dest, DeploymentPlan plan, Map params, + long internalLbProviderId, long svcOffId, Long vpcId, + List> networks, boolean startVm) throws ConcurrentOperationException, + InsufficientAddressCapacityException, InsufficientServerCapacityException, InsufficientCapacityException, + StorageUnavailableException, ResourceUnavailableException { + + long id = _internalLbVmDao.getNextInSequence(Long.class, "id"); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Creating the internal lb vm " + id + " in datacenter " + dest.getDataCenter()); + } + + ServiceOfferingVO routerOffering = _serviceOfferingDao.findById(svcOffId); + + // Internal lb is the network element, we don't know the hypervisor type yet. + // Try to allocate the internal lb twice using diff hypervisors, and when failed both times, throw the exception up + List hypervisors = getHypervisors(dest, plan, null); + + int allocateRetry = 0; + int startRetry = 0; + DomainRouterVO internalLbVm = null; + for (Iterator iter = hypervisors.iterator(); iter.hasNext();) { + HypervisorType hType = iter.next(); + try { + s_logger.debug("Allocating the Internal lb with the hypervisor type " + hType); + String templateName = null; + switch (hType) { + case XenServer: + templateName = _configServer.getConfigValue(Config.RouterTemplateXen.key(), Config.ConfigurationParameterScope.zone.toString(), dest.getDataCenter().getId()); + break; + case KVM: + templateName = _configServer.getConfigValue(Config.RouterTemplateKVM.key(), Config.ConfigurationParameterScope.zone.toString(), dest.getDataCenter().getId()); + break; + case VMware: + templateName = _configServer.getConfigValue(Config.RouterTemplateVmware.key(), Config.ConfigurationParameterScope.zone.toString(), dest.getDataCenter().getId()); + break; + case Hyperv: + templateName = _configServer.getConfigValue(Config.RouterTemplateHyperv.key(), Config.ConfigurationParameterScope.zone.toString(), dest.getDataCenter().getId()); + break; + case LXC: + templateName = _configServer.getConfigValue(Config.RouterTemplateLXC.key(), Config.ConfigurationParameterScope.zone.toString(), dest.getDataCenter().getId()); + break; + default: break; + } + VMTemplateVO template = _templateDao.findRoutingTemplate(hType, templateName); + + if (template == null) { + s_logger.debug(hType + " won't support system vm, skip it"); + continue; + } + + internalLbVm = new DomainRouterVO(id, routerOffering.getId(), internalLbProviderId, + VirtualMachineName.getSystemVmName(id, _instance, _internalLbVmNamePrefix), template.getId(), template.getHypervisorType(), + template.getGuestOSId(), owner.getDomainId(), owner.getId(), false, 0, false, + RedundantState.UNKNOWN, false, false, VirtualMachine.Type.InternalLoadBalancerVm, vpcId); + internalLbVm.setRole(Role.INTERNAL_LB_VM); + internalLbVm = _itMgr.allocate(internalLbVm, template, routerOffering, networks, plan, null, owner); + } catch (InsufficientCapacityException ex) { + if (allocateRetry < 2 && iter.hasNext()) { + s_logger.debug("Failed to allocate the Internal lb vm with hypervisor type " + hType + ", retrying one more time"); + continue; + } else { + throw ex; + } + } finally { + allocateRetry++; + } + + if (startVm) { + try { + internalLbVm = startInternalLbVm(internalLbVm, _accountMgr.getSystemAccount(), User.UID_SYSTEM, params); + break; + } catch (InsufficientCapacityException ex) { + if (startRetry < 2 && iter.hasNext()) { + s_logger.debug("Failed to start the Internal lb vm " + internalLbVm + " with hypervisor type " + hType + ", " + + "destroying it and recreating one more time"); + // destroy the internal lb vm + destroyInternalLbVm(internalLbVm.getId(), _accountMgr.getSystemAccount(), User.UID_SYSTEM); + continue; + } else { + throw ex; + } + } finally { + startRetry++; + } + } else { + //return stopped internal lb vm + return internalLbVm; + } + } + return internalLbVm; + } + + + + protected DomainRouterVO startInternalLbVm(DomainRouterVO internalLbVm, Account caller, long callerUserId, Map params) + throws StorageUnavailableException, InsufficientCapacityException, + ConcurrentOperationException, ResourceUnavailableException { + s_logger.debug("Starting Internal LB VM " + internalLbVm); + if (_itMgr.start(internalLbVm, params, _accountMgr.getUserIncludingRemoved(callerUserId), caller, null) != null) { + if (internalLbVm.isStopPending()) { + s_logger.info("Clear the stop pending flag of Internal LB VM " + internalLbVm.getHostName() + " after start router successfully!"); + internalLbVm.setStopPending(false); + internalLbVm = _internalLbVmDao.persist(internalLbVm); + } + return _internalLbVmDao.findById(internalLbVm.getId()); + } else { + return null; + } + } + + + protected List getHypervisors(DeployDestination dest, DeploymentPlan plan, + List supportedHypervisors) throws InsufficientServerCapacityException { + List hypervisors = new ArrayList(); + + HypervisorType defaults = _resourceMgr.getDefaultHypervisor(dest.getDataCenter().getId()); + if (defaults != HypervisorType.None) { + hypervisors.add(defaults); + } else { + //if there is no default hypervisor, get it from the cluster + hypervisors = _resourceMgr.getSupportedHypervisorTypes(dest.getDataCenter().getId(), true, + plan.getPodId()); + } + + //keep only elements defined in supported hypervisors + StringBuilder hTypesStr = new StringBuilder(); + if (supportedHypervisors != null && !supportedHypervisors.isEmpty()) { + hypervisors.retainAll(supportedHypervisors); + for (HypervisorType hType : supportedHypervisors) { + hTypesStr.append(hType).append(" "); + } + } + + if (hypervisors.isEmpty()) { + throw new InsufficientServerCapacityException("Unable to create internal lb vm, " + + "there are no clusters in the zone ", DataCenter.class, dest.getDataCenter().getId()); + } + return hypervisors; + } + + @Override + public boolean applyLoadBalancingRules(Network network, final List rules, List internalLbVms) + throws ResourceUnavailableException { + if (rules == null || rules.isEmpty()) { + s_logger.debug("No lb rules to be applied for network " + network); + return true; + } + + //only one internal lb vm is supported per ip address at this time + if (internalLbVms == null || internalLbVms.isEmpty()) { + throw new CloudRuntimeException("Can't apply the lb rules on network " + network + " as the list of internal lb vms is empty"); + } + + VirtualRouter lbVm = internalLbVms.get(0); + if (lbVm.getState() == State.Running) { + return sendLBRules(lbVm, rules, network.getId()); + } else if (lbVm.getState() == State.Stopped || lbVm.getState() == State.Stopping) { + s_logger.debug("Internal LB VM " + lbVm.getInstanceName() + " is in " + lbVm.getState() + + ", so not sending apply lb rules commands to the backend"); + return true; + } else { + s_logger.warn("Unable to apply lb rules, Internal LB VM is not in the right state " + lbVm.getState()); + throw new ResourceUnavailableException("Unable to apply lb rules; Internal LB VM is not in the right state", DataCenter.class, lbVm.getDataCenterId()); + } + } + + protected boolean sendLBRules(VirtualRouter internalLbVm, List rules, long guestNetworkId) throws ResourceUnavailableException { + Commands cmds = new Commands(OnError.Continue); + createApplyLoadBalancingRulesCommands(rules, internalLbVm, cmds, guestNetworkId); + return sendCommandsToInternalLbVm(internalLbVm, cmds); + } + + + protected boolean sendCommandsToInternalLbVm(final VirtualRouter internalLbVm, Commands cmds) throws AgentUnavailableException { + Answer[] answers = null; + try { + answers = _agentMgr.send(internalLbVm.getHostId(), cmds); + } catch (OperationTimedoutException e) { + s_logger.warn("Timed Out", e); + throw new AgentUnavailableException("Unable to send commands to virtual router ", internalLbVm.getHostId(), e); + } + + if (answers == null) { + return false; + } + + if (answers.length != cmds.size()) { + return false; + } + + boolean result = true; + if (answers.length > 0) { + for (Answer answer : answers) { + if (!answer.getResult()) { + result = false; + break; + } + } + } + return result; + } + + + @Override + public VirtualRouter startInternalLbVm(long internalLbVmId, Account caller, long callerUserId) + throws StorageUnavailableException, InsufficientCapacityException, + ConcurrentOperationException, ResourceUnavailableException { + + DomainRouterVO internalLbVm = _internalLbVmDao.findById(internalLbVmId); + if (internalLbVm == null || internalLbVm.getRole() != Role.INTERNAL_LB_VM) { + throw new InvalidParameterValueException("Can't find internal lb vm by id specified"); + } + + return startInternalLbVm(internalLbVm, caller, callerUserId, null); + } +} diff --git a/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/ElementChildTestConfiguration.java b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/ElementChildTestConfiguration.java new file mode 100644 index 00000000000..6959b951fc3 --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/ElementChildTestConfiguration.java @@ -0,0 +1,124 @@ +// 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. +package org.apache.cloudstack.internallbelement; + +import java.io.IOException; + +import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; +import org.apache.cloudstack.network.lb.InternalLoadBalancerVMManager; +import org.apache.cloudstack.test.utils.SpringUtils; +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.filter.TypeFilter; + +import com.cloud.configuration.ConfigurationManager; +import com.cloud.dc.dao.AccountVlanMapDaoImpl; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkModel; +import com.cloud.network.dao.NetworkServiceMapDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.VirtualRouterProviderDao; +import com.cloud.user.AccountManager; +import com.cloud.vm.dao.DomainRouterDao; + +@Configuration +@ComponentScan( + basePackageClasses={ + AccountVlanMapDaoImpl.class + }, + includeFilters={@Filter(value=ElementChildTestConfiguration.Library.class, type=FilterType.CUSTOM)}, + useDefaultFilters=false + ) + +public class ElementChildTestConfiguration { + public static class Library implements TypeFilter { + @Bean + public AccountManager accountManager() { + return Mockito.mock(AccountManager.class); + } + + + @Bean + public DomainRouterDao domainRouterDao() { + return Mockito.mock(DomainRouterDao.class); + } + + @Bean + public VirtualRouterProviderDao virtualRouterProviderDao() { + return Mockito.mock(VirtualRouterProviderDao.class); + } + + @Bean + public NetworkModel networkModel() { + return Mockito.mock(NetworkModel.class); + } + + + @Bean + public NetworkManager networkManager() { + return Mockito.mock(NetworkManager.class); + } + + + @Bean + public PhysicalNetworkServiceProviderDao physicalNetworkServiceProviderDao() { + return Mockito.mock(PhysicalNetworkServiceProviderDao.class); + } + + @Bean + public NetworkServiceMapDao networkServiceMapDao() { + return Mockito.mock(NetworkServiceMapDao.class); + } + + @Bean + public InternalLoadBalancerVMManager internalLoadBalancerVMManager() { + return Mockito.mock(InternalLoadBalancerVMManager.class); + } + + @Bean + public ConfigurationManager confugurationManager() { + return Mockito.mock(ConfigurationManager.class); + } + + + @Bean + public ApplicationLoadBalancerRuleDao applicationLoadBalancerRuleDao() { + return Mockito.mock(ApplicationLoadBalancerRuleDao.class); + } + + @Bean + public DataCenterDao dataCenterDao() { + return Mockito.mock(DataCenterDao.class); + } + + + + @Override + public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { + mdr.getClassMetadata().getClassName(); + ComponentScan cs = ElementChildTestConfiguration.class.getAnnotation(ComponentScan.class); + return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + } + } +} diff --git a/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/InternalLbElementServiceTest.java b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/InternalLbElementServiceTest.java new file mode 100644 index 00000000000..f0e951cdc7a --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/InternalLbElementServiceTest.java @@ -0,0 +1,190 @@ +// 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. +package org.apache.cloudstack.internallbelement; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import javax.inject.Inject; + +import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.VirtualRouterProvider; +import com.cloud.network.VirtualRouterProvider.VirtualRouterProviderType; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; +import com.cloud.network.dao.VirtualRouterProviderDao; +import com.cloud.network.element.VirtualRouterProviderVO; +import com.cloud.user.AccountManager; +import com.cloud.utils.component.ComponentContext; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations="classpath:/lb_element.xml") +public class InternalLbElementServiceTest { + //The interface to test + @Inject InternalLoadBalancerElementService _lbElSvc; + + //Mocked interfaces + @Inject AccountManager _accountMgr; + @Inject VirtualRouterProviderDao _vrProviderDao; + @Inject PhysicalNetworkServiceProviderDao _pNtwkProviderDao; + + long validElId = 1L; + long nonExistingElId = 2L; + long invalidElId = 3L; //not of VirtualRouterProviderType + + long validProviderId = 1L; + long nonExistingProviderId = 2L; + long invalidProviderId = 3L; + + + @Before + public void setUp() { + + ComponentContext.initComponentsLifeCycle(); + VirtualRouterProviderVO validElement = new VirtualRouterProviderVO(1, VirtualRouterProviderType.InternalLbVm); + VirtualRouterProviderVO invalidElement = new VirtualRouterProviderVO(1, VirtualRouterProviderType.VirtualRouter); + + Mockito.when(_vrProviderDao.findById(validElId)).thenReturn(validElement); + Mockito.when(_vrProviderDao.findById(invalidElId)).thenReturn(invalidElement); + + Mockito.when(_vrProviderDao.persist(validElement)).thenReturn(validElement); + + Mockito.when(_vrProviderDao.findByNspIdAndType(validProviderId, VirtualRouterProviderType.InternalLbVm)).thenReturn(validElement); + + PhysicalNetworkServiceProviderVO validProvider = new PhysicalNetworkServiceProviderVO(1, "InternalLoadBalancerElement"); + PhysicalNetworkServiceProviderVO invalidProvider = new PhysicalNetworkServiceProviderVO(1, "Invalid name!"); + + Mockito.when(_pNtwkProviderDao.findById(validProviderId)).thenReturn(validProvider); + Mockito.when(_pNtwkProviderDao.findById(invalidProviderId)).thenReturn(invalidProvider); + + Mockito.when(_vrProviderDao.persist(Mockito.any(VirtualRouterProviderVO.class))).thenReturn(validElement); + } + + //TESTS FOR getInternalLoadBalancerElement METHOD + + + @Test (expected = InvalidParameterValueException.class) + public void findNonExistingVm() { + String expectedExcText = null; + try { + _lbElSvc.getInternalLoadBalancerElement(nonExistingElId); + } catch (InvalidParameterValueException e) { + expectedExcText = e.getMessage(); + throw e; + } finally { + assertEquals("Test failed. The non-existing intenral lb provider was found" + + expectedExcText, expectedExcText, "Unable to find InternalLoadBalancerElementService by id"); + } + } + + + @Test (expected = InvalidParameterValueException.class) + public void findInvalidVm() { + String expectedExcText = null; + try { + _lbElSvc.getInternalLoadBalancerElement(invalidElId); + } catch (InvalidParameterValueException e) { + expectedExcText = e.getMessage(); + throw e; + } finally { + assertEquals("Test failed. The non-existing intenral lb provider was found" + + expectedExcText, expectedExcText, "Unable to find InternalLoadBalancerElementService by id"); + } + } + + + @Test + public void findValidVm() { + VirtualRouterProvider provider = null; + try { + provider = _lbElSvc.getInternalLoadBalancerElement(validElId); + } finally { + assertNotNull("Test failed. Couldn't find the VR provider by the valid id",provider); + } + } + + + //TESTS FOR configureInternalLoadBalancerElement METHOD + + @Test (expected = InvalidParameterValueException.class) + public void configureNonExistingVm() { + + _lbElSvc.configureInternalLoadBalancerElement(nonExistingElId, true); + + } + + + @Test (expected = InvalidParameterValueException.class) + public void ConfigureInvalidVm() { + _lbElSvc.configureInternalLoadBalancerElement(invalidElId, true); + } + + + @Test + public void enableProvider() { + VirtualRouterProvider provider = null; + try { + provider = _lbElSvc.configureInternalLoadBalancerElement(validElId, true); + } finally { + assertNotNull("Test failed. Couldn't find the VR provider by the valid id ",provider); + assertTrue("Test failed. The provider wasn't eanbled ", provider.isEnabled()); + } + } + + @Test + public void disableProvider() { + VirtualRouterProvider provider = null; + try { + provider = _lbElSvc.configureInternalLoadBalancerElement(validElId, false); + } finally { + assertNotNull("Test failed. Couldn't find the VR provider by the valid id ",provider); + assertFalse("Test failed. The provider wasn't disabled ", provider.isEnabled()); + } + } + + //TESTS FOR addInternalLoadBalancerElement METHOD + + @Test (expected = InvalidParameterValueException.class) + public void addToNonExistingProvider() { + + _lbElSvc.addInternalLoadBalancerElement(nonExistingProviderId); + + } + + @Test (expected = InvalidParameterValueException.class) + public void addToInvalidProvider() { + _lbElSvc.addInternalLoadBalancerElement(invalidProviderId); + } + + @Test + public void addToExistingProvider() { + _lbElSvc.addInternalLoadBalancerElement(validProviderId); + } + +} + + diff --git a/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/InternalLbElementTest.java b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/InternalLbElementTest.java new file mode 100644 index 00000000000..f19612f6b0f --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/InternalLbElementTest.java @@ -0,0 +1,226 @@ +// 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. +package org.apache.cloudstack.internallbelement; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.lb.ApplicationLoadBalancerRuleVO; +import org.apache.cloudstack.network.element.InternalLoadBalancerElement; +import org.apache.cloudstack.network.lb.InternalLoadBalancerVMManager; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.cloud.agent.api.to.LoadBalancerTO; +import com.cloud.configuration.ConfigurationManager; +import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.dc.DataCenterVO; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.network.VirtualRouterProvider.VirtualRouterProviderType; +import com.cloud.network.addr.PublicIp; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; +import com.cloud.network.dao.VirtualRouterProviderDao; +import com.cloud.network.element.VirtualRouterProviderVO; +import com.cloud.network.lb.LoadBalancingRule; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.user.AccountManager; +import com.cloud.utils.component.ComponentContext; +import com.cloud.utils.net.Ip; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations="classpath:/lb_element.xml") +public class InternalLbElementTest { + //The class to test + @Inject InternalLoadBalancerElement _lbEl; + + //Mocked interfaces + @Inject AccountManager _accountMgr; + @Inject VirtualRouterProviderDao _vrProviderDao; + @Inject PhysicalNetworkServiceProviderDao _pNtwkProviderDao; + @Inject InternalLoadBalancerVMManager _internalLbMgr; + @Inject ConfigurationManager _configMgr; + + long validElId = 1L; + long nonExistingElId = 2L; + long invalidElId = 3L; //not of VirtualRouterProviderType + long notEnabledElId = 4L; + + long validProviderId = 1L; + long nonExistingProviderId = 2L; + long invalidProviderId = 3L; + + + @Before + public void setUp() { + + ComponentContext.initComponentsLifeCycle(); + VirtualRouterProviderVO validElement = new VirtualRouterProviderVO(1, VirtualRouterProviderType.InternalLbVm); + validElement.setEnabled(true); + VirtualRouterProviderVO invalidElement = new VirtualRouterProviderVO(1, VirtualRouterProviderType.VirtualRouter); + VirtualRouterProviderVO notEnabledElement = new VirtualRouterProviderVO(1, VirtualRouterProviderType.InternalLbVm); + + Mockito.when(_vrProviderDao.findByNspIdAndType(validElId, VirtualRouterProviderType.InternalLbVm)).thenReturn(validElement); + Mockito.when(_vrProviderDao.findByNspIdAndType(invalidElId, VirtualRouterProviderType.InternalLbVm)).thenReturn(invalidElement); + Mockito.when(_vrProviderDao.findByNspIdAndType(notEnabledElId, VirtualRouterProviderType.InternalLbVm)).thenReturn(notEnabledElement); + + Mockito.when(_vrProviderDao.persist(validElement)).thenReturn(validElement); + + Mockito.when(_vrProviderDao.findByNspIdAndType(validProviderId, VirtualRouterProviderType.InternalLbVm)).thenReturn(validElement); + + PhysicalNetworkServiceProviderVO validProvider = new PhysicalNetworkServiceProviderVO(1, "InternalLoadBalancerElement"); + PhysicalNetworkServiceProviderVO invalidProvider = new PhysicalNetworkServiceProviderVO(1, "Invalid name!"); + + Mockito.when(_pNtwkProviderDao.findById(validProviderId)).thenReturn(validProvider); + Mockito.when(_pNtwkProviderDao.findById(invalidProviderId)).thenReturn(invalidProvider); + + Mockito.when(_vrProviderDao.persist(Mockito.any(VirtualRouterProviderVO.class))).thenReturn(validElement); + + DataCenterVO dc = new DataCenterVO + (1L, null, null, null, null, null, null, null, null, null, NetworkType.Advanced, null, null); + Mockito.when(_configMgr.getZone(Mockito.anyLong())).thenReturn(dc); + } + + //TEST FOR getProvider() method + + @Test + public void verifyProviderName() { + Provider pr = _lbEl.getProvider(); + assertEquals("Wrong provider is returned", pr.getName(), Provider.InternalLbVm.getName()); + } + + //TEST FOR isReady() METHOD + + @Test + public void verifyValidProviderState() { + PhysicalNetworkServiceProviderVO provider = new PhysicalNetworkServiceProviderVO(); + provider = setId(provider, validElId); + boolean isReady = _lbEl.isReady(provider); + assertTrue("Valid provider is returned as not ready", isReady); + } + + + @Test + public void verifyNonExistingProviderState() { + PhysicalNetworkServiceProviderVO provider = new PhysicalNetworkServiceProviderVO(); + provider = setId(provider, nonExistingElId); + boolean isReady = _lbEl.isReady(provider); + assertFalse("Non existing provider is returned as ready", isReady); + } + + + @Test + public void verifyInvalidProviderState() { + PhysicalNetworkServiceProviderVO provider = new PhysicalNetworkServiceProviderVO(); + provider = setId(provider, invalidElId); + boolean isReady = _lbEl.isReady(provider); + assertFalse("Not valid provider is returned as ready", isReady); + } + + @Test + public void verifyNotEnabledProviderState() { + PhysicalNetworkServiceProviderVO provider = new PhysicalNetworkServiceProviderVO(); + provider = setId(provider, notEnabledElId); + boolean isReady = _lbEl.isReady(provider); + assertFalse("Not enabled provider is returned as ready", isReady); + } + + //TEST FOR canEnableIndividualServices METHOD + @Test + public void verifyCanEnableIndividualSvc() { + boolean result = _lbEl.canEnableIndividualServices(); + assertTrue("Wrong value is returned by canEnableIndividualSvc", result); + } + + //TEST FOR verifyServicesCombination METHOD + @Test + public void verifyServicesCombination() { + boolean result = _lbEl.verifyServicesCombination(new HashSet()); + assertTrue("Wrong value is returned by verifyServicesCombination", result); + } + + + //TEST FOR applyIps METHOD + @Test + public void verifyApplyIps() throws ResourceUnavailableException { + List ips = new ArrayList(); + boolean result = _lbEl.applyIps(new NetworkVO(), ips, new HashSet()); + assertTrue("Wrong value is returned by applyIps method", result); + } + + + //TEST FOR updateHealthChecks METHOD + @Test + public void verifyUpdateHealthChecks() throws ResourceUnavailableException { + List check = _lbEl.updateHealthChecks(new NetworkVO(), new ArrayList()); + assertNull("Wrong value is returned by updateHealthChecks method", check); + } + + //TEST FOR validateLBRule METHOD + @Test + public void verifyValidateLBRule() throws ResourceUnavailableException { + ApplicationLoadBalancerRuleVO lb = new ApplicationLoadBalancerRuleVO(null, null, 22, 22, "roundrobin", + 1L, 1L, 1L, new Ip("10.10.10.1"), 1L, Scheme.Internal); + lb.setState(FirewallRule.State.Add); + + LoadBalancingRule rule = new LoadBalancingRule(lb, null, + null, null, new Ip("10.10.10.1")); + + + boolean result = _lbEl.validateLBRule(new NetworkVO(), rule); + assertTrue("Wrong value is returned by validateLBRule method", result); + } + + + private static PhysicalNetworkServiceProviderVO setId(PhysicalNetworkServiceProviderVO vo, long id) { + PhysicalNetworkServiceProviderVO voToReturn = vo; + Class c = voToReturn.getClass(); + try { + Field f = c.getDeclaredField("id"); + f.setAccessible(true); + f.setLong(voToReturn, id); + } catch (NoSuchFieldException ex) { + return null; + } catch (IllegalAccessException ex) { + return null; + } + + return voToReturn; + } + + + +} + + diff --git a/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/InternalLBVMManagerTest.java b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/InternalLBVMManagerTest.java new file mode 100644 index 00000000000..a19a82e30c1 --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/InternalLBVMManagerTest.java @@ -0,0 +1,388 @@ +// 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. +package org.apache.cloudstack.internallbvmmgr; + +import java.lang.reflect.Field; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import junit.framework.TestCase; + +import org.apache.cloudstack.lb.ApplicationLoadBalancerRuleVO; +import org.apache.cloudstack.network.lb.InternalLoadBalancerVMManager; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.agent.manager.Commands; +import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.exception.AgentUnavailableException; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.OperationTimedoutException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.NetworkModel; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.lb.LoadBalancingRule; +import com.cloud.network.router.VirtualRouter; +import com.cloud.network.router.VirtualRouter.Role; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.User; +import com.cloud.utils.component.ComponentContext; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; +import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.NicProfile; +import com.cloud.vm.NicVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.State; +import com.cloud.vm.VirtualMachineManager; +import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.NicDao; + +/** + * Set of unittests for InternalLoadBalancerVMManager + * + */ + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations="classpath:/lb_mgr.xml") +public class InternalLBVMManagerTest extends TestCase { + //The interface to test + @Inject InternalLoadBalancerVMManager _lbVmMgr; + + //Mocked interfaces + @Inject AccountManager _accountMgr; + @Inject ServiceOfferingDao _svcOffDao; + @Inject DomainRouterDao _domainRouterDao; + @Inject NicDao _nicDao; + @Inject AgentManager _agentMgr; + @Inject NetworkModel _ntwkModel; + @Inject VirtualMachineManager _itMgr; + @Inject DataCenterDao _dcDao; + + long validNtwkId = 1L; + long invalidNtwkId = 2L; + String requestedIp = "10.1.1.1"; + DomainRouterVO vm = null; + NetworkVO ntwk = createNetwork(); + long validVmId = 1L; + long invalidVmId = 2L; + + @Before + public void setUp() { + //mock system offering creation as it's used by configure() method called by initComponentsLifeCycle + Mockito.when(_accountMgr.getAccount(1L)).thenReturn(new AccountVO()); + ServiceOfferingVO off = new ServiceOfferingVO("alena", 1, 1, + 1, 1, 1, false, "alena", false, false, null, false, VirtualMachine.Type.InternalLoadBalancerVm, false); + off = setId(off, 1); + Mockito.when(_svcOffDao.persistSystemServiceOffering(Mockito.any(ServiceOfferingVO.class))).thenReturn(off); + + ComponentContext.initComponentsLifeCycle(); + + vm = new DomainRouterVO(1L,off.getId(),1,"alena",1,HypervisorType.XenServer,1,1,1, + false, 0,false,null,false,false, + VirtualMachine.Type.InternalLoadBalancerVm, null); + vm.setRole(Role.INTERNAL_LB_VM); + vm = setId(vm, 1); + vm.setPrivateIpAddress("10.2.2.2"); + NicVO nic = new NicVO("somereserver", 1L, 1L, VirtualMachine.Type.InternalLoadBalancerVm); + nic.setIp4Address(requestedIp); + + List emptyList = new ArrayList(); + List nonEmptyList = new ArrayList(); + nonEmptyList.add(vm); + + Mockito.when(_domainRouterDao.listByNetworkAndRole(invalidNtwkId, Role.INTERNAL_LB_VM)).thenReturn(emptyList); + Mockito.when(_domainRouterDao.listByNetworkAndRole(validNtwkId, Role.INTERNAL_LB_VM)).thenReturn(nonEmptyList); + + Mockito.when(_nicDao.findByNtwkIdAndInstanceId(validNtwkId, 1)).thenReturn(nic); + Mockito.when(_nicDao.findByNtwkIdAndInstanceId(invalidNtwkId, 1)).thenReturn(nic); + + Answer answer= new Answer(null, true, null); + Answer[] answers = new Answer[1]; + answers[0] = answer; + + try { + Mockito.when(_agentMgr.send(Mockito.anyLong(), Mockito.any(Commands.class))).thenReturn(answers); + } catch (AgentUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (OperationTimedoutException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + createNetwork(); + Mockito.when(_ntwkModel.getNetwork(Mockito.anyLong())).thenReturn(ntwk); + + + Mockito.when(_itMgr.toNicTO(Mockito.any(NicProfile.class), Mockito.any(HypervisorType.class))).thenReturn(null); + Mockito.when(_domainRouterDao.findById(Mockito.anyLong())).thenReturn(vm); + DataCenterVO dc = new DataCenterVO + (1L, null, null, null, null, null, null, null, null, null, NetworkType.Advanced, null, null); + Mockito.when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + + try { + Mockito.when(_itMgr.expunge(Mockito.any(DomainRouterVO.class), Mockito.any(User.class), Mockito.any(Account.class))).thenReturn(true); + } catch (ResourceUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + Mockito.when(_domainRouterDao.findById(validVmId)).thenReturn(vm); + Mockito.when(_domainRouterDao.findById(invalidVmId)).thenReturn(null); + + } + + protected NetworkVO createNetwork() { + ntwk = new NetworkVO(); + try { + ntwk.setBroadcastUri(new URI("somevlan")); + } catch (URISyntaxException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + ntwk = setId(ntwk, 1L); + return ntwk; + } + + //TESTS FOR findInternalLbVms METHOD + + @Test + public void findInternalLbVmsForInvalidNetwork() { + List vms = _lbVmMgr.findInternalLbVms(invalidNtwkId, new Ip(requestedIp)); + assertTrue("Non empty vm list was returned for invalid network id", vms.isEmpty()); + } + + @Test + public void findInternalLbVmsForValidNetwork() { + List vms = _lbVmMgr.findInternalLbVms(validNtwkId, new Ip(requestedIp)); + assertTrue("Empty vm list was returned for valid network id", !vms.isEmpty()); + } + + + //TESTS FOR applyLoadBalancingRules METHOD + @Test + public void applyEmptyRulesSet() { + boolean result = false; + List vms = new ArrayList(); + try { + result = _lbVmMgr.applyLoadBalancingRules(new NetworkVO(), new ArrayList(), vms); + } catch (ResourceUnavailableException e) { + + } finally { + assertTrue("Got failure when tried to apply empty list of rules", result); + } + } + + @Test (expected = CloudRuntimeException.class) + public void applyWithEmptyVmsSet() { + boolean result = false; + List vms = new ArrayList(); + List rules = new ArrayList(); + LoadBalancingRule rule = new LoadBalancingRule(null, null, + null, null, null); + + rules.add(rule); + try { + result = _lbVmMgr.applyLoadBalancingRules(new NetworkVO(), rules, vms); + } catch (ResourceUnavailableException e) { + } finally { + assertFalse("Got success when tried to apply with the empty internal lb vm list", result); + } + } + + @Test (expected = ResourceUnavailableException.class) + public void applyToVmInStartingState() throws ResourceUnavailableException { + boolean result = false; + List vms = new ArrayList(); + vm.setState(State.Starting); + vms.add(vm); + + List rules = new ArrayList(); + LoadBalancingRule rule = new LoadBalancingRule(null, null, + null, null, null); + + rules.add(rule); + try { + result = _lbVmMgr.applyLoadBalancingRules(new NetworkVO(), rules, vms); + } finally { + assertFalse("Rules were applied to vm in Starting state", result); + } + } + + + @Test + public void applyToVmInStoppedState() throws ResourceUnavailableException { + boolean result = false; + List vms = new ArrayList(); + vm.setState(State.Stopped); + vms.add(vm); + + List rules = new ArrayList(); + LoadBalancingRule rule = new LoadBalancingRule(null, null, + null, null, null); + + rules.add(rule); + try { + result = _lbVmMgr.applyLoadBalancingRules(new NetworkVO(), rules, vms); + } finally { + assertTrue("Rules failed to apply to vm in Stopped state", result); + } + } + + + @Test + public void applyToVmInStoppingState() throws ResourceUnavailableException { + boolean result = false; + List vms = new ArrayList(); + vm.setState(State.Stopping); + vms.add(vm); + + List rules = new ArrayList(); + LoadBalancingRule rule = new LoadBalancingRule(null, null, + null, null, null); + + rules.add(rule); + try { + result = _lbVmMgr.applyLoadBalancingRules(new NetworkVO(), rules, vms); + } finally { + assertTrue("Rules failed to apply to vm in Stopping state", result); + } + } + + + @Test + public void applyToVmInRunningState() throws ResourceUnavailableException { + boolean result = false; + List vms = new ArrayList(); + vm.setState(State.Running); + vms.add(vm); + + List rules = new ArrayList(); + ApplicationLoadBalancerRuleVO lb = new ApplicationLoadBalancerRuleVO(null, null, 22, 22, "roundrobin", + 1L, 1L, 1L, new Ip(requestedIp), 1L, Scheme.Internal); + lb.setState(FirewallRule.State.Add); + + LoadBalancingRule rule = new LoadBalancingRule(lb, null, + null, null, new Ip(requestedIp)); + + rules.add(rule); + + ntwk.getId(); + + try { + result = _lbVmMgr.applyLoadBalancingRules(ntwk, rules, vms); + } finally { + assertTrue("Rules failed to apply to vm in Running state", result); + } + } + + + //TESTS FOR destroyInternalLbVm METHOD + @Test + public void destroyNonExistingVM() throws ResourceUnavailableException, ConcurrentOperationException { + boolean result = false; + + try { + result = _lbVmMgr.destroyInternalLbVm(invalidVmId, new AccountVO(), 1L); + } finally { + assertTrue("Failed to destroy non-existing vm", result); + } + } + + @Test + public void destroyExistingVM() throws ResourceUnavailableException, ConcurrentOperationException { + boolean result = false; + + try { + result = _lbVmMgr.destroyInternalLbVm(validVmId, new AccountVO(), 1L); + } finally { + assertTrue("Failed to destroy valid vm", result); + } + } + + + private static ServiceOfferingVO setId(ServiceOfferingVO vo, long id) { + ServiceOfferingVO voToReturn = vo; + Class c = voToReturn.getClass(); + try { + Field f = c.getSuperclass().getDeclaredField("id"); + f.setAccessible(true); + f.setLong(voToReturn, id); + } catch (NoSuchFieldException ex) { + return null; + } catch (IllegalAccessException ex) { + return null; + } + + return voToReturn; + } + + + private static NetworkVO setId(NetworkVO vo, long id) { + NetworkVO voToReturn = vo; + Class c = voToReturn.getClass(); + try { + Field f = c.getDeclaredField("id"); + f.setAccessible(true); + f.setLong(voToReturn, id); + } catch (NoSuchFieldException ex) { + return null; + } catch (IllegalAccessException ex) { + return null; + } + + return voToReturn; + } + + private static DomainRouterVO setId(DomainRouterVO vo, long id) { + DomainRouterVO voToReturn = vo; + Class c = voToReturn.getClass(); + try { + Field f = c.getSuperclass().getDeclaredField("id"); + f.setAccessible(true); + f.setLong(voToReturn, id); + } catch (NoSuchFieldException ex) { + return null; + } catch (IllegalAccessException ex) { + return null; + } + + return voToReturn; + } + +} diff --git a/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/InternalLBVMServiceTest.java b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/InternalLBVMServiceTest.java new file mode 100644 index 00000000000..75f54faf8f0 --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/InternalLBVMServiceTest.java @@ -0,0 +1,291 @@ +// 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. +package org.apache.cloudstack.internallbvmmgr; + +import java.lang.reflect.Field; +import java.util.Map; + +import javax.inject.Inject; + +import junit.framework.TestCase; + +import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.cloud.deploy.DeploymentPlan; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.OperationTimedoutException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.exception.StorageUnavailableException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.router.VirtualRouter; +import com.cloud.network.router.VirtualRouter.Role; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.User; +import com.cloud.utils.component.ComponentContext; +import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineManager; +import com.cloud.vm.dao.DomainRouterDao; + +/** + * Set of unittests for InternalLoadBalancerVMService + * + */ + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations="classpath:/lb_svc.xml") +@SuppressWarnings("unchecked") +public class InternalLBVMServiceTest extends TestCase { + //The interface to test + @Inject InternalLoadBalancerVMService _lbVmSvc; + + //Mocked interfaces + @Inject AccountManager _accountMgr; + @Inject ServiceOfferingDao _svcOffDao; + @Inject DomainRouterDao _domainRouterDao; + @Inject VirtualMachineManager _itMgr; + + long validVmId = 1L; + long nonExistingVmId = 2L; + long nonInternalLbVmId = 3L; + + @Before + public void setUp() { + //mock system offering creation as it's used by configure() method called by initComponentsLifeCycle + Mockito.when(_accountMgr.getAccount(1L)).thenReturn(new AccountVO()); + ServiceOfferingVO off = new ServiceOfferingVO("alena", 1, 1, + 1, 1, 1, false, "alena", false, false, null, false, VirtualMachine.Type.InternalLoadBalancerVm, false); + off = setId(off, 1); + Mockito.when(_svcOffDao.persistSystemServiceOffering(Mockito.any(ServiceOfferingVO.class))).thenReturn(off); + + ComponentContext.initComponentsLifeCycle(); + + DomainRouterVO validVm = new DomainRouterVO(validVmId,off.getId(),1,"alena",1,HypervisorType.XenServer,1,1,1, + false, 0,false,null,false,false, + VirtualMachine.Type.InternalLoadBalancerVm, null); + validVm.setRole(Role.INTERNAL_LB_VM); + DomainRouterVO nonInternalLbVm = new DomainRouterVO(validVmId,off.getId(),1,"alena",1,HypervisorType.XenServer,1,1,1, + false, 0,false,null,false,false, + VirtualMachine.Type.DomainRouter, null); + nonInternalLbVm.setRole(Role.VIRTUAL_ROUTER); + + Mockito.when(_domainRouterDao.findById(validVmId)).thenReturn(validVm); + Mockito.when(_domainRouterDao.findById(nonExistingVmId)).thenReturn(null); + Mockito.when(_domainRouterDao.findById(nonInternalLbVmId)).thenReturn(nonInternalLbVm); + + try { + Mockito.when(_itMgr.start(Mockito.any(DomainRouterVO.class), + Mockito.any(Map.class), Mockito.any(User.class), Mockito.any(Account.class), Mockito.any(DeploymentPlan.class))).thenReturn(validVm); + } catch (InsufficientCapacityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ResourceUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + try { + Mockito.when(_itMgr.advanceStop(Mockito.any(DomainRouterVO.class), Mockito.any(Boolean.class), Mockito.any(User.class), Mockito.any(Account.class))).thenReturn(true); + } catch (ResourceUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (OperationTimedoutException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ConcurrentOperationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + //TESTS FOR START COMMAND + + + @Test (expected = InvalidParameterValueException.class) + public void startNonExistingVm() { + String expectedExcText = null; + try { + _lbVmSvc.startInternalLbVm(nonExistingVmId, _accountMgr.getAccount(1L), 1L); + } catch (StorageUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InsufficientCapacityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ConcurrentOperationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ResourceUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvalidParameterValueException e) { + expectedExcText = e.getMessage(); + throw e; + } finally { + assertEquals("Test failed. The non-existing internal lb vm was attempted to start" + + expectedExcText, expectedExcText, "Can't find internal lb vm by id specified"); + } + } + + @Test (expected = InvalidParameterValueException.class) + public void startNonInternalLbVmVm() { + String expectedExcText = null; + try { + _lbVmSvc.startInternalLbVm(nonInternalLbVmId, _accountMgr.getAccount(1L), 1L); + } catch (StorageUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InsufficientCapacityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ConcurrentOperationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ResourceUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + }catch (InvalidParameterValueException e) { + expectedExcText = e.getMessage(); + throw e; + } finally { + assertEquals("Test failed. The existing vm of not Internal lb vm type was attempted to start" + + expectedExcText, expectedExcText, "Can't find internal lb vm by id specified"); + } + } + + @Test + public void startValidLbVmVm() { + VirtualRouter vr = null; + try { + vr = _lbVmSvc.startInternalLbVm(validVmId, _accountMgr.getAccount(1L), 1L); + } catch (StorageUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InsufficientCapacityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ConcurrentOperationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ResourceUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } finally { + assertNotNull("Internal LB vm is null which means it failed to start " + vr, vr); + } + } + + + //TEST FOR STOP COMMAND + @Test (expected = InvalidParameterValueException.class) + public void stopNonExistingVm() { + String expectedExcText = null; + try { + _lbVmSvc.stopInternalLbVm(nonExistingVmId, false,_accountMgr.getAccount(1L), 1L); + } catch (StorageUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ConcurrentOperationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ResourceUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvalidParameterValueException e) { + expectedExcText = e.getMessage(); + throw e; + } finally { + assertEquals("Test failed. The non-existing internal lb vm was attempted to stop" + + expectedExcText, expectedExcText, "Can't find internal lb vm by id specified"); + } + } + + + @Test (expected = InvalidParameterValueException.class) + public void stopNonInternalLbVmVm() { + String expectedExcText = null; + try { + _lbVmSvc.stopInternalLbVm(nonInternalLbVmId, false, _accountMgr.getAccount(1L), 1L); + } catch (StorageUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ConcurrentOperationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ResourceUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + }catch (InvalidParameterValueException e) { + expectedExcText = e.getMessage(); + throw e; + } finally { + assertEquals("Test failed. The existing vm of not Internal lb vm type was attempted to stop" + + expectedExcText, expectedExcText, "Can't find internal lb vm by id specified"); + } + } + + + @Test + public void stopValidLbVmVm() { + VirtualRouter vr = null; + try { + vr = _lbVmSvc.stopInternalLbVm(validVmId, false, _accountMgr.getAccount(1L), 1L); + } catch (StorageUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ConcurrentOperationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ResourceUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } finally { + assertNotNull("Internal LB vm is null which means it failed to stop " + vr, vr); + } + } + + + + private static ServiceOfferingVO setId(ServiceOfferingVO vo, long id) { + ServiceOfferingVO voToReturn = vo; + Class c = voToReturn.getClass(); + try { + Field f = c.getSuperclass().getDeclaredField("id"); + f.setAccessible(true); + f.setLong(voToReturn, id); + } catch (NoSuchFieldException ex) { + return null; + } catch (IllegalAccessException ex) { + return null; + } + + return voToReturn; + } +} diff --git a/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/LbChildTestConfiguration.java b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/LbChildTestConfiguration.java new file mode 100644 index 00000000000..0f24f963ae6 --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/LbChildTestConfiguration.java @@ -0,0 +1,170 @@ +// 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. +package org.apache.cloudstack.internallbvmmgr; + +import java.io.IOException; + +import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; +import org.apache.cloudstack.test.utils.SpringUtils; +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.filter.TypeFilter; + +import com.cloud.agent.AgentManager; +import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.dc.dao.AccountVlanMapDaoImpl; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkModel; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.VirtualRouterProviderDao; +import com.cloud.network.lb.LoadBalancingRulesManager; +import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.resource.ResourceManager; +import com.cloud.server.ConfigurationServer; +import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.user.AccountManager; +import com.cloud.vm.VirtualMachineManager; +import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.NicDao; + +@Configuration +@ComponentScan( + basePackageClasses={ + AccountVlanMapDaoImpl.class + }, + includeFilters={@Filter(value=LbChildTestConfiguration.Library.class, type=FilterType.CUSTOM)}, + useDefaultFilters=false + ) + + public class LbChildTestConfiguration { + + public static class Library implements TypeFilter { + + + @Bean + public AccountManager accountManager() { + return Mockito.mock(AccountManager.class); + } + + @Bean + public VirtualMachineManager virtualMachineManager() { + return Mockito.mock(VirtualMachineManager.class); + } + + @Bean + public DomainRouterDao domainRouterDao() { + return Mockito.mock(DomainRouterDao.class); + } + + @Bean + public ConfigurationDao configurationDao() { + return Mockito.mock(ConfigurationDao.class); + } + + @Bean + public VirtualRouterProviderDao virtualRouterProviderDao() { + return Mockito.mock(VirtualRouterProviderDao.class); + } + + @Bean + public ApplicationLoadBalancerRuleDao applicationLoadBalancerRuleDao() { + return Mockito.mock(ApplicationLoadBalancerRuleDao.class); + } + + @Bean + public NetworkModel networkModel() { + return Mockito.mock(NetworkModel.class); + } + + @Bean + public LoadBalancingRulesManager loadBalancingRulesManager() { + return Mockito.mock(LoadBalancingRulesManager.class); + } + + @Bean + public NicDao nicDao() { + return Mockito.mock(NicDao.class); + } + + @Bean + public NetworkDao networkDao() { + return Mockito.mock(NetworkDao.class); + } + + @Bean + public NetworkManager networkManager() { + return Mockito.mock(NetworkManager.class); + } + + @Bean + public ServiceOfferingDao serviceOfferingDao() { + return Mockito.mock(ServiceOfferingDao.class); + } + + @Bean + public PhysicalNetworkServiceProviderDao physicalNetworkServiceProviderDao() { + return Mockito.mock(PhysicalNetworkServiceProviderDao.class); + } + + @Bean + public NetworkOfferingDao networkOfferingDao() { + return Mockito.mock(NetworkOfferingDao.class); + } + + @Bean + public VMTemplateDao vmTemplateDao() { + return Mockito.mock(VMTemplateDao.class); + } + + @Bean + public ResourceManager resourceManager() { + return Mockito.mock(ResourceManager.class); + } + + @Bean + public AgentManager agentManager() { + return Mockito.mock(AgentManager.class); + } + + @Bean + public DataCenterDao dataCenterDao() { + return Mockito.mock(DataCenterDao.class); + } + + @Bean + public ConfigurationServer configurationServer() { + return Mockito.mock(ConfigurationServer.class); + } + + @Override + public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { + mdr.getClassMetadata().getClassName(); + ComponentScan cs = LbChildTestConfiguration.class.getAnnotation(ComponentScan.class); + return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + } + + } +} diff --git a/plugins/network-elements/internal-loadbalancer/test/resources/lb_element.xml b/plugins/network-elements/internal-loadbalancer/test/resources/lb_element.xml new file mode 100644 index 00000000000..5dec9c314f6 --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/test/resources/lb_element.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/internal-loadbalancer/test/resources/lb_mgr.xml b/plugins/network-elements/internal-loadbalancer/test/resources/lb_mgr.xml new file mode 100644 index 00000000000..1ad6403861c --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/test/resources/lb_mgr.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/internal-loadbalancer/test/resources/lb_svc.xml b/plugins/network-elements/internal-loadbalancer/test/resources/lb_svc.xml new file mode 100644 index 00000000000..fa822f35302 --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/test/resources/lb_svc.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java b/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java index b8144301810..4f2a0a1da42 100644 --- a/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java +++ b/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java @@ -16,6 +16,22 @@ // under the License. package com.cloud.network.element; +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.ejb.Local; +import javax.inject.Inject; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.network.ExternalNetworkDeviceManager.NetworkDevice; +import org.apache.cloudstack.region.gslb.GslbServiceProvider; +import org.apache.log4j.Logger; + import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.routing.GlobalLoadBalancerConfigCommand; @@ -27,7 +43,11 @@ import com.cloud.agent.api.routing.SetStaticNatRulesCommand; import com.cloud.agent.api.to.LoadBalancerTO; import com.cloud.agent.api.to.StaticNatRuleTO; import com.cloud.api.ApiDBUtils; -import com.cloud.api.commands.*; +import com.cloud.api.commands.AddNetscalerLoadBalancerCmd; +import com.cloud.api.commands.ConfigureNetscalerLoadBalancerCmd; +import com.cloud.api.commands.DeleteNetscalerLoadBalancerCmd; +import com.cloud.api.commands.ListNetscalerLoadBalancerNetworksCmd; +import com.cloud.api.commands.ListNetscalerLoadBalancersCmd; import com.cloud.api.response.NetscalerLoadBalancerResponse; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; @@ -39,27 +59,48 @@ import com.cloud.dc.HostPodVO; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.DataCenterIpAddressDao; import com.cloud.deploy.DeployDestination; -import com.cloud.exception.*; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InsufficientNetworkCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceUnavailableException; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.host.dao.HostDetailsDao; -import com.cloud.network.*; +import com.cloud.network.ExternalLoadBalancerDeviceManager; +import com.cloud.network.ExternalLoadBalancerDeviceManagerImpl; +import com.cloud.network.IpAddress; +import com.cloud.network.NetScalerPodVO; +import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; +import com.cloud.network.NetworkModel; import com.cloud.network.Networks.TrafficType; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.PublicIpAddress; import com.cloud.network.as.AutoScaleCounter; import com.cloud.network.as.AutoScaleCounter.AutoScaleCounterType; -import com.cloud.network.dao.*; +import com.cloud.network.dao.ExternalLoadBalancerDeviceDao; +import com.cloud.network.dao.ExternalLoadBalancerDeviceVO; import com.cloud.network.dao.ExternalLoadBalancerDeviceVO.LBDeviceState; +import com.cloud.network.dao.NetScalerPodDao; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkExternalLoadBalancerDao; +import com.cloud.network.dao.NetworkExternalLoadBalancerVO; +import com.cloud.network.dao.NetworkServiceMapDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.resource.NetscalerResource; import com.cloud.network.rules.FirewallRule; -import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.LbStickinessMethod; import com.cloud.network.rules.LbStickinessMethod.StickinessMethodType; +import com.cloud.network.rules.LoadBalancerContainer; import com.cloud.network.rules.StaticNat; import com.cloud.network.vpc.PrivateGateway; import com.cloud.network.vpc.StaticRouteProfile; @@ -75,15 +116,6 @@ import com.cloud.vm.ReservationContext; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; import com.google.gson.Gson; -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.network.ExternalNetworkDeviceManager.NetworkDevice; -import org.apache.cloudstack.region.gslb.GslbServiceProvider; -import org.apache.log4j.Logger; - -import javax.ejb.Local; -import javax.inject.Inject; -import java.net.URI; -import java.util.*; @Local(value = {NetworkElement.class, StaticNatServiceProvider.class, LoadBalancingServiceProvider.class, GslbServiceProvider.class}) public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl implements LoadBalancingServiceProvider, @@ -207,6 +239,10 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl if (!canHandle(config, Service.Lb)) { return false; } + + if (canHandleLbRules(rules)) { + return false; + } if (isBasicZoneNetwok(config)) { return applyElasticLoadBalancerRules(config, rules); @@ -237,6 +273,9 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl // Specifies that load balancing rules can only be made with public IPs that aren't source NAT IPs lbCapabilities.put(Capability.LoadBalancingSupportedIps, "additional"); + // Supports only Public load balancing + lbCapabilities.put(Capability.LbSchemes, LoadBalancerContainer.Scheme.Public.toString()); + // Specifies that load balancing rules can support autoscaling and the list of counters it supports AutoScaleCounter counter; List counterList = new ArrayList(); @@ -644,14 +683,7 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl return this; } - public boolean applyElasticLoadBalancerRules(Network network, List rules) throws ResourceUnavailableException { - - List loadBalancingRules = new ArrayList(); - for (FirewallRule rule : rules) { - if (rule.getPurpose().equals(Purpose.LoadBalancing)) { - loadBalancingRules.add((LoadBalancingRule) rule); - } - } + public boolean applyElasticLoadBalancerRules(Network network, List loadBalancingRules) throws ResourceUnavailableException { if (loadBalancingRules == null || loadBalancingRules.isEmpty()) { return true; @@ -682,7 +714,7 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl String protocol = rule.getProtocol(); String algorithm = rule.getAlgorithm(); String lbUuid = rule.getUuid(); - String srcIp = _networkMgr.getIp(rule.getSourceIpAddressId()).getAddress().addr(); + String srcIp = rule.getSourceIp().addr(); int srcPort = rule.getSourcePortStart(); List destinations = rule.getDestinations(); @@ -813,16 +845,10 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl return null; } - public List getElasticLBRulesHealthCheck(Network network, List rules) + public List getElasticLBRulesHealthCheck(Network network, List loadBalancingRules) throws ResourceUnavailableException { HealthCheckLBConfigAnswer answer = null; - List loadBalancingRules = new ArrayList(); - for (FirewallRule rule : rules) { - if (rule.getPurpose().equals(Purpose.LoadBalancing)) { - loadBalancingRules.add((LoadBalancingRule) rule); - } - } if (loadBalancingRules == null || loadBalancingRules.isEmpty()) { return null; @@ -849,7 +875,7 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl String protocol = rule.getProtocol(); String algorithm = rule.getAlgorithm(); String lbUuid = rule.getUuid(); - String srcIp = _networkMgr.getIp(rule.getSourceIpAddressId()).getAddress().addr(); + String srcIp = rule.getSourceIp().addr(); int srcPort = rule.getSourcePortStart(); List destinations = rule.getDestinations(); @@ -874,7 +900,7 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl public List updateHealthChecks(Network network, List lbrules) { - if (canHandle(network, Service.Lb)) { + if (canHandle(network, Service.Lb) && canHandleLbRules(lbrules)) { try { if (isBasicZoneNetwok(network)) { @@ -891,7 +917,7 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl return null; } - public List getLBHealthChecks(Network network, List rules) + public List getLBHealthChecks(Network network, List rules) throws ResourceUnavailableException { return super.getLBHealthChecks(network, rules); } @@ -960,6 +986,22 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl } return null; } + + private boolean canHandleLbRules(List rules) { + Map lbCaps = this.getCapabilities().get(Service.Lb); + if (!lbCaps.isEmpty()) { + String schemeCaps = lbCaps.get(Capability.LbSchemes); + if (schemeCaps != null) { + for (LoadBalancingRule rule : rules) { + if (!schemeCaps.contains(rule.getScheme().toString())) { + s_logger.debug("Scheme " + rules.get(0).getScheme() + " is not supported by the provider " + this.getName()); + return false; + } + } + } + } + return true; + } @Override public boolean implementVpc(Vpc vpc, DeployDestination dest, ReservationContext context) diff --git a/plugins/pom.xml b/plugins/pom.xml index b9402718b89..e49fac9533a 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -62,6 +62,7 @@ storage/volume/default alert-handlers/snmp-alerts alert-handlers/syslog-alerts + network-elements/internal-loadbalancer diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index b8eea12b4cf..fce1f719086 100755 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -25,8 +25,6 @@ import java.util.Set; import javax.annotation.PostConstruct; import javax.inject.Inject; -import com.cloud.network.rules.LoadBalancer; -import com.cloud.region.ha.GlobalLoadBalancingRulesService; import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.affinity.dao.AffinityGroupDao; @@ -37,8 +35,8 @@ import org.apache.cloudstack.api.response.AsyncJobResponse; import org.apache.cloudstack.api.response.DiskOfferingResponse; import org.apache.cloudstack.api.response.DomainRouterResponse; import org.apache.cloudstack.api.response.EventResponse; -import org.apache.cloudstack.api.response.HostResponse; import org.apache.cloudstack.api.response.HostForMigrationResponse; +import org.apache.cloudstack.api.response.HostResponse; import org.apache.cloudstack.api.response.InstanceGroupResponse; import org.apache.cloudstack.api.response.ProjectAccountResponse; import org.apache.cloudstack.api.response.ProjectInvitationResponse; @@ -52,6 +50,7 @@ import org.apache.cloudstack.api.response.UserResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.api.response.VolumeResponse; import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.springframework.stereotype.Component; @@ -157,6 +156,8 @@ import com.cloud.network.as.dao.AutoScaleVmGroupPolicyMapDao; import com.cloud.network.as.dao.AutoScaleVmProfileDao; import com.cloud.network.as.dao.ConditionDao; import com.cloud.network.as.dao.CounterDao; +import com.cloud.network.dao.AccountGuestVlanMapDao; +import com.cloud.network.dao.AccountGuestVlanMapVO; import com.cloud.network.dao.FirewallRulesCidrsDao; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; @@ -181,6 +182,7 @@ import com.cloud.network.dao.Site2SiteVpnGatewayDao; import com.cloud.network.dao.Site2SiteVpnGatewayVO; import com.cloud.network.router.VirtualRouter; import com.cloud.network.rules.FirewallRuleVO; +import com.cloud.network.rules.LoadBalancer; import com.cloud.network.security.SecurityGroup; import com.cloud.network.security.SecurityGroupManager; import com.cloud.network.security.SecurityGroupVO; @@ -204,6 +206,7 @@ import com.cloud.projects.Project; import com.cloud.projects.ProjectAccount; import com.cloud.projects.ProjectInvitation; import com.cloud.projects.ProjectService; +import com.cloud.region.ha.GlobalLoadBalancingRulesService; import com.cloud.resource.ResourceManager; import com.cloud.server.Criteria; import com.cloud.server.ManagementServer; @@ -499,6 +502,7 @@ public class ApiDBUtils { @Inject private VMSnapshotDao vmSnapshotDao; @Inject private NicSecondaryIpDao nicSecondaryIpDao; @Inject private VpcProvisioningService vpcProvSvc; + @Inject private ApplicationLoadBalancerRuleDao _appLbDao; @Inject private AffinityGroupDao affinityGroupDao; @Inject private AffinityGroupJoinDao affinityGroupJoinDao; @Inject private GlobalLoadBalancingRulesService gslbService; diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index d7eaa2604b1..d5960abba8b 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -44,6 +44,9 @@ import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.ResponseGenerator; import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd; import org.apache.cloudstack.api.response.AccountResponse; +import org.apache.cloudstack.api.response.ApplicationLoadBalancerInstanceResponse; +import org.apache.cloudstack.api.response.ApplicationLoadBalancerResponse; +import org.apache.cloudstack.api.response.ApplicationLoadBalancerRuleResponse; import org.apache.cloudstack.api.response.AsyncJobResponse; import org.apache.cloudstack.api.response.AutoScalePolicyResponse; import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse; @@ -72,6 +75,7 @@ import org.apache.cloudstack.api.response.HostResponse; import org.apache.cloudstack.api.response.HypervisorCapabilitiesResponse; import org.apache.cloudstack.api.response.IPAddressResponse; import org.apache.cloudstack.api.response.InstanceGroupResponse; +import org.apache.cloudstack.api.response.InternalLoadBalancerElementResponse; import org.apache.cloudstack.api.response.IpForwardingRuleResponse; import org.apache.cloudstack.api.response.IsolationMethodResponse; import org.apache.cloudstack.api.response.LBHealthCheckPolicyResponse; @@ -130,6 +134,7 @@ import org.apache.cloudstack.api.response.VpcOfferingResponse; import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.api.response.VpnUsersResponse; import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule; import org.apache.cloudstack.region.Region; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.usage.Usage; @@ -189,6 +194,7 @@ import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; +import com.cloud.network.NetworkModel; import com.cloud.network.NetworkProfile; import com.cloud.network.Networks.IsolationType; import com.cloud.network.Networks.TrafficType; @@ -216,6 +222,7 @@ import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.HealthCheckPolicy; import com.cloud.network.rules.LoadBalancer; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.StaticNatRule; import com.cloud.network.rules.StickinessPolicy; @@ -229,6 +236,7 @@ import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.VpcOffering; import com.cloud.offering.DiskOffering; import com.cloud.offering.NetworkOffering; +import com.cloud.offering.NetworkOffering.Detail; import com.cloud.offering.ServiceOffering; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.org.Cluster; @@ -269,6 +277,7 @@ import com.cloud.user.UserContext; import com.cloud.uservm.UserVm; import com.cloud.utils.Pair; import com.cloud.utils.StringUtils; +import com.cloud.utils.net.Ip; import com.cloud.utils.net.NetUtils; import com.cloud.vm.ConsoleProxyVO; import com.cloud.vm.InstanceGroup; @@ -289,6 +298,7 @@ public class ApiResponseHelper implements ResponseGenerator { private static final DecimalFormat s_percentFormat = new DecimalFormat("##.##"); @Inject private EntityManager _entityMgr = null; @Inject private UsageService _usageSvc = null; + @Inject NetworkModel _ntwkModel; @Override public UserResponse createUserResponse(User user) { @@ -750,7 +760,7 @@ public class ApiResponseHelper implements ResponseGenerator { } //set tag information - List tags = ApiDBUtils.listByResourceTypeAndId(TaggedResourceType.UserVm, loadBalancer.getId()); + List tags = ApiDBUtils.listByResourceTypeAndId(TaggedResourceType.LoadBalancer, loadBalancer.getId()); List tagResponses = new ArrayList(); for (ResourceTag tag : tags) { ResourceTagResponse tagResponse = createResourceTagResponse(tag, true); @@ -2263,6 +2273,13 @@ public class ApiResponseHelper implements ResponseGenerator { response.setForVpc(ApiDBUtils.isOfferingForVpc(offering)); response.setServices(serviceResponses); + + //set network offering details + Map details = _ntwkModel.getNtwkOffDetails(offering.getId()); + if (details != null && !details.isEmpty()) { + response.setDetails(details); + } + response.setObjectName("networkoffering"); return response; } @@ -2826,6 +2843,11 @@ public class ApiResponseHelper implements ResponseGenerator { @Override public VirtualRouterProviderResponse createVirtualRouterProviderResponse(VirtualRouterProvider result) { + //generate only response of the VR/VPCVR provider type + if (!(result.getType() == VirtualRouterProvider.VirtualRouterProviderType.VirtualRouter + || result.getType() == VirtualRouterProvider.VirtualRouterProviderType.VPCVirtualRouter)) { + return null; + } VirtualRouterProviderResponse response = new VirtualRouterProviderResponse(); response.setId(result.getUuid()); PhysicalNetworkServiceProvider nsp = ApiDBUtils.findPhysicalNetworkServiceProviderById(result.getNspId()); @@ -3689,6 +3711,73 @@ public class ApiResponseHelper implements ResponseGenerator { return response; } + + @Override + public ApplicationLoadBalancerResponse createLoadBalancerContainerReponse(ApplicationLoadBalancerRule lb, Map lbInstances) { + + ApplicationLoadBalancerResponse lbResponse = new ApplicationLoadBalancerResponse(); + lbResponse.setId(lb.getUuid()); + lbResponse.setName(lb.getName()); + lbResponse.setDescription(lb.getDescription()); + lbResponse.setAlgorithm(lb.getAlgorithm()); + Network nw = ApiDBUtils.findNetworkById(lb.getNetworkId()); + lbResponse.setNetworkId(nw.getUuid()); + populateOwner(lbResponse, lb); + + if (lb.getScheme() == Scheme.Internal) { + lbResponse.setSourceIp(lb.getSourceIp().addr()); + //TODO - create the view for the load balancer rule to reflect the network uuid + Network network = ApiDBUtils.findNetworkById(lb.getNetworkId()); + lbResponse.setSourceIpNetworkId(network.getUuid()); + } else { + //for public, populate the ip information from the ip address + IpAddress publicIp = ApiDBUtils.findIpAddressById(lb.getSourceIpAddressId()); + lbResponse.setSourceIp(publicIp.getAddress().addr()); + Network ntwk = ApiDBUtils.findNetworkById(publicIp.getNetworkId()); + lbResponse.setSourceIpNetworkId(ntwk.getUuid()); + } + + //set load balancer rules information (only one rule per load balancer in this release) + List ruleResponses = new ArrayList(); + ApplicationLoadBalancerRuleResponse ruleResponse = new ApplicationLoadBalancerRuleResponse(); + ruleResponse.setInstancePort(lb.getDefaultPortStart()); + ruleResponse.setSourcePort(lb.getSourcePortStart()); + String stateToSet = lb.getState().toString(); + if (stateToSet.equals(FirewallRule.State.Revoke)) { + stateToSet = "Deleting"; + } + ruleResponse.setState(stateToSet); + ruleResponse.setObjectName("loadbalancerrule"); + ruleResponses.add(ruleResponse); + lbResponse.setLbRules(ruleResponses); + + //set Lb instances information + List instanceResponses = new ArrayList(); + for (Ip ip : lbInstances.keySet()) { + ApplicationLoadBalancerInstanceResponse instanceResponse = new ApplicationLoadBalancerInstanceResponse(); + instanceResponse.setIpAddress(ip.addr()); + UserVm vm = lbInstances.get(ip); + instanceResponse.setId(vm.getUuid()); + instanceResponse.setName(vm.getInstanceName()); + instanceResponse.setObjectName("loadbalancerinstance"); + instanceResponses.add(instanceResponse); + } + + lbResponse.setLbInstances(instanceResponses); + + //set tag information + List tags = ApiDBUtils.listByResourceTypeAndId(TaggedResourceType.LoadBalancer, lb.getId()); + List tagResponses = new ArrayList(); + for (ResourceTag tag : tags) { + ResourceTagResponse tagResponse = createResourceTagResponse(tag, true); + tagResponses.add(tagResponse); + } + lbResponse.setTags(tagResponses); + + lbResponse.setObjectName("loadbalancer"); + return lbResponse; + } + @Override public AffinityGroupResponse createAffinityGroupResponse(AffinityGroup group) { @@ -3719,8 +3808,25 @@ public class ApiResponseHelper implements ResponseGenerator { } } + + @Override + public InternalLoadBalancerElementResponse createInternalLbElementResponse(VirtualRouterProvider result) { + if (result.getType() != VirtualRouterProvider.VirtualRouterProviderType.InternalLbVm) { + return null; + } + InternalLoadBalancerElementResponse response = new InternalLoadBalancerElementResponse(); + response.setId(result.getUuid()); + PhysicalNetworkServiceProvider nsp = ApiDBUtils.findPhysicalNetworkServiceProviderById(result.getNspId()); + if (nsp != null) { + response.setNspId(nsp.getUuid()); + } + response.setEnabled(result.isEnabled()); + response.setObjectName("internalloadbalancerelement"); + return response; + } + @Override public IsolationMethodResponse createIsolationMethodResponse(IsolationType method) { IsolationMethodResponse response = new IsolationMethodResponse(); diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index 50018e53efb..808b1efceb1 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -29,7 +29,9 @@ import javax.inject.Inject; import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.affinity.AffinityGroupVMMapVO; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; +import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd; import org.apache.cloudstack.api.command.admin.host.ListHostsCmd; +import org.apache.cloudstack.api.command.admin.internallb.ListInternalLBVMsCmd; import org.apache.cloudstack.api.command.admin.router.ListRoutersCmd; import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolsCmd; import org.apache.cloudstack.api.command.admin.user.ListUsersCmd; @@ -981,7 +983,21 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { @Override public ListResponse searchForRouters(ListRoutersCmd cmd) { - Pair, Integer> result = searchForRoutersInternal(cmd); + Pair, Integer> result = searchForRoutersInternal(cmd, cmd.getId(), cmd.getRouterName(), + cmd.getState(), cmd.getZoneId(), cmd.getPodId(), cmd.getHostId(), cmd.getKeyword(), cmd.getNetworkId(), + cmd.getVpcId(), cmd.getForVpc(), cmd.getRole(), cmd.getZoneType()); + ListResponse response = new ListResponse(); + + List routerResponses = ViewResponseHelper.createDomainRouterResponse(result.first().toArray(new DomainRouterJoinVO[result.first().size()])); + response.setResponses(routerResponses, result.second()); + return response; + } + + @Override + public ListResponse searchForInternalLbVms(ListInternalLBVMsCmd cmd) { + Pair, Integer> result = searchForRoutersInternal(cmd, cmd.getId(), cmd.getRouterName(), + cmd.getState(), cmd.getZoneId(), cmd.getPodId(), cmd.getHostId(), cmd.getKeyword(), cmd.getNetworkId(), + cmd.getVpcId(), cmd.getForVpc(), cmd.getRole(), cmd.getZoneType()); ListResponse response = new ListResponse(); List routerResponses = ViewResponseHelper.createDomainRouterResponse(result.first().toArray(new DomainRouterJoinVO[result.first().size()])); @@ -990,18 +1006,9 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { } - private Pair, Integer> searchForRoutersInternal(ListRoutersCmd cmd) { - Long id = cmd.getId(); - String name = cmd.getRouterName(); - String state = cmd.getState(); - Long zoneId = cmd.getZoneId(); - String zoneType = cmd.getZoneType(); - Long pod = cmd.getPodId(); - Long hostId = cmd.getHostId(); - String keyword = cmd.getKeyword(); - Long networkId = cmd.getNetworkId(); - Long vpcId = cmd.getVpcId(); - Boolean forVpc = cmd.getForVpc(); + private Pair, Integer> searchForRoutersInternal(BaseListProjectAndAccountResourcesCmd cmd, Long id, + String name, String state, Long zoneId, Long podId, Long hostId, String keyword, Long networkId, Long vpcId, Boolean forVpc, String role, String zoneType) { + Account caller = UserContext.current().getCaller(); List permittedAccounts = new ArrayList(); @@ -1032,6 +1039,7 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { sb.and("podId", sb.entity().getPodId(), SearchCriteria.Op.EQ); sb.and("hostId", sb.entity().getHostId(), SearchCriteria.Op.EQ); sb.and("vpcId", sb.entity().getVpcId(), SearchCriteria.Op.EQ); + sb.and("role", sb.entity().getRole(), SearchCriteria.Op.EQ); if (forVpc != null) { if (forVpc) { @@ -1073,13 +1081,14 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { sc.setParameters("dataCenterId", zoneId); } + if (podId != null) { + sc.setParameters("podId", podId); + } + if (zoneType != null) { sc.setParameters("dataCenterType", zoneType); } - if (pod != null) { - sc.setParameters("podId", pod); - } if (hostId != null) { sc.setParameters("hostId", hostId); @@ -1092,6 +1101,10 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { if (vpcId != null) { sc.setParameters("vpcId", vpcId); } + + if (role != null) { + sc.setParameters("role", role); + } // search VR details by ids Pair, Integer> uniqueVrPair = _routerJoinDao.searchAndCount(sc, searchFilter); diff --git a/server/src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java index 125db17c760..a7a83de14a1 100644 --- a/server/src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java @@ -32,6 +32,7 @@ import com.cloud.api.query.vo.DomainRouterJoinVO; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.network.Networks.TrafficType; import com.cloud.network.router.VirtualRouter; +import com.cloud.network.router.VirtualRouter.Role; import com.cloud.user.Account; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; @@ -156,6 +157,8 @@ public class DomainRouterJoinDaoImpl extends GenericDaoBase> serviceProviderMap, boolean isDefault, Network.GuestType type, boolean systemOnly, Long serviceOfferingId, boolean conserveMode, Map> serviceCapabilityMap, - boolean specifyIpRanges, boolean isPersistent); + boolean specifyIpRanges, boolean isPersistent, Map details); Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, Long podId, String startIP, String endIP, String vlanGateway, String vlanNetmask, String vlanId, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr) throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException; diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 37ca793c556..fdc0ffbabe1 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -39,6 +39,7 @@ import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; + import com.cloud.dc.*; import com.cloud.dc.dao.*; import com.cloud.user.*; @@ -81,6 +82,17 @@ import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.Vlan.VlanType; +import com.cloud.dc.VlanVO; +import com.cloud.dc.dao.AccountVlanMapDao; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.DataCenterIpAddressDao; +import com.cloud.dc.dao.DataCenterLinkLocalIpAddressDao; +import com.cloud.dc.dao.DcDetailsDao; +import com.cloud.dc.dao.HostPodDao; +import com.cloud.dc.dao.PodVlanMapDao; +import com.cloud.dc.dao.VlanDao; + import com.cloud.deploy.DataCenterDeployment; import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; @@ -115,10 +127,12 @@ import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao; import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO; import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.vpc.VpcManager; import com.cloud.offering.DiskOffering; import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.Availability; +import com.cloud.offering.NetworkOffering.Detail; import com.cloud.offering.ServiceOffering; import com.cloud.offerings.NetworkOfferingServiceMapVO; import com.cloud.offerings.NetworkOfferingVO; @@ -1919,6 +1933,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati vmType = VirtualMachine.Type.ConsoleProxy; } else if (VirtualMachine.Type.SecondaryStorageVm.toString().toLowerCase().equals(vmTypeString)) { vmType = VirtualMachine.Type.SecondaryStorageVm; + } else if (VirtualMachine.Type.InternalLoadBalancerVm.toString().toLowerCase().equals(vmTypeString)) { + vmType = VirtualMachine.Type.InternalLoadBalancerVm; } else { throw new InvalidParameterValueException("Invalid systemVmType. Supported types are: " + VirtualMachine.Type.DomainRouter + ", " + VirtualMachine.Type.ConsoleProxy + ", " + VirtualMachine.Type.SecondaryStorageVm); @@ -3340,6 +3356,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati Network.GuestType guestType = null; boolean specifyIpRanges = cmd.getSpecifyIpRanges(); boolean isPersistent = cmd.getIsPersistent(); + Map detailsStr = cmd.getDetails(); // Verify traffic type for (TrafficType tType : TrafficType.values()) { @@ -3432,10 +3449,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati Network.Service service = Network.Service.getService(serviceStr); if (serviceProviderMap.containsKey(service)) { Set providers = new HashSet(); - // in Acton, don't allow to specify more than 1 provider per service - if (svcPrv.get(serviceStr) != null && svcPrv.get(serviceStr).size() > 1) { + // Allow to specify more than 1 provider per service only if the service is LB + if (!serviceStr.equalsIgnoreCase(Service.Lb.getName()) && svcPrv.get(serviceStr) != null && svcPrv.get(serviceStr).size() > 1) { throw new InvalidParameterValueException("In the current release only one provider can be " + - "specified for the service"); + "specified for the service if the service is not LB"); } for (String prvNameStr : svcPrv.get(serviceStr)) { // check if provider is supported @@ -3508,9 +3525,26 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati firewallProviderSet.add(firewallProvider); serviceProviderMap.put(Service.Firewall, firewallProviderSet); } + + Map details = new HashMap(); + if (detailsStr != null) { + for (String detailStr : detailsStr.keySet()) { + NetworkOffering.Detail offDetail = null; + for (NetworkOffering.Detail supportedDetail: NetworkOffering.Detail.values()) { + if (detailStr.equalsIgnoreCase(supportedDetail.toString())) { + offDetail = supportedDetail; + break; + } + } + if (offDetail == null) { + throw new InvalidParameterValueException("Unsupported detail " + detailStr); + } + details.put(offDetail, detailsStr.get(detailStr)); + } + } return createNetworkOffering(name, displayText, trafficType, tags, specifyVlan, availability, networkRate, serviceProviderMap, false, guestType, false, - serviceOfferingId, conserveMode, serviceCapabilityMap, specifyIpRanges, isPersistent); + serviceOfferingId, conserveMode, serviceCapabilityMap, specifyIpRanges, isPersistent, details); } void validateLoadBalancerServiceCapabilities(Map lbServiceCapabilityMap) { @@ -3539,8 +3573,16 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if (!enabled && !disabled) { throw new InvalidParameterValueException("Unknown specified value for " + Capability.InlineMode.getName()); } + } else if (cap == Capability.LbSchemes) { + boolean internalLb = value.contains("internal"); + boolean publicLb = value.contains("public"); + if (!internalLb && !publicLb) { + throw new InvalidParameterValueException("Unknown specified value for " + Capability.LbSchemes.getName()); + } } else { - throw new InvalidParameterValueException("Only " + Capability.SupportedLBIsolation.getName() + ", " + Capability.ElasticLb.getName() + ", " + Capability.InlineMode.getName() + " capabilities can be sepcified for LB service"); + throw new InvalidParameterValueException("Only " + Capability.SupportedLBIsolation.getName() + + ", " + Capability.ElasticLb.getName() + ", " + Capability.InlineMode.getName() + + ", " + Capability.LbSchemes.getName() + " capabilities can be sepcified for LB service"); } } } @@ -3612,7 +3654,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati @DB public NetworkOfferingVO createNetworkOffering(String name, String displayText, TrafficType trafficType, String tags, boolean specifyVlan, Availability availability, Integer networkRate, Map> serviceProviderMap, boolean isDefault, Network.GuestType type, boolean systemOnly, Long serviceOfferingId, - boolean conserveMode, Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent) { + boolean conserveMode, Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent, Map details) { String multicastRateStr = _configDao.getValue("multicast.throttling.rate"); int multicastRate = ((multicastRateStr == null) ? 10 : Integer.parseInt(multicastRateStr)); @@ -3666,6 +3708,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati boolean elasticIp = false; boolean associatePublicIp = false; boolean inline = false; + boolean publicLb = false; + boolean internalLb = false; if (serviceCapabilityMap != null && !serviceCapabilityMap.isEmpty()) { Map lbServiceCapabilityMap = serviceCapabilityMap.get(Service.Lb); @@ -3690,6 +3734,23 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } else { inline = false; } + + String publicLbStr = lbServiceCapabilityMap.get(Capability.LbSchemes); + if (serviceProviderMap.containsKey(Service.Lb)) { + if (publicLbStr != null) { + _networkModel.checkCapabilityForProvider(serviceProviderMap.get(Service.Lb), Service.Lb, Capability.LbSchemes, publicLbStr); + internalLb = publicLbStr.contains("internal"); + publicLb = publicLbStr.contains("public"); + } else { + //if not specified, default public lb to true + publicLb = true; + } + } + } + + //in the current version of the code, publicLb and specificLb can't both be set to true for the same network offering + if (publicLb && internalLb) { + throw new InvalidParameterValueException("Public lb and internal lb can't be enabled at the same time on the offering"); } Map sourceNatServiceCapabilityMap = serviceCapabilityMap.get(Service.SourceNat); @@ -3724,18 +3785,23 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati NetworkOfferingVO offering = new NetworkOfferingVO(name, displayText, trafficType, systemOnly, specifyVlan, networkRate, multicastRate, isDefault, availability, tags, type, conserveMode, dedicatedLb, - sharedSourceNat, redundantRouter, elasticIp, elasticLb, specifyIpRanges, inline, isPersistent, associatePublicIp); + sharedSourceNat, redundantRouter, elasticIp, elasticLb, specifyIpRanges, inline, isPersistent, associatePublicIp, publicLb, internalLb); if (serviceOfferingId != null) { offering.setServiceOfferingId(serviceOfferingId); } + + //validate the details + if (details != null) { + validateNtwkOffDetails(details, serviceProviderMap); + } Transaction txn = Transaction.currentTxn(); txn.start(); - // create network offering object + //1) create network offering object s_logger.debug("Adding network offering " + offering); - offering = _networkOfferingDao.persist(offering); - // populate services and providers + offering = _networkOfferingDao.persist(offering, details); + //2) populate services and providers if (serviceProviderMap != null) { for (Network.Service service : serviceProviderMap.keySet()) { Set providers = serviceProviderMap.get(service); @@ -3769,6 +3835,42 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati return offering; } + protected void validateNtwkOffDetails(Map details, Map> serviceProviderMap) { + for (Detail detail : details.keySet()) { + + Provider lbProvider = null; + if (detail == NetworkOffering.Detail.InternalLbProvider || detail == NetworkOffering.Detail.PublicLbProvider) { + //1) Vaidate the detail values - have to match the lb provider name + String providerStr = details.get(detail); + if (Network.Provider.getProvider(providerStr) == null) { + throw new InvalidParameterValueException("Invalid value " + providerStr + " for the detail " + detail); + } + if (serviceProviderMap.get(Service.Lb) != null) { + for (Provider provider : serviceProviderMap.get(Service.Lb)) { + if (provider.getName().equalsIgnoreCase(providerStr)) { + lbProvider = provider; + break; + } + } + } + + if (lbProvider == null) { + throw new InvalidParameterValueException("Invalid value " + details.get(detail) + + " for the detail " + detail + ". The provider is not supported by the network offering"); + } + + //2) validate if the provider supports the scheme + Set lbProviders = new HashSet(); + lbProviders.add(lbProvider); + if (detail == NetworkOffering.Detail.InternalLbProvider) { + _networkModel.checkCapabilityForProvider(lbProviders, Service.Lb, Capability.LbSchemes, Scheme.Internal.toString()); + } else if (detail == NetworkOffering.Detail.PublicLbProvider){ + _networkModel.checkCapabilityForProvider(lbProviders, Service.Lb, Capability.LbSchemes, Scheme.Public.toString()); + } + } + } + } + @Override public List searchForNetworkOfferings(ListNetworkOfferingsCmd cmd) { @@ -3994,6 +4096,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati public boolean isOfferingForVpc(NetworkOffering offering) { boolean vpcProvider = _ntwkOffServiceMapDao.isProviderForNetworkOffering(offering.getId(), Provider.VPCVirtualRouter); + boolean internalLb = offering.getInternalLb(); return vpcProvider; } diff --git a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManager.java b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManager.java index 9f11b850180..cb00614b086 100644 --- a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManager.java +++ b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManager.java @@ -23,7 +23,7 @@ import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.host.Host; import com.cloud.network.dao.ExternalLoadBalancerDeviceVO; -import com.cloud.network.rules.FirewallRule; +import com.cloud.network.lb.LoadBalancingRule; import com.cloud.resource.ServerResource; import com.cloud.utils.component.Manager; @@ -89,7 +89,7 @@ public interface ExternalLoadBalancerDeviceManager extends Manager{ * @return true if successfully applied rules * @throws ResourceUnavailableException */ - public boolean applyLoadBalancerRules(Network network, List rules) throws ResourceUnavailableException; + public boolean applyLoadBalancerRules(Network network, List rules) throws ResourceUnavailableException; /** * implements or shutdowns guest network on the load balancer device assigned to the guest network @@ -102,6 +102,6 @@ public interface ExternalLoadBalancerDeviceManager extends Manager{ public boolean manageGuestNetworkWithExternalLoadBalancer(boolean add, Network guestConfig) throws ResourceUnavailableException, InsufficientCapacityException; - public List getLBHealthChecks(Network network, List rules) + public List getLBHealthChecks(Network network, List rules) throws ResourceUnavailableException; } diff --git a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java index 686f5bc2a05..f93bf7ae9b5 100644 --- a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java +++ b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java @@ -829,19 +829,11 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase } @Override - public boolean applyLoadBalancerRules(Network network, List rules) throws ResourceUnavailableException { + public boolean applyLoadBalancerRules(Network network, List loadBalancingRules) throws ResourceUnavailableException { // Find the external load balancer in this zone long zoneId = network.getDataCenterId(); DataCenterVO zone = _dcDao.findById(zoneId); - List loadBalancingRules = new ArrayList(); - - for (FirewallRule rule : rules) { - if (rule.getPurpose().equals(Purpose.LoadBalancing)) { - loadBalancingRules.add((LoadBalancingRule) rule); - } - } - if (loadBalancingRules == null || loadBalancingRules.isEmpty()) { return true; } @@ -870,12 +862,13 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase String protocol = rule.getProtocol(); String algorithm = rule.getAlgorithm(); String uuid = rule.getUuid(); - String srcIp = _networkModel.getIp(rule.getSourceIpAddressId()).getAddress().addr(); + String srcIp = rule.getSourceIp().addr(); int srcPort = rule.getSourcePortStart(); List destinations = rule.getDestinations(); if (externalLoadBalancerIsInline) { - MappingNic nic = getLoadBalancingIpNic(zone, network, rule.getSourceIpAddressId(), revoked, null); + long ipId = _networkModel.getPublicIpAddress(rule.getSourceIp().addr(), network.getDataCenterId()).getId(); + MappingNic nic = getLoadBalancingIpNic(zone, network, ipId, revoked, null); mappingStates.add(nic.getState()); NicVO loadBalancingIpNic = nic.getNic(); if (loadBalancingIpNic == null) { @@ -927,7 +920,8 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase } else { continue; } - getLoadBalancingIpNic(zone, network, rule.getSourceIpAddressId(), revoke, existedGuestIp); + long sourceIpId = _networkModel.getPublicIpAddress(rule.getSourceIp().addr(), network.getDataCenterId()).getId(); + getLoadBalancingIpNic(zone, network, sourceIpId, revoke, existedGuestIp); } } throw new ResourceUnavailableException(ex.getMessage(), DataCenter.class, network.getDataCenterId()); @@ -1113,7 +1107,7 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase } @Override - public List getLBHealthChecks(Network network, List rules) + public List getLBHealthChecks(Network network, List loadBalancingRules) throws ResourceUnavailableException { // Find the external load balancer in this zone @@ -1121,14 +1115,6 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase DataCenterVO zone = _dcDao.findById(zoneId); HealthCheckLBConfigAnswer answer = null; - List loadBalancingRules = new ArrayList(); - - for (FirewallRule rule : rules) { - if (rule.getPurpose().equals(Purpose.LoadBalancing)) { - loadBalancingRules.add((LoadBalancingRule) rule); - } - } - if (loadBalancingRules == null || loadBalancingRules.isEmpty()) { return null; } @@ -1158,12 +1144,13 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase String protocol = rule.getProtocol(); String algorithm = rule.getAlgorithm(); String uuid = rule.getUuid(); - String srcIp = _networkModel.getIp(rule.getSourceIpAddressId()).getAddress().addr(); + String srcIp = rule.getSourceIp().addr(); int srcPort = rule.getSourcePortStart(); List destinations = rule.getDestinations(); if (externalLoadBalancerIsInline) { - MappingNic nic = getLoadBalancingIpNic(zone, network, rule.getSourceIpAddressId(), revoked, null); + long sourceIpId = _networkModel.getPublicIpAddress(rule.getSourceIp().addr(), network.getDataCenterId()).getId(); + MappingNic nic = getLoadBalancingIpNic(zone, network, sourceIpId, revoked, null); mappingStates.add(nic.getState()); NicVO loadBalancingIpNic = nic.getNic(); if (loadBalancingIpNic == null) { diff --git a/server/src/com/cloud/network/ExternalLoadBalancerUsageManagerImpl.java b/server/src/com/cloud/network/ExternalLoadBalancerUsageManagerImpl.java index d405382f89c..2c8031c64f0 100644 --- a/server/src/com/cloud/network/ExternalLoadBalancerUsageManagerImpl.java +++ b/server/src/com/cloud/network/ExternalLoadBalancerUsageManagerImpl.java @@ -16,6 +16,22 @@ // under the License. package com.cloud.network; +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + import com.cloud.agent.AgentManager; import com.cloud.agent.api.ExternalNetworkResourceUsageAnswer; import com.cloud.agent.api.ExternalNetworkResourceUsageCommand; @@ -48,6 +64,7 @@ import com.cloud.network.dao.NetworkServiceMapDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.rules.PortForwardingRuleVO; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.offerings.dao.NetworkOfferingDao; @@ -68,20 +85,6 @@ import com.cloud.vm.DomainRouterVO; import com.cloud.vm.NicVO; import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.NicDao; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; @Component @Local(value = { ExternalLoadBalancerUsageManager.class }) @@ -647,9 +650,10 @@ public class ExternalLoadBalancerUsageManagerImpl extends ManagerBase implements // If an external load balancer is added, manage one entry for each load balancing rule in this network if (externalLoadBalancer != null && lbAnswer != null) { boolean inline = _networkMgr.isNetworkInlineMode(network); - List loadBalancers = _loadBalancerDao.listByNetworkId(network.getId()); + List loadBalancers = _loadBalancerDao.listByNetworkIdAndScheme(network.getId(), Scheme.Public); for (LoadBalancerVO loadBalancer : loadBalancers) { String publicIp = _networkMgr.getIp(loadBalancer.getSourceIpAddressId()).getAddress().addr(); + if (!createOrUpdateStatsEntry(create, accountId, zoneId, network.getId(), publicIp, externalLoadBalancer.getId(), lbAnswer, inline)) { throw new ExecutionException(networkErrorMsg + ", load balancing rule public IP = " + publicIp); } diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index 4af716ca12a..34a092a465a 100755 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -43,6 +43,7 @@ import com.cloud.network.element.StaticNatServiceProvider; import com.cloud.network.element.UserDataServiceProvider; import com.cloud.network.guru.NetworkGuru; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.rules.StaticNat; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.NetworkOfferingVO; @@ -333,7 +334,7 @@ public interface NetworkManager { int getRuleCountForIp(Long addressId, FirewallRule.Purpose purpose, FirewallRule.State state); - LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network); + LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network, Scheme lbScheme); boolean isSecondaryIpSetForNic(long nicId); diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 4fffbc11072..c91243095da 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -62,6 +62,13 @@ import com.cloud.network.guru.NetworkGuru; import com.cloud.network.lb.LoadBalancingRulesManager; import com.cloud.network.rules.*; import com.cloud.network.rules.FirewallRule.Purpose; +import com.cloud.network.rules.FirewallRuleVO; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.network.rules.PortForwardingRuleVO; +import com.cloud.network.rules.RulesManager; +import com.cloud.network.rules.StaticNat; +import com.cloud.network.rules.StaticNatRule; +import com.cloud.network.rules.StaticNatRuleImpl; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.vpc.NetworkACLManager; import com.cloud.network.vpc.VpcManager; @@ -72,6 +79,7 @@ import com.cloud.offering.NetworkOffering.Availability; import com.cloud.offerings.NetworkOfferingServiceMapVO; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.offerings.dao.NetworkOfferingDetailsDao; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.org.Grouping; import com.cloud.user.*; @@ -156,6 +164,8 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L @Inject PodVlanMapDao _podVlanMapDao; @Inject + NetworkOfferingDetailsDao _ntwkOffDetailsDao; + @Inject ConfigurationServer _configServer; @Inject AccountGuestVlanMapDao _accountGuestVlanMapDao; @@ -948,7 +958,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L _configMgr.createNetworkOffering(NetworkOffering.QuickCloudNoServices, "Offering for QuickCloud with no services", TrafficType.Guest, null, true, Availability.Optional, null, new HashMap>(), true, - Network.GuestType.Shared, false, null, true, null, true, false); + Network.GuestType.Shared, false, null, true, null, true, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -957,14 +967,14 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOfferingWithSGService, "Offering for Shared Security group enabled networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, - Network.GuestType.Shared, false, null, true, null, true, false); + Network.GuestType.Shared, false, null, true, null, true, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOffering, "Offering for Shared networks", TrafficType.Guest, null, true, Availability.Optional, null, - defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, null, true, false); + defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, null, true, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -987,7 +997,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingWithSourceNatService, "Offering for Isolated networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Required, null, defaultINetworkOfferingProvidersForVpcNetwork, - true, Network.GuestType.Isolated, false, null, true, null, false, false); + true, Network.GuestType.Isolated, false, null, true, null, false, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -996,7 +1006,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks, "Offering for Isolated VPC networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Optional, null, defaultVPCOffProviders, - true, Network.GuestType.Isolated, false, null, false, null, false, false); + true, Network.GuestType.Isolated, false, null, false, null, false, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -1007,7 +1017,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksNoLB, "Offering for Isolated VPC networks with Source Nat service enabled and LB service disabled", TrafficType.Guest, null, false, Availability.Optional, null, defaultVPCOffProviders, - true, Network.GuestType.Isolated, false, null, false, null, false, false); + true, Network.GuestType.Isolated, false, null, false, null, false, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -1016,7 +1026,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOffering, "Offering for Isolated networks with no Source Nat service", TrafficType.Guest, null, true, Availability.Optional, null, defaultIsolatedNetworkOfferingProviders, true, Network.GuestType.Isolated, - false, null, true, null, true, false); + false, null, true, null, true, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -1045,7 +1055,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedEIPandELBNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedEIPandELBNetworkOffering, "Offering for Shared networks with Elastic IP and Elastic LB capabilities", TrafficType.Guest, null, true, - Availability.Optional, null, netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false); + Availability.Optional, null, netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, null); offering.setState(NetworkOffering.State.Enabled); offering.setDedicatedLB(false); _networkOfferingDao.update(offering.getId(), offering); @@ -2651,9 +2661,15 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L success = false; } - // apply load balancer rules - if (!_lbMgr.applyLoadBalancersForNetwork(networkId)) { - s_logger.warn("Failed to reapply load balancer rules as a part of network id=" + networkId + " restart"); + // apply public load balancer rules + if (!_lbMgr.applyLoadBalancersForNetwork(networkId, Scheme.Public)) { + s_logger.warn("Failed to reapply Public load balancer rules as a part of network id=" + networkId + " restart"); + success = false; + } + + // apply internal load balancer rules + if (!_lbMgr.applyLoadBalancersForNetwork(networkId, Scheme.Internal)) { + s_logger.warn("Failed to reapply internal load balancer rules as a part of network id=" + networkId + " restart"); success = false; } @@ -3234,12 +3250,22 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L } try { - if (!_lbMgr.revokeLoadBalancersForNetwork(networkId)) { - s_logger.warn("Failed to cleanup lb rules as a part of shutdownNetworkRules"); + if (!_lbMgr.revokeLoadBalancersForNetwork(networkId, Scheme.Public)) { + s_logger.warn("Failed to cleanup public lb rules as a part of shutdownNetworkRules"); success = false; } } catch (ResourceUnavailableException ex) { - s_logger.warn("Failed to cleanup lb rules as a part of shutdownNetworkRules due to ", ex); + s_logger.warn("Failed to cleanup public lb rules as a part of shutdownNetworkRules due to ", ex); + success = false; + } + + try { + if (!_lbMgr.revokeLoadBalancersForNetwork(networkId, Scheme.Internal)) { + s_logger.warn("Failed to cleanup internal lb rules as a part of shutdownNetworkRules"); + success = false; + } + } catch (ResourceUnavailableException ex) { + s_logger.warn("Failed to cleanup public lb rules as a part of shutdownNetworkRules due to ", ex); success = false; } @@ -3645,7 +3671,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L } } } else { - NicVO nicVO = _nicDao.findByInstanceIdAndNetworkId(network.getId(), vm.getId()); + NicVO nicVO = _nicDao.findByNtwkIdAndInstanceId(network.getId(), vm.getId()); if (nicVO != null) { nic = _networkModel.getNicProfile(vm, network.getId(), null); } @@ -3747,35 +3773,62 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L return null; } - protected NetworkElement getElementForServiceInNetwork(Network network, Service service) { + protected List getElementForServiceInNetwork(Network network, Service service) { + List elements = new ArrayList(); List providers = getProvidersForServiceInNetwork(network, service); //Only support one provider now if (providers == null) { s_logger.error("Cannot find " + service.getName() + " provider for network " + network.getId()); return null; } - if (providers.size() != 1) { + if (providers.size() != 1 && service != Service.Lb) { + //support more than one LB providers only s_logger.error("Found " + providers.size() + " " + service.getName() + " providers for network!" + network.getId()); return null; + } + + for (Provider provider : providers) { + NetworkElement element = _networkModel.getElementImplementingProvider(provider.getName()); + s_logger.info("Let " + element.getName() + " handle " + service.getName() + " in network " + network.getId()); + elements.add(element); } - NetworkElement element = _networkModel.getElementImplementingProvider(providers.get(0).getName()); - s_logger.info("Let " + element.getName() + " handle " + service.getName() + " in network " + network.getId()); - return element; + return elements; } @Override public StaticNatServiceProvider getStaticNatProviderForNetwork(Network network) { - NetworkElement element = getElementForServiceInNetwork(network, Service.StaticNat); + //only one provider per Static nat service is supoprted + NetworkElement element = getElementForServiceInNetwork(network, Service.StaticNat).get(0); assert element instanceof StaticNatServiceProvider; return (StaticNatServiceProvider)element; } @Override - public LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network) { - NetworkElement element = getElementForServiceInNetwork(network, Service.Lb); - assert element instanceof LoadBalancingServiceProvider; - return (LoadBalancingServiceProvider)element; + public LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network, Scheme lbScheme) { + List lbElements = getElementForServiceInNetwork(network, Service.Lb); + NetworkElement lbElement = null; + if (lbElements.size() > 1) { + String providerName = null; + //get network offering details + NetworkOffering off = _configMgr.getNetworkOffering(network.getNetworkOfferingId()); + if (lbScheme == Scheme.Public) { + providerName = _ntwkOffDetailsDao.getDetail(off.getId(), NetworkOffering.Detail.PublicLbProvider); + } else { + providerName = _ntwkOffDetailsDao.getDetail(off.getId(), NetworkOffering.Detail.InternalLbProvider); + } + if (providerName == null) { + throw new InvalidParameterValueException("Can't find Lb provider supporting scheme " + lbScheme.toString() + " in network " + network); + } + lbElement = _networkModel.getElementImplementingProvider(providerName); + } else if (lbElements.size() == 1){ + lbElement = lbElements.get(0); + } + + assert lbElement != null; + assert lbElement instanceof LoadBalancingServiceProvider; + return (LoadBalancingServiceProvider)lbElement; } + @Override public boolean isNetworkInlineMode(Network network) { NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); diff --git a/server/src/com/cloud/network/NetworkModelImpl.java b/server/src/com/cloud/network/NetworkModelImpl.java index eaec6a6b42f..135fd290535 100755 --- a/server/src/com/cloud/network/NetworkModelImpl.java +++ b/server/src/com/cloud/network/NetworkModelImpl.java @@ -32,6 +32,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -52,13 +53,11 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.UnsupportedServiceException; import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.server.ConfigurationServer; import com.cloud.network.IpAddress.State; import com.cloud.network.Network.Capability; import com.cloud.network.Network.GuestType; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; -import com.cloud.network.Networks.IsolationType; import com.cloud.network.Networks.TrafficType; import com.cloud.network.addr.PublicIp; import com.cloud.network.dao.FirewallRulesDao; @@ -86,11 +85,14 @@ import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.vpc.dao.PrivateIpDao; import com.cloud.offering.NetworkOffering; +import com.cloud.offering.NetworkOffering.Detail; import com.cloud.offerings.NetworkOfferingServiceMapVO; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.offerings.dao.NetworkOfferingDetailsDao; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.projects.dao.ProjectAccountDao; +import com.cloud.server.ConfigurationServer; import com.cloud.user.Account; import com.cloud.user.AccountVO; import com.cloud.user.DomainManager; @@ -183,9 +185,13 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { @Inject UserIpv6AddressDao _ipv6Dao; @Inject - NicSecondaryIpDao _nicSecondaryIpDao;; + NicSecondaryIpDao _nicSecondaryIpDao; + @Inject + ApplicationLoadBalancerRuleDao _appLbRuleDao; @Inject private ProjectAccountDao _projectAccountDao; + @Inject + NetworkOfferingDetailsDao _ntwkOffDetailsDao; private final HashMap _systemNetworks = new HashMap(5); static Long _privateOfferingId = null; @@ -604,7 +610,6 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { NetworkElement element = getElementImplementingProvider(instance.getProvider()); if (element != null) { Map> elementCapabilities = element.getCapabilities(); - ; if (elementCapabilities != null) { networkCapabilities.put(service, elementCapabilities.get(service)); } @@ -917,7 +922,7 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { boolean isUserVmsDefaultNetwork = false; boolean isDomRGuestOrPublicNetwork = false; if (vm != null) { - Nic nic = _nicDao.findByInstanceIdAndNetworkId(networkId, vmId); + Nic nic = _nicDao.findByNtwkIdAndInstanceId(networkId, vmId); if (vm.getType() == Type.User && nic != null && nic.isDefaultNic()) { isUserVmsDefaultNetwork = true; } else if (vm.getType() == Type.DomainRouter && ntwkOff != null && (ntwkOff.getTrafficType() == TrafficType.Public || ntwkOff.getTrafficType() == TrafficType.Guest)) { @@ -1465,10 +1470,8 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { throw new UnsupportedServiceException("Service " + service.getName() + " doesn't have capability " + cap.getName() + " for element=" + element.getName() + " implementing Provider=" + provider.getName()); } - - capValue = capValue.toLowerCase(); - - if (!value.contains(capValue)) { + + if (!value.toLowerCase().contains(capValue.toLowerCase())) { throw new UnsupportedServiceException("Service " + service.getName() + " doesn't support value " + capValue + " for capability " + cap.getName() + " for element=" + element.getName() + " implementing Provider=" + provider.getName()); } @@ -1664,9 +1667,7 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { @Override public Set getAvailableIps(Network network, String requestedIp) { String[] cidr = network.getCidr().split("/"); - List ips = _nicDao.listIpAddressInNetwork(network.getId()); - List secondaryIps = _nicSecondaryIpDao.listSecondaryIpAddressInNetwork(network.getId()); - ips.addAll(secondaryIps); + List ips = getUsedIpsInNetwork(network); Set usedIps = new TreeSet(); for (String ip : ips) { @@ -1677,6 +1678,7 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { usedIps.add(NetUtils.ip2Long(ip)); } + Set allPossibleIps = NetUtils.getAllIpsFromCidr(cidr[0], Integer.parseInt(cidr[1]), usedIps); String gateway = network.getGateway(); @@ -1685,6 +1687,19 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { return allPossibleIps; } + + @Override + public List getUsedIpsInNetwork(Network network) { + //Get all ips used by vms nics + List ips = _nicDao.listIpAddressInNetwork(network.getId()); + //Get all secondary ips for nics + List secondaryIps = _nicSecondaryIpDao.listSecondaryIpAddressInNetwork(network.getId()); + ips.addAll(secondaryIps); + //Get ips used by load balancers + List lbIps = _appLbRuleDao.listLbIpsBySourceIpNetworkId(network.getId()); + ips.addAll(lbIps); + return ips; + } @Override public String getDomainNetworkDomain(long domainId, long zoneId) { @@ -1792,7 +1807,7 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { if (broadcastUri != null) { nic = _nicDao.findByNetworkIdInstanceIdAndBroadcastUri(networkId, vm.getId(), broadcastUri); } else { - nic = _nicDao.findByInstanceIdAndNetworkId(networkId, vm.getId()); + nic = _nicDao.findByNtwkIdAndInstanceId(networkId, vm.getId()); } if (nic == null) { return null; @@ -2051,6 +2066,22 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { return null; } + + @Override + public IpAddress getPublicIpAddress(String ipAddress, long zoneId) { + List networks = _networksDao.listByZoneAndTrafficType(zoneId, TrafficType.Public); + if (networks.isEmpty() || networks.size() > 1) { + throw new CloudRuntimeException("Can't find public network in the zone specified"); + } + + return _ipAddressDao.findByIpAndSourceNetworkId(networks.get(0).getId(), ipAddress); + } + + @Override + public Map getNtwkOffDetails(long offId) { + return _ntwkOffDetailsDao.getNtwkOffDetails(offId); + } + @Override public Networks.IsolationType[] listNetworkIsolationMethods() { diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index f44688c7594..88155582569 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -47,6 +47,7 @@ import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; +import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -170,6 +171,33 @@ import com.cloud.vm.dao.NicSecondaryIpDao; import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; +import com.cloud.vm.*; +import com.cloud.vm.dao.*; +import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.acl.SecurityChecker; +import org.apache.cloudstack.acl.SecurityChecker.AccessType; +import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd; +import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd; +import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; +import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; +import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; +import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; +import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.security.InvalidParameterException; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; + /** * NetworkServiceImpl implements NetworkService. @@ -267,6 +295,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { HostDao _hostDao; @Inject HostPodDao _hostPodDao; + @Inject + InternalLoadBalancerElementService _internalLbElementSvc; @Inject DataCenterVnetDao _datacneter_vnet; @Inject @@ -1187,6 +1217,10 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { if (_configMgr.isOfferingForVpc(ntwkOff)){ throw new InvalidParameterValueException("Network offering can be used for VPC networks only"); } + if (ntwkOff.getInternalLb()) { + throw new InvalidParameterValueException("Internal Lb can be enabled on vpc networks only"); + } + network = _networkMgr.createGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId, networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, ip6Gateway, ip6Cidr); } @@ -2134,8 +2168,6 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } - - protected Set getAvailableIps(Network network, String requestedIp) { String[] cidr = network.getCidr().split("/"); List ips = _nicDao.listIpAddressInNetwork(network.getId()); @@ -2159,7 +2191,6 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } - protected boolean canUpgrade(Network network, long oldNetworkOfferingId, long newNetworkOfferingId) { NetworkOffering oldNetworkOffering = _networkOfferingDao.findByIdIncludingRemoved(oldNetworkOfferingId); NetworkOffering newNetworkOffering = _networkOfferingDao.findById(newNetworkOfferingId); @@ -2225,6 +2256,14 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { return false; } } + + //can't update from internal LB to public LB + if (areServicesSupportedByNetworkOffering(oldNetworkOfferingId, Service.Lb) && areServicesSupportedByNetworkOffering(newNetworkOfferingId, Service.Lb)) { + if (oldNetworkOffering.getPublicLb() != newNetworkOffering.getPublicLb() || oldNetworkOffering.getInternalLb() != newNetworkOffering.getInternalLb()) { + throw new InvalidParameterValueException("Original and new offerings support different types of LB - Internal vs Public," + + " can't upgrade"); + } + } return canIpsUseOffering(publicIps, newNetworkOfferingId); } @@ -2345,7 +2384,10 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { // add baremetal as the defualt network service provider /* addDefaultBaremetalProvidersToPhysicalNetwork(pNetwork.getId()); */ - + + //Add Internal Load Balancer element as a default network service provider + addDefaultInternalLbProviderToPhysicalNetwork(pNetwork.getId()); + txn.commit(); return pNetwork; } catch (Exception ex) { @@ -3564,6 +3606,22 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { return nsp; } + + + protected PhysicalNetworkServiceProvider addDefaultInternalLbProviderToPhysicalNetwork(long physicalNetworkId) { + + PhysicalNetworkServiceProvider nsp = addProviderToPhysicalNetwork(physicalNetworkId, + Network.Provider.InternalLbVm.getName(), null, null); + + NetworkElement networkElement = _networkModel.getElementImplementingProvider(Network.Provider.InternalLbVm.getName()); + if (networkElement == null) { + throw new CloudRuntimeException("Unable to find the Network Element implementing the " + Network.Provider.InternalLbVm.getName() + " Provider"); + } + + _internalLbElementSvc.addInternalLoadBalancerElement(nsp.getId()); + + return nsp; + } protected PhysicalNetworkServiceProvider addDefaultSecurityGroupProviderToPhysicalNetwork(long physicalNetworkId) { @@ -3572,6 +3630,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { return nsp; } + + private PhysicalNetworkServiceProvider addDefaultBaremetalProvidersToPhysicalNetwork(long physicalNetworkId) { PhysicalNetworkVO pvo = _physicalNetworkDao.findById(physicalNetworkId); diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java index f601f4fa2e4..28473cc7bc2 100755 --- a/server/src/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VirtualRouterElement.java @@ -25,7 +25,6 @@ import java.util.Set; import javax.ejb.Local; import javax.inject.Inject; -import com.cloud.utils.PropertiesUtil; import org.apache.cloudstack.api.command.admin.router.ConfigureVirtualRouterElementCmd; import org.apache.cloudstack.api.command.admin.router.CreateVirtualRouterElementCmd; import org.apache.cloudstack.api.command.admin.router.ListVirtualRouterElementsCmd; @@ -66,6 +65,7 @@ import com.cloud.network.router.VpcVirtualNetworkApplianceManager; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.LbStickinessMethod; import com.cloud.network.rules.LbStickinessMethod.StickinessMethodType; +import com.cloud.network.rules.LoadBalancerContainer; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.RulesManager; import com.cloud.network.rules.StaticNat; @@ -242,7 +242,7 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl * number like 12 2) time or tablesize like 12h, 34m, 45k, 54m , here * last character is non-digit but from known characters . */ - private boolean containsOnlyNumbers(String str, String endChar) { + private static boolean containsOnlyNumbers(String str, String endChar) { if (str == null) return false; @@ -271,7 +271,7 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl return true; } - private boolean validateHAProxyLBRule(LoadBalancingRule rule) { + public static boolean validateHAProxyLBRule(LoadBalancingRule rule) { String timeEndChar = "dhms"; for (LbStickinessPolicy stickinessPolicy : rule.getStickinessPolicies()) { @@ -338,7 +338,9 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl @Override public boolean validateLBRule(Network network, LoadBalancingRule rule) { - if (canHandle(network, Service.Lb)) { + List rules = new ArrayList(); + rules.add(rule); + if (canHandle(network, Service.Lb) && canHandleLbRules(rules)) { List routers = _routerDao.listByNetworkAndRole(network.getId(), Role.VIRTUAL_ROUTER); if (routers == null || routers.isEmpty()) { return true; @@ -351,6 +353,10 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl @Override public boolean applyLBRules(Network network, List rules) throws ResourceUnavailableException { if (canHandle(network, Service.Lb)) { + if (!canHandleLbRules(rules)) { + return false; + } + List routers = _routerDao.listByNetworkAndRole(network.getId(), Role.VIRTUAL_ROUTER); if (routers == null || routers.isEmpty()) { s_logger.debug("Virtual router elemnt doesn't need to apply firewall rules on the backend; virtual " + @@ -358,8 +364,8 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl return true; } - if (!_routerMgr.applyFirewallRules(network, rules, routers)) { - throw new CloudRuntimeException("Failed to apply firewall rules in network " + network.getId()); + if (!_routerMgr.applyLoadBalancingRules(network, rules, routers)) { + throw new CloudRuntimeException("Failed to apply load balancing rules in network " + network.getId()); } else { return true; } @@ -452,7 +458,7 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl return capabilities; } - private static String getHAProxyStickinessCapability() { + public static String getHAProxyStickinessCapability() { LbStickinessMethod method; List methodList = new ArrayList(1); @@ -557,8 +563,8 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl lbCapabilities.put(Capability.SupportedLBAlgorithms, "roundrobin,leastconn,source"); lbCapabilities.put(Capability.SupportedLBIsolation, "dedicated"); lbCapabilities.put(Capability.SupportedProtocols, "tcp, udp"); - lbCapabilities.put(Capability.SupportedStickinessMethods, getHAProxyStickinessCapability()); + lbCapabilities.put(Capability.LbSchemes, LoadBalancerContainer.Scheme.Public.toString()); capabilities.put(Service.Lb, lbCapabilities); @@ -715,8 +721,8 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl @Override public VirtualRouterProvider configure(ConfigureVirtualRouterElementCmd cmd) { VirtualRouterProviderVO element = _vrProviderDao.findById(cmd.getId()); - if (element == null) { - s_logger.debug("Can't find element with network service provider id " + cmd.getId()); + if (element == null || !(element.getType() == VirtualRouterProviderType.VirtualRouter || element.getType() == VirtualRouterProviderType.VPCVirtualRouter)) { + s_logger.debug("Can't find Virtual Router element with network service provider id " + cmd.getId()); return null; } @@ -728,6 +734,10 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl @Override public VirtualRouterProvider addElement(Long nspId, VirtualRouterProviderType providerType) { + if (!(providerType == VirtualRouterProviderType.VirtualRouter || providerType == VirtualRouterProviderType.VPCVirtualRouter)) { + throw new InvalidParameterValueException("Element " + this.getName() + " supports only providerTypes: " + + VirtualRouterProviderType.VirtualRouter.toString() + " and " + VirtualRouterProviderType.VPCVirtualRouter); + } VirtualRouterProviderVO element = _vrProviderDao.findByNspIdAndType(nspId, providerType); if (element != null) { s_logger.debug("There is already a virtual router element with service provider id " + nspId); @@ -801,7 +811,11 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl @Override public VirtualRouterProvider getCreatedElement(long id) { - return _vrProviderDao.findById(id); + VirtualRouterProvider provider = _vrProviderDao.findById(id); + if (!(provider.getType() == VirtualRouterProviderType.VirtualRouter || provider.getType() == VirtualRouterProviderType.VPCVirtualRouter)) { + throw new InvalidParameterValueException("Unable to find provider by id"); + } + return provider; } @Override @@ -911,6 +925,10 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl if (enabled != null) { sc.addAnd(sc.getEntity().isEnabled(), Op.EQ, enabled); } + + //return only VR and VPC VR + sc.addAnd(sc.getEntity().getType(), Op.IN, VirtualRouterProvider.VirtualRouterProviderType.VPCVirtualRouter, VirtualRouterProvider.VirtualRouterProviderType.VirtualRouter); + return sc.list(); } @@ -946,4 +964,20 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl // TODO Auto-generated method stub return null; } + + private boolean canHandleLbRules(List rules) { + Map lbCaps = this.getCapabilities().get(Service.Lb); + if (!lbCaps.isEmpty()) { + String schemeCaps = lbCaps.get(Capability.LbSchemes); + if (schemeCaps != null) { + for (LoadBalancingRule rule : rules) { + if (!schemeCaps.contains(rule.getScheme().toString())) { + s_logger.debug("Scheme " + rules.get(0).getScheme() + " is not supported by the provider " + this.getName()); + return false; + } + } + } + } + return true; + } } diff --git a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java index 4ad8868b86a..def4c1ed06f 100644 --- a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java +++ b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java @@ -27,17 +27,12 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.api.command.user.firewall.ListEgressFirewallRulesCmd; import com.cloud.network.dao.*; import org.apache.cloudstack.api.command.user.firewall.ListFirewallRulesCmd; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import com.mysql.jdbc.ConnectionPropertiesImpl; -import org.apache.log4j.Logger; - -import org.apache.cloudstack.api.BaseListCmd; -import org.apache.cloudstack.api.command.user.firewall.ListEgressFirewallRulesCmd; -import org.apache.cloudstack.api.command.user.firewall.ListFirewallRulesCmd; import com.cloud.configuration.Config; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.domain.dao.DomainDao; @@ -53,7 +48,6 @@ import com.cloud.network.IpAddress; import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Service; -import com.cloud.network.Networks.TrafficType; import com.cloud.network.NetworkManager; import com.cloud.network.NetworkModel; import com.cloud.network.NetworkRuleApplier; @@ -61,10 +55,15 @@ import com.cloud.network.element.FirewallServiceProvider; import com.cloud.network.element.NetworkACLServiceProvider; import com.cloud.network.element.PortForwardingServiceProvider; import com.cloud.network.element.StaticNatServiceProvider; -import com.cloud.network.rules.*; +import com.cloud.network.rules.FirewallManager; +import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.FirewallRuleType; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRule.State; +import com.cloud.network.rules.FirewallRuleVO; +import com.cloud.network.rules.PortForwardingRule; +import com.cloud.network.rules.PortForwardingRuleVO; +import com.cloud.network.rules.StaticNat; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.vpc.VpcManager; import com.cloud.projects.Project.ListProjectResourcesCriteria; @@ -83,8 +82,8 @@ import com.cloud.utils.db.Filter; import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.*; import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.vm.UserVmVO; @@ -438,22 +437,28 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, return; } - if (ipAddress!=null){ - if (ipAddress.getAssociatedWithNetworkId() == null) { - throw new InvalidParameterValueException("Unable to create firewall rule ; ip with specified id is not associated with any network"); - } else { - networkId = ipAddress.getAssociatedWithNetworkId(); - } - + if (ipAddress != null){ + if (ipAddress.getAssociatedWithNetworkId() == null) { + throw new InvalidParameterValueException("Unable to create firewall rule ; ip with specified id is not associated with any network"); + } else { + networkId = ipAddress.getAssociatedWithNetworkId(); + } + // Validate ip address _accountMgr.checkAccess(caller, null, true, ipAddress); - + } + + //network id either has to be passed explicitly, or implicitly as a part of ipAddress object + if (networkId == null) { + throw new InvalidParameterValueException("Unable to retrieve network id to validate the rule"); + } + Network network = _networkModel.getNetwork(networkId); - assert network != null : "Can't create port forwarding rule as network associated with public ip address is null?"; + assert network != null : "Can't create rule as network associated with public ip address is null?"; - if (trafficType == FirewallRule.TrafficType.Egress) { - _accountMgr.checkAccess(caller, null, true, network); - } + if (trafficType == FirewallRule.TrafficType.Egress) { + _accountMgr.checkAccess(caller, null, true, network); + } // Verify that the network guru supports the protocol specified Map caps = null; @@ -464,32 +469,32 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, } } else if (purpose == Purpose.PortForwarding) { caps = _networkModel.getNetworkServiceCapabilities(network.getId(), Service.PortForwarding); - }else if (purpose == Purpose.Firewall){ - caps = _networkModel.getNetworkServiceCapabilities(network.getId(),Service.Firewall); + } else if (purpose == Purpose.Firewall){ + caps = _networkModel.getNetworkServiceCapabilities(network.getId(),Service.Firewall); } if (caps != null) { - String supportedProtocols; - String supportedTrafficTypes = null; - if (purpose == FirewallRule.Purpose.Firewall) { - supportedTrafficTypes = caps.get(Capability.SupportedTrafficDirection).toLowerCase(); - } + String supportedProtocols; + String supportedTrafficTypes = null; + if (purpose == FirewallRule.Purpose.Firewall) { + supportedTrafficTypes = caps.get(Capability.SupportedTrafficDirection).toLowerCase(); + } - if (purpose == FirewallRule.Purpose.Firewall && trafficType == FirewallRule.TrafficType.Egress) { - supportedProtocols = caps.get(Capability.SupportedEgressProtocols).toLowerCase(); - } else { - supportedProtocols = caps.get(Capability.SupportedProtocols).toLowerCase(); - } + if (purpose == FirewallRule.Purpose.Firewall && trafficType == FirewallRule.TrafficType.Egress) { + supportedProtocols = caps.get(Capability.SupportedEgressProtocols).toLowerCase(); + } else { + supportedProtocols = caps.get(Capability.SupportedProtocols).toLowerCase(); + } if (!supportedProtocols.contains(proto.toLowerCase())) { throw new InvalidParameterValueException("Protocol " + proto + " is not supported in zone " + network.getDataCenterId()); } else if (proto.equalsIgnoreCase(NetUtils.ICMP_PROTO) && purpose != Purpose.Firewall) { throw new InvalidParameterValueException("Protocol " + proto + " is currently supported only for rules with purpose " + Purpose.Firewall); - } else if (purpose == Purpose.Firewall && !supportedTrafficTypes.contains(trafficType.toString().toLowerCase())) { - throw new InvalidParameterValueException("Traffic Type " + trafficType + " is currently supported by Firewall in network " + networkId); - } + } else if (purpose == Purpose.Firewall && !supportedTrafficTypes.contains(trafficType.toString().toLowerCase())) { + throw new InvalidParameterValueException("Traffic Type " + trafficType + " is currently supported by Firewall in network " + networkId); } } + } @Override diff --git a/server/src/com/cloud/network/guru/GuestNetworkGuru.java b/server/src/com/cloud/network/guru/GuestNetworkGuru.java index 291e3ccbc77..32ce744979b 100755 --- a/server/src/com/cloud/network/guru/GuestNetworkGuru.java +++ b/server/src/com/cloud/network/guru/GuestNetworkGuru.java @@ -223,48 +223,7 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur nic.deallocate(); } } - - public Ip4Address acquireIp4Address(Network network, Ip4Address requestedIp, String reservationId) { - List ips = _nicDao.listIpAddressInNetwork(network.getId()); - String[] cidr = network.getCidr().split("/"); - SortedSet usedIps = new TreeSet(); - - if (requestedIp != null && requestedIp.equals(network.getGateway())) { - s_logger.warn("Requested ip address " + requestedIp + " is used as a gateway address in network " + network); - return null; - } - - for (String ip : ips) { - usedIps.add(NetUtils.ip2Long(ip)); - } - - if (network.getGateway() != null) { - usedIps.add(NetUtils.ip2Long(network.getGateway())); - } - - if (requestedIp != null) { - if (usedIps.contains(requestedIp.toLong())) { - s_logger.warn("Requested ip address " + requestedIp + " is already in used in " + network); - return null; - } - //check that requested ip has the same cidr - boolean isSameCidr = NetUtils.sameSubnetCIDR(requestedIp.ip4(), cidr[0], Integer.parseInt(cidr[1])); - if (!isSameCidr) { - s_logger.warn("Requested ip address " + requestedIp + " doesn't belong to the network " + network + " cidr"); - return null; - } - - return requestedIp; - } - - long ip = NetUtils.getRandomIpFromCidr(cidr[0], Integer.parseInt(cidr[1]), usedIps); - if (ip == -1) { - s_logger.warn("Unable to allocate any more ip address in " + network); - return null; - } - - return new Ip4Address(ip); - } + public int getVlanOffset(long physicalNetworkId, int vlanTag) { PhysicalNetworkVO pNetwork = _physicalNetworkDao.findById(physicalNetworkId); diff --git a/server/src/com/cloud/network/lb/LBHealthCheckManager.java b/server/src/com/cloud/network/lb/LBHealthCheckManager.java index 2e24965aa35..a9969eb7ce1 100644 --- a/server/src/com/cloud/network/lb/LBHealthCheckManager.java +++ b/server/src/com/cloud/network/lb/LBHealthCheckManager.java @@ -16,9 +16,11 @@ // under the License. package com.cloud.network.lb; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; + public interface LBHealthCheckManager { - void updateLBHealthCheck(); + void updateLBHealthCheck(Scheme scheme); } diff --git a/server/src/com/cloud/network/lb/LBHealthCheckManagerImpl.java b/server/src/com/cloud/network/lb/LBHealthCheckManagerImpl.java index 90547328714..62b738bb498 100644 --- a/server/src/com/cloud/network/lb/LBHealthCheckManagerImpl.java +++ b/server/src/com/cloud/network/lb/LBHealthCheckManagerImpl.java @@ -19,7 +19,6 @@ package com.cloud.network.lb; import static java.lang.String.format; import java.util.Map; - import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -34,6 +33,7 @@ import org.springframework.stereotype.Component; import com.cloud.configuration.Config; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.utils.NumbersUtil; import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; @@ -90,7 +90,8 @@ public class LBHealthCheckManagerImpl extends ManagerBase implements LBHealthChe @Override public void run() { try { - updateLBHealthCheck(); + updateLBHealthCheck(Scheme.Public); + updateLBHealthCheck(Scheme.Internal); } catch (Exception e) { s_logger.error("Exception in LB HealthCheck Update Checker", e); } @@ -98,9 +99,9 @@ public class LBHealthCheckManagerImpl extends ManagerBase implements LBHealthChe } @Override - public void updateLBHealthCheck() { + public void updateLBHealthCheck(Scheme scheme) { try { - _lbService.updateLBHealthChecks(); + _lbService.updateLBHealthChecks(scheme); } catch (ResourceUnavailableException e) { s_logger.debug("Error while updating the LB HealtCheck ", e); } diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManager.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManager.java index d98872a0906..a23d96f8aea 100644 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManager.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManager.java @@ -16,23 +16,24 @@ // under the License. package com.cloud.network.lb; +import java.util.List; + import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceUnavailableException; -import com.cloud.network.Network; import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.lb.LoadBalancingRule.LbHealthCheckPolicy; import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; -import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.LbStickinessMethod; import com.cloud.network.rules.LoadBalancer; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.user.Account; -import org.apache.cloudstack.api.command.user.loadbalancer.CreateLoadBalancerRuleCmd; - -import java.util.List; +import com.cloud.user.UserContext; public interface LoadBalancingRulesManager extends LoadBalancingRulesService { - LoadBalancer createLoadBalancer(CreateLoadBalancerRuleCmd lb, boolean openFirewall) throws NetworkRuleConflictException; + LoadBalancer createPublicLoadBalancer(String xId, String name, String description, + int srcPort, int destPort, long sourceIpId, String protocol, String algorithm, boolean openFirewall, UserContext caller) + throws NetworkRuleConflictException; boolean removeAllLoadBalanacersForIp(long ipId, Account caller, long callerUserId); boolean removeAllLoadBalanacersForNetwork(long networkId, Account caller, long callerUserId); @@ -47,9 +48,14 @@ public interface LoadBalancingRulesManager extends LoadBalancingRulesService { * @return true if removal is successful */ boolean removeVmFromLoadBalancers(long vmId); - boolean applyRules(Network network, FirewallRule.Purpose purpose, List rules) throws ResourceUnavailableException ; - boolean applyLoadBalancersForNetwork(long networkId) throws ResourceUnavailableException; + boolean applyLoadBalancersForNetwork(long networkId, Scheme scheme) throws ResourceUnavailableException; String getLBCapability(long networkid, String capabilityName); boolean configureLbAutoScaleVmGroup(long vmGroupid, String currentState) throws ResourceUnavailableException; - boolean revokeLoadBalancersForNetwork(long networkId) throws ResourceUnavailableException; + boolean revokeLoadBalancersForNetwork(long networkId, Scheme scheme) throws ResourceUnavailableException; + + boolean validateLbRule(LoadBalancingRule lbRule); + + void removeLBRule(LoadBalancer rule); + + void isLbServiceSupportedInNetwork(long networkId, Scheme scheme); } diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index 7ad1070e1c7..520dd763667 100755 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -16,6 +16,34 @@ // under the License. package com.cloud.network.lb; +import java.security.InvalidParameterException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.ejb.Local; +import javax.inject.Inject; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.command.user.loadbalancer.CreateLBHealthCheckPolicyCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.CreateLBStickinessPolicyCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListLBHealthCheckPoliciesCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListLBStickinessPoliciesCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerRuleInstancesCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerRulesCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.UpdateLoadBalancerRuleCmd; +import org.apache.cloudstack.api.response.ServiceResponse; +import org.apache.cloudstack.lb.ApplicationLoadBalancerRuleVO; +import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + import com.cloud.agent.api.to.LoadBalancerTO; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; @@ -30,21 +58,70 @@ import com.cloud.event.EventTypes; import com.cloud.event.UsageEventUtils; import com.cloud.event.dao.EventDao; import com.cloud.event.dao.UsageEventDao; -import com.cloud.exception.*; -import com.cloud.network.*; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.ExternalLoadBalancerUsageManager; +import com.cloud.network.IpAddress; +import com.cloud.network.LBHealthCheckPolicyVO; +import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; -import com.cloud.network.as.*; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkModel; +import com.cloud.network.addr.PublicIp; +import com.cloud.network.as.AutoScalePolicy; +import com.cloud.network.as.AutoScalePolicyConditionMapVO; +import com.cloud.network.as.AutoScaleVmGroup; +import com.cloud.network.as.AutoScaleVmGroupPolicyMapVO; +import com.cloud.network.as.AutoScaleVmGroupVO; +import com.cloud.network.as.AutoScaleVmProfile; import com.cloud.network.as.Condition; -import com.cloud.network.as.dao.*; -import com.cloud.network.dao.*; +import com.cloud.network.as.Counter; +import com.cloud.network.as.dao.AutoScalePolicyConditionMapDao; +import com.cloud.network.as.dao.AutoScalePolicyDao; +import com.cloud.network.as.dao.AutoScaleVmGroupDao; +import com.cloud.network.as.dao.AutoScaleVmGroupPolicyMapDao; +import com.cloud.network.as.dao.AutoScaleVmProfileDao; +import com.cloud.network.as.dao.ConditionDao; +import com.cloud.network.as.dao.CounterDao; +import com.cloud.network.dao.FirewallRulesCidrsDao; +import com.cloud.network.dao.FirewallRulesDao; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.LBHealthCheckPolicyDao; +import com.cloud.network.dao.LBStickinessPolicyDao; +import com.cloud.network.dao.LBStickinessPolicyVO; +import com.cloud.network.dao.LoadBalancerDao; +import com.cloud.network.dao.LoadBalancerVMMapDao; +import com.cloud.network.dao.LoadBalancerVMMapVO; +import com.cloud.network.dao.LoadBalancerVO; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkServiceMapDao; +import com.cloud.network.dao.NetworkVO; import com.cloud.network.element.LoadBalancingServiceProvider; -import com.cloud.network.lb.LoadBalancingRule.*; -import com.cloud.network.rules.*; +import com.cloud.network.lb.LoadBalancingRule.LbAutoScalePolicy; +import com.cloud.network.lb.LoadBalancingRule.LbAutoScaleVmGroup; +import com.cloud.network.lb.LoadBalancingRule.LbAutoScaleVmProfile; +import com.cloud.network.lb.LoadBalancingRule.LbCondition; +import com.cloud.network.lb.LoadBalancingRule.LbDestination; +import com.cloud.network.lb.LoadBalancingRule.LbHealthCheckPolicy; +import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; +import com.cloud.network.rules.FirewallManager; +import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.FirewallRuleType; import com.cloud.network.rules.FirewallRule.Purpose; +import com.cloud.network.rules.FirewallRuleVO; +import com.cloud.network.rules.HealthCheckPolicy; +import com.cloud.network.rules.LbStickinessMethod; import com.cloud.network.rules.LbStickinessMethod.LbStickinessMethodParam; +import com.cloud.network.rules.LoadBalancer; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.network.rules.RulesManager; +import com.cloud.network.rules.StickinessPolicy; import com.cloud.network.vpc.VpcManager; import com.cloud.offering.NetworkOffering; import com.cloud.projects.Project.ListProjectResourcesCriteria; @@ -53,15 +130,25 @@ import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.tags.ResourceTagVO; import com.cloud.tags.dao.ResourceTagDao; -import com.cloud.user.*; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.DomainService; +import com.cloud.user.User; +import com.cloud.user.UserContext; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; import com.cloud.uservm.UserVm; import com.cloud.utils.Pair; import com.cloud.utils.Ternary; import com.cloud.utils.component.ManagerBase; -import com.cloud.utils.db.*; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.JoinBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; import com.cloud.utils.net.NetUtils; import com.cloud.vm.Nic; import com.cloud.vm.UserVmVO; @@ -70,21 +157,11 @@ import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.UserVmDao; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.command.user.loadbalancer.*; -import org.apache.cloudstack.api.response.ServiceResponse; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import javax.ejb.Local; -import javax.inject.Inject; -import java.security.InvalidParameterException; -import java.util.*; @Component @Local(value = { LoadBalancingRulesManager.class, LoadBalancingRulesService.class }) public class LoadBalancingRulesManagerImpl extends ManagerBase implements LoadBalancingRulesManager, - LoadBalancingRulesService, NetworkRuleApplier { + LoadBalancingRulesService { private static final Logger s_logger = Logger.getLogger(LoadBalancingRulesManagerImpl.class); @Inject @@ -166,6 +243,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements UserDao _userDao; @Inject List _lbProviders; + @Inject ApplicationLoadBalancerRuleDao _appLbRuleDao; // Will return a string. For LB Stickiness this will be a json, for // autoscale this will be "," separated values @@ -261,8 +339,9 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements * Regular config like destinations need not be packed for applying * autoscale config as of today. */ - List policyList = getStickinessPolicies(lb.getId()); - LoadBalancingRule rule = new LoadBalancingRule(lb, null, policyList, null); + List policyList = getStickinessPolicies(lb.getId()); + Ip sourceIp = getSourceIp(lb); + LoadBalancingRule rule = new LoadBalancingRule(lb, null, policyList, null, sourceIp); rule.setAutoScaleVmGroup(lbAutoScaleVmGroup); if (!isRollBackAllowedForProvider(lb)) { @@ -273,7 +352,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements List rules = Arrays.asList(rule); - if (!_networkMgr.applyRules(rules, FirewallRule.Purpose.LoadBalancing, this, false)) { + if (!applyLbRules(rules, false)) { s_logger.debug("LB rules' autoscale config are not completely applied"); return false; } @@ -281,6 +360,17 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements return true; } + private Ip getSourceIp(LoadBalancer lb) { + Ip sourceIp = null; + if (lb.getScheme() == Scheme.Public) { + sourceIp = _networkModel.getPublicIpAddress(lb.getSourceIpAddressId()).getAddress(); + } else if (lb.getScheme() == Scheme.Internal) { + ApplicationLoadBalancerRuleVO appLbRule = _appLbRuleDao.findById(lb.getId()); + sourceIp = appLbRule.getSourceIp(); + } + return sourceIp; + } + @Override @DB public boolean configureLbAutoScaleVmGroup(long vmGroupid, String currentState) throws ResourceUnavailableException { @@ -454,9 +544,10 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements cmd.getStickinessMethodName(), cmd.getparamList(), cmd.getDescription()); List policyList = new ArrayList(); policyList.add(new LbStickinessPolicy(cmd.getStickinessMethodName(), lbpolicy.getParams())); + Ip sourceIp = getSourceIp(loadBalancer); LoadBalancingRule lbRule = new LoadBalancingRule(loadBalancer, getExistingDestinations(lbpolicy.getId()), - policyList, null); - if (!validateRule(lbRule)) { + policyList, null, sourceIp); + if (!validateLbRule(lbRule)) { throw new InvalidParameterValueException("Failed to create Stickiness policy: Validation Failed " + cmd.getLbRuleId()); } @@ -539,7 +630,8 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements return policy; } - private boolean validateRule(LoadBalancingRule lbRule) { + @Override + public boolean validateLbRule(LoadBalancingRule lbRule) { Network network = _networkDao.findById(lbRule.getNetworkId()); Purpose purpose = lbRule.getPurpose(); if (purpose != Purpose.LoadBalancing) { @@ -748,7 +840,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements // by CloudStack and update them in lbvmmap table @DB @Override - public void updateLBHealthChecks() throws ResourceUnavailableException { + public void updateLBHealthChecks(Scheme scheme) throws ResourceUnavailableException { List rules = _lbDao.listAll(); List networks = _networkDao.listAll(); List stateRules = null; @@ -763,7 +855,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements * "HealthCheck Manager :: LB Provider in the Network has the Healthcheck policy capability :: " * + provider.get(0).getName()); */ - rules = _lbDao.listByNetworkId(network.getId()); + rules = _lbDao.listByNetworkIdAndScheme(network.getId(), scheme); if (rules != null && rules.size() > 0) { List lbrules = new ArrayList(); for (LoadBalancerVO lb : rules) { @@ -772,7 +864,8 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements // adding to lbrules list only if the LB rule // hashealtChecks if (hcPolicyList != null && hcPolicyList.size() > 0) { - LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, null, hcPolicyList); + Ip sourceIp = getSourceIp(lb); + LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, null, hcPolicyList, sourceIp); lbrules.add(loadBalancing); } } @@ -1168,31 +1261,21 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements @Override @ActionEvent(eventType = EventTypes.EVENT_LOAD_BALANCER_CREATE, eventDescription = "creating load balancer") - public LoadBalancer createLoadBalancerRule(CreateLoadBalancerRuleCmd lb, boolean openFirewall) + public LoadBalancer createPublicLoadBalancerRule(String xId, String name, String description, + int srcPortStart, int srcPortEnd, int defPortStart, int defPortEnd, Long ipAddrId, String protocol, String algorithm, long networkId, long lbOwnerId, boolean openFirewall) throws NetworkRuleConflictException, InsufficientAddressCapacityException { - Account lbOwner = _accountMgr.getAccount(lb.getEntityOwnerId()); - - int defPortStart = lb.getDefaultPortStart(); - int defPortEnd = lb.getDefaultPortEnd(); - - if (!NetUtils.isValidPort(defPortEnd)) { - throw new InvalidParameterValueException("privatePort is an invalid value: " + defPortEnd); - } - if (defPortStart > defPortEnd) { - throw new InvalidParameterValueException("private port range is invalid: " + defPortStart + "-" - + defPortEnd); - } - if ((lb.getAlgorithm() == null) || !NetUtils.isValidAlgorithm(lb.getAlgorithm())) { - throw new InvalidParameterValueException("Invalid algorithm: " + lb.getAlgorithm()); + Account lbOwner = _accountMgr.getAccount(lbOwnerId); + + if (srcPortStart != srcPortEnd) { + throw new InvalidParameterValueException("Port ranges are not supported by the load balancer"); } - Long ipAddrId = lb.getSourceIpAddressId(); IPAddressVO ipVO = null; if (ipAddrId != null) { ipVO = _ipAddressDao.findById(ipAddrId); } - Network network = _networkModel.getNetwork(lb.getNetworkId()); + Network network = _networkModel.getNetwork(networkId); // FIXME: breaking the dependency on ELB manager. This breaks // functionality of ELB using virtual router @@ -1204,8 +1287,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements IpAddress systemIp = null; NetworkOffering off = _configMgr.getNetworkOffering(network.getNetworkOfferingId()); if (off.getElasticLb() && ipVO == null && network.getVpcId() == null) { - systemIp = _networkMgr.assignSystemIp(lb.getNetworkId(), lbOwner, true, false); - lb.setSourceIpAddressId(systemIp.getId()); + systemIp = _networkMgr.assignSystemIp(networkId, lbOwner, true, false); ipVO = _ipAddressDao.findById(systemIp.getId()); } @@ -1224,11 +1306,11 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements && ipVO.getVpcId().longValue() == network.getVpcId(); if (assignToVpcNtwk) { // set networkId just for verification purposes - _networkModel.checkIpForService(ipVO, Service.Lb, lb.getNetworkId()); + _networkModel.checkIpForService(ipVO, Service.Lb, networkId); - s_logger.debug("The ip is not associated with the VPC network id=" + lb.getNetworkId() + s_logger.debug("The ip is not associated with the VPC network id=" + networkId + " so assigning"); - ipVO = _networkMgr.associateIPToGuestNetwork(ipAddrId, lb.getNetworkId(), false); + ipVO = _networkMgr.associateIPToGuestNetwork(ipAddrId, networkId, false); performedIpAssoc = true; } } else { @@ -1240,10 +1322,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements + network); } - if (lb.getSourceIpAddressId() == null) { - throw new CloudRuntimeException("No ip address is defined to assign the LB to"); - } - result = createLoadBalancer(lb, openFirewall); + result = createPublicLoadBalancer(xId, name, description, srcPortStart, defPortStart, ipVO.getId(), protocol, algorithm, openFirewall, UserContext.current()); } catch (Exception ex) { s_logger.warn("Failed to create load balancer due to ", ex); if (ex instanceof NetworkRuleConflictException) { @@ -1258,27 +1337,31 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements // release ip address if ipassoc was perfored if (performedIpAssoc) { ipVO = _ipAddressDao.findById(ipVO.getId()); - _vpcMgr.unassignIPFromVpcNetwork(ipVO.getId(), lb.getNetworkId()); + _vpcMgr.unassignIPFromVpcNetwork(ipVO.getId(), networkId); } } } if (result == null) { - throw new CloudRuntimeException("Failed to create load balancer rule: " + lb.getName()); + throw new CloudRuntimeException("Failed to create load balancer rule: " + name); } return result; } - @Override @DB - public LoadBalancer createLoadBalancer(CreateLoadBalancerRuleCmd lb, boolean openFirewall) + @Override + public LoadBalancer createPublicLoadBalancer(String xId, String name, String description, + int srcPort, int destPort, long sourceIpId, String protocol, String algorithm, boolean openFirewall, UserContext caller) throws NetworkRuleConflictException { - UserContext caller = UserContext.current(); - int srcPortStart = lb.getSourcePortStart(); - int defPortStart = lb.getDefaultPortStart(); - int srcPortEnd = lb.getSourcePortEnd(); - long sourceIpId = lb.getSourceIpAddressId(); + + if (!NetUtils.isValidPort(destPort)) { + throw new InvalidParameterValueException("privatePort is an invalid value: " + destPort); + } + + if ((algorithm == null) || !NetUtils.isValidAlgorithm(algorithm)) { + throw new InvalidParameterValueException("Invalid algorithm: " + algorithm); + } IPAddressVO ipAddr = _ipAddressDao.findById(sourceIpId); // make sure ip address exists @@ -1293,6 +1376,9 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements ex.addProxyObject(ipAddr, sourceIpId, "sourceIpId"); throw ex; } + + _accountMgr.checkAccess(caller.getCaller(), null, true, ipAddr); + Long networkId = ipAddr.getAssociatedWithNetworkId(); if (networkId == null) { @@ -1301,39 +1387,34 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements ex.addProxyObject(ipAddr, sourceIpId, "sourceIpId"); throw ex; } - - _firewallMgr.validateFirewallRule(caller.getCaller(), ipAddr, srcPortStart, srcPortEnd, lb.getProtocol(), - Purpose.LoadBalancing, FirewallRuleType.User, networkId, null); - NetworkVO network = _networkDao.findById(networkId); - _accountMgr.checkAccess(caller.getCaller(), null, true, ipAddr); - + // verify that lb service is supported by the network - if (!_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Lb)) { - InvalidParameterValueException ex = new InvalidParameterValueException( - "LB service is not supported in specified network id"); - ex.addProxyObject(network, networkId, "networkId"); - throw ex; + isLbServiceSupportedInNetwork(networkId, Scheme.Public); + + _firewallMgr.validateFirewallRule(caller.getCaller(), ipAddr, srcPort, srcPort, protocol, + Purpose.LoadBalancing, FirewallRuleType.User, networkId, null); + + LoadBalancerVO newRule = new LoadBalancerVO(xId, name, description, + sourceIpId, srcPort, srcPort, algorithm, + networkId, ipAddr.getAllocatedToAccountId(), ipAddr.getAllocatedInDomainId()); + + // verify rule is supported by Lb provider of the network + Ip sourceIp = getSourceIp(newRule); + LoadBalancingRule loadBalancing = new LoadBalancingRule(newRule, new ArrayList(), + new ArrayList(), new ArrayList(), sourceIp); + if (!validateLbRule(loadBalancing)) { + throw new InvalidParameterValueException("LB service provider cannot support this rule"); } Transaction txn = Transaction.currentTxn(); txn.start(); - - LoadBalancerVO newRule = new LoadBalancerVO(lb.getXid(), lb.getName(), lb.getDescription(), - lb.getSourceIpAddressId(), lb.getSourcePortEnd(), lb.getDefaultPortStart(), lb.getAlgorithm(), - network.getId(), ipAddr.getAllocatedToAccountId(), ipAddr.getAllocatedInDomainId()); - - // verify rule is supported by Lb provider of the network - LoadBalancingRule loadBalancing = new LoadBalancingRule(newRule, new ArrayList(), - new ArrayList(), new ArrayList()); - if (!validateRule(loadBalancing)) { - throw new InvalidParameterValueException("LB service provider cannot support this rule"); - } - + newRule = _lbDao.persist(newRule); + //create rule for all CIDRs if (openFirewall) { - _firewallMgr.createRuleForAllCidrs(sourceIpId, caller.getCaller(), lb.getSourcePortStart(), - lb.getSourcePortEnd(), lb.getProtocol(), null, null, newRule.getId(), networkId); + _firewallMgr.createRuleForAllCidrs(sourceIpId, caller.getCaller(), srcPort, + srcPort, protocol, null, null, newRule.getId(), networkId); } boolean success = true; @@ -1344,7 +1425,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements throw new CloudRuntimeException("Unable to update the state to add for " + newRule); } s_logger.debug("Load balancer " + newRule.getId() + " for Ip address id=" + sourceIpId + ", public port " - + srcPortStart + ", private port " + defPortStart + " is added successfully."); + + srcPort + ", private port " + destPort + " is added successfully."); UserContext.current().setEventDetails("Load balancer Id: " + newRule.getId()); UsageEventUtils.publishUsageEvent(EventTypes.EVENT_LOAD_BALANCER_CREATE, ipAddr.getAllocatedToAccountId(), ipAddr.getDataCenterId(), newRule.getId(), null, LoadBalancingRule.class.getName(), @@ -1380,14 +1461,17 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements lbs = Arrays.asList(lb); } else { // get all rules in transition state - lbs = _lbDao.listInTransitionStateByNetworkId(lb.getNetworkId()); + lbs = _lbDao.listInTransitionStateByNetworkIdAndScheme(lb.getNetworkId(), lb.getScheme()); } return applyLoadBalancerRules(lbs, true); } @Override - public boolean revokeLoadBalancersForNetwork(long networkId) throws ResourceUnavailableException { - List lbs = _lbDao.listByNetworkId(networkId); + public boolean revokeLoadBalancersForNetwork(long networkId, Scheme scheme) throws ResourceUnavailableException { + List lbs = _lbDao.listByNetworkIdAndScheme(networkId, scheme); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Revoking " + lbs.size() + " " + scheme + " load balancing rules for network id=" + networkId); + } if (lbs != null) { for(LoadBalancerVO lb : lbs) { // called during restart, not persisting state in db lb.setState(FirewallRule.State.Revoke); @@ -1400,20 +1484,20 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements } @Override - public boolean applyLoadBalancersForNetwork(long networkId) throws ResourceUnavailableException { - List lbs = _lbDao.listByNetworkId(networkId); + public boolean applyLoadBalancersForNetwork(long networkId, Scheme scheme) throws ResourceUnavailableException { + List lbs = _lbDao.listByNetworkIdAndScheme(networkId, scheme); if (lbs != null) { + s_logger.debug("Applying load balancer rules of scheme " + scheme + " in network id=" + networkId); return applyLoadBalancerRules(lbs, true); } else { - s_logger.info("Network id=" + networkId + " doesn't have load balancer rules, nothing to apply"); + s_logger.info("Network id=" + networkId + " doesn't have load balancer rules of scheme " + scheme + ", nothing to apply"); return true; } } - @Override - public boolean applyRules(Network network, Purpose purpose, List rules) + + protected boolean applyLbRules(Network network, List rules) throws ResourceUnavailableException { - assert (purpose == Purpose.LoadBalancing) : "LB Manager asked to handle non-LB rules"; boolean handled = false; for (LoadBalancingServiceProvider lbElement : _lbProviders) { Provider provider = lbElement.getProvider(); @@ -1422,7 +1506,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements if (!isLbProvider) { continue; } - handled = lbElement.applyLBRules(network, (List) rules); + handled = lbElement.applyLBRules(network, rules); if (handled) break; } @@ -1432,7 +1516,8 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements private LoadBalancingRule getLoadBalancerRuleToApply(LoadBalancerVO lb) { List policyList = getStickinessPolicies(lb.getId()); - LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, null, policyList, null); + Ip sourceIp = getSourceIp(lb); + LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, null, policyList, null, sourceIp); if (_autoScaleVmGroupDao.isAutoScaleLoadBalancer(lb.getId())) { // Get the associated VmGroup @@ -1442,7 +1527,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements } else { List dstList = getExistingDestinations(lb.getId()); loadBalancing.setDestinations(dstList); - List hcPolicyList = getHealthCheckPolicies(lb.getId()); + List hcPolicyList = getHealthCheckPolicies(lb.getId()); loadBalancing.setHealthCheckPolicies(hcPolicyList); } @@ -1458,7 +1543,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements rules.add(getLoadBalancerRuleToApply(lb)); } - if (!_networkMgr.applyRules(rules, FirewallRule.Purpose.LoadBalancing, this, false)) { + if (!applyLbRules(rules, false)) { s_logger.debug("LB rules are not completely applied"); return false; } @@ -1515,7 +1600,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements } txn.commit(); - if (checkForReleaseElasticIp) { + if (checkForReleaseElasticIp && lb.getSourceIpAddressId() != null) { boolean success = true; long count = _firewallDao.countRulesByIpId(lb.getSourceIpAddressId()); if (count == 0) { @@ -1534,8 +1619,10 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements } // if the rule is the last one for the ip address assigned to // VPC, unassign it from the network - IpAddress ip = _ipAddressDao.findById(lb.getSourceIpAddressId()); - _vpcMgr.unassignIPFromVpcNetwork(ip.getId(), lb.getNetworkId()); + if (lb.getSourceIpAddressId() != null) { + IpAddress ip = _ipAddressDao.findById(lb.getSourceIpAddressId()); + _vpcMgr.unassignIPFromVpcNetwork(ip.getId(), lb.getNetworkId()); + } } } @@ -1902,32 +1989,115 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements count++; } } + + //list only Public load balancers using this command + sc.setParameters("scheme", Scheme.Public); Pair, Integer> result = _lbDao.searchAndCount(sc, searchFilter); return new Pair, Integer>(result.first(), result.second()); } - @Override - public List listByNetworkId(long networkId) { - List lbs = _lbDao.listByNetworkId(networkId); - List lbRules = new ArrayList(); - for (LoadBalancerVO lb : lbs) { - List dstList = getExistingDestinations(lb.getId()); - List policyList = this.getStickinessPolicies(lb.getId()); - List hcPolicyList = this.getHealthCheckPolicies(lb.getId()); - LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList); - lbRules.add(loadBalancing); - } - return lbRules; - } @Override public LoadBalancerVO findById(long lbId) { return _lbDao.findById(lbId); } - protected void removeLBRule(LoadBalancerVO rule) { + @Override + public void removeLBRule(LoadBalancer rule) { // remove the rule _lbDao.remove(rule.getId()); } + + + public boolean applyLbRules(List rules, boolean continueOnError) throws ResourceUnavailableException { + if (rules == null || rules.size() == 0) { + s_logger.debug("There are no Load Balancing Rules to forward to the network elements"); + return true; + } + + boolean success = true; + Network network = _networkModel.getNetwork(rules.get(0).getNetworkId()); + List publicIps = new ArrayList(); + + + // get the list of public ip's owned by the network + List userIps = _ipAddressDao.listByAssociatedNetwork(network.getId(), null); + if (userIps != null && !userIps.isEmpty()) { + for (IPAddressVO userIp : userIps) { + PublicIp publicIp = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId())); + publicIps.add(publicIp); + } + } + + // rules can not programmed unless IP is associated with network + // service provider, so run IP assoication for + // the network so as to ensure IP is associated before applying + // rules (in add state) + _networkMgr.applyIpAssociations(network, false, continueOnError, publicIps); + + + try { + applyLbRules(network, rules); + } catch (ResourceUnavailableException e) { + if (!continueOnError) { + throw e; + } + s_logger.warn("Problems with applying load balancing rules but pushing on", e); + success = false; + } + + // if all the rules configured on public IP are revoked then + // dis-associate IP with network service provider + _networkMgr.applyIpAssociations(network, true, continueOnError, publicIps); + + return success; + } + + @Override + public Map getLbInstances(long lbId) { + Map dstList = new HashMap(); + List lbVmMaps = _lb2VmMapDao.listByLoadBalancerId(lbId); + LoadBalancerVO lb = _lbDao.findById(lbId); + + for (LoadBalancerVMMapVO lbVmMap : lbVmMaps) { + UserVm vm = _vmDao.findById(lbVmMap.getInstanceId()); + Nic nic = _nicDao.findByInstanceIdAndNetworkIdIncludingRemoved(lb.getNetworkId(), vm.getId()); + Ip ip = new Ip(nic.getIp4Address()); + dstList.put(ip, vm); + } + return dstList; + } + + @Override + public void isLbServiceSupportedInNetwork(long networkId, Scheme scheme) { + Network network = _networkDao.findById(networkId); + + //1) Check if the LB service is supported + if (!_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Lb)) { + InvalidParameterValueException ex = new InvalidParameterValueException( + "LB service is not supported in specified network id"); + ex.addProxyObject(network, network.getId(), "networkId"); + throw ex; + } + + //2) Check if the Scheme is supported\ + NetworkOffering off = _configMgr.getNetworkOffering(network.getNetworkOfferingId()); + if (scheme == Scheme.Public) { + if (!off.getPublicLb()) { + throw new InvalidParameterValueException("Scheme " + scheme + " is not supported by the network offering " + off); + } + } else { + if (!off.getInternalLb()) { + throw new InvalidParameterValueException("Scheme " + scheme + " is not supported by the network offering " + off); + } + } + + //3) Check if the provider supports the scheme + LoadBalancingServiceProvider lbProvider = _networkMgr.getLoadBalancingProviderForNetwork(network, scheme); + if (lbProvider == null) { + throw new InvalidParameterValueException("Lb rule with scheme " + scheme.toString() + " is not supported by lb providers in network " + network); + } + } + } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java index f49ab79b500..fcf650f900c 100644 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java @@ -28,6 +28,7 @@ import com.cloud.network.PublicIpAddress; import com.cloud.network.RemoteAccessVpn; import com.cloud.network.VirtualNetworkApplianceService; import com.cloud.network.VpnUser; +import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.StaticNat; import com.cloud.user.Account; @@ -103,4 +104,7 @@ public interface VirtualNetworkApplianceManager extends Manager, VirtualNetworkA boolean applyUserData(Network config, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, List routers) throws ResourceUnavailableException; + + boolean applyLoadBalancingRules(Network network, List rules, List routers) throws ResourceUnavailableException; + } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 6620e0a6379..e3dd06ba47c 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -173,6 +173,7 @@ import com.cloud.network.router.VirtualRouter.RedundantState; import com.cloud.network.router.VirtualRouter.Role; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.RulesManager; import com.cloud.network.rules.StaticNat; @@ -218,6 +219,7 @@ import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; import com.cloud.utils.net.MacAddress; import com.cloud.utils.net.NetUtils; import com.cloud.vm.DomainRouterVO; @@ -1526,7 +1528,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V for (int i = 0; i < count; i++) { List> networks = createRouterNetworks(owner, isRedundant, plan, guestNetwork, new Pair(publicNetwork, sourceNatIp)); - //don't start the router as we are holding the network lock that needs to be released at the end of router allocation + //don't start the router as we are holding the network lock that needs to be released at the end of router allocation DomainRouterVO router = deployRouter(owner, destination, plan, params, isRedundant, vrProvider, offeringId, null, networks, false, null); @@ -2410,7 +2412,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V } } - List lbs = _loadBalancerDao.listByNetworkId(guestNetworkId); + List lbs = _loadBalancerDao.listByNetworkIdAndScheme(guestNetworkId, Scheme.Public); List lbRules = new ArrayList(); if (_networkModel.isProviderSupportServiceInNetwork(guestNetworkId, Service.Lb, provider)) { // Re-apply load balancing rules @@ -2418,7 +2420,8 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V List dstList = _lbMgr.getExistingDestinations(lb.getId()); List policyList = _lbMgr.getStickinessPolicies(lb.getId()); List hcPolicyList = _lbMgr.getHealthCheckPolicies(lb.getId()); - LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList); + Ip sourceIp = _networkModel.getPublicIpAddress(lb.getSourceIpAddressId()).getAddress(); + LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList, sourceIp); lbRules.add(loadBalancing); } } @@ -2509,7 +2512,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V Network network = _networkModel.getNetwork(routerNic.getNetworkId()); if (network.getTrafficType() == TrafficType.Guest) { guestNetworks.add(network); - } + } } answer = cmds.getAnswer("getDomRVersion"); @@ -3036,7 +3039,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V String algorithm = rule.getAlgorithm(); String uuid = rule.getUuid(); - String srcIp = _networkModel.getIp(rule.getSourceIpAddressId()).getAddress().addr(); + String srcIp = rule.getSourceIp().addr(); int srcPort = rule.getSourcePortStart(); List destinations = rule.getDestinations(); List stickinessPolicies = rule.getStickinessPolicies(); @@ -3051,7 +3054,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V } Network guestNetwork = _networkModel.getNetwork(guestNetworkId); - Nic nic = _nicDao.findByInstanceIdAndNetworkId(guestNetwork.getId(), router.getId()); + Nic nic = _nicDao.findByNtwkIdAndInstanceId(guestNetwork.getId(), router.getId()); NicProfile nicProfile = new NicProfile(nic, guestNetwork, nic.getBroadcastUri(), nic.getIsolationUri(), _networkModel.getNetworkRate(guestNetwork.getId(), router.getId()), _networkModel.isSecurityGroupSupportedInNetwork(guestNetwork), @@ -3144,7 +3147,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V } if (createVmData) { - NicVO nic = _nicDao.findByInstanceIdAndNetworkId(guestNetworkId, vm.getId()); + NicVO nic = _nicDao.findByNtwkIdAndInstanceId(guestNetworkId, vm.getId()); if (nic != null) { s_logger.debug("Creating user data entry for vm " + vm + " on domR " + router); createVmDataCommand(router, vm, nic, null, cmds); @@ -3197,7 +3200,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V createDhcp = false; } if (createDhcp) { - NicVO nic = _nicDao.findByInstanceIdAndNetworkId(guestNetworkId, vm.getId()); + NicVO nic = _nicDao.findByNtwkIdAndInstanceId(guestNetworkId, vm.getId()); if (nic != null) { s_logger.debug("Creating dhcp entry for vm " + vm + " on domR " + router + "."); createDhcpEntryCommand(router, vm, nic, cmds); @@ -3315,13 +3318,14 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V public boolean execute(Network network, VirtualRouter router) throws ResourceUnavailableException { if (rules.get(0).getPurpose() == Purpose.LoadBalancing) { // for load balancer we have to resend all lb rules for the network - List lbs = _loadBalancerDao.listByNetworkId(network.getId()); + List lbs = _loadBalancerDao.listByNetworkIdAndScheme(network.getId(), Scheme.Public); List lbRules = new ArrayList(); for (LoadBalancerVO lb : lbs) { List dstList = _lbMgr.getExistingDestinations(lb.getId()); List policyList = _lbMgr.getStickinessPolicies(lb.getId()); - List hcPolicyList = _lbMgr.getHealthCheckPolicies(lb.getId() ); - LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList); + List hcPolicyList = _lbMgr.getHealthCheckPolicies(lb.getId()); + Ip sourceIp = _networkModel.getPublicIpAddress(lb.getSourceIpAddressId()).getAddress(); + LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList, sourceIp); lbRules.add(loadBalancing); } return sendLBRules(router, lbRules, network.getId()); @@ -3338,6 +3342,32 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V } }); } + + + @Override + public boolean applyLoadBalancingRules(Network network, final List rules, List routers) throws ResourceUnavailableException { + if (rules == null || rules.isEmpty()) { + s_logger.debug("No lb rules to be applied for network " + network.getId()); + return true; + } + return applyRules(network, routers, "loadbalancing rules", false, null, false, new RuleApplier() { + @Override + public boolean execute(Network network, VirtualRouter router) throws ResourceUnavailableException { + // for load balancer we have to resend all lb rules for the network + List lbs = _loadBalancerDao.listByNetworkIdAndScheme(network.getId(), Scheme.Public); + List lbRules = new ArrayList(); + for (LoadBalancerVO lb : lbs) { + List dstList = _lbMgr.getExistingDestinations(lb.getId()); + List policyList = _lbMgr.getStickinessPolicies(lb.getId()); + List hcPolicyList = _lbMgr.getHealthCheckPolicies(lb.getId()); + Ip sourceIp = _networkModel.getPublicIpAddress(lb.getSourceIpAddressId()).getAddress(); + LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList, sourceIp); + lbRules.add(loadBalancing); + } + return sendLBRules(router, lbRules, network.getId()); + } + }); + } protected boolean sendLBRules(VirtualRouter router, List rules, long guestNetworkId) throws ResourceUnavailableException { Commands cmds = new Commands(OnError.Continue); @@ -3734,4 +3764,11 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V } } } + + + + @Override + public VirtualRouter findRouter(long routerId) { + return _routerDao.findById(routerId); + } } diff --git a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java index ebf2d4257e3..611100955e7 100644 --- a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java @@ -440,7 +440,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian defaultDns2 = guestNic.getDns2(); } - Nic nic = _nicDao.findByInstanceIdAndNetworkId(network.getId(), router.getId()); + Nic nic = _nicDao.findByNtwkIdAndInstanceId(network.getId(), router.getId()); String networkDomain = network.getNetworkDomain(); String dhcpRange = getGuestDhcpRange(guestNic, network, _configMgr.getZone(network.getDataCenterId())); diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index 9be22084e11..55656d8b4fb 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -184,7 +184,9 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("VpcChecker")); private List vpcElements = null; private final List nonSupportedServices = Arrays.asList(Service.SecurityGroup, Service.Firewall); - private final List supportedProviders = Arrays.asList(Provider.VPCVirtualRouter, Provider.NiciraNvp, Provider.Netscaler); + private final List supportedProviders = Arrays.asList(Provider.VPCVirtualRouter, Provider.NiciraNvp, Provider.InternalLbVm, Provider.Netscaler); + + int _cleanupInterval; int _maxNetworks; SearchBuilder IpAddressSearch; @@ -206,6 +208,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis if (svc == Service.Lb) { Set lbProviders = new HashSet(); lbProviders.add(Provider.VPCVirtualRouter); + lbProviders.add(Provider.InternalLbVm); svcProviderMap.put(svc, lbProviders); } else { svcProviderMap.put(svc, defaultProviders); @@ -1057,16 +1060,17 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } } - //4) Only one network in the VPC can support LB - if (_ntwkModel.areServicesSupportedByNetworkOffering(guestNtwkOff.getId(), Service.Lb)) { + //4) Only one network in the VPC can support public LB inside the VPC. Internal LB can be supported on multiple VPC tiers + if (_ntwkModel.areServicesSupportedByNetworkOffering(guestNtwkOff.getId(), Service.Lb) && guestNtwkOff.getPublicLb()) { List networks = getVpcNetworks(vpc.getId()); for (Network network : networks) { if (networkId != null && network.getId() == networkId.longValue()) { //skip my own network continue; } else { - if (_ntwkModel.areServicesSupportedInNetwork(network.getId(), Service.Lb)) { - throw new InvalidParameterValueException("LB service is already supported " + + NetworkOffering otherOff = _configMgr.getNetworkOffering(network.getNetworkOfferingId()); + if (_ntwkModel.areServicesSupportedInNetwork(network.getId(), Service.Lb) && otherOff.getPublicLb()) { + throw new InvalidParameterValueException("Public LB service is already supported " + "by network " + network + " in VPC " + vpc); } } diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java index 3d97447fe40..bc52e9a881c 100755 --- a/server/src/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/com/cloud/server/ConfigurationServerImpl.java @@ -1017,7 +1017,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio "Offering for Shared Security group enabled networks", TrafficType.Guest, false, true, null, null, true, Availability.Optional, - null, Network.GuestType.Shared, true, true, false); + null, Network.GuestType.Shared, true, true, false, false, false); defaultSharedSGNetworkOffering.setState(NetworkOffering.State.Enabled); defaultSharedSGNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultSharedSGNetworkOffering); @@ -1034,7 +1034,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio "Offering for Shared networks", TrafficType.Guest, false, true, null, null, true, Availability.Optional, - null, Network.GuestType.Shared, true, true, false); + null, Network.GuestType.Shared, true, true, false, false, false); defaultSharedNetworkOffering.setState(NetworkOffering.State.Enabled); defaultSharedNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultSharedNetworkOffering); @@ -1051,7 +1051,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio "Offering for Isolated networks with Source Nat service enabled", TrafficType.Guest, false, false, null, null, true, Availability.Required, - null, Network.GuestType.Isolated, true, false, false); + null, Network.GuestType.Isolated, true, false, false, false, true); defaultIsolatedSourceNatEnabledNetworkOffering.setState(NetworkOffering.State.Enabled); defaultIsolatedSourceNatEnabledNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultIsolatedSourceNatEnabledNetworkOffering); @@ -1069,7 +1069,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio "Offering for Isolated networks with no Source Nat service", TrafficType.Guest, false, true, null, null, true, Availability.Optional, - null, Network.GuestType.Isolated, true, true, false); + null, Network.GuestType.Isolated, true, true, false, false, false); defaultIsolatedEnabledNetworkOffering.setState(NetworkOffering.State.Enabled); defaultIsolatedEnabledNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultIsolatedEnabledNetworkOffering); @@ -1086,7 +1086,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio "Offering for Shared networks with Elastic IP and Elastic LB capabilities", TrafficType.Guest, false, true, null, null, true, Availability.Optional, - null, Network.GuestType.Shared, true, false, false, false, true, true, true, false, false, true); + null, Network.GuestType.Shared, true, false, false, false, true, true, true, false, false, true, true, false); defaultNetscalerNetworkOffering.setState(NetworkOffering.State.Enabled); defaultNetscalerNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultNetscalerNetworkOffering); @@ -1103,7 +1103,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio "Offering for Isolated Vpc networks with Source Nat service enabled", TrafficType.Guest, false, false, null, null, true, Availability.Optional, - null, Network.GuestType.Isolated, false, false, false); + null, Network.GuestType.Isolated, false, false, false, false, true); defaultNetworkOfferingForVpcNetworks.setState(NetworkOffering.State.Enabled); defaultNetworkOfferingForVpcNetworks = _networkOfferingDao.persistDefaultNetworkOffering(defaultNetworkOfferingForVpcNetworks); @@ -1133,7 +1133,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio "Offering for Isolated Vpc networks with Source Nat service enabled and LB service Disabled", TrafficType.Guest, false, false, null, null, true, Availability.Optional, - null, Network.GuestType.Isolated, false, false, false); + null, Network.GuestType.Isolated, false, false, false, false, false); defaultNetworkOfferingForVpcNetworksNoLB.setState(NetworkOffering.State.Enabled); defaultNetworkOfferingForVpcNetworksNoLB = _networkOfferingDao.persistDefaultNetworkOffering(defaultNetworkOfferingForVpcNetworksNoLB); diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index da8f30ed759..86c1a640da9 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -34,7 +34,6 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.TimeZone; -import java.util.UUID; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -44,52 +43,371 @@ import javax.crypto.spec.SecretKeySpec; import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.configuration.*; -import com.cloud.storage.dao.*; +import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.SecurityChecker.AccessType; -import org.apache.cloudstack.api.ApiConstants; - -import com.cloud.event.ActionEventUtils; -import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoCmd; -import org.apache.cloudstack.api.command.admin.account.*; -import org.apache.cloudstack.api.command.admin.domain.*; -import org.apache.cloudstack.api.command.admin.host.*; -import org.apache.cloudstack.api.command.admin.network.*; -import org.apache.cloudstack.api.command.admin.offering.*; -import org.apache.cloudstack.api.command.admin.resource.*; -import org.apache.cloudstack.api.command.admin.router.*; -import org.apache.cloudstack.api.command.admin.storage.*; -import org.apache.cloudstack.api.command.admin.systemvm.*; -import org.apache.cloudstack.api.command.admin.usage.*; -import org.apache.cloudstack.api.command.admin.user.*; -import org.apache.cloudstack.api.command.admin.vlan.*; -import org.apache.cloudstack.api.command.admin.vpc.*; -import org.apache.cloudstack.api.command.user.autoscale.*; -import org.apache.cloudstack.api.command.user.firewall.*; -import org.apache.cloudstack.api.command.user.iso.*; -import org.apache.cloudstack.api.command.user.loadbalancer.*; -import org.apache.cloudstack.api.command.user.nat.*; -import org.apache.cloudstack.api.command.user.network.*; -import org.apache.cloudstack.api.command.user.project.*; -import org.apache.cloudstack.api.command.user.resource.*; -import org.apache.cloudstack.api.command.user.securitygroup.*; -import org.apache.cloudstack.api.command.user.snapshot.*; -import org.apache.cloudstack.api.command.user.template.*; -import org.apache.cloudstack.api.command.user.vm.*; -import org.apache.cloudstack.api.command.user.volume.*; -import org.apache.cloudstack.api.command.user.vpc.*; -import org.apache.cloudstack.api.command.user.vpn.*; -import org.apache.cloudstack.api.response.ExtractResponse; -import org.apache.commons.codec.binary.Base64; -import org.apache.log4j.Logger; import org.apache.cloudstack.affinity.AffinityGroupProcessor; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; - +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoCmd; +import org.apache.cloudstack.api.command.admin.account.CreateAccountCmd; +import org.apache.cloudstack.api.command.admin.account.DeleteAccountCmd; +import org.apache.cloudstack.api.command.admin.account.DisableAccountCmd; +import org.apache.cloudstack.api.command.admin.account.EnableAccountCmd; +import org.apache.cloudstack.api.command.admin.account.LockAccountCmd; +import org.apache.cloudstack.api.command.admin.account.UpdateAccountCmd; +import org.apache.cloudstack.api.command.admin.autoscale.CreateCounterCmd; +import org.apache.cloudstack.api.command.admin.autoscale.DeleteCounterCmd; +import org.apache.cloudstack.api.command.admin.cluster.AddClusterCmd; +import org.apache.cloudstack.api.command.admin.cluster.DeleteClusterCmd; +import org.apache.cloudstack.api.command.admin.cluster.ListClustersCmd; +import org.apache.cloudstack.api.command.admin.cluster.UpdateClusterCmd; +import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd; +import org.apache.cloudstack.api.command.admin.config.ListHypervisorCapabilitiesCmd; +import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd; +import org.apache.cloudstack.api.command.admin.config.UpdateHypervisorCapabilitiesCmd; +import org.apache.cloudstack.api.command.admin.domain.CreateDomainCmd; +import org.apache.cloudstack.api.command.admin.domain.DeleteDomainCmd; +import org.apache.cloudstack.api.command.admin.domain.ListDomainChildrenCmd; +import org.apache.cloudstack.api.command.admin.domain.ListDomainsCmd; +import org.apache.cloudstack.api.command.admin.domain.UpdateDomainCmd; +import org.apache.cloudstack.api.command.admin.host.AddHostCmd; +import org.apache.cloudstack.api.command.admin.host.AddSecondaryStorageCmd; +import org.apache.cloudstack.api.command.admin.host.CancelMaintenanceCmd; +import org.apache.cloudstack.api.command.admin.host.DeleteHostCmd; +import org.apache.cloudstack.api.command.admin.host.FindHostsForMigrationCmd; +import org.apache.cloudstack.api.command.admin.host.ListHostsCmd; +import org.apache.cloudstack.api.command.admin.host.PrepareForMaintenanceCmd; +import org.apache.cloudstack.api.command.admin.host.ReconnectHostCmd; +import org.apache.cloudstack.api.command.admin.host.UpdateHostCmd; +import org.apache.cloudstack.api.command.admin.host.UpdateHostPasswordCmd; +import org.apache.cloudstack.api.command.admin.internallb.ConfigureInternalLoadBalancerElementCmd; +import org.apache.cloudstack.api.command.admin.internallb.CreateInternalLoadBalancerElementCmd; +import org.apache.cloudstack.api.command.admin.internallb.ListInternalLBVMsCmd; +import org.apache.cloudstack.api.command.admin.internallb.ListInternalLoadBalancerElementsCmd; +import org.apache.cloudstack.api.command.admin.internallb.StartInternalLBVMCmd; +import org.apache.cloudstack.api.command.admin.internallb.StopInternalLBVMCmd; +import org.apache.cloudstack.api.command.admin.ldap.LDAPConfigCmd; +import org.apache.cloudstack.api.command.admin.ldap.LDAPRemoveCmd; +import org.apache.cloudstack.api.command.admin.network.AddNetworkDeviceCmd; +import org.apache.cloudstack.api.command.admin.network.AddNetworkServiceProviderCmd; +import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd; +import org.apache.cloudstack.api.command.admin.network.CreatePhysicalNetworkCmd; +import org.apache.cloudstack.api.command.admin.network.CreateStorageNetworkIpRangeCmd; +import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd; +import org.apache.cloudstack.api.command.admin.network.DeleteNetworkDeviceCmd; +import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd; +import org.apache.cloudstack.api.command.admin.network.DeleteNetworkServiceProviderCmd; +import org.apache.cloudstack.api.command.admin.network.DeletePhysicalNetworkCmd; +import org.apache.cloudstack.api.command.admin.network.DeleteStorageNetworkIpRangeCmd; +import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd; +import org.apache.cloudstack.api.command.admin.network.ListNetworkDeviceCmd; +import org.apache.cloudstack.api.command.admin.network.ListNetworkIsolationMethodsCmd; +import org.apache.cloudstack.api.command.admin.network.ListNetworkServiceProvidersCmd; +import org.apache.cloudstack.api.command.admin.network.ListPhysicalNetworksCmd; +import org.apache.cloudstack.api.command.admin.network.ListStorageNetworkIpRangeCmd; +import org.apache.cloudstack.api.command.admin.network.ListSupportedNetworkServicesCmd; +import org.apache.cloudstack.api.command.admin.network.ReleaseDedicatedGuestVlanRangeCmd; +import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd; +import org.apache.cloudstack.api.command.admin.network.UpdateNetworkServiceProviderCmd; +import org.apache.cloudstack.api.command.admin.network.UpdatePhysicalNetworkCmd; +import org.apache.cloudstack.api.command.admin.network.UpdateStorageNetworkIpRangeCmd; +import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd; +import org.apache.cloudstack.api.command.admin.offering.CreateServiceOfferingCmd; +import org.apache.cloudstack.api.command.admin.offering.DeleteDiskOfferingCmd; +import org.apache.cloudstack.api.command.admin.offering.DeleteServiceOfferingCmd; +import org.apache.cloudstack.api.command.admin.offering.UpdateDiskOfferingCmd; +import org.apache.cloudstack.api.command.admin.offering.UpdateServiceOfferingCmd; +import org.apache.cloudstack.api.command.admin.pod.CreatePodCmd; +import org.apache.cloudstack.api.command.admin.pod.DeletePodCmd; +import org.apache.cloudstack.api.command.admin.pod.ListPodsByCmd; +import org.apache.cloudstack.api.command.admin.pod.UpdatePodCmd; +import org.apache.cloudstack.api.command.admin.region.AddRegionCmd; +import org.apache.cloudstack.api.command.admin.region.RemoveRegionCmd; +import org.apache.cloudstack.api.command.admin.region.UpdateRegionCmd; +import org.apache.cloudstack.api.command.admin.resource.ArchiveAlertsCmd; +import org.apache.cloudstack.api.command.admin.resource.DeleteAlertsCmd; +import org.apache.cloudstack.api.command.admin.resource.ListAlertsCmd; +import org.apache.cloudstack.api.command.admin.resource.ListCapacityCmd; +import org.apache.cloudstack.api.command.admin.resource.UploadCustomCertificateCmd; +import org.apache.cloudstack.api.command.admin.router.ConfigureVirtualRouterElementCmd; +import org.apache.cloudstack.api.command.admin.router.CreateVirtualRouterElementCmd; +import org.apache.cloudstack.api.command.admin.router.DestroyRouterCmd; +import org.apache.cloudstack.api.command.admin.router.ListRoutersCmd; +import org.apache.cloudstack.api.command.admin.router.ListVirtualRouterElementsCmd; +import org.apache.cloudstack.api.command.admin.router.RebootRouterCmd; +import org.apache.cloudstack.api.command.admin.router.StartRouterCmd; +import org.apache.cloudstack.api.command.admin.router.StopRouterCmd; +import org.apache.cloudstack.api.command.admin.router.UpgradeRouterCmd; +import org.apache.cloudstack.api.command.admin.storage.AddS3Cmd; +import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaintenanceCmd; +import org.apache.cloudstack.api.command.admin.storage.CreateStoragePoolCmd; +import org.apache.cloudstack.api.command.admin.storage.DeletePoolCmd; +import org.apache.cloudstack.api.command.admin.storage.FindStoragePoolsForMigrationCmd; +import org.apache.cloudstack.api.command.admin.storage.ListS3sCmd; +import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolsCmd; +import org.apache.cloudstack.api.command.admin.storage.ListStorageProvidersCmd; +import org.apache.cloudstack.api.command.admin.storage.PreparePrimaryStorageForMaintenanceCmd; +import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd; +import org.apache.cloudstack.api.command.admin.swift.AddSwiftCmd; +import org.apache.cloudstack.api.command.admin.swift.ListSwiftsCmd; +import org.apache.cloudstack.api.command.admin.systemvm.DestroySystemVmCmd; +import org.apache.cloudstack.api.command.admin.systemvm.ListSystemVMsCmd; +import org.apache.cloudstack.api.command.admin.systemvm.MigrateSystemVMCmd; +import org.apache.cloudstack.api.command.admin.systemvm.RebootSystemVmCmd; +import org.apache.cloudstack.api.command.admin.systemvm.StartSystemVMCmd; +import org.apache.cloudstack.api.command.admin.systemvm.StopSystemVmCmd; +import org.apache.cloudstack.api.command.admin.systemvm.UpgradeSystemVMCmd; +import org.apache.cloudstack.api.command.admin.template.PrepareTemplateCmd; +import org.apache.cloudstack.api.command.admin.usage.AddTrafficMonitorCmd; +import org.apache.cloudstack.api.command.admin.usage.AddTrafficTypeCmd; +import org.apache.cloudstack.api.command.admin.usage.DeleteTrafficMonitorCmd; +import org.apache.cloudstack.api.command.admin.usage.DeleteTrafficTypeCmd; +import org.apache.cloudstack.api.command.admin.usage.GenerateUsageRecordsCmd; +import org.apache.cloudstack.api.command.admin.usage.GetUsageRecordsCmd; +import org.apache.cloudstack.api.command.admin.usage.ListTrafficMonitorsCmd; +import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; +import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypesCmd; +import org.apache.cloudstack.api.command.admin.usage.ListUsageTypesCmd; +import org.apache.cloudstack.api.command.admin.usage.UpdateTrafficTypeCmd; +import org.apache.cloudstack.api.command.admin.user.CreateUserCmd; +import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd; +import org.apache.cloudstack.api.command.admin.user.DisableUserCmd; +import org.apache.cloudstack.api.command.admin.user.EnableUserCmd; +import org.apache.cloudstack.api.command.admin.user.GetUserCmd; +import org.apache.cloudstack.api.command.admin.user.ListUsersCmd; +import org.apache.cloudstack.api.command.admin.user.LockUserCmd; +import org.apache.cloudstack.api.command.admin.user.RegisterCmd; +import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd; +import org.apache.cloudstack.api.command.admin.vlan.CreateVlanIpRangeCmd; +import org.apache.cloudstack.api.command.admin.vlan.DedicatePublicIpRangeCmd; +import org.apache.cloudstack.api.command.admin.vlan.DeleteVlanIpRangeCmd; +import org.apache.cloudstack.api.command.admin.vlan.ListVlanIpRangesCmd; +import org.apache.cloudstack.api.command.admin.vlan.ReleasePublicIpRangeCmd; +import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; +import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd; +import org.apache.cloudstack.api.command.admin.vm.MigrateVirtualMachineWithVolumeCmd; +import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; +import org.apache.cloudstack.api.command.admin.vpc.CreatePrivateGatewayCmd; +import org.apache.cloudstack.api.command.admin.vpc.CreateVPCOfferingCmd; +import org.apache.cloudstack.api.command.admin.vpc.DeletePrivateGatewayCmd; +import org.apache.cloudstack.api.command.admin.vpc.DeleteVPCOfferingCmd; +import org.apache.cloudstack.api.command.admin.vpc.UpdateVPCOfferingCmd; +import org.apache.cloudstack.api.command.admin.zone.CreateZoneCmd; +import org.apache.cloudstack.api.command.admin.zone.DeleteZoneCmd; +import org.apache.cloudstack.api.command.admin.zone.MarkDefaultZoneForAccountCmd; +import org.apache.cloudstack.api.command.admin.zone.UpdateZoneCmd; +import org.apache.cloudstack.api.command.user.account.AddAccountToProjectCmd; +import org.apache.cloudstack.api.command.user.account.DeleteAccountFromProjectCmd; +import org.apache.cloudstack.api.command.user.account.ListAccountsCmd; +import org.apache.cloudstack.api.command.user.account.ListProjectAccountsCmd; +import org.apache.cloudstack.api.command.user.address.AssociateIPAddrCmd; +import org.apache.cloudstack.api.command.user.address.DisassociateIPAddrCmd; +import org.apache.cloudstack.api.command.user.address.ListPublicIpAddressesCmd; import org.apache.cloudstack.api.command.user.affinitygroup.CreateAffinityGroupCmd; import org.apache.cloudstack.api.command.user.affinitygroup.DeleteAffinityGroupCmd; import org.apache.cloudstack.api.command.user.affinitygroup.ListAffinityGroupTypesCmd; import org.apache.cloudstack.api.command.user.affinitygroup.ListAffinityGroupsCmd; import org.apache.cloudstack.api.command.user.affinitygroup.UpdateVMAffinityGroupCmd; +import org.apache.cloudstack.api.command.user.autoscale.CreateAutoScalePolicyCmd; +import org.apache.cloudstack.api.command.user.autoscale.CreateAutoScaleVmGroupCmd; +import org.apache.cloudstack.api.command.user.autoscale.CreateAutoScaleVmProfileCmd; +import org.apache.cloudstack.api.command.user.autoscale.CreateConditionCmd; +import org.apache.cloudstack.api.command.user.autoscale.DeleteAutoScalePolicyCmd; +import org.apache.cloudstack.api.command.user.autoscale.DeleteAutoScaleVmGroupCmd; +import org.apache.cloudstack.api.command.user.autoscale.DeleteAutoScaleVmProfileCmd; +import org.apache.cloudstack.api.command.user.autoscale.DeleteConditionCmd; +import org.apache.cloudstack.api.command.user.autoscale.DisableAutoScaleVmGroupCmd; +import org.apache.cloudstack.api.command.user.autoscale.EnableAutoScaleVmGroupCmd; +import org.apache.cloudstack.api.command.user.autoscale.ListAutoScalePoliciesCmd; +import org.apache.cloudstack.api.command.user.autoscale.ListAutoScaleVmGroupsCmd; +import org.apache.cloudstack.api.command.user.autoscale.ListAutoScaleVmProfilesCmd; +import org.apache.cloudstack.api.command.user.autoscale.ListConditionsCmd; +import org.apache.cloudstack.api.command.user.autoscale.ListCountersCmd; +import org.apache.cloudstack.api.command.user.autoscale.UpdateAutoScalePolicyCmd; +import org.apache.cloudstack.api.command.user.autoscale.UpdateAutoScaleVmGroupCmd; +import org.apache.cloudstack.api.command.user.autoscale.UpdateAutoScaleVmProfileCmd; +import org.apache.cloudstack.api.command.user.config.ListCapabilitiesCmd; +import org.apache.cloudstack.api.command.user.event.ArchiveEventsCmd; +import org.apache.cloudstack.api.command.user.event.DeleteEventsCmd; +import org.apache.cloudstack.api.command.user.event.ListEventTypesCmd; +import org.apache.cloudstack.api.command.user.event.ListEventsCmd; +import org.apache.cloudstack.api.command.user.firewall.CreateEgressFirewallRuleCmd; +import org.apache.cloudstack.api.command.user.firewall.CreateFirewallRuleCmd; +import org.apache.cloudstack.api.command.user.firewall.CreatePortForwardingRuleCmd; +import org.apache.cloudstack.api.command.user.firewall.DeleteEgressFirewallRuleCmd; +import org.apache.cloudstack.api.command.user.firewall.DeleteFirewallRuleCmd; +import org.apache.cloudstack.api.command.user.firewall.DeletePortForwardingRuleCmd; +import org.apache.cloudstack.api.command.user.firewall.ListEgressFirewallRulesCmd; +import org.apache.cloudstack.api.command.user.firewall.ListFirewallRulesCmd; +import org.apache.cloudstack.api.command.user.firewall.ListPortForwardingRulesCmd; +import org.apache.cloudstack.api.command.user.firewall.UpdatePortForwardingRuleCmd; +import org.apache.cloudstack.api.command.user.guest.ListGuestOsCategoriesCmd; +import org.apache.cloudstack.api.command.user.guest.ListGuestOsCmd; +import org.apache.cloudstack.api.command.user.iso.AttachIsoCmd; +import org.apache.cloudstack.api.command.user.iso.CopyIsoCmd; +import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; +import org.apache.cloudstack.api.command.user.iso.DetachIsoCmd; +import org.apache.cloudstack.api.command.user.iso.ExtractIsoCmd; +import org.apache.cloudstack.api.command.user.iso.ListIsoPermissionsCmd; +import org.apache.cloudstack.api.command.user.iso.ListIsosCmd; +import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; +import org.apache.cloudstack.api.command.user.iso.UpdateIsoCmd; +import org.apache.cloudstack.api.command.user.iso.UpdateIsoPermissionsCmd; +import org.apache.cloudstack.api.command.user.job.ListAsyncJobsCmd; +import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.AssignToLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.CreateApplicationLoadBalancerCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.CreateLBHealthCheckPolicyCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.CreateLBStickinessPolicyCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.CreateLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.DeleteApplicationLoadBalancerCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.DeleteLBHealthCheckPolicyCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.DeleteLBStickinessPolicyCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.DeleteLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListApplicationLoadBalancersCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListLBHealthCheckPoliciesCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListLBStickinessPoliciesCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerRuleInstancesCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerRulesCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.RemoveFromLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.UpdateLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.nat.CreateIpForwardingRuleCmd; +import org.apache.cloudstack.api.command.user.nat.DeleteIpForwardingRuleCmd; +import org.apache.cloudstack.api.command.user.nat.DisableStaticNatCmd; +import org.apache.cloudstack.api.command.user.nat.EnableStaticNatCmd; +import org.apache.cloudstack.api.command.user.nat.ListIpForwardingRulesCmd; +import org.apache.cloudstack.api.command.user.network.CreateNetworkACLCmd; +import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; +import org.apache.cloudstack.api.command.user.network.DeleteNetworkACLCmd; +import org.apache.cloudstack.api.command.user.network.DeleteNetworkCmd; +import org.apache.cloudstack.api.command.user.network.ListNetworkACLsCmd; +import org.apache.cloudstack.api.command.user.network.ListNetworkOfferingsCmd; +import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; +import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; +import org.apache.cloudstack.api.command.user.network.UpdateNetworkCmd; +import org.apache.cloudstack.api.command.user.offering.ListDiskOfferingsCmd; +import org.apache.cloudstack.api.command.user.offering.ListServiceOfferingsCmd; +import org.apache.cloudstack.api.command.user.project.ActivateProjectCmd; +import org.apache.cloudstack.api.command.user.project.CreateProjectCmd; +import org.apache.cloudstack.api.command.user.project.DeleteProjectCmd; +import org.apache.cloudstack.api.command.user.project.DeleteProjectInvitationCmd; +import org.apache.cloudstack.api.command.user.project.ListProjectInvitationsCmd; +import org.apache.cloudstack.api.command.user.project.ListProjectsCmd; +import org.apache.cloudstack.api.command.user.project.SuspendProjectCmd; +import org.apache.cloudstack.api.command.user.project.UpdateProjectCmd; +import org.apache.cloudstack.api.command.user.project.UpdateProjectInvitationCmd; +import org.apache.cloudstack.api.command.user.region.ListRegionsCmd; +import org.apache.cloudstack.api.command.user.region.ha.gslb.AssignToGlobalLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.region.ha.gslb.CreateGlobalLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.region.ha.gslb.DeleteGlobalLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.region.ha.gslb.ListGlobalLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.region.ha.gslb.RemoveFromGlobalLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.resource.GetCloudIdentifierCmd; +import org.apache.cloudstack.api.command.user.resource.ListHypervisorsCmd; +import org.apache.cloudstack.api.command.user.resource.ListResourceLimitsCmd; +import org.apache.cloudstack.api.command.user.resource.UpdateResourceCountCmd; +import org.apache.cloudstack.api.command.user.resource.UpdateResourceLimitCmd; +import org.apache.cloudstack.api.command.user.securitygroup.AuthorizeSecurityGroupEgressCmd; +import org.apache.cloudstack.api.command.user.securitygroup.AuthorizeSecurityGroupIngressCmd; +import org.apache.cloudstack.api.command.user.securitygroup.CreateSecurityGroupCmd; +import org.apache.cloudstack.api.command.user.securitygroup.DeleteSecurityGroupCmd; +import org.apache.cloudstack.api.command.user.securitygroup.ListSecurityGroupsCmd; +import org.apache.cloudstack.api.command.user.securitygroup.RevokeSecurityGroupEgressCmd; +import org.apache.cloudstack.api.command.user.securitygroup.RevokeSecurityGroupIngressCmd; +import org.apache.cloudstack.api.command.user.snapshot.CreateSnapshotCmd; +import org.apache.cloudstack.api.command.user.snapshot.CreateSnapshotPolicyCmd; +import org.apache.cloudstack.api.command.user.snapshot.DeleteSnapshotCmd; +import org.apache.cloudstack.api.command.user.snapshot.DeleteSnapshotPoliciesCmd; +import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotPoliciesCmd; +import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotsCmd; +import org.apache.cloudstack.api.command.user.ssh.CreateSSHKeyPairCmd; +import org.apache.cloudstack.api.command.user.ssh.DeleteSSHKeyPairCmd; +import org.apache.cloudstack.api.command.user.ssh.ListSSHKeyPairsCmd; +import org.apache.cloudstack.api.command.user.ssh.RegisterSSHKeyPairCmd; +import org.apache.cloudstack.api.command.user.tag.CreateTagsCmd; +import org.apache.cloudstack.api.command.user.tag.DeleteTagsCmd; +import org.apache.cloudstack.api.command.user.tag.ListTagsCmd; +import org.apache.cloudstack.api.command.user.template.CopyTemplateCmd; +import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd; +import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; +import org.apache.cloudstack.api.command.user.template.ExtractTemplateCmd; +import org.apache.cloudstack.api.command.user.template.ListTemplatePermissionsCmd; +import org.apache.cloudstack.api.command.user.template.ListTemplatesCmd; +import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; +import org.apache.cloudstack.api.command.user.template.UpdateTemplateCmd; +import org.apache.cloudstack.api.command.user.template.UpdateTemplatePermissionsCmd; +import org.apache.cloudstack.api.command.user.vm.AddIpToVmNicCmd; +import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd; +import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; +import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd; +import org.apache.cloudstack.api.command.user.vm.GetVMPasswordCmd; +import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; +import org.apache.cloudstack.api.command.user.vm.ListVMsCmd; +import org.apache.cloudstack.api.command.user.vm.RebootVMCmd; +import org.apache.cloudstack.api.command.user.vm.RemoveIpFromVmNicCmd; +import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd; +import org.apache.cloudstack.api.command.user.vm.ResetVMPasswordCmd; +import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd; +import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; +import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd; +import org.apache.cloudstack.api.command.user.vm.StartVMCmd; +import org.apache.cloudstack.api.command.user.vm.StopVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd; +import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; +import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; +import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd; +import org.apache.cloudstack.api.command.user.vmgroup.UpdateVMGroupCmd; +import org.apache.cloudstack.api.command.user.vmsnapshot.CreateVMSnapshotCmd; +import org.apache.cloudstack.api.command.user.vmsnapshot.DeleteVMSnapshotCmd; +import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd; +import org.apache.cloudstack.api.command.user.vmsnapshot.RevertToVMSnapshotCmd; +import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.DeleteVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.ExtractVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.ListVolumesCmd; +import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd; +import org.apache.cloudstack.api.command.user.vpc.CreateStaticRouteCmd; +import org.apache.cloudstack.api.command.user.vpc.CreateVPCCmd; +import org.apache.cloudstack.api.command.user.vpc.DeleteStaticRouteCmd; +import org.apache.cloudstack.api.command.user.vpc.DeleteVPCCmd; +import org.apache.cloudstack.api.command.user.vpc.ListPrivateGatewaysCmd; +import org.apache.cloudstack.api.command.user.vpc.ListStaticRoutesCmd; +import org.apache.cloudstack.api.command.user.vpc.ListVPCOfferingsCmd; +import org.apache.cloudstack.api.command.user.vpc.ListVPCsCmd; +import org.apache.cloudstack.api.command.user.vpc.RestartVPCCmd; +import org.apache.cloudstack.api.command.user.vpc.UpdateVPCCmd; +import org.apache.cloudstack.api.command.user.vpn.AddVpnUserCmd; +import org.apache.cloudstack.api.command.user.vpn.CreateRemoteAccessVpnCmd; +import org.apache.cloudstack.api.command.user.vpn.CreateVpnConnectionCmd; +import org.apache.cloudstack.api.command.user.vpn.CreateVpnCustomerGatewayCmd; +import org.apache.cloudstack.api.command.user.vpn.CreateVpnGatewayCmd; +import org.apache.cloudstack.api.command.user.vpn.DeleteRemoteAccessVpnCmd; +import org.apache.cloudstack.api.command.user.vpn.DeleteVpnConnectionCmd; +import org.apache.cloudstack.api.command.user.vpn.DeleteVpnCustomerGatewayCmd; +import org.apache.cloudstack.api.command.user.vpn.DeleteVpnGatewayCmd; +import org.apache.cloudstack.api.command.user.vpn.ListRemoteAccessVpnsCmd; +import org.apache.cloudstack.api.command.user.vpn.ListVpnConnectionsCmd; +import org.apache.cloudstack.api.command.user.vpn.ListVpnCustomerGatewaysCmd; +import org.apache.cloudstack.api.command.user.vpn.ListVpnGatewaysCmd; +import org.apache.cloudstack.api.command.user.vpn.ListVpnUsersCmd; +import org.apache.cloudstack.api.command.user.vpn.RemoveVpnUserCmd; +import org.apache.cloudstack.api.command.user.vpn.ResetVpnConnectionCmd; +import org.apache.cloudstack.api.command.user.vpn.UpdateVpnCustomerGatewayCmd; +import org.apache.cloudstack.api.command.user.zone.ListZonesByCmd; +import org.apache.cloudstack.api.response.ExtractResponse; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.commons.codec.binary.Base64; +import org.apache.log4j.Logger; + import com.cloud.agent.AgentManager; import com.cloud.agent.api.GetVncPortAnswer; import com.cloud.agent.api.GetVncPortCommand; @@ -103,28 +421,53 @@ import com.cloud.alert.AlertManager; import com.cloud.alert.AlertVO; import com.cloud.alert.dao.AlertDao; import com.cloud.api.ApiDBUtils; -import com.cloud.async.*; +import com.cloud.async.AsyncJobExecutor; +import com.cloud.async.AsyncJobManager; +import com.cloud.async.AsyncJobResult; +import com.cloud.async.AsyncJobVO; +import com.cloud.async.BaseAsyncJobExecutor; import com.cloud.capacity.Capacity; import com.cloud.capacity.CapacityVO; import com.cloud.capacity.dao.CapacityDao; import com.cloud.capacity.dao.CapacityDaoImpl.SummedCapacity; import com.cloud.cluster.ClusterManager; +import com.cloud.configuration.Config; +import com.cloud.configuration.Configuration; +import com.cloud.configuration.ConfigurationManager; +import com.cloud.configuration.ConfigurationVO; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.consoleproxy.ConsoleProxyManagementState; import com.cloud.consoleproxy.ConsoleProxyManager; -import com.cloud.dc.*; +import com.cloud.dc.AccountVlanMapVO; +import com.cloud.dc.ClusterVO; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.HostPodVO; +import com.cloud.dc.Pod; +import com.cloud.dc.PodVlanMapVO; +import com.cloud.dc.Vlan; import com.cloud.dc.Vlan.VlanType; -import com.cloud.dc.dao.*; +import com.cloud.dc.VlanVO; +import com.cloud.dc.dao.AccountVlanMapDao; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.HostPodDao; +import com.cloud.dc.dao.PodVlanMapDao; +import com.cloud.dc.dao.VlanDao; import com.cloud.deploy.DataCenterDeployment; -import com.cloud.deploy.DeploymentPlanner; import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; +import com.cloud.event.ActionEventUtils; import com.cloud.event.EventTypes; import com.cloud.event.EventVO; import com.cloud.event.dao.EventDao; -import com.cloud.exception.*; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.OperationTimedoutException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.exception.StorageUnavailableException; import com.cloud.ha.HighAvailabilityManager; import com.cloud.host.DetailVO; import com.cloud.host.Host; @@ -141,7 +484,12 @@ import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; import com.cloud.info.ConsoleProxyInfo; import com.cloud.keystore.KeystoreManager; import com.cloud.network.IpAddress; -import com.cloud.network.dao.*; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.LoadBalancerDao; +import com.cloud.network.dao.LoadBalancerVO; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; import com.cloud.org.Cluster; import com.cloud.org.Grouping.AllocationState; import com.cloud.projects.Project; @@ -150,11 +498,29 @@ import com.cloud.projects.ProjectManager; import com.cloud.resource.ResourceManager; import com.cloud.server.ResourceTag.TaggedResourceType; import com.cloud.server.auth.UserAuthenticator; -import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; -import com.cloud.storage.*; +import com.cloud.storage.DiskOfferingVO; +import com.cloud.storage.GuestOS; +import com.cloud.storage.GuestOSCategoryVO; +import com.cloud.storage.GuestOSVO; +import com.cloud.storage.GuestOsCategory; +import com.cloud.storage.Storage; import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.StorageManager; +import com.cloud.storage.StoragePool; +import com.cloud.storage.Upload; import com.cloud.storage.Upload.Mode; +import com.cloud.storage.UploadVO; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.Volume; +import com.cloud.storage.VolumeManager; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.storage.dao.GuestOSCategoryDao; +import com.cloud.storage.dao.GuestOSDao; +import com.cloud.storage.dao.UploadDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.s3.S3Manager; import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.storage.snapshot.SnapshotManager; @@ -164,7 +530,13 @@ import com.cloud.tags.ResourceTagVO; import com.cloud.tags.dao.ResourceTagDao; import com.cloud.template.TemplateManager; import com.cloud.template.VirtualMachineTemplate.TemplateFilter; -import com.cloud.user.*; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.SSHKeyPair; +import com.cloud.user.SSHKeyPairVO; +import com.cloud.user.User; +import com.cloud.user.UserContext; +import com.cloud.user.UserVO; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.SSHKeyPairDao; import com.cloud.user.dao.UserDao; @@ -177,91 +549,39 @@ import com.cloud.utils.component.ComponentLifecycle; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.crypt.DBEncryptionUtil; -import com.cloud.utils.db.*; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.GlobalLock; +import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.JoinBuilder.JoinType; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.MacAddress; import com.cloud.utils.net.NetUtils; import com.cloud.utils.ssh.SSHKeysHelper; -import com.cloud.vm.*; +import com.cloud.vm.ConsoleProxyVO; +import com.cloud.vm.DiskProfile; +import com.cloud.vm.InstanceGroupVO; +import com.cloud.vm.SecondaryStorageVmVO; +import com.cloud.vm.UserVmVO; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.State; -import com.cloud.vm.dao.*; +import com.cloud.vm.VirtualMachineManager; +import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.VirtualMachineProfileImpl; +import com.cloud.vm.dao.ConsoleProxyDao; +import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.InstanceGroupDao; +import com.cloud.vm.dao.SecondaryStorageVmDao; +import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.VMInstanceDao; + import edu.emory.mathcs.backport.java.util.Arrays; import edu.emory.mathcs.backport.java.util.Collections; -import org.apache.cloudstack.acl.ControlledEntity; -import org.apache.cloudstack.api.command.admin.autoscale.CreateCounterCmd; -import org.apache.cloudstack.api.command.admin.autoscale.DeleteCounterCmd; -import org.apache.cloudstack.api.command.admin.cluster.AddClusterCmd; -import org.apache.cloudstack.api.command.admin.cluster.DeleteClusterCmd; -import org.apache.cloudstack.api.command.admin.cluster.ListClustersCmd; -import org.apache.cloudstack.api.command.admin.cluster.UpdateClusterCmd; -import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd; -import org.apache.cloudstack.api.command.admin.config.ListHypervisorCapabilitiesCmd; -import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd; -import org.apache.cloudstack.api.command.admin.config.UpdateHypervisorCapabilitiesCmd; -import org.apache.cloudstack.api.command.admin.ldap.LDAPConfigCmd; -import org.apache.cloudstack.api.command.admin.ldap.LDAPRemoveCmd; -import org.apache.cloudstack.api.command.admin.pod.CreatePodCmd; -import org.apache.cloudstack.api.command.admin.pod.DeletePodCmd; -import org.apache.cloudstack.api.command.admin.pod.ListPodsByCmd; -import org.apache.cloudstack.api.command.admin.pod.UpdatePodCmd; -import org.apache.cloudstack.api.command.admin.region.AddRegionCmd; -import org.apache.cloudstack.api.command.admin.region.RemoveRegionCmd; -import org.apache.cloudstack.api.command.admin.region.UpdateRegionCmd; -import org.apache.cloudstack.api.command.admin.swift.AddSwiftCmd; -import org.apache.cloudstack.api.command.admin.swift.ListSwiftsCmd; -import org.apache.cloudstack.api.command.admin.template.PrepareTemplateCmd; -import org.apache.cloudstack.api.command.admin.vlan.CreateVlanIpRangeCmd; -import org.apache.cloudstack.api.command.admin.vlan.DeleteVlanIpRangeCmd; -import org.apache.cloudstack.api.command.admin.vlan.ListVlanIpRangesCmd; -import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; -import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd; -import org.apache.cloudstack.api.command.admin.vm.MigrateVirtualMachineWithVolumeCmd; -import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; -import org.apache.cloudstack.api.command.admin.zone.CreateZoneCmd; -import org.apache.cloudstack.api.command.admin.zone.DeleteZoneCmd; -import org.apache.cloudstack.api.command.admin.zone.MarkDefaultZoneForAccountCmd; -import org.apache.cloudstack.api.command.admin.zone.UpdateZoneCmd; -import org.apache.cloudstack.api.command.user.account.AddAccountToProjectCmd; -import org.apache.cloudstack.api.command.user.account.DeleteAccountFromProjectCmd; -import org.apache.cloudstack.api.command.user.account.ListAccountsCmd; -import org.apache.cloudstack.api.command.user.account.ListProjectAccountsCmd; -import org.apache.cloudstack.api.command.user.address.AssociateIPAddrCmd; -import org.apache.cloudstack.api.command.user.address.DisassociateIPAddrCmd; -import org.apache.cloudstack.api.command.user.address.ListPublicIpAddressesCmd; -import org.apache.cloudstack.api.command.user.config.ListCapabilitiesCmd; -import org.apache.cloudstack.api.command.user.event.ArchiveEventsCmd; -import org.apache.cloudstack.api.command.user.event.DeleteEventsCmd; -import org.apache.cloudstack.api.command.user.event.ListEventTypesCmd; -import org.apache.cloudstack.api.command.user.event.ListEventsCmd; -import org.apache.cloudstack.api.command.user.guest.ListGuestOsCategoriesCmd; -import org.apache.cloudstack.api.command.user.guest.ListGuestOsCmd; -import org.apache.cloudstack.api.command.user.job.ListAsyncJobsCmd; -import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd; -import org.apache.cloudstack.api.command.user.offering.ListDiskOfferingsCmd; -import org.apache.cloudstack.api.command.user.offering.ListServiceOfferingsCmd; -import org.apache.cloudstack.api.command.user.region.ListRegionsCmd; -import org.apache.cloudstack.api.command.user.region.ha.gslb.*; -import org.apache.cloudstack.api.command.user.ssh.CreateSSHKeyPairCmd; -import org.apache.cloudstack.api.command.user.ssh.DeleteSSHKeyPairCmd; -import org.apache.cloudstack.api.command.user.ssh.ListSSHKeyPairsCmd; -import org.apache.cloudstack.api.command.user.ssh.RegisterSSHKeyPairCmd; -import org.apache.cloudstack.api.command.user.tag.CreateTagsCmd; -import org.apache.cloudstack.api.command.user.tag.DeleteTagsCmd; -import org.apache.cloudstack.api.command.user.tag.ListTagsCmd; -import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; -import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; -import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd; -import org.apache.cloudstack.api.command.user.vmgroup.UpdateVMGroupCmd; -import org.apache.cloudstack.api.command.user.vmsnapshot.CreateVMSnapshotCmd; -import org.apache.cloudstack.api.command.user.vmsnapshot.DeleteVMSnapshotCmd; -import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd; -import org.apache.cloudstack.api.command.user.vmsnapshot.RevertToVMSnapshotCmd; -import org.apache.cloudstack.api.command.user.zone.ListZonesByCmd; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; -import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; + public class ManagementServerImpl extends ManagerBase implements ManagementServer { public static final Logger s_logger = Logger.getLogger(ManagementServerImpl.class.getName()); @@ -2542,11 +2862,21 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(AssignToGlobalLoadBalancerRuleCmd.class); cmdList.add(RemoveFromGlobalLoadBalancerRuleCmd.class); cmdList.add(ListStorageProvidersCmd.class); + cmdList.add(CreateApplicationLoadBalancerCmd.class); + cmdList.add(ListApplicationLoadBalancersCmd.class); + cmdList.add(DeleteApplicationLoadBalancerCmd.class); + cmdList.add(ConfigureInternalLoadBalancerElementCmd.class); + cmdList.add(CreateInternalLoadBalancerElementCmd.class); + cmdList.add(ListInternalLoadBalancerElementsCmd.class); cmdList.add(CreateAffinityGroupCmd.class); cmdList.add(DeleteAffinityGroupCmd.class); cmdList.add(ListAffinityGroupsCmd.class); cmdList.add(UpdateVMAffinityGroupCmd.class); cmdList.add(ListAffinityGroupTypesCmd.class); + cmdList.add(StopInternalLBVMCmd.class); + cmdList.add(StartInternalLBVMCmd.class); + cmdList.add(ListInternalLBVMsCmd.class); + cmdList.add(ListNetworkIsolationMethodsCmd.class); cmdList.add(ListNetworkIsolationMethodsCmd.class); return cmdList; diff --git a/server/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerManagerImpl.java b/server/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerManagerImpl.java new file mode 100644 index 00000000000..ec0be8c9d96 --- /dev/null +++ b/server/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerManagerImpl.java @@ -0,0 +1,524 @@ +// 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. + +package org.apache.cloudstack.network.lb; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; +import javax.inject.Inject; + +import org.apache.cloudstack.acl.SecurityChecker.AccessType; +import org.apache.cloudstack.api.command.user.loadbalancer.ListApplicationLoadBalancersCmd; +import org.apache.cloudstack.lb.ApplicationLoadBalancerRuleVO; +import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.event.ActionEvent; +import com.cloud.event.EventTypes; +import com.cloud.event.UsageEventUtils; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapcityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.UnsupportedServiceException; +import com.cloud.network.Network; +import com.cloud.network.Network.Capability; +import com.cloud.network.Network.Service; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkModel; +import com.cloud.network.Networks.TrafficType; +import com.cloud.network.dao.FirewallRulesDao; +import com.cloud.network.lb.LoadBalancingRule; +import com.cloud.network.lb.LoadBalancingRule.LbDestination; +import com.cloud.network.lb.LoadBalancingRule.LbHealthCheckPolicy; +import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; +import com.cloud.network.lb.LoadBalancingRulesManager; +import com.cloud.network.rules.FirewallRule.State; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.projects.Project.ListProjectResourcesCriteria; +import com.cloud.server.ResourceTag.TaggedResourceType; +import com.cloud.tags.ResourceTagVO; +import com.cloud.tags.dao.ResourceTagDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.UserContext; +import com.cloud.utils.Pair; +import com.cloud.utils.Ternary; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.JoinBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; +import com.cloud.utils.net.NetUtils; + +@Component +@Local(value = { ApplicationLoadBalancerService.class }) +public class ApplicationLoadBalancerManagerImpl extends ManagerBase implements ApplicationLoadBalancerService { + private static final Logger s_logger = Logger.getLogger(ApplicationLoadBalancerManagerImpl.class); + + @Inject NetworkModel _networkModel; + @Inject ApplicationLoadBalancerRuleDao _lbDao; + @Inject AccountManager _accountMgr; + @Inject LoadBalancingRulesManager _lbMgr; + @Inject FirewallRulesDao _firewallDao; + @Inject ResourceTagDao _resourceTagDao; + @Inject NetworkManager _ntwkMgr; + + + @Override + @ActionEvent(eventType = EventTypes.EVENT_LOAD_BALANCER_CREATE, eventDescription = "creating load balancer") + public ApplicationLoadBalancerRule createApplicationLoadBalancer(String name, String description, Scheme scheme, long sourceIpNetworkId, String sourceIp, + int sourcePort, int instancePort, String algorithm, long networkId, long lbOwnerId) throws InsufficientAddressCapacityException, + NetworkRuleConflictException, InsufficientVirtualNetworkCapcityException { + + //Validate LB rule guest network + Network guestNtwk = _networkModel.getNetwork(networkId); + if (guestNtwk == null || guestNtwk.getTrafficType() != TrafficType.Guest) { + throw new InvalidParameterValueException("Can't find guest network by id"); + } + + Account caller = UserContext.current().getCaller(); + _accountMgr.checkAccess(caller, AccessType.UseNetwork, false, guestNtwk); + + Network sourceIpNtwk = _networkModel.getNetwork(sourceIpNetworkId); + if (sourceIpNtwk == null) { + throw new InvalidParameterValueException("Can't find source ip network by id"); + } + + Account lbOwner = _accountMgr.getAccount(lbOwnerId); + if (lbOwner == null) { + throw new InvalidParameterValueException("Can't find the lb owner account"); + } + + return createApplicationLoadBalancer(name, description, scheme, sourceIpNtwk, sourceIp, sourcePort, instancePort, algorithm, lbOwner, guestNtwk); + } + + + protected ApplicationLoadBalancerRule createApplicationLoadBalancer(String name, String description, Scheme scheme, Network sourceIpNtwk, String sourceIp, int sourcePort, int instancePort, String algorithm, + Account lbOwner, Network guestNtwk) throws NetworkRuleConflictException, InsufficientVirtualNetworkCapcityException { + + //Only Internal scheme is supported in this release + if (scheme != Scheme.Internal) { + throw new UnsupportedServiceException("Only scheme of type " + Scheme.Internal + " is supported"); + } + + //1) Validate LB rule's parameters + validateLbRule(sourcePort, instancePort, algorithm, guestNtwk, scheme); + + //2) Validate source network + validateSourceIpNtwkForLbRule(sourceIpNtwk, scheme); + + //3) Get source ip address + Ip sourceIpAddr = getSourceIp(scheme, sourceIpNtwk, sourceIp); + + ApplicationLoadBalancerRuleVO newRule = new ApplicationLoadBalancerRuleVO(name, description, sourcePort, instancePort, algorithm, guestNtwk.getId(), + lbOwner.getId(), lbOwner.getDomainId(), sourceIpAddr, sourceIpNtwk.getId(), scheme); + + //4) Validate Load Balancing rule on the providers + LoadBalancingRule loadBalancing = new LoadBalancingRule(newRule, new ArrayList(), + new ArrayList(), new ArrayList(), sourceIpAddr); + if (!_lbMgr.validateLbRule(loadBalancing)) { + throw new InvalidParameterValueException("LB service provider cannot support this rule"); + } + + //5) Persist Load Balancer rule + return persistLbRule(newRule); + } + + + @DB + protected ApplicationLoadBalancerRule persistLbRule(ApplicationLoadBalancerRuleVO newRule) throws NetworkRuleConflictException { + + Transaction txn = Transaction.currentTxn(); + txn.start(); + + //1) Persist the rule + newRule = _lbDao.persist(newRule); + boolean success = true; + + try { + //2) Detect conflicts + detectLbRulesConflicts(newRule); + if (!_firewallDao.setStateToAdd(newRule)) { + throw new CloudRuntimeException("Unable to update the state to add for " + newRule); + } + s_logger.debug("Load balancer " + newRule.getId() + " for Ip address " + newRule.getSourceIp().addr() + ", source port " + + newRule.getSourcePortStart() + ", instance port " + newRule.getDefaultPortStart() + " is added successfully."); + UserContext.current().setEventDetails("Load balancer Id: " + newRule.getId()); + Network ntwk = _networkModel.getNetwork(newRule.getNetworkId()); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_LOAD_BALANCER_CREATE, newRule.getAccountId(), + ntwk.getDataCenterId(), newRule.getId(), null, LoadBalancingRule.class.getName(), + newRule.getUuid()); + txn.commit(); + + return newRule; + } catch (Exception e) { + success = false; + if (e instanceof NetworkRuleConflictException) { + throw (NetworkRuleConflictException) e; + } + throw new CloudRuntimeException("Unable to add lb rule for ip address " + newRule.getSourceIpAddressId(), e); + } finally { + if (!success && newRule != null) { + _lbMgr.removeLBRule(newRule); + } + } + } + + /** + * Validates Lb rule parameters + * @param sourcePort + * @param instancePort + * @param algorithm + * @param network + * @param scheme TODO + * @param networkId + */ + protected void validateLbRule(int sourcePort, int instancePort, String algorithm, Network network, Scheme scheme) { + //1) verify that lb service is supported by the network + if (!_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Lb)) { + InvalidParameterValueException ex = new InvalidParameterValueException( + "LB service is not supported in specified network id"); + ex.addProxyObject(network, network.getId(), "networkId"); + throw ex; + } + + //2) verify that lb service is supported by the network + _lbMgr.isLbServiceSupportedInNetwork(network.getId(), scheme); + + Map caps = _networkModel.getNetworkServiceCapabilities(network.getId(), Service.Lb); + String supportedProtocols = caps.get(Capability.SupportedProtocols).toLowerCase(); + if (!supportedProtocols.contains(NetUtils.TCP_PROTO.toLowerCase())) { + throw new InvalidParameterValueException("Protocol " + NetUtils.TCP_PROTO.toLowerCase() + " is not supported in zone " + network.getDataCenterId()); + } + + //3) Validate rule parameters + if (!NetUtils.isValidPort(instancePort)) { + throw new InvalidParameterValueException("Invalid value for instance port: " + instancePort); + } + + if (!NetUtils.isValidPort(sourcePort)) { + throw new InvalidParameterValueException("Invalid value for source port: " + sourcePort); + } + + if ((algorithm == null) || !NetUtils.isValidAlgorithm(algorithm)) { + throw new InvalidParameterValueException("Invalid algorithm: " + algorithm); + } + } + + + /** + * Gets source ip address based on the LB rule scheme/source IP network/requested IP address + * @param scheme + * @param sourceIpNtwk + * @param requestedIp + * @return + * @throws InsufficientVirtualNetworkCapcityException + */ + protected Ip getSourceIp(Scheme scheme, Network sourceIpNtwk, String requestedIp) throws InsufficientVirtualNetworkCapcityException { + + if (requestedIp != null) { + if (_lbDao.countBySourceIp(new Ip(requestedIp), sourceIpNtwk.getId()) > 0) { + s_logger.debug("IP address " + requestedIp + " is already used by existing LB rule, returning it"); + return new Ip(requestedIp); + } + + validateRequestedSourceIpForLbRule(sourceIpNtwk, new Ip(requestedIp), scheme); + } + + requestedIp = allocateSourceIpForLbRule(scheme, sourceIpNtwk, requestedIp); + + if (requestedIp == null) { + throw new InsufficientVirtualNetworkCapcityException("Unable to acquire IP address for network " + sourceIpNtwk, Network.class, sourceIpNtwk.getId()); + } + return new Ip(requestedIp); + } + + + /** + * Allocates new Source IP address for the Load Balancer rule based on LB rule scheme/sourceNetwork + * @param scheme + * @param sourceIpNtwk + * @param requestedIp TODO + * @param sourceIp + * @return + */ + protected String allocateSourceIpForLbRule(Scheme scheme, Network sourceIpNtwk, String requestedIp) { + String sourceIp = null; + if (scheme != Scheme.Internal) { + throw new InvalidParameterValueException("Only scheme " + Scheme.Internal + " is supported"); + } else { + sourceIp = allocateSourceIpForInternalLbRule(sourceIpNtwk, requestedIp); + } + return sourceIp; + } + + + /** + * Allocates sourceIp for the Internal LB rule + * @param sourceIpNtwk + * @param requestedIp TODO + * @return + */ + protected String allocateSourceIpForInternalLbRule(Network sourceIpNtwk, String requestedIp) { + return _ntwkMgr.acquireGuestIpAddress(sourceIpNtwk, requestedIp); + } + + + /** + * Validates requested source ip address of the LB rule based on Lb rule scheme/sourceNetwork + * @param sourceIpNtwk + * @param requestedSourceIp + * @param scheme + */ + void validateRequestedSourceIpForLbRule(Network sourceIpNtwk, Ip requestedSourceIp, Scheme scheme) { + //only Internal scheme is supported in this release + if (scheme != Scheme.Internal) { + throw new UnsupportedServiceException("Only scheme of type " + Scheme.Internal + " is supported"); + } else { + //validate guest source ip + validateRequestedSourceIpForInternalLbRule(sourceIpNtwk, requestedSourceIp); + } + } + + + /** + * Validates requested source IP address of Internal Lb rule against sourceNetworkId + * @param sourceIpNtwk + * @param requestedSourceIp + */ + protected void validateRequestedSourceIpForInternalLbRule(Network sourceIpNtwk, Ip requestedSourceIp) { + //Check if the IP is within the network cidr + Pair cidr = NetUtils.getCidr(sourceIpNtwk.getCidr()); + if (!NetUtils.getCidrSubNet(requestedSourceIp.addr(), cidr.second()).equalsIgnoreCase(NetUtils.getCidrSubNet(cidr.first(), cidr.second()))) { + throw new InvalidParameterValueException("The requested IP is not in the network's CIDR subnet."); + } + } + + + /** + * Validates source IP network for the LB rule + * @param sourceNtwk + * @param scheme + * @return + */ + protected Network validateSourceIpNtwkForLbRule(Network sourceNtwk, Scheme scheme) { + //only Internal scheme is supported in this release + if (scheme != Scheme.Internal) { + throw new UnsupportedServiceException("Only scheme of type " + Scheme.Internal + " is supported"); + } else { + //validate source ip network + return validateSourceIpNtwkForInternalLbRule(sourceNtwk); + } + + } + + /** + * Validates source IP network for the Internal LB rule + * @param sourceIpNtwk + * @return + */ + protected Network validateSourceIpNtwkForInternalLbRule(Network sourceIpNtwk) { + if (sourceIpNtwk.getTrafficType() != TrafficType.Guest) { + throw new InvalidParameterValueException("Only traffic type " + TrafficType.Guest + " is supported"); + } + + //Can't create the LB rule if the network's cidr is NULL + String ntwkCidr = sourceIpNtwk.getCidr(); + if (ntwkCidr == null) { + throw new InvalidParameterValueException("Can't create the application load balancer rule for the network having NULL cidr"); + } + + //check if the requested ip address is within the cidr + return sourceIpNtwk; + } + + + @Override + public boolean deleteApplicationLoadBalancer(long id) { + return _lbMgr.deleteLoadBalancerRule(id, true); + } + + @Override + public Pair, Integer> listApplicationLoadBalancers(ListApplicationLoadBalancersCmd cmd) { + Long id = cmd.getId(); + String name = cmd.getLoadBalancerRuleName(); + String ip = cmd.getSourceIp(); + Long ipNtwkId = cmd.getSourceIpNetworkId(); + String keyword = cmd.getKeyword(); + Scheme scheme = cmd.getScheme(); + Long networkId = cmd.getNetworkId(); + + Map tags = cmd.getTags(); + + Account caller = UserContext.current().getCaller(); + List permittedAccounts = new ArrayList(); + + Ternary domainIdRecursiveListProject = new Ternary( + cmd.getDomainId(), cmd.isRecursive(), null); + _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, + domainIdRecursiveListProject, cmd.listAll(), false); + Long domainId = domainIdRecursiveListProject.first(); + Boolean isRecursive = domainIdRecursiveListProject.second(); + ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); + + Filter searchFilter = new Filter(ApplicationLoadBalancerRuleVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal()); + SearchBuilder sb = _lbDao.createSearchBuilder(); + _accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); + + sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); + sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ); + sb.and("sourceIpAddress", sb.entity().getSourceIp(), SearchCriteria.Op.EQ); + sb.and("sourceIpAddressNetworkId", sb.entity().getSourceIpNetworkId(), SearchCriteria.Op.EQ); + sb.and("scheme", sb.entity().getScheme(), SearchCriteria.Op.EQ); + sb.and("networkId", sb.entity().getNetworkId(), SearchCriteria.Op.EQ); + + //list only load balancers having not null sourceIp/sourceIpNtwkId + sb.and("sourceIpAddress", sb.entity().getSourceIp(), SearchCriteria.Op.NNULL); + sb.and("sourceIpAddressNetworkId", sb.entity().getSourceIpNetworkId(), SearchCriteria.Op.NNULL); + + if (tags != null && !tags.isEmpty()) { + SearchBuilder tagSearch = _resourceTagDao.createSearchBuilder(); + for (int count = 0; count < tags.size(); count++) { + tagSearch.or().op("key" + String.valueOf(count), tagSearch.entity().getKey(), SearchCriteria.Op.EQ); + tagSearch.and("value" + String.valueOf(count), tagSearch.entity().getValue(), SearchCriteria.Op.EQ); + tagSearch.cp(); + } + tagSearch.and("resourceType", tagSearch.entity().getResourceType(), SearchCriteria.Op.EQ); + sb.groupBy(sb.entity().getId()); + sb.join("tagSearch", tagSearch, sb.entity().getId(), tagSearch.entity().getResourceId(), + JoinBuilder.JoinType.INNER); + } + + SearchCriteria sc = sb.create(); + _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); + + if (keyword != null) { + SearchCriteria ssc = _lbDao.createSearchCriteria(); + ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%"); + ssc.addOr("description", SearchCriteria.Op.LIKE, "%" + keyword + "%"); + sc.addAnd("name", SearchCriteria.Op.SC, ssc); + } + + if (name != null) { + sc.setParameters("name", name); + } + + if (id != null) { + sc.setParameters("id", id); + } + + if (ip != null) { + sc.setParameters("sourceIpAddress", ip); + } + + if (ipNtwkId != null) { + sc.setParameters("sourceIpAddressNetworkId", ipNtwkId); + } + + if (scheme != null) { + sc.setParameters("scheme", scheme); + } + + if (networkId != null) { + sc.setParameters("networkId", networkId); + } + + if (tags != null && !tags.isEmpty()) { + int count = 0; + sc.setJoinParameters("tagSearch", "resourceType", TaggedResourceType.LoadBalancer.toString()); + for (String key : tags.keySet()) { + sc.setJoinParameters("tagSearch", "key" + String.valueOf(count), key); + sc.setJoinParameters("tagSearch", "value" + String.valueOf(count), tags.get(key)); + count++; + } + } + + Pair, Integer> result = _lbDao.searchAndCount(sc, searchFilter); + return new Pair, Integer>(result.first(), result.second()); + } + + @Override + public ApplicationLoadBalancerRule getApplicationLoadBalancer(long ruleId) { + ApplicationLoadBalancerRule lbRule = _lbDao.findById(ruleId); + if (lbRule == null) { + throw new InvalidParameterValueException("Can't find the load balancer by id"); + } + return lbRule; + } + + + /** + * Detects lb rule conflicts against other rules + * @param newLbRule + * @throws NetworkRuleConflictException + */ + protected void detectLbRulesConflicts(ApplicationLoadBalancerRule newLbRule) throws NetworkRuleConflictException { + if (newLbRule.getScheme() != Scheme.Internal) { + throw new UnsupportedServiceException("Only scheme of type " + Scheme.Internal + " is supported"); + } else { + detectInternalLbRulesConflict(newLbRule); + } + } + + + /** + * Detects Internal Lb Rules conflicts + * @param newLbRule + * @throws NetworkRuleConflictException + */ + protected void detectInternalLbRulesConflict(ApplicationLoadBalancerRule newLbRule) throws NetworkRuleConflictException { + List lbRules = _lbDao.listBySourceIpAndNotRevoked(newLbRule.getSourceIp(), newLbRule.getSourceIpNetworkId()); + + for (ApplicationLoadBalancerRuleVO lbRule : lbRules) { + if (lbRule.getId() == newLbRule.getId()) { + continue; // Skips my own rule. + } + + if (lbRule.getNetworkId() != newLbRule.getNetworkId() && lbRule.getState() != State.Revoke) { + throw new NetworkRuleConflictException("New rule is for a different network than what's specified in rule " + + lbRule.getXid()); + } + + if ((lbRule.getSourcePortStart().intValue() <= newLbRule.getSourcePortStart().intValue() + && lbRule.getSourcePortEnd().intValue() >= newLbRule.getSourcePortStart().intValue()) + || (lbRule.getSourcePortStart().intValue() <= newLbRule.getSourcePortEnd().intValue() + && lbRule.getSourcePortEnd().intValue() >= newLbRule.getSourcePortEnd().intValue()) + || (newLbRule.getSourcePortStart().intValue() <= lbRule.getSourcePortStart().intValue() + && newLbRule.getSourcePortEnd().intValue() >= lbRule.getSourcePortStart().intValue()) + || (newLbRule.getSourcePortStart().intValue() <= lbRule.getSourcePortEnd().intValue() + && newLbRule.getSourcePortEnd().intValue() >= lbRule.getSourcePortEnd().intValue())) { + + + throw new NetworkRuleConflictException("The range specified, " + newLbRule.getSourcePortStart() + "-" + newLbRule.getSourcePortEnd() + ", conflicts with rule " + lbRule.getId() + + " which has " + lbRule.getSourcePortStart() + "-" + lbRule.getSourcePortEnd()); + } + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("No network rule conflicts detected for " + newLbRule + " against " + (lbRules.size() - 1) + " existing rules"); + } + } +} diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index 2f717c8c156..eb5fc253784 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -16,13 +16,33 @@ // under the License. package com.cloud.network; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; +import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; +import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; +import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; +import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; +import org.springframework.stereotype.Component; + import com.cloud.dc.DataCenter; import com.cloud.dc.Pod; import com.cloud.dc.Vlan.VlanType; import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; -import com.cloud.exception.*; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapcityException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.Networks.TrafficType; @@ -37,6 +57,7 @@ import com.cloud.network.guru.NetworkGuru; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRule.State; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.rules.StaticNat; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.NetworkOfferingVO; @@ -46,6 +67,7 @@ import com.cloud.utils.Pair; import com.cloud.utils.component.ManagerBase; import com.cloud.vm.*; import com.cloud.vm.VirtualMachine.Type; +import com.cloud.vm.VirtualMachineProfile; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd; import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd; @@ -62,6 +84,7 @@ import java.util.List; import java.util.Map; import java.util.Set; + @Component @Local(value = { NetworkManager.class, NetworkService.class }) public class MockNetworkManagerImpl extends ManagerBase implements NetworkManager, NetworkService { @@ -820,7 +843,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage } @Override - public LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network) { + public LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network, Scheme lbScheme) { // TODO Auto-generated method stub return null; } diff --git a/server/test/com/cloud/network/MockNetworkModelImpl.java b/server/test/com/cloud/network/MockNetworkModelImpl.java index 7df45a01715..c3a0d6c5ae9 100644 --- a/server/test/com/cloud/network/MockNetworkModelImpl.java +++ b/server/test/com/cloud/network/MockNetworkModelImpl.java @@ -40,6 +40,7 @@ import com.cloud.network.dao.NetworkVO; import com.cloud.network.element.NetworkElement; import com.cloud.network.element.UserDataServiceProvider; import com.cloud.offering.NetworkOffering; +import com.cloud.offering.NetworkOffering.Detail; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.user.Account; import com.cloud.utils.component.ManagerBase; @@ -853,6 +854,22 @@ public class MockNetworkModelImpl extends ManagerBase implements NetworkModel { } @Override + public IpAddress getPublicIpAddress(String ipAddress, long zoneId) { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getUsedIpsInNetwork(Network network) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Map getNtwkOffDetails(long offId) { + return null; + } + public IsolationType[] listNetworkIsolationMethods() { // TODO Auto-generated method stub return null; diff --git a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java index 83b19247093..90587985f74 100755 --- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -501,7 +501,7 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu @Override public NetworkOfferingVO createNetworkOffering(String name, String displayText, TrafficType trafficType, String tags, boolean specifyVlan, Availability availability, Integer networkRate, Map> serviceProviderMap, boolean isDefault, GuestType type, boolean systemOnly, Long serviceOfferingId, boolean conserveMode, - Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent) { + Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent, Map details) { // TODO Auto-generated method stub return null; } diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index f884ba1d767..84ae818f489 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -16,17 +16,51 @@ // under the License. package com.cloud.vpc; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd; +import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd; +import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; +import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; +import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; +import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; +import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + import com.cloud.dc.DataCenter; import com.cloud.dc.Pod; import com.cloud.dc.Vlan.VlanType; import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; -import com.cloud.exception.*; -import com.cloud.network.*; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapcityException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.GuestVlan; +import com.cloud.network.IpAddress; +import com.cloud.network.Network; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkProfile; +import com.cloud.network.NetworkRuleApplier; +import com.cloud.network.NetworkService; import com.cloud.network.Networks.TrafficType; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.PhysicalNetworkTrafficType; +import com.cloud.network.PublicIpAddress; import com.cloud.network.addr.PublicIp; import com.cloud.network.dao.AccountGuestVlanMapVO; import com.cloud.network.dao.IPAddressVO; @@ -40,6 +74,7 @@ import com.cloud.network.guru.NetworkGuru; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRule.State; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.rules.StaticNat; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.NetworkOfferingVO; @@ -48,8 +83,15 @@ import com.cloud.user.Account; import com.cloud.user.User; import com.cloud.utils.Pair; import com.cloud.utils.component.ManagerBase; -import com.cloud.vm.*; +import com.cloud.vm.Nic; +import com.cloud.vm.NicProfile; +import com.cloud.vm.NicSecondaryIp; +import com.cloud.vm.NicVO; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; +import com.cloud.vm.VirtualMachineProfile; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd; import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd; @@ -61,12 +103,6 @@ import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; @Component @Local(value = { NetworkManager.class, NetworkService.class }) @@ -1301,7 +1337,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage } @Override - public LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network) { + public LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network, Scheme lbScheme) { // TODO Auto-generated method stub return null; } diff --git a/server/test/com/cloud/vpc/MockNetworkModelImpl.java b/server/test/com/cloud/vpc/MockNetworkModelImpl.java index c9d043ad0d1..d9e33b75616 100644 --- a/server/test/com/cloud/vpc/MockNetworkModelImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkModelImpl.java @@ -47,6 +47,7 @@ import com.cloud.network.dao.NetworkVO; import com.cloud.network.element.NetworkElement; import com.cloud.network.element.UserDataServiceProvider; import com.cloud.offering.NetworkOffering; +import com.cloud.offering.NetworkOffering.Detail; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.user.Account; @@ -865,6 +866,22 @@ public class MockNetworkModelImpl extends ManagerBase implements NetworkModel { } @Override + public IpAddress getPublicIpAddress(String ipAddress, long zoneId) { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getUsedIpsInNetwork(Network network) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Map getNtwkOffDetails(long offId) { + return null; + } + public IsolationType[] listNetworkIsolationMethods() { // TODO Auto-generated method stub return null; diff --git a/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java b/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java index ef5478bb1f8..9010f1f5acb 100644 --- a/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java +++ b/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java @@ -36,6 +36,7 @@ import com.cloud.network.RemoteAccessVpn; import com.cloud.network.Site2SiteVpnConnection; import com.cloud.network.VpcVirtualNetworkApplianceService; import com.cloud.network.VpnUser; +import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.router.VirtualRouter; import com.cloud.network.router.VpcVirtualNetworkApplianceManager; import com.cloud.network.rules.FirewallRule; @@ -46,7 +47,6 @@ import com.cloud.network.vpc.Vpc; import com.cloud.user.Account; import com.cloud.user.User; import com.cloud.uservm.UserVm; -import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.vm.DomainRouterVO; import com.cloud.vm.NicProfile; @@ -402,4 +402,16 @@ VpcVirtualNetworkApplianceService { return null; } + @Override + public boolean applyLoadBalancingRules(Network network, List rules, List routers) throws ResourceUnavailableException { + // TODO Auto-generated method stub + return false; + } + + @Override + public VirtualRouter findRouter(long routerId) { + // TODO Auto-generated method stub + return null; + } + } diff --git a/server/test/com/cloud/vpc/dao/MockNetworkOfferingDaoImpl.java b/server/test/com/cloud/vpc/dao/MockNetworkOfferingDaoImpl.java index dbf14113de4..a8208dd7d9c 100644 --- a/server/test/com/cloud/vpc/dao/MockNetworkOfferingDaoImpl.java +++ b/server/test/com/cloud/vpc/dao/MockNetworkOfferingDaoImpl.java @@ -101,28 +101,28 @@ public class MockNetworkOfferingDaoImpl extends NetworkOfferingDaoImpl implement if (id.longValue() == 1) { //network offering valid for vpc vo = new NetworkOfferingVO("vpc", "vpc", TrafficType.Guest, false, true, null, null, false, - Availability.Optional, null, Network.GuestType.Isolated, false, false, false); + Availability.Optional, null, Network.GuestType.Isolated, false, false, false, false, false); } else if (id.longValue() == 2) { //invalid offering - source nat is not included vo = new NetworkOfferingVO("vpc", "vpc", TrafficType.Guest, false, true, null, null, false, - Availability.Optional, null, Network.GuestType.Isolated, false, false, false); + Availability.Optional, null, Network.GuestType.Isolated, false, false, false, false, false); } else if (id.longValue() == 3) { //network offering invalid for vpc (conserve mode off) vo = new NetworkOfferingVO("non vpc", "non vpc", TrafficType.Guest, false, true, null, null, false, - Availability.Optional, null, Network.GuestType.Isolated, true, false, false); + Availability.Optional, null, Network.GuestType.Isolated, true, false, false, false, false); } else if (id.longValue() == 4) { //network offering invalid for vpc (Shared) vo = new NetworkOfferingVO("non vpc", "non vpc", TrafficType.Guest, false, true, null, null, false, - Availability.Optional, null, Network.GuestType.Shared, false, false, false); + Availability.Optional, null, Network.GuestType.Shared, false, false, false, false, false); } else if (id.longValue() == 5) { //network offering invalid for vpc (has redundant router) vo = new NetworkOfferingVO("vpc", "vpc", TrafficType.Guest, false, true, null, null, false, - Availability.Optional, null, Network.GuestType.Isolated, false, false, false); + Availability.Optional, null, Network.GuestType.Isolated, false, false, false, false, false); vo.setRedundantRouter(true); } else if (id.longValue() == 6) { //network offering invalid for vpc (has lb service) vo = new NetworkOfferingVO("vpc", "vpc", TrafficType.Guest, false, true, null, null, false, - Availability.Optional, null, Network.GuestType.Isolated, false, false, false); + Availability.Optional, null, Network.GuestType.Isolated, false, false, false, false, false); } if (vo != null) { diff --git a/server/test/com/cloud/vpc/dao/MockNetworkServiceMapDaoImpl.java b/server/test/com/cloud/vpc/dao/MockNetworkServiceMapDaoImpl.java index 002b61dcbc4..103f04ea8b9 100644 --- a/server/test/com/cloud/vpc/dao/MockNetworkServiceMapDaoImpl.java +++ b/server/test/com/cloud/vpc/dao/MockNetworkServiceMapDaoImpl.java @@ -95,4 +95,10 @@ public class MockNetworkServiceMapDaoImpl extends GenericDaoBase getProvidersForServiceInNetwork(long networkId, Service service) { + // TODO Auto-generated method stub + return null; + } } diff --git a/server/test/org/apache/cloudstack/lb/ApplicationLoadBalancerTest.java b/server/test/org/apache/cloudstack/lb/ApplicationLoadBalancerTest.java new file mode 100644 index 00000000000..461cbbdf012 --- /dev/null +++ b/server/test/org/apache/cloudstack/lb/ApplicationLoadBalancerTest.java @@ -0,0 +1,292 @@ +// 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. +package org.apache.cloudstack.lb; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +import javax.inject.Inject; + +import junit.framework.TestCase; + +import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; +import org.apache.cloudstack.network.lb.ApplicationLoadBalancerManagerImpl; +import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.cloud.event.dao.UsageEventDao; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapcityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.UnsupportedServiceException; +import com.cloud.network.Network; +import com.cloud.network.Network.Capability; +import com.cloud.network.Network.Service; +import com.cloud.network.NetworkModel; +import com.cloud.network.Networks.TrafficType; +import com.cloud.network.dao.FirewallRulesDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.lb.LoadBalancingRule; +import com.cloud.network.lb.LoadBalancingRulesManager; +import com.cloud.network.rules.FirewallRuleVO; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.UserContext; +import com.cloud.user.UserVO; +import com.cloud.utils.component.ComponentContext; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; +import com.cloud.utils.net.NetUtils; + +/** + * This class is responsible for unittesting the methods defined in ApplicationLoadBalancerService + * + */ + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations="classpath:/appLoadBalancer.xml") +public class ApplicationLoadBalancerTest extends TestCase{ + //The interface to test + @Inject ApplicationLoadBalancerManagerImpl _appLbSvc; + + //The interfaces below are mocked + @Inject ApplicationLoadBalancerRuleDao _lbDao; + @Inject LoadBalancingRulesManager _lbMgr; + @Inject NetworkModel _ntwkModel; + @Inject AccountManager _accountMgr; + @Inject FirewallRulesDao _firewallDao; + @Inject UsageEventDao _usageEventDao; + + + public static long existingLbId = 1L; + public static long nonExistingLbId = 2L; + + public static long validGuestNetworkId = 1L; + public static long invalidGuestNetworkId = 2L; + public static long validPublicNetworkId = 3L; + + public static long validAccountId = 1L; + public static long invalidAccountId = 2L; + + public String validRequestedIp = "10.1.1.1"; + + + + @Before + public void setUp() { + ComponentContext.initComponentsLifeCycle(); + //mockito for .getApplicationLoadBalancer tests + Mockito.when(_lbDao.findById(1L)).thenReturn(new ApplicationLoadBalancerRuleVO()); + Mockito.when(_lbDao.findById(2L)).thenReturn(null); + + //mockito for .deleteApplicationLoadBalancer tests + Mockito.when(_lbMgr.deleteLoadBalancerRule(existingLbId, true)).thenReturn(true); + Mockito.when(_lbMgr.deleteLoadBalancerRule(nonExistingLbId, true)).thenReturn(false); + + //mockito for .createApplicationLoadBalancer tests + NetworkVO guestNetwork = new NetworkVO(TrafficType.Guest, null, null, 1, + null, 1, 1L); + setId(guestNetwork, validGuestNetworkId); + guestNetwork.setCidr("10.1.1.1/24"); + + NetworkVO publicNetwork = new NetworkVO(TrafficType.Public, null, null, 1, + null, 1, 1L); + + Mockito.when(_ntwkModel.getNetwork(validGuestNetworkId)).thenReturn(guestNetwork); + Mockito.when(_ntwkModel.getNetwork(invalidGuestNetworkId)).thenReturn(null); + Mockito.when(_ntwkModel.getNetwork(validPublicNetworkId)).thenReturn(publicNetwork); + + Mockito.when(_accountMgr.getAccount(validAccountId)).thenReturn(new AccountVO()); + Mockito.when(_accountMgr.getAccount(invalidAccountId)).thenReturn(null); + Mockito.when(_ntwkModel.areServicesSupportedInNetwork(validGuestNetworkId, Service.Lb)).thenReturn(true); + Mockito.when(_ntwkModel.areServicesSupportedInNetwork(invalidGuestNetworkId, Service.Lb)).thenReturn(false); + + ApplicationLoadBalancerRuleVO lbRule = new ApplicationLoadBalancerRuleVO("new", "new", 22, 22, "roundrobin", + validGuestNetworkId, validAccountId, 1L, new Ip(validRequestedIp), validGuestNetworkId, Scheme.Internal); + Mockito.when(_lbDao.persist(Mockito.any(ApplicationLoadBalancerRuleVO.class))).thenReturn(lbRule); + + Mockito.when(_lbMgr.validateLbRule(Mockito.any(LoadBalancingRule.class))).thenReturn(true); + + Mockito.when(_firewallDao.setStateToAdd(Mockito.any(FirewallRuleVO.class))).thenReturn(true); + + Mockito.when(_accountMgr.getSystemUser()).thenReturn(new UserVO(1)); + Mockito.when(_accountMgr.getSystemAccount()).thenReturn(new AccountVO(2)); + UserContext.registerContext(_accountMgr.getSystemUser().getId(), _accountMgr.getSystemAccount(), null, false); + + Mockito.when(_ntwkModel.areServicesSupportedInNetwork(Mockito.anyLong(), Mockito.any(Network.Service.class))).thenReturn(true); + + Map caps = new HashMap(); + caps.put(Capability.SupportedProtocols, NetUtils.TCP_PROTO); + Mockito.when(_ntwkModel.getNetworkServiceCapabilities(Mockito.anyLong(), Mockito.any(Network.Service.class))).thenReturn(caps); + + + Mockito.when(_lbDao.countBySourceIp(new Ip(validRequestedIp), validGuestNetworkId)).thenReturn(1L); + + } + + /** + * TESTS FOR .getApplicationLoadBalancer + */ + + @Test + //Positive test - retrieve existing lb + public void searchForExistingLoadBalancer() { + ApplicationLoadBalancerRule rule = _appLbSvc.getApplicationLoadBalancer(existingLbId); + assertNotNull("Couldn't find existing application load balancer", rule); + } + + @Test + //Negative test - try to retrieve non-existing lb + public void searchForNonExistingLoadBalancer() { + boolean notFound = false; + ApplicationLoadBalancerRule rule = null; + try { + rule = _appLbSvc.getApplicationLoadBalancer(nonExistingLbId); + if (rule != null) { + notFound = false; + } + } catch (InvalidParameterValueException ex) { + notFound = true; + } + + assertTrue("Found non-existing load balancer; no invalid parameter value exception was thrown", notFound); + } + + /** + * TESTS FOR .deleteApplicationLoadBalancer + */ + + + @Test + //Positive test - delete existing lb + public void deleteExistingLoadBalancer() { + boolean result = false; + try { + result = _appLbSvc.deleteApplicationLoadBalancer(existingLbId); + } finally { + assertTrue("Couldn't delete existing application load balancer", result); + } + } + + + @Test + //Negative test - try to delete non-existing lb + public void deleteNonExistingLoadBalancer() { + boolean result = true; + try { + result = _appLbSvc.deleteApplicationLoadBalancer(nonExistingLbId); + } finally { + assertFalse("Didn't fail when try to delete non-existing load balancer", result); + } + } + + /** + * TESTS FOR .createApplicationLoadBalancer + * @throws NetworkRuleConflictException + * @throws InsufficientVirtualNetworkCapcityException + * @throws InsufficientAddressCapacityException + */ + + @Test (expected = CloudRuntimeException.class) + //Positive test + public void createValidLoadBalancer() throws InsufficientAddressCapacityException, + InsufficientVirtualNetworkCapcityException, NetworkRuleConflictException { + _appLbSvc.createApplicationLoadBalancer("alena", "alena", Scheme.Internal, validGuestNetworkId, validRequestedIp, + 22, 22, "roundrobin", validGuestNetworkId, validAccountId); + } + + + @Test(expected = UnsupportedServiceException.class) + //Negative test - only internal scheme value is supported in the current release + public void createPublicLoadBalancer() throws InsufficientAddressCapacityException, + InsufficientVirtualNetworkCapcityException, NetworkRuleConflictException { + _appLbSvc.createApplicationLoadBalancer("alena", "alena", Scheme.Public, validGuestNetworkId, validRequestedIp, + 22, 22, "roundrobin", validGuestNetworkId, validAccountId); + } + + + @Test(expected = InvalidParameterValueException.class) + //Negative test - invalid SourcePort + public void createWithInvalidSourcePort() throws InsufficientAddressCapacityException, + InsufficientVirtualNetworkCapcityException, NetworkRuleConflictException { + _appLbSvc.createApplicationLoadBalancer("alena", "alena", Scheme.Internal, validGuestNetworkId, validRequestedIp, + 65536, 22, "roundrobin", validGuestNetworkId, validAccountId); + } + + @Test(expected = InvalidParameterValueException.class) + //Negative test - invalid instancePort + public void createWithInvalidInstandePort() throws InsufficientAddressCapacityException, + InsufficientVirtualNetworkCapcityException, NetworkRuleConflictException { + _appLbSvc.createApplicationLoadBalancer("alena", "alena", Scheme.Internal, validGuestNetworkId, validRequestedIp, + 22, 65536, "roundrobin", validGuestNetworkId, validAccountId); + + } + + + @Test(expected = InvalidParameterValueException.class) + //Negative test - invalid algorithm + public void createWithInvalidAlgorithm() throws InsufficientAddressCapacityException, InsufficientVirtualNetworkCapcityException, NetworkRuleConflictException { + String expectedExcText = null; + _appLbSvc.createApplicationLoadBalancer("alena", "alena", Scheme.Internal, validGuestNetworkId, validRequestedIp, + 22, 22, "invalidalgorithm", validGuestNetworkId, validAccountId); + + } + + @Test(expected = InvalidParameterValueException.class) + //Negative test - invalid sourceNetworkId (of Public type, which is not supported) + public void createWithInvalidSourceIpNtwk() throws InsufficientAddressCapacityException, + InsufficientVirtualNetworkCapcityException, NetworkRuleConflictException { + _appLbSvc.createApplicationLoadBalancer("alena", "alena", Scheme.Internal, validPublicNetworkId, validRequestedIp, + 22, 22, "roundrobin", validGuestNetworkId, validAccountId); + + } + + + @Test(expected = InvalidParameterValueException.class) + //Negative test - invalid requested IP (outside of guest network cidr range) + public void createWithInvalidRequestedIp() throws InsufficientAddressCapacityException, + InsufficientVirtualNetworkCapcityException, NetworkRuleConflictException { + + _appLbSvc.createApplicationLoadBalancer("alena", "alena", Scheme.Internal, validGuestNetworkId, "10.2.1.1", + 22, 22, "roundrobin", validGuestNetworkId, validAccountId); + } + + + private static NetworkVO setId(NetworkVO vo, long id) { + NetworkVO voToReturn = vo; + Class c = voToReturn.getClass(); + try { + Field f = c.getDeclaredField("id"); + f.setAccessible(true); + f.setLong(voToReturn, id); + } catch (NoSuchFieldException ex) { + return null; + } catch (IllegalAccessException ex) { + return null; + } + + return voToReturn; + } +} diff --git a/server/test/org/apache/cloudstack/lb/ChildTestConfiguration.java b/server/test/org/apache/cloudstack/lb/ChildTestConfiguration.java new file mode 100644 index 00000000000..918de81c0c5 --- /dev/null +++ b/server/test/org/apache/cloudstack/lb/ChildTestConfiguration.java @@ -0,0 +1,103 @@ +// 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. +package org.apache.cloudstack.lb; + +import java.io.IOException; + +import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; +import org.apache.cloudstack.test.utils.SpringUtils; +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.filter.TypeFilter; + +import com.cloud.dc.dao.AccountVlanMapDaoImpl; +import com.cloud.event.dao.UsageEventDao; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkModel; +import com.cloud.network.dao.FirewallRulesDao; +import com.cloud.network.lb.LoadBalancingRulesManager; +import com.cloud.tags.dao.ResourceTagDao; +import com.cloud.user.AccountManager; + +@Configuration +@ComponentScan( + basePackageClasses={ + AccountVlanMapDaoImpl.class + }, + includeFilters={@Filter(value=ChildTestConfiguration.Library.class, type=FilterType.CUSTOM)}, + useDefaultFilters=false + ) + + public class ChildTestConfiguration { + + public static class Library implements TypeFilter { + + @Bean + public ApplicationLoadBalancerRuleDao applicationLoadBalancerDao() { + return Mockito.mock(ApplicationLoadBalancerRuleDao.class); + } + + @Bean + public NetworkModel networkModel() { + return Mockito.mock(NetworkModel.class); + } + + @Bean + public AccountManager accountManager() { + return Mockito.mock(AccountManager.class); + } + + @Bean + public LoadBalancingRulesManager loadBalancingRulesManager() { + return Mockito.mock(LoadBalancingRulesManager.class); + } + + @Bean + public FirewallRulesDao firewallRulesDao() { + return Mockito.mock(FirewallRulesDao.class); + } + + @Bean + public ResourceTagDao resourceTagDao() { + return Mockito.mock(ResourceTagDao.class); + } + + @Bean + public NetworkManager networkManager() { + return Mockito.mock(NetworkManager.class); + } + + @Bean + public UsageEventDao UsageEventDao() { + return Mockito.mock(UsageEventDao.class); + } + + @Override + public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { + mdr.getClassMetadata().getClassName(); + ComponentScan cs = ChildTestConfiguration.class.getAnnotation(ComponentScan.class); + return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + } + + } +} diff --git a/server/test/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java b/server/test/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java index 7946c1aa740..92aa2a2c8ff 100644 --- a/server/test/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java +++ b/server/test/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java @@ -84,6 +84,7 @@ public class CreateNetworkOfferingTest extends TestCase{ Mockito.when(configDao.findByName(Mockito.anyString())).thenReturn(configVO); Mockito.when(offDao.persist(Mockito.any(NetworkOfferingVO.class))).thenReturn(new NetworkOfferingVO()); + Mockito.when(offDao.persist(Mockito.any(NetworkOfferingVO.class), Mockito.anyMap())).thenReturn(new NetworkOfferingVO()); Mockito.when(mapDao.persist(Mockito.any(NetworkOfferingServiceMapVO.class))).thenReturn(new NetworkOfferingServiceMapVO()); Mockito.when(accountMgr.getSystemUser()).thenReturn(new UserVO(1)); Mockito.when(accountMgr.getSystemAccount()).thenReturn(new AccountVO(2)); @@ -96,7 +97,7 @@ public class CreateNetworkOfferingTest extends TestCase{ public void createSharedNtwkOffWithVlan() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, - null, false, null, true, false); + null, false, null, true, false, null); assertNotNull("Shared network offering with specifyVlan=true failed to create ", off); } @@ -105,7 +106,7 @@ public class CreateNetworkOfferingTest extends TestCase{ try { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, false, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, - null, false, null, true, false); + null, false, null, true, false, null); assertNull("Shared network offering with specifyVlan=false was created", off); } catch (InvalidParameterValueException ex) { } @@ -115,7 +116,7 @@ public class CreateNetworkOfferingTest extends TestCase{ public void createSharedNtwkOffWithSpecifyIpRanges() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, - null, false, null, true, false); + null, false, null, true, false, null); assertNotNull("Shared network offering with specifyIpRanges=true failed to create ", off); } @@ -125,7 +126,7 @@ public class CreateNetworkOfferingTest extends TestCase{ try { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, - null, false, null, false, false); + null, false, null, false, false, null); assertNull("Shared network offering with specifyIpRanges=false was created", off); } catch (InvalidParameterValueException ex) { } @@ -140,7 +141,7 @@ public class CreateNetworkOfferingTest extends TestCase{ serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, Network.GuestType.Isolated, false, - null, false, null, false, false); + null, false, null, false, false, null); assertNotNull("Isolated network offering with specifyIpRanges=false failed to create ", off); } @@ -153,7 +154,7 @@ public class CreateNetworkOfferingTest extends TestCase{ serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, Network.GuestType.Isolated, false, - null, false, null, false, false); + null, false, null, false, false, null); assertNotNull("Isolated network offering with specifyVlan=true wasn't created", off); } @@ -167,7 +168,7 @@ public class CreateNetworkOfferingTest extends TestCase{ serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, Network.GuestType.Isolated, false, - null, false, null, true, false); + null, false, null, true, false, null); assertNull("Isolated network offering with specifyIpRanges=true and source nat service enabled, was created", off); } catch (InvalidParameterValueException ex) { } @@ -180,7 +181,7 @@ public class CreateNetworkOfferingTest extends TestCase{ Set vrProvider = new HashSet(); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, Network.GuestType.Isolated, false, - null, false, null, true, false); + null, false, null, true, false, null); assertNotNull("Isolated network offering with specifyIpRanges=true and with no sourceNatService, failed to create", off); } @@ -198,7 +199,7 @@ public class CreateNetworkOfferingTest extends TestCase{ serviceProviderMap.put(Network.Service.Lb , vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, Network.GuestType.Isolated, false, - null, false, null, false, false); + null, false, null, false, false, null); // System.out.println("Creating Vpc Network Offering"); assertNotNull("Vpc Isolated network offering with Vpc provider ", off); } @@ -218,7 +219,7 @@ public class CreateNetworkOfferingTest extends TestCase{ serviceProviderMap.put(Network.Service.Lb, lbProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, Network.GuestType.Isolated, false, null, false, - null, false, false); + null, false, false, null); // System.out.println("Creating Vpc Network Offering"); assertNotNull("Vpc Isolated network offering with Vpc and Netscaler provider ", off); } diff --git a/server/test/resources/appLoadBalancer.xml b/server/test/resources/appLoadBalancer.xml new file mode 100644 index 00000000000..d7c1502a715 --- /dev/null +++ b/server/test/resources/appLoadBalancer.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/setup/db/db/schema-40to410.sql b/setup/db/db/schema-40to410.sql index a3426e2caaa..b7b1c7a91dd 100644 --- a/setup/db/db/schema-40to410.sql +++ b/setup/db/db/schema-40to410.sql @@ -644,6 +644,7 @@ CREATE VIEW `cloud`.`domain_router_view` AS data_center.id data_center_id, data_center.uuid data_center_uuid, data_center.name data_center_name, + data_center.networktype data_center_type, data_center.dns1 dns1, data_center.dns2 dns2, data_center.ip6_dns1 ip6_dns1, @@ -684,7 +685,8 @@ CREATE VIEW `cloud`.`domain_router_view` AS domain_router.scripts_version scripts_version, domain_router.is_redundant_router is_redundant_router, domain_router.redundant_state redundant_state, - domain_router.stop_pending stop_pending + domain_router.stop_pending stop_pending, + domain_router.role role from `cloud`.`domain_router` inner join diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index c8ac1ecfc2e..065b35ca501 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -339,7 +339,7 @@ CREATE TABLE `cloud`.`vm_snapshots` ( ALTER TABLE `cloud`.`hypervisor_capabilities` ADD COLUMN `vm_snapshot_enabled` tinyint(1) DEFAULT 0 NOT NULL COMMENT 'Whether VM snapshot is supported by hypervisor'; UPDATE `cloud`.`hypervisor_capabilities` SET `vm_snapshot_enabled`=1 WHERE `hypervisor_type` in ('VMware', 'XenServer'); - + DROP VIEW IF EXISTS `cloud`.`user_vm_view`; CREATE VIEW `cloud`.`user_vm_view` AS select @@ -450,7 +450,7 @@ CREATE VIEW `cloud`.`user_vm_view` AS async_job.uuid job_uuid, async_job.job_status job_status, async_job.account_id job_account_id, - affinity_group.id affinity_group_id, + affinity_group.id affinity_group_id, affinity_group.uuid affinity_group_uuid, affinity_group.name affinity_group_name, affinity_group.description affinity_group_description @@ -515,7 +515,7 @@ CREATE VIEW `cloud`.`user_vm_view` AS and async_job.job_status = 0 left join `cloud`.`affinity_group_vm_map` ON vm_instance.id = affinity_group_vm_map.instance_id - left join + left join `cloud`.`affinity_group` ON affinity_group_vm_map.affinity_group_id = affinity_group.id; DROP VIEW IF EXISTS `cloud`.`affinity_group_view`; @@ -844,7 +844,8 @@ CREATE VIEW `cloud`.`domain_router_view` AS domain_router.scripts_version scripts_version, domain_router.is_redundant_router is_redundant_router, domain_router.redundant_state redundant_state, - domain_router.stop_pending stop_pending + domain_router.stop_pending stop_pending, + domain_router.role role from `cloud`.`domain_router` inner join @@ -919,7 +920,7 @@ CREATE TABLE `cloud`.`network_asa1000v_map` ( ALTER TABLE `cloud`.`network_offerings` ADD COLUMN `eip_associate_public_ip` int(1) unsigned NOT NULL DEFAULT 0 COMMENT 'true if public IP is associated with user VM creation by default when EIP service is enabled.' AFTER `elastic_ip_service`; -- Re-enable foreign key checking, at the end of the upgrade path -SET foreign_key_checks = 1; +SET foreign_key_checks = 1; -- Add "default" field to account/user tables @@ -1116,6 +1117,40 @@ CREATE VIEW `cloud`.`account_view` AS and async_job.job_status = 0; + +ALTER TABLE `cloud`.`load_balancing_rules` ADD COLUMN `source_ip_address` varchar(40) COMMENT 'source ip address for the load balancer rule'; +ALTER TABLE `cloud`.`load_balancing_rules` ADD COLUMN `source_ip_address_network_id` bigint unsigned COMMENT 'the id of the network where source ip belongs to'; +ALTER TABLE `cloud`.`load_balancing_rules` ADD COLUMN `scheme` varchar(40) NOT NULL COMMENT 'load balancer scheme; can be Internal or Public'; +UPDATE `cloud`.`load_balancing_rules` SET `scheme`='Public'; + + + +-- Add details talbe for the network offering +CREATE TABLE `cloud`.`network_offering_details` ( + `id` bigint unsigned NOT NULL auto_increment, + `network_offering_id` bigint unsigned NOT NULL COMMENT 'network offering id', + `name` varchar(255) NOT NULL, + `value` varchar(1024) NOT NULL, + PRIMARY KEY (`id`), + CONSTRAINT `fk_network_offering_details__network_offering_id` FOREIGN KEY `fk_network_offering_details__network_offering_id`(`network_offering_id`) REFERENCES `network_offerings`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- Change the constraint for the network service map table. Now we support multiple provider for the same service +ALTER TABLE `cloud`.`ntwk_service_map` DROP FOREIGN KEY `fk_ntwk_service_map__network_id`; +ALTER TABLE `cloud`.`ntwk_service_map` DROP INDEX `network_id`; + +ALTER TABLE `cloud`.`ntwk_service_map` ADD UNIQUE `network_id` (`network_id`,`service`,`provider`); +ALTER TABLE `cloud`.`ntwk_service_map` ADD CONSTRAINT `fk_ntwk_service_map__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks` (`id`) ON DELETE CASCADE; + + +ALTER TABLE `cloud`.`network_offerings` ADD COLUMN `internal_lb` int(1) unsigned NOT NULL DEFAULT '0' COMMENT 'true if the network offering supports Internal lb service'; +ALTER TABLE `cloud`.`network_offerings` ADD COLUMN `public_lb` int(1) unsigned NOT NULL DEFAULT '0' COMMENT 'true if the network offering supports Public lb service'; +UPDATE `cloud`.`network_offerings` SET public_lb=1 where id IN (SELECT DISTINCT network_offering_id FROM `cloud`.`ntwk_offering_service_map` WHERE service='Lb'); + + +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'NetworkManager', 'internallbvm.service.offering', null, 'Uuid of the service offering used by internal lb vm; if NULL - default system internal lb offering will be used'); + + alter table `cloud_usage`.`usage_network_offering` add column nic_id bigint(20) unsigned NOT NULL; ALTER TABLE `cloud`.`data_center_details` MODIFY value varchar(1024); ALTER TABLE `cloud`.`cluster_details` MODIFY value varchar(255); diff --git a/setup/dev/advanced.cfg b/setup/dev/advanced.cfg index 63e435bb18f..83357866ca7 100644 --- a/setup/dev/advanced.cfg +++ b/setup/dev/advanced.cfg @@ -45,6 +45,10 @@ { "broadcastdomainrange": "ZONE", "name": "VpcVirtualRouter" + }, + { + "broadcastdomainrange": "ZONE", + "name": "InternalLbVm" } ], "isolationmethods": [ diff --git a/test/integration/component/test_multiple_ip_ranges.py b/test/integration/component/test_multiple_ip_ranges.py index 7e9eeb1028d..7e9e712aef0 100644 --- a/test/integration/component/test_multiple_ip_ranges.py +++ b/test/integration/component/test_multiple_ip_ranges.py @@ -369,6 +369,7 @@ class TestMultipleIpRanges(cloudstackTestCase): self.fail("CS should not accept overlapped ip ranges in guest traffic, but it allowed") return + @attr(tags=["advanced_sg", "sg"]) def test_06_add_ip_range_overlapped_with_two_ranges(self): """Test adding overlapped ip range in existing cidr diff --git a/test/integration/smoke/test_guest_vlan_range.py b/test/integration/smoke/test_guest_vlan_range.py index bd533430f51..704fe59bfff 100644 --- a/test/integration/smoke/test_guest_vlan_range.py +++ b/test/integration/smoke/test_guest_vlan_range.py @@ -44,6 +44,7 @@ class Services: "password": "password", }, "name": "testphysicalnetwork", + "vlan": "2118-2120", } @@ -149,6 +150,19 @@ class TestDedicateGuestVlanRange(cloudstackTestCase): ) self.debug("Releasing guest vlan range"); +<<<<<<< HEAD + dedicated_guest_vlan_response.release(self.apiclient) + list_dedicated_guest_vlan_range_response = PhysicalNetwork.listDedicated( + self.apiclient, + id=dedicate_guest_vlan_range_response.id + ) + dedicated_guest_vlan_response = list_dedicated_guest_vlan_range_response[0] + self.assertEqual( + dedicated_guest_vlan_response.account, + "system", + "Check account name is system account in listDedicatedGuestVlanRanges" + ) +======= dedicate_guest_vlan_range_response.release(self.apiclient) list_dedicated_guest_vlan_range_response = PhysicalNetwork.listDedicated(self.apiclient) self.assertEqual( @@ -157,4 +171,5 @@ class TestDedicateGuestVlanRange(cloudstackTestCase): "Check vlan range is not available in listDedicatedGuestVlanRanges" ) +>>>>>>> master diff --git a/test/integration/smoke/test_internal_lb.py b/test/integration/smoke/test_internal_lb.py new file mode 100644 index 00000000000..ae64297bf1c --- /dev/null +++ b/test/integration/smoke/test_internal_lb.py @@ -0,0 +1,250 @@ +# 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. +""" Tests for configuring Internal Load Balancing Rules. +""" +#Import Local Modules +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.integration.lib.utils import * +from marvin.integration.lib.base import * +from marvin.integration.lib.common import * + + +class TestInternalLb(cloudstackTestCase): + networkOfferingId = None + networkId = None + vmId = None + lbId = None + + zoneId = 1 + serviceOfferingId = 1 + templateId = 5 + + + serviceProviderList = [ + { + "provider": "VpcVirtualRouter", + "service": "Vpn" + }, + { + "provider": "VpcVirtualRouter", + "service": "UserData" + }, + { + "provider": "VpcVirtualRouter", + "service": "Dhcp" + }, + { + "provider": "VpcVirtualRouter", + "service": "Dns" + }, + { + "provider": "InternalLbVM", + "service": "Lb" + }, + { + "provider": "VpcVirtualRouter", + "service": "SourceNat" + }, + { + "provider": "VpcVirtualRouter", + "service": "StaticNat" + }, + { + "provider": "VpcVirtualRouter", + "service": "PortForwarding" + }, + { + "provider": "VpcVirtualRouter", + "service": "NetworkACL" + } + ] + + serviceCapsList = [ + { + "service": "SourceNat", + "capabilitytype": "SupportedSourceNatTypes", + "capabilityvalue": "peraccount" + }, + { + "service": "Lb", + "capabilitytype": "SupportedLbIsolation", + "capabilityvalue": "dedicated" + }, + { + "service": "Lb", + "capabilitytype": "lbSchemes", + "capabilityvalue": "internal" + } + ] + + def setUp(self): + self.apiClient = self.testClient.getApiClient() + + + + def test_internallb(self): + + #1) Create and enable network offering with Internal Lb vm service + self.createNetworkOffering() + + #2) Create VPC and network in it + self.createNetwork() + + #3) Deploy a vm + self.deployVm() + + #4) Create an Internal Load Balancer + self.createInternalLoadBalancer() + + #5) Assign the VM to the Internal Load Balancer + self.assignToLoadBalancerRule() + + #6) Remove the vm from the Interanl Load Balancer + self.removeFromLoadBalancerRule() + + #7) Delete the Load Balancer + self.deleteLoadBalancer() + + + def deployVm(self): + deployVirtualMachineCmd = deployVirtualMachine.deployVirtualMachineCmd() + deployVirtualMachineCmd.networkids = TestInternalLb.networkId + deployVirtualMachineCmd.serviceofferingid = TestInternalLb.serviceOfferingId + deployVirtualMachineCmd.zoneid = TestInternalLb.zoneId + deployVirtualMachineCmd.templateid = TestInternalLb.templateId + deployVirtualMachineCmd.hypervisor = "XenServer" + deployVMResponse = self.apiClient.deployVirtualMachine(deployVirtualMachineCmd) + TestInternalLb.vmId = deployVMResponse.id + + + def createInternalLoadBalancer(self): + createLoadBalancerCmd = createLoadBalancer.createLoadBalancerCmd() + createLoadBalancerCmd.name = "lb rule" + createLoadBalancerCmd.sourceport = 22 + createLoadBalancerCmd.instanceport = 22 + createLoadBalancerCmd.algorithm = "roundrobin" + createLoadBalancerCmd.scheme = "internal" + createLoadBalancerCmd.sourceipaddressnetworkid = TestInternalLb.networkId + createLoadBalancerCmd.networkid = TestInternalLb.networkId + createLoadBalancerResponse = self.apiClient.createLoadBalancer(createLoadBalancerCmd) + TestInternalLb.lbId = createLoadBalancerResponse.id + self.assertIsNotNone(createLoadBalancerResponse.id, "Failed to create a load balancer") + + + def assignToLoadBalancerRule(self): + assignToLoadBalancerRuleCmd = assignToLoadBalancerRule.assignToLoadBalancerRuleCmd() + assignToLoadBalancerRuleCmd.id = TestInternalLb.lbId + assignToLoadBalancerRuleCmd.virtualMachineIds = TestInternalLb.vmId + assignToLoadBalancerRuleResponse = self.apiClient.assignToLoadBalancerRule(assignToLoadBalancerRuleCmd) + self.assertTrue(assignToLoadBalancerRuleResponse.success, "Failed to assign the vm to the load balancer") + + + + def removeFromLoadBalancerRule(self): + removeFromLoadBalancerRuleCmd = removeFromLoadBalancerRule.removeFromLoadBalancerRuleCmd() + removeFromLoadBalancerRuleCmd.id = TestInternalLb.lbId + removeFromLoadBalancerRuleCmd.virtualMachineIds = TestInternalLb.vmId + removeFromLoadBalancerRuleResponse = self.apiClient.removeFromLoadBalancerRule(removeFromLoadBalancerRuleCmd) + self.assertTrue(removeFromLoadBalancerRuleResponse.success, "Failed to remove the vm from the load balancer") + + + + #def removeInternalLoadBalancer(self): + def deleteLoadBalancer(self): + deleteLoadBalancerCmd = deleteLoadBalancer.deleteLoadBalancerCmd() + deleteLoadBalancerCmd.id = TestInternalLb.lbId + deleteLoadBalancerResponse = self.apiClient.deleteLoadBalancer(deleteLoadBalancerCmd) + self.assertTrue(deleteLoadBalancerResponse.success, "Failed to remove the load balancer") + + + + def createNetwork(self): + createVPCCmd = createVPC.createVPCCmd() + createVPCCmd.name = "new vpc" + createVPCCmd.cidr = "10.1.1.0/24" + createVPCCmd.displaytext = "new vpc" + createVPCCmd.vpcofferingid = 1 + createVPCCmd.zoneid = self.zoneId + createVPCResponse = self.apiClient.createVPC(createVPCCmd) + + + createNetworkCmd = createNetwork.createNetworkCmd() + createNetworkCmd.name = "vpc network" + createNetworkCmd.displaytext = "vpc network" + createNetworkCmd.netmask = "255.255.255.0" + createNetworkCmd.gateway = "10.1.1.1" + createNetworkCmd.zoneid = self.zoneId + createNetworkCmd.vpcid = createVPCResponse.id + createNetworkCmd.networkofferingid = TestInternalLb.networkOfferingId + createNetworkResponse = self.apiClient.createNetwork(createNetworkCmd) + TestInternalLb.networkId = createNetworkResponse.id + + self.assertIsNotNone(createNetworkResponse.id, "Network failed to create") + + + def createNetworkOffering(self): + createNetworkOfferingCmd = createNetworkOffering.createNetworkOfferingCmd() + createNetworkOfferingCmd.name = "Network offering for internal lb service - " + str(random.randrange(1,100+1)) + createNetworkOfferingCmd.displaytext = "Network offering for internal lb service" + createNetworkOfferingCmd.guestiptype = "isolated" + createNetworkOfferingCmd.traffictype = "Guest" + createNetworkOfferingCmd.conservemode = "false" + createNetworkOfferingCmd.supportedservices = "Vpn,Dhcp,Dns,Lb,UserData,SourceNat,StaticNat,PortForwarding,NetworkACL" + + + createNetworkOfferingCmd.serviceproviderlist = [] + for item in self.serviceProviderList: + createNetworkOfferingCmd.serviceproviderlist.append({ + 'service': item['service'], + 'provider': item['provider'] + }) + + createNetworkOfferingCmd.servicecapabilitylist = [] + for item in self.serviceCapsList: + createNetworkOfferingCmd.servicecapabilitylist.append({ + 'service': item['service'], + 'capabilitytype': item['capabilitytype'], + 'capabilityvalue': item['capabilityvalue'] + }) + + + createNetworkOfferingResponse = self.apiClient.createNetworkOffering(createNetworkOfferingCmd) + TestInternalLb.networkOfferingId = createNetworkOfferingResponse.id + + #enable network offering + updateNetworkOfferingCmd = updateNetworkOffering.updateNetworkOfferingCmd() + updateNetworkOfferingCmd.id = TestInternalLb.networkOfferingId + updateNetworkOfferingCmd.state = "Enabled" + updateNetworkOfferingResponse = self.apiClient.updateNetworkOffering(updateNetworkOfferingCmd) + + + #list network offering to see if its enabled + listNetworkOfferingsCmd = listNetworkOfferings.listNetworkOfferingsCmd() + listNetworkOfferingsCmd.id = TestInternalLb.networkOfferingId + listOffResponse = self.apiClient.listNetworkOfferings(listNetworkOfferingsCmd) + + self.assertNotEqual(len(listOffResponse), 0, "Check if the list network offerings API \ + returns a non-empty response") + + + def tearDown(self): + #destroy the vm + if TestInternalLb.vmId is not None: + destroyVirtualMachineCmd = destroyVirtualMachine.destroyVirtualMachineCmd() + destroyVirtualMachineCmd.id = TestInternalLb.vmId + destroyVirtualMachineResponse = self.apiClient.destroyVirtualMachine(destroyVirtualMachineCmd) diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index f8bdae281b2..bd8c0f1668f 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -140,6 +140,7 @@ known_categories = { 'removeIpFromNic': 'Nic', 'listNics':'Nic', 'AffinityGroup': 'Affinity Group', + 'InternalLoadBalancer': 'Internal LB', } diff --git a/tools/marvin/marvin/deployDataCenter.py b/tools/marvin/marvin/deployDataCenter.py index 21685923b37..7059059beb1 100644 --- a/tools/marvin/marvin/deployDataCenter.py +++ b/tools/marvin/marvin/deployDataCenter.py @@ -216,6 +216,18 @@ class deployDataCenters(): vrconfig.id = vrprovid self.apiClient.configureVirtualRouterElement(vrconfig) self.enableProvider(pnetprovres[0].id) + elif provider.name == 'InternalLbVm': + internallbprov = listInternalLoadBalancerElements.listInternalLoadBalancerElementsCmd() + internallbprov.nspid = pnetprovres[0].id + internallbresponse = self.apiClient.listInternalLoadBalancerElements(internallbprov) + internallbid = internallbresponse[0].id + + internallbconfig = \ + configureInternalLoadBalancerElement.configureInternalLoadBalancerElementCmd() + internallbconfig.enabled = "true" + internallbconfig.id = internallbid + self.apiClient.configureInternalLoadBalancerElement(internallbconfig) + self.enableProvider(pnetprovres[0].id) elif provider.name == 'SecurityGroupProvider': self.enableProvider(pnetprovres[0].id) elif provider.name in ['Netscaler', 'JuniperSRX', 'F5BigIp']: diff --git a/tools/marvin/marvin/sandbox/advanced/advanced_env.py b/tools/marvin/marvin/sandbox/advanced/advanced_env.py index bf880f38055..6343293aa62 100644 --- a/tools/marvin/marvin/sandbox/advanced/advanced_env.py +++ b/tools/marvin/marvin/sandbox/advanced/advanced_env.py @@ -50,6 +50,9 @@ def describeResources(config): vpcprovider = provider() vpcprovider.name = 'VpcVirtualRouter' + + lbprovider = provider() + lbprovider.name = 'InternalLbVm' pn = physical_network() pn.name = "Sandbox-pnet" @@ -60,6 +63,7 @@ def describeResources(config): traffictype("Public", {"simulator":"cloud-simulator-public"})] pn.isolationmethods = ["VLAN"] pn.providers.append(vpcprovider) + pn.providers.append(lbprovider) pn2 = physical_network() pn2.name = "Sandbox-pnet2" @@ -68,6 +72,7 @@ def describeResources(config): pn2.traffictypes = [traffictype('Guest', {'simulator': 'cloud-simulator-guest'})] pn2.isolationmethods = ["VLAN"] pn2.providers.append(vpcprovider) + pn2.providers.append(lbprovider) z.physical_networks.append(pn) z.physical_networks.append(pn2) diff --git a/tools/marvin/marvin/sandbox/advanced/sandbox.cfg b/tools/marvin/marvin/sandbox/advanced/sandbox.cfg new file mode 100644 index 00000000000..01a84730dad --- /dev/null +++ b/tools/marvin/marvin/sandbox/advanced/sandbox.cfg @@ -0,0 +1,209 @@ +{ + "zones": [ + { + "name": "Sandbox-Simulator", + "guestcidraddress": "10.1.1.0/24", + "dns1": "10.147.28.6", + "physical_networks": [ + { + "providers": [ + { + "broadcastdomainrange": "ZONE", + "name": "VirtualRouter" + }, + { + "broadcastdomainrange": "ZONE", + "name": "VpcVirtualRouter" + }, + { + "broadcastdomainrange": "ZONE", + "name": "InternalLb" + } + ], + "name": "Sandbox-pnet", + "tags": [ + "cloud-simulator-public" + ], + "broadcastdomainrange": "Zone", + "vlan": "675-679", + "traffictypes": [ + { + "typ": "Guest" + }, + { + "typ": "Management", + "simulator": "cloud-simulator-mgmt" + }, + { + "typ": "Public", + "simulator": "cloud-simulator-public" + } + ], + "isolationmethods": [ + "VLAN" + ] + }, + { + "providers": [ + { + "broadcastdomainrange": "ZONE", + "name": "VirtualRouter" + }, + { + "broadcastdomainrange": "ZONE", + "name": "VpcVirtualRouter" + }, + { + "broadcastdomainrange": "ZONE", + "name": "InternalLb" + } + ], + "name": "Sandbox-pnet2", + "tags": [ + "cloud-simulator-guest" + ], + "broadcastdomainrange": "Zone", + "vlan": "800-1000", + "traffictypes": [ + { + "typ": "Guest", + "simulator": "cloud-simulator-guest" + } + ], + "isolationmethods": [ + "VLAN" + ] + } + ], + "securitygroupenabled": "false", + "ipranges": [ + { + "startip": "10.147.31.150", + "endip": "10.147.31.159", + "netmask": "255.255.255.0", + "vlan": "31", + "gateway": "10.147.31.1" + } + ], + "networktype": "Advanced", + "pods": [ + { + "endip": "10.147.29.159", + "name": "POD0", + "startip": "10.147.29.150", + "netmask": "255.255.255.0", + "clusters": [ + { + "clustername": "C0", + "hypervisor": "Simulator", + "hosts": [ + { + "username": "root", + "url": "http://simulator0", + "password": "password" + } + ], + "clustertype": "CloudManaged", + "primaryStorages": [ + { + "url": "nfs://10.147.28.6:/export/home/sandbox/primary", + "name": "PS0" + } + ] + } + ], + "gateway": "10.147.29.1" + } + ], + "internaldns1": "10.147.28.6", + "secondaryStorages": [ + { + "url": "nfs://10.147.28.6:/export/home/sandbox/sstor" + } + ] + } + ], + "dbSvr": { + "dbSvr": "localhost", + "passwd": "cloud", + "db": "cloud", + "port": 3306, + "user": "cloud" + }, + "logger": [ + { + "name": "TestClient", + "file": "testclient.log" + }, + { + "name": "TestCase", + "file": "testcase.log" + } + ], + "globalConfig": [ + { + "name": "storage.cleanup.interval", + "value": "300" + }, + { + "name": "direct.agent.load.size", + "value": "1000" + }, + { + "name": "default.page.size", + "value": "10000" + }, + { + "name": "instance.name", + "value": "QA" + }, + { + "name": "workers", + "value": "10" + }, + { + "name": "vm.op.wait.interval", + "value": "5" + }, + { + "name": "account.cleanup.interval", + "value": "600" + }, + { + "name": "guest.domain.suffix", + "value": "sandbox.simulator" + }, + { + "name": "expunge.delay", + "value": "60" + }, + { + "name": "vm.allocation.algorithm", + "value": "random" + }, + { + "name": "expunge.interval", + "value": "60" + }, + { + "name": "expunge.workers", + "value": "3" + }, + { + "name": "secstorage.allowed.internal.sites", + "value": "10.147.28.0/24" + }, + { + "name": "check.pod.cidrs", + "value": "true" + } + ], + "mgtSvr": [ + { + "mgtSvrIp": "localhost", + "passwd": "password", + "user": "root", + "port": 8096 + } + ] +} \ No newline at end of file diff --git a/ui/scripts/zoneWizard.js b/ui/scripts/zoneWizard.js index b28258544b7..9b28c327b78 100755 --- a/ui/scripts/zoneWizard.js +++ b/ui/scripts/zoneWizard.js @@ -2376,6 +2376,110 @@ }); // ***** Virtual Router ***** (end) ***** + // ***** Internal LB ***** (begin) ***** + var internalLbProviderId; + $.ajax({ + url: createURL("listNetworkServiceProviders&name=Internallbvm&physicalNetworkId=" + thisPhysicalNetwork.id), + dataType: "json", + async: false, + success: function(json) { + var items = json.listnetworkserviceprovidersresponse.networkserviceprovider; + if(items != null && items.length > 0) { + internalLbProviderId = items[0].id; + } + } + }); + if(internalLbProviderId == null) { + alert("error: listNetworkServiceProviders API doesn't return internalLb provider ID"); + return; + } + + var internalLbElementId; + $.ajax({ + url: createURL("listInternalLoadBalancerElements&nspid=" + internalLbProviderId), + dataType: "json", + async: false, + success: function(json) { + var items = json.listinternalloadbalancerelementsresponse.internalloadbalancerelement; + if(items != null && items.length > 0) { + internalLbElementId = items[0].id; + } + } + }); + if(internalLbElementId == null) { + alert("error: listInternalLoadBalancerElements API doesn't return Internal LB Element Id"); + return; + } + + $.ajax({ + url: createURL("configureInternalLoadBalancerElement&enabled=true&id=" + internalLbElementId), + dataType: "json", + async: false, + success: function(json) { + var jobId = json.configureinternalloadbalancerelementresponse.jobid; + var enableInternalLbElementIntervalID = setInterval(function() { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId="+jobId), + dataType: "json", + success: function(json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } + else { + clearInterval(enableInternalLbElementIntervalID); + + if (result.jobstatus == 1) { //configureVirtualRouterElement succeeded + $.ajax({ + url: createURL("updateNetworkServiceProvider&state=Enabled&id=" + internalLbProviderId), + dataType: "json", + async: false, + success: function(json) { + var jobId = json.updatenetworkserviceproviderresponse.jobid; + var enableInternalLbProviderIntervalID = setInterval(function() { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId="+jobId), + dataType: "json", + success: function(json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } + else { + clearInterval(enableInternalLbProviderIntervalID); + + if (result.jobstatus == 1) { //Internal LB has been enabled successfully + //don't need to do anything here + } + else if (result.jobstatus == 2) { + alert("failed to enable Internal LB Provider. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function(XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("failed to enable Internal LB Provider. Error: " + errorMsg); + } + }); + }, g_queryAsyncJobResultInterval); + } + }); + } + else if (result.jobstatus == 2) { + alert("configureVirtualRouterElement failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function(XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("configureVirtualRouterElement failed. Error: " + errorMsg); + } + }); + }, g_queryAsyncJobResultInterval); + } + }); + // ***** Internal LB ***** (end) ***** + if(args.data.zone.sgEnabled != true) { //Advanced SG-disabled zone // ***** VPC Virtual Router ***** (begin) ***** var vpcVirtualRouterProviderId; From b73156a56ece6153bca6b9c5ce99a6200c1ad4e4 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Thu, 9 May 2013 12:51:40 -0700 Subject: [PATCH 025/114] CLOUDSTACK-1816: Cisco VNMC ASA1000v - object name in API response has been corrected. Here is related UI change. --- ui/modules/vnmcAsa1000v/vnmcAsa1000v.js | 12 ++-- .../vnmcNetworkProvider.js | 57 ++++++++++++------- 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/ui/modules/vnmcAsa1000v/vnmcAsa1000v.js b/ui/modules/vnmcAsa1000v/vnmcAsa1000v.js index 6a29c707551..621c52a3ddc 100644 --- a/ui/modules/vnmcAsa1000v/vnmcAsa1000v.js +++ b/ui/modules/vnmcAsa1000v/vnmcAsa1000v.js @@ -32,8 +32,7 @@ physicalnetworkid: args.context.physicalNetworks[0].id }, success: function(json){ - var items = json.listCiscoAsa1000vResources["null"]; //waiting for Koushik to fix object name to be "CiscoAsa1000vResource" instead of "null" - //var items = json.listCiscoAsa1000vResources.CiscoAsa1000vResource; + var items = json.listCiscoAsa1000vResources.CiscoAsa1000vResource; args.response.success({ data: items }); } }); @@ -124,8 +123,7 @@ return 'delete CiscoASA1000v'; } }, - action: function(args) { - debugger; + action: function(args) { $.ajax({ url: createURL('deleteCiscoAsa1000vResource'), data: { @@ -164,16 +162,14 @@ } ], - dataProvider: function(args) { - debugger; + dataProvider: function(args) { $.ajax({ url: createURL('listCiscoAsa1000vResources'), data: { resourceid: args.context.asa1000vDevices[0].resourceid }, success: function(json) { - var item = json.listCiscoAsa1000vResources["null"][0]; //waiting for Koushik to fix object name to be "CiscoAsa1000vResource" instead of "null" - //var item = json.listCiscoAsa1000vResources.CiscoAsa1000vResource[0]; + var item = json.listCiscoAsa1000vResources.CiscoAsa1000vResource[0]; args.response.success({ data: item }); } }); diff --git a/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js b/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js index c4c371cbc4f..82a5a3e454b 100644 --- a/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js +++ b/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js @@ -28,8 +28,21 @@ fields: { resourcename: { label: 'Resource Name' }, provider: { label: 'Provider' } - }, - + }, + dataProvider: function(args) { + $.ajax({ + url: createURL('listCiscoVnmcResources'), + data: { + physicalnetworkid: args.context.physicalNetworks[0].id + }, + success: function(json){ + var items = json.listCiscoVnmcResources.CiscoVnmcResource; + args.response.success({ + data: items + }); + } + }); + }, actions: { add: { label: 'Add VNMC device', @@ -182,21 +195,6 @@ } } } - }, - - dataProvider: function(args) { - $.ajax({ - url: createURL('listCiscoVnmcResources'), - data: { - physicalnetworkid: args.context.physicalNetworks[0].id - }, - success: function(json){ - var items = json.listCiscoVnmcResources["null"]; //change it after API is fixed. - args.response.success({ - data: items - }); - } - }); } }; @@ -233,14 +231,29 @@ title: 'label.details', fields: [ { - name: { label: 'label.name' } + resourcename: { label: 'Resource Name' } }, - { - ipaddress: { label: 'label.ip.address' }, - state: { label: 'label.state' } + { + resourceid: { label: 'Resource ID'}, + provider: { label: 'Provider' }, + RESOURCE_NAME: { label: 'Resource Name'} } ], - dataProvider: function(args) { + dataProvider: function(args) { + $.ajax({ + url: createURL('listCiscoVnmcResources'), + data: { + resourceid: args.context.vnmcDevices[0].id + }, + success: function(json){ + var item = json.listCiscoVnmcResources.CiscoVnmcResource[0]; + args.response.success({ + data: item + }); + } + }); + + args.response.success({ data: args.context.vnmcDevices[0] }); From ea4cb0e988bc09145cde9c5e6d62c84bb21e76da Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Thu, 9 May 2013 13:20:02 -0700 Subject: [PATCH 026/114] CLOUDSTACK-1816: Cisco VNMC ASA1000v - implement Delete VNMC Resource action. --- .../vnmcNetworkProvider.js | 107 +++++++++++------- 1 file changed, 67 insertions(+), 40 deletions(-) diff --git a/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js b/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js index 82a5a3e454b..acd00568589 100644 --- a/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js +++ b/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js @@ -195,10 +195,74 @@ } } } - } + }, + + detailView: { + name: 'CiscoVNMC resource details', + actions: { + remove: { + label: 'delete CiscoVNMC resource', + messages: { + confirm: function(args) { + return 'Please confirm you want to delete CiscoVNMC resource'; + }, + notification: function(args) { + return 'delete CiscoVNMC resource'; + } + }, + action: function(args) { + $.ajax({ + url: createURL('deleteCiscoVnmcResource'), + data: { + resourceid: args.context.vnmcDevices[0].resourceid + }, + success: function(json) { + args.response.success(); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + notification: { + poll: function(args) { + args.complete(); + } + } + } + }, + + tabs: { + details: { + title: 'label.details', + fields: [ + { + resourcename: { label: 'Resource Name' } + }, + { + resourceid: { label: 'Resource ID'}, + provider: { label: 'Provider' }, + RESOURCE_NAME: { label: 'Resource Name'} + } + ], + dataProvider: function(args) { + $.ajax({ + url: createURL('listCiscoVnmcResources'), + data: { + resourceid: args.context.vnmcDevices[0].resourceid + }, + success: function(json){ + var item = json.listCiscoVnmcResources.CiscoVnmcResource[0]; + args.response.success({ data: item }); + } + }); + } + } + } + } }; - var vnmcProviderDetailView = vnmcListView.detailView = { + var vnmcProviderDetailView = { id: 'vnmcProvider', label: 'VNMC', viewAll: vnmcDeviceViewAll, @@ -224,44 +288,7 @@ } } }; - - var vnmcDeviceDetailView = { - tabs: { - details: { - title: 'label.details', - fields: [ - { - resourcename: { label: 'Resource Name' } - }, - { - resourceid: { label: 'Resource ID'}, - provider: { label: 'Provider' }, - RESOURCE_NAME: { label: 'Resource Name'} - } - ], - dataProvider: function(args) { - $.ajax({ - url: createURL('listCiscoVnmcResources'), - data: { - resourceid: args.context.vnmcDevices[0].id - }, - success: function(json){ - var item = json.listCiscoVnmcResources.CiscoVnmcResource[0]; - args.response.success({ - data: item - }); - } - }); - - - args.response.success({ - data: args.context.vnmcDevices[0] - }); - } - } - } - }; - + module.pluginAPI.extend({ addDevice: function(device) { cloudStack.sections.system.subsections[device.id] = device; From 04be0cdec2ab37bd1975e85dc2c406a6d39b688c Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Thu, 9 May 2013 14:33:18 -0700 Subject: [PATCH 027/114] CLOUDSTACK-1816: Cisco VNMC ASA1000v - UI - Infrastructure menu - network service providers - show Cisco VNMC in Advanced zone, hide it in Basic zone. --- ui/modules/infrastructure/infrastructure.js | 14 ++++++++------ ui/scripts/system.js | 3 ++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/ui/modules/infrastructure/infrastructure.js b/ui/modules/infrastructure/infrastructure.js index ad43108259b..dae797e39df 100644 --- a/ui/modules/infrastructure/infrastructure.js +++ b/ui/modules/infrastructure/infrastructure.js @@ -33,12 +33,14 @@ $(window).bind('cloudStack.system.serviceProviders.makeHarcodedArray', function(event, data) { var nspHardcodingArray = data.nspHardcodingArray; - - nspHardcodingArray.push({ - id: id, - name: name, - state: state - }); + var selectedZoneObj = data.selectedZoneObj; + if(selectedZoneObj.networktype == "Advanced"){ + nspHardcodingArray.push({ + id: id, + name: name, + state: state + }); + } }); }, diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 6f4e116b4e8..81fda3a71c3 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -12144,7 +12144,8 @@ ]; $(window).trigger('cloudStack.system.serviceProviders.makeHarcodedArray', { - nspHardcodingArray: nspHardcodingArray + nspHardcodingArray: nspHardcodingArray, + selectedZoneObj: selectedZoneObj }); if(selectedZoneObj.networktype == "Basic") { From 19f014585e1d2a85b66ecd5ad57ee0c6338beb4c Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Thu, 9 May 2013 14:47:49 -0700 Subject: [PATCH 028/114] Marvin test: exclude sandbox.cfg from the rat check --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 9dbd1bf8d7a..e8fdb2f83ea 100644 --- a/pom.xml +++ b/pom.xml @@ -437,6 +437,7 @@ patches/systemvm/debian/config/var/www/html/latest/.htaccess patches/systemvm/debian/vpn/etc/ipsec.d/l2tp.conf tools/transifex/.tx/config + tools/marvin/marvin/sandbox/advanced/sandbox.cfg From b1f6d8914154114fe5c70618a7618d9dd0419df0 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Thu, 9 May 2013 15:31:25 -0700 Subject: [PATCH 029/114] CLOUDSTACK-1816: Cisco VNMC ASA1000v - UI - Infrastructure menu - network service providers - populate provider detailView. --- ui/modules/infrastructure/infrastructure.js | 23 ++++++++++++-- .../vnmcNetworkProvider.js | 30 ++++++++++++++----- ui/scripts/system.js | 3 +- 3 files changed, 44 insertions(+), 12 deletions(-) diff --git a/ui/modules/infrastructure/infrastructure.js b/ui/modules/infrastructure/infrastructure.js index dae797e39df..4111aa5af37 100644 --- a/ui/modules/infrastructure/infrastructure.js +++ b/ui/modules/infrastructure/infrastructure.js @@ -33,12 +33,29 @@ $(window).bind('cloudStack.system.serviceProviders.makeHarcodedArray', function(event, data) { var nspHardcodingArray = data.nspHardcodingArray; - var selectedZoneObj = data.selectedZoneObj; - if(selectedZoneObj.networktype == "Advanced"){ + var selectedZoneObj = data.selectedZoneObj; + var selectedPhysicalNetworkObj = data.selectedPhysicalNetworkObj; + if(selectedZoneObj.networktype == "Advanced"){ + var selectedProviderObj = {}; + $.ajax({ + url: createURL('listNetworkServiceProviders'), + data: { + name: id, //e.g. 'CiscoVnmc' + physicalnetworkid: selectedPhysicalNetworkObj.id + }, + async: false, + success: function(json){ + var items = json.listnetworkserviceprovidersresponse.networkserviceprovider; + if(items != null && items.length > 0) { + selectedProviderObj = items[0]; + } + } + }); + nspHardcodingArray.push({ id: id, name: name, - state: state + state: selectedProviderObj.state }); } }); diff --git a/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js b/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js index acd00568589..cecf56c79ea 100644 --- a/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js +++ b/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js @@ -274,16 +274,30 @@ name: { label: 'label.name' } }, { - state: { label: 'label.state' } + state: { label: 'label.state' }, + id: { label: 'label.id' }, + servicelist: { + label: 'Services', + converter: function(args){ + return args.join(', '); + } + } } ], - dataProvider: function(args) { - args.response.success({ + dataProvider: function(args) { + $.ajax({ + url: createURL('listNetworkServiceProviders'), data: { - name: 'VNMC Devices', - state: 'Disabled' + name: 'CiscoVnmc', + physicalnetworkid: args.context.physicalNetworks[0].id + }, + success: function(json){ + var items = json.listnetworkserviceprovidersresponse.networkserviceprovider; + if(items != null && items.length > 0) { + args.response.success({ data: items[0] }); + } } - }); + }); } } } @@ -297,9 +311,9 @@ }); module.infrastructure.networkServiceProvider({ - id: 'vnmc', + id: 'CiscoVnmc', name: 'Cisco VNMC', - state: 'Disabled', + //state: 'Disabled', //don't know state until log in and visit Infrastructure menu > zone detail > physical network > network service providers listView: vnmcListView, detailView: vnmcProviderDetailView diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 81fda3a71c3..0164e21cb68 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -12145,7 +12145,8 @@ $(window).trigger('cloudStack.system.serviceProviders.makeHarcodedArray', { nspHardcodingArray: nspHardcodingArray, - selectedZoneObj: selectedZoneObj + selectedZoneObj: selectedZoneObj, + selectedPhysicalNetworkObj: selectedPhysicalNetworkObj }); if(selectedZoneObj.networktype == "Basic") { From 75a2457af639e6bcf751c2e97d1360df1a0265e4 Mon Sep 17 00:00:00 2001 From: Hari Patanala Date: Fri, 10 May 2013 09:29:41 +0530 Subject: [PATCH 030/114] CLOUDSTACK-658 - Adding scale vm support for vmware with unit tests Signed off by : Nitin Mehta --- plugins/hypervisors/vmware/pom.xml | 10 +++ .../vmware/resource/VmwareResource.java | 31 ++++++- .../vmware/resource/VmwareResourceTest.java | 82 +++++++++++++++++++ .../src/com/cloud/vm/UserVmManagerImpl.java | 2 +- .../hypervisor/vmware/util/VmwareHelper.java | 26 +++++- 5 files changed, 148 insertions(+), 3 deletions(-) create mode 100644 plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java diff --git a/plugins/hypervisors/vmware/pom.xml b/plugins/hypervisors/vmware/pom.xml index d65ef640655..79779decf62 100644 --- a/plugins/hypervisors/vmware/pom.xml +++ b/plugins/hypervisors/vmware/pom.xml @@ -58,5 +58,15 @@ wsdl4j 1.4 + + junit + junit + 4.10 + + + org.mockito + mockito-all + 1.9.5 + diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index d87da64040b..6d7e0e7289c 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -111,6 +111,8 @@ import com.cloud.agent.api.RebootCommand; import com.cloud.agent.api.RebootRouterCommand; import com.cloud.agent.api.RevertToVMSnapshotAnswer; import com.cloud.agent.api.RevertToVMSnapshotCommand; +import com.cloud.agent.api.ScaleVmCommand; +import com.cloud.agent.api.ScaleVmAnswer; import com.cloud.agent.api.SetupAnswer; import com.cloud.agent.api.SetupCommand; import com.cloud.agent.api.SetupGuestNetworkAnswer; @@ -485,6 +487,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa return execute((ResizeVolumeCommand) cmd); } else if (clz == UnregisterVMCommand.class) { return execute((UnregisterVMCommand) cmd); + } else if (clz == ScaleVmCommand.class) { + return execute((ScaleVmCommand) cmd); } else { answer = Answer.createUnsupportedCommandAnswer(cmd); } @@ -2088,6 +2092,28 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa return validatedDisks.toArray(new VolumeTO[0]); } + protected ScaleVmAnswer execute(ScaleVmCommand cmd) { + + VmwareContext context = getServiceContext(); + VirtualMachineTO vmSpec = cmd.getVirtualMachine(); + try{ + VmwareHypervisorHost hyperHost = getHyperHost(context); + VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(cmd.getVmName()); + VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec(); + int ramMb = (int) (vmSpec.getMinRam()); + + VmwareHelper.setVmScaleUpConfig(vmConfigSpec, vmSpec.getCpus(), vmSpec.getSpeed(), vmSpec.getSpeed(),(int) (vmSpec.getMaxRam()), ramMb, vmSpec.getLimitCpuUse()); + + if(!vmMo.configureVm(vmConfigSpec)) { + throw new Exception("Unable to execute ScaleVmCommand"); + } + }catch(Exception e) { + s_logger.error("Unexpected exception: ", e); + return new ScaleVmAnswer(cmd, false, "Unable to execute ScaleVmCommand due to " + e.toString()); + } + return new ScaleVmAnswer(cmd, true, null); + } + protected StartAnswer execute(StartCommand cmd) { if (s_logger.isInfoEnabled()) { @@ -2191,7 +2217,10 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa VmwareHelper.setBasicVmConfig(vmConfigSpec, vmSpec.getCpus(), vmSpec.getMaxSpeed(), vmSpec.getMinSpeed(),(int) (vmSpec.getMaxRam()/(1024*1024)), ramMb, translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs()).value(), vmSpec.getLimitCpuUse()); - + + vmConfigSpec.setMemoryHotAddEnabled(true); + vmConfigSpec.setCpuHotAddEnabled(true); + if ("true".equals(vmSpec.getDetails().get(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG))) { s_logger.debug("Nested Virtualization enabled in configuration, checking hypervisor capability"); ManagedObjectReference hostMor = vmMo.getRunningHost().getMor(); diff --git a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java new file mode 100644 index 00000000000..3ca0b600e36 --- /dev/null +++ b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java @@ -0,0 +1,82 @@ +// 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. +package com.cloud.hypervisor.vmware.resource; + +import com.cloud.agent.api.Command; +import com.cloud.agent.api.ScaleVmAnswer; +import com.cloud.agent.api.ScaleVmCommand; +import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.hypervisor.vmware.mo.VirtualMachineMO; +import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost; +import com.cloud.hypervisor.vmware.util.VmwareContext; +import com.cloud.hypervisor.vmware.util.VmwareHelper; +import com.vmware.vim25.VirtualMachineConfigSpec; +import org.junit.Test; +import org.junit.Before; + +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.MockitoAnnotations; +import static org.mockito.Mockito.*; + + +public class VmwareResourceTest { + + @Spy VmwareResource _resource = new VmwareResource() { + + @Override + public ScaleVmAnswer execute(ScaleVmCommand cmd) { + return super.execute(cmd); + } + @Override + public VmwareHypervisorHost getHyperHost(VmwareContext context, Command cmd) { + return hyperHost; + } + }; + + @Mock VmwareContext context; + @Mock ScaleVmCommand cmd; + @Mock VirtualMachineTO vmSpec; + @Mock + VmwareHypervisorHost hyperHost; + @Mock VirtualMachineMO vmMo; + @Mock VirtualMachineConfigSpec vmConfigSpec; + + @Before + public void setup(){ + MockitoAnnotations.initMocks(this); + doReturn(context).when(_resource).getServiceContext(null); + when(cmd.getVirtualMachine()).thenReturn(vmSpec); + } + //Test successful scaling up the vm + @Test + public void testScaleVMF1() throws Exception { + when(_resource.getHyperHost(context, null)).thenReturn(hyperHost); + doReturn("i-2-3-VM").when(cmd).getVmName(); + when(hyperHost.findVmOnHyperHost("i-2-3-VM")).thenReturn(vmMo); + doReturn(1024L).when(vmSpec).getMinRam(); + doReturn(1).when(vmSpec).getCpus(); + doReturn(1000).when(vmSpec).getSpeed(); + doReturn(1024L).when(vmSpec).getMaxRam(); + doReturn(false).when(vmSpec).getLimitCpuUse(); + when(vmMo.configureVm(vmConfigSpec)).thenReturn(true); + + ScaleVmAnswer answer = _resource.execute(cmd); + verify(_resource).execute(cmd); + } + +} diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index eee8503b3f5..9fbc5099374 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -1064,7 +1064,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use // Verify input parameters VMInstanceVO vmInstance = _vmInstanceDao.findById(vmId); - if(vmInstance.getHypervisorType() != HypervisorType.XenServer){ + if(vmInstance.getHypervisorType() != HypervisorType.XenServer && vmInstance.getHypervisorType() != HypervisorType.VMware){ throw new InvalidParameterValueException("This operation not permitted for this hypervisor of the vm"); } diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java index 9c467dc8b6b..4a6a135a5b8 100644 --- a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java @@ -524,7 +524,31 @@ public class VmwareHelper { return options; } - public static void setBasicVmConfig(VirtualMachineConfigSpec vmConfig, int cpuCount, int cpuSpeedMHz, int cpuReservedMhz, + public static void setVmScaleUpConfig(VirtualMachineConfigSpec vmConfig, int cpuCount, int cpuSpeedMHz, int cpuReservedMhz, + int memoryMB, int memoryReserveMB, boolean limitCpuUse) { + + // VM config for scaling up + vmConfig.setMemoryMB((long)memoryMB); + vmConfig.setNumCPUs(cpuCount); + + ResourceAllocationInfo cpuInfo = new ResourceAllocationInfo(); + if (limitCpuUse) { + cpuInfo.setLimit((long)(cpuSpeedMHz * cpuCount)); + } else { + cpuInfo.setLimit(-1L); + } + + cpuInfo.setReservation((long)cpuReservedMhz); + vmConfig.setCpuAllocation(cpuInfo); + + ResourceAllocationInfo memInfo = new ResourceAllocationInfo(); + memInfo.setLimit((long)memoryMB); + memInfo.setReservation((long)memoryReserveMB); + vmConfig.setMemoryAllocation(memInfo); + + } + + public static void setBasicVmConfig(VirtualMachineConfigSpec vmConfig, int cpuCount, int cpuSpeedMHz, int cpuReservedMhz, int memoryMB, int memoryReserveMB, String guestOsIdentifier, boolean limitCpuUse) { // VM config basics From 7fea21e31f25e0a42a4e2d311faa3cba429e0101 Mon Sep 17 00:00:00 2001 From: Radhika PC Date: Fri, 10 May 2013 10:03:11 +0530 Subject: [PATCH 031/114] CLOUDSTACK-893 conceptual info around gslb --- docs/en-US/added-API-commands-4.2.xml | 33 ++++--- docs/en-US/gslb.xml | 120 ++++++++++++++++++++------ 2 files changed, 118 insertions(+), 35 deletions(-) diff --git a/docs/en-US/added-API-commands-4.2.xml b/docs/en-US/added-API-commands-4.2.xml index 7417bd15f35..3abb780663e 100644 --- a/docs/en-US/added-API-commands-4.2.xml +++ b/docs/en-US/added-API-commands-4.2.xml @@ -91,20 +91,31 @@ listGlobalLoadBalancerRule - Lists load balancer rules. account (lists resources by account. Use with the domainId - parameter); domainid (lists only resources belonging to the domain specified) id (the unique - ID of the global load balancer rule) isrecursive (defaults to false, but if true, lists all - resources from the parent specified by the domainId till leaves); keyword (List by keyword); - listall (if set to false, list only resources belonging to the command's caller; if set to - true - list resources that the caller is authorized to see. Default value is false); page; - pagesize; projectid (lists objects by project); regionid (region ID); tags (lists resources - by tags: key/value pairs). + Lists load balancer rules. + The request parameters are: account (lists resources by account. Use with the domainid + parameter); domainid (lists only resources belonging to the domain specified); id (the + unique ID of the global load balancer rule); isrecursive (defaults to false; but if true, + lists all the resources from the parent specified by the domainid); keyword (lists by + keyword); listall (if set to false, lists only resources belonging to the command's caller; + if set to true, lists resources that the caller is authorized to see. Default value is + false); page; pagesize; projectid (lists objects by project); regionid ; tags (lists + resources by tags: key/value pairs). updateGlobalLoadBalancerRule - Archives the specified events. The request parameters are: ids (allowed to pass one or - more IDs separated by comma); type (string); olderthan (yyyy-mm-dd format). - The response parameters are: true, false + Updates global load balancer rules. + The request parameters are: id (the unique ID of the global load balancer rule); account + (lists resources by account. Use with the domainid parameter); description (the description + of the load balancer rule); domainid (lists only resources belonging to the domain + specified); gslblbmethod (the load balancer algorithm that is used to distributed traffic + across the zones participating in global server load balancing, if not specified defaults to + round robin); gslbstickysessionmethodname (the session sticky method; if not specified + defaults to sourceip); isrecursive (defaults to false, but if true, lists all resources from + the parent specified by the domainid till leaves); keyword (lists by keyword); listall (if + set to false, list only those resources belonging to the command's caller; if set to true, + lists resources that the caller is authorized to see. Default value is false); page; + pagesize; projectid (lists objects by project); regionid; tags (lists resources by tags: + key/value pairs) diff --git a/docs/en-US/gslb.xml b/docs/en-US/gslb.xml index 385642d394d..ac17d61d69c 100644 --- a/docs/en-US/gslb.xml +++ b/docs/en-US/gslb.xml @@ -41,6 +41,60 @@ alternate location for accessing a resource in the event of a failure, or to provide a means of shifting traffic easily to simplify maintenance, or both. +
+ Components of GSLB + A typical GSLB environment is comprised of the following components: + + + GSLB Site: In &PRODUCT;terminology, GSLB sites are + represented by zones that are mapped to data centers, each of which has various network + appliances. Each GSLB site is managed by a NetScaler appliance that is local to that site. + Each of these appliances treats its own site as the local site and all other sites, + managed by other appliances, as remote sites. + + + GSLB Services: A GSLB service is typically + represented by a load balancing or content switching virtual server. In a GSLB + environment, you can have a local as well as remote GSLB services. A local GSLB service + represents a local load balancing or content switching virtual server. A remote GSLB + service is the one configured at one of the other sites in the GSLB setup. At each site in + the GSLB setup, you can create one local GSLB service and any number of remote GSLB + services. + + + GSLB Virtual Servers: A GSLB virtual server refers to + one or more GSLB services and balances traffic between traffic across the VMs in multiple + zones by using the &PRODUCT; functionality. It evaluates the configured GSLB methods or + algorithms to select a GSLB service to which to send the client requests. One or more + virtual servers from different zones are bound to the GSLB virtual server. GSLB virtual + server does not have a public IP associated with it, instead it will have a FQDN DNS + name. + + + Load Balancing or Content Switching Virtual Servers: + According to Citrix NetScaler terminology, a load balancing or content switching virtual + server represents one or many servers on the local network. Clients send their requests to + the load balancing or content switching virtual server’s virtual IP (VIP) address, and the + virtual server balances the load across the local servers. After a GSLB virtual server + selects a GSLB service representing either a local or a remote load balancing or content + switching virtual server, the client sends the request to that virtual server’s VIP + address. + + + DNS VIPs: DNS virtual IP represents a load balancing + DNS virtual server on the GSLB service provider. The DNS requests for domains for which + the GSLB service provider is authoritative can be sent to a DNS VIP. + + + ADNS: ADNS (Authoritative Domain Name Server) is a + service that provides actual answer to DNS queries, such as web site IP address. In a GSLB + environment, an ADNS service responds only to DNS requests for domains for which the GSLB + service provider is authoritative. When an ADNS service is configured, the service + provider owns that IP address and advertises it. When you create an ADNS service, the + NetScaler responds to DNS queries on the configured ADNS service IP and port. + + +
Prerequisites and Guidelines @@ -63,23 +117,23 @@ When users have VMs deployed in multiple availability zones which are GSLB enabled, - user is allowed to use the GSLB functionality to load balance traffic across the VMs in - multiple zones. + they can use the GSLB functionality to load balance traffic across the VMs in multiple + zones. - The users are allowed to use GSLB to load balance across the VMs across zones in a - region only if the admin has enabled GSLB in that region. + The users can use GSLB to load balance across the VMs across zones in a region only if + the admin has enabled GSLB in that region. - The users are allowed to load balance traffic across the availability zones in the - same region or different regions. + The users can load balance traffic across the availability zones in the same region or + different regions. - The admin is allowed to configure DNS name for the entire cloud. + The admin can configure DNS name for the entire cloud. - The users can specify an unique name, across the cloud, for a globally load balanced - service. The provided name will be used as the domain under the DNS name associated with + The users can specify an unique name across the cloud for a globally load balanced + service. The provided name is used as the domain name under the DNS name associated with the cloud. The user-provided name along with the admin-provided DNS name is used to produce a globally resolvable FQDN for the globally load balanced service of the user. For example, @@ -88,13 +142,12 @@ foo.xyztelco.com. - While setting up GSLB, users can select a load balancing method, such as round robin - or least RTT, that would be the load balance traffic used across the zones that are part - of GSLB. + While setting up GSLB, users can select a load balancing method, such as round robin, + for using across the zones that are part of GSLB. The user shall be able to set weight to zone-level virtual server. Weight shall be - considered by the load balancing method is distributing the traffic. + considered by the load balancing method for distributing the traffic. The GSLB functionality shall support session persistence, where series of client @@ -103,6 +156,24 @@
+
+ Configuring GSLB + To configure GSLB in your cloud environment, as a cloud administrator you must perform the + following. + To configure such a GSLB setup, you must first configure a standard load balancing setup + for each server farm or data center. This enables you to balance load across the different + servers in each server farm. Then, configure both NetScaler appliances as authoritative DNS + (ADNS) servers. Next, create a GSLB site for each server farm, configure GSLB virtual servers + for each site, create GLSB services, and bind the GSLB services to the GSLB virtual servers. + Finally, bind the domain to the GSLB virtual servers. The GSLB configurations on the two + appliances at the two different sites are identical, although each sites load-balancing + configuration is specific to that site. + + + + + +
Adding a GSLB Rule @@ -174,17 +245,18 @@
How Does GSLB Works in &PRODUCT;? - The following is an illustrated conceptual model of how GLSB functionality is provided in - &PRODUCT;: An organization, xyztelco, has set up a public cloud that spans two zones, Zone-1 - and Zone-2, across geographically separated data centers that are managed by &PRODUCT;. - Tenant-A of the cloud launches a highly available solution by using xyztelco cloud. For that - purpose, they launch two instances each in both the zones: VM1 and VM2 in Zone-1 and VM5 and - VM6 in Zone-2. Tenant-A acquires a public IP, IP-1 in Zone-1, and configures a load balancer - rule to load balance the traffic between VM1 and VM2 instances. &PRODUCT; orchestrates setting - up a virtual server on the LB service provider in Zone-1. Virtual server 1 that is set up on - the LB service provider in Zone-1 represents a publicly accessible virtual server that client - reaches at IP-1. The client traffic to virtual server 1 at IP-1 will be load balanced across - VM1 and VM2 instances. + Global server load balancing is used to manage traffic flow to a web site hosted on two + separate zones that ideally are in different geographic locations. The following is an + illustration of how GLSB functionality is provided in &PRODUCT;: An organization, xyztelco, + has set up a public cloud that spans two zones, Zone-1 and Zone-2, across geographically + separated data centers that are managed by &PRODUCT;. Tenant-A of the cloud launches a highly + available solution by using xyztelco cloud. For that purpose, they launch two instances each + in both the zones: VM1 and VM2 in Zone-1 and VM5 and VM6 in Zone-2. Tenant-A acquires a public + IP, IP-1 in Zone-1, and configures a load balancer rule to load balance the traffic between + VM1 and VM2 instances. &PRODUCT; orchestrates setting up a virtual server on the LB service + provider in Zone-1. Virtual server 1 that is set up on the LB service provider in Zone-1 + represents a publicly accessible virtual server that client reaches at IP-1. The client + traffic to virtual server 1 at IP-1 will be load balanced across VM1 and VM2 instances. Tenant-A acquires another public IP, IP-2 in Zone-2 and sets up a load balancer rule to load balance the traffic between VM5 and VM6 instances. Similarly in Zone-2, &PRODUCT; orchestrates setting up a virtual server on the LB service provider. Virtual server 2 that is From fa9987753c530c8e9560297986ac8848b7526854 Mon Sep 17 00:00:00 2001 From: Sanjay Tripathi Date: Thu, 9 May 2013 18:01:40 +0530 Subject: [PATCH 032/114] CLOUDSTACK-2419 : Localization - Some Japanese are not working --- services/console-proxy/server/js/ajaxkeys.js | 70 +++++++++++++------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/services/console-proxy/server/js/ajaxkeys.js b/services/console-proxy/server/js/ajaxkeys.js index 1ed41c562d4..5f497bbb785 100644 --- a/services/console-proxy/server/js/ajaxkeys.js +++ b/services/console-proxy/server/js/ajaxkeys.js @@ -155,7 +155,7 @@ KEYBOARD_TYPE_JP = "jp"; KEYBOARD_TYPE_UK = "uk"; //JP keyboard type -// + var keyboardTables = [ {tindex: 0, keyboardType: KEYBOARD_TYPE_COOKED, mappingTable: {X11: [ {keycode: 222, entry: X11_KEY_CIRCUMFLEX_ACCENT}, @@ -220,15 +220,31 @@ var keyboardTables = [ {keycode: JS_KEY_SHIFT, entry : X11_KEY_SHIFT}, {keycode: JS_KEY_CTRL, entry : X11_KEY_CTRL}, {keycode: JS_KEY_ALT, entry : X11_KEY_ALT}, - {keycode: JS_KEY_GRAVE_ACCENT, entry : X11_KEY_GRAVE_ACCENT}, - {keycode: JS_KEY_SUBSTRACT, entry : X11_KEY_SUBSTRACT}, - {keycode: JS_KEY_ADD, entry : X11_KEY_ADD}, - {keycode: JS_KEY_OPEN_BRACKET, entry : X11_KEY_OPEN_BRACKET}, - {keycode: JS_KEY_CLOSE_BRACKET, entry : X11_KEY_CLOSE_BRACKET}, + //{keycode: JS_KEY_GRAVE_ACCENT, entry : X11_KEY_GRAVE_ACCENT}, + //[192 / 64 = "' @"] + {keycode: 192, entry : 0x5b, browser: "IE"}, + {keycode: 64, entry : 0x5b, browser: "Firefox"}, + //{keycode: JS_KEY_ADD, entry : X11_KEY_ADD}, + //[187 / 59 = "; +"] + {keycode: 187, entry : 0x3a, browser: "IE"}, + {keycode: 59, entry : 0x3b, browser: "Firefox"}, + //{keycode: JS_KEY_OPEN_BRACKET, entry : X11_KEY_OPEN_BRACKET}, + //[219 = "[{"] + {keycode: 219, entry : 0x5d, browser: "IE"}, + {keycode: 219, entry : 0x5d, browser: "Firefox"}, + //{keycode: JS_KEY_CLOSE_BRACKET, entry : X11_KEY_CLOSE_BRACKET}, + //[221 = "]}"] + {keycode: 221, entry : 0x5c, browser: "IE"}, + {keycode: 221, entry : 0x5c, browser: "Firefox"}, {keycode: JS_KEY_BACK_SLASH, entry : X11_KEY_BACK_SLASH}, - {keycode: JS_KEY_SINGLE_QUOTE, entry : X11_KEY_SINGLE_QUOTE}, + //{keycode: JS_KEY_SINGLE_QUOTE, entry : X11_KEY_SINGLE_QUOTE}, + //[222 / 160 = "~^"] + {keycode: 222, entry : 0x3d, browser: "IE"}, + {keycode: 160, entry : 0x3d, browser: "Firefox"}, + //[173 = "-=" ] specific to Firefox browser + {keycode: 173, entry : 0x2d, browser: "Firefox"}, {keycode: JS_KEY_COMMA, entry : X11_KEY_COMMA}, - {keycode: JS_KEY_PERIOD, entry : X11_KEY_PERIOD}, + {keycode: JS_KEY_PERIOD, entry : X11_KEY_PERIOD}, {keycode: JS_KEY_FORWARD_SLASH, entry : X11_KEY_FORWARD_SLASH}, {keycode: JS_KEY_DASH, entry : X11_KEY_DASH}, {keycode: JS_KEY_SEMI_COLON, entry : X11_KEY_SEMI_COLON}, @@ -243,8 +259,16 @@ var keyboardTables = [ {keycode: JS_KEY_NUMPAD8, entry : X11_KEY_NUMPAD8}, {keycode: JS_KEY_NUMPAD9, entry : X11_KEY_NUMPAD9}, {keycode: JS_KEY_DECIMAL_POINT, entry : X11_KEY_DECIMAL_POINT}, - {keycode: JS_KEY_DIVIDE, entry : X11_KEY_DIVIDE}, - + {keycode: JS_KEY_DIVIDE, entry : 0xffaf}, + {keycode: JS_KEY_MULTIPLY, entry : 0xffaa}, + {keycode: JS_KEY_ADD, entry : 0xffab}, + {keycode: JS_KEY_SUBSTRACT, entry : 0xffad}, + //Kanji Key = 243 / 244 + {keycode: 243, entry : 0x7e, browser: "IE"}, + {keycode: 244, entry : 0x7e, browser: "IE"}, + //Caps Lock = 240 + {keycode: 240, entry : 0xffe5}, + /* {keycode: JS_KEY_MULTIPLY, entry : [ {type: KEY_DOWN, code: X11_KEY_SHIFT, modifiers: 0 }, {type: KEY_DOWN, code: X11_KEY_ASTERISK, modifiers: 0 }, @@ -252,21 +276,17 @@ var keyboardTables = [ {type: KEY_UP, code: X11_KEY_SHIFT, modifiers: 0 } ]}, {keycode: JS_KEY_ADD, entry : false} - ], - keyPress: [ - {keycode: 61, entry: [ - {type: KEY_DOWN, code: X11_KEY_ADD, modifiers: 0, shift: false }, - {type: KEY_UP, code: X11_KEY_ADD, modifiers: 0, shift: false } - ]}, - {keycode: 43, entry: [ - {type: KEY_DOWN, code: X11_KEY_SHIFT, modifiers: 0, shift: false }, - {type: KEY_DOWN, code: X11_KEY_ADD, modifiers: 0, shift: false }, - {type: KEY_UP, code: X11_KEY_ADD, modifiers: 0, shift: false }, - {type: KEY_UP, code: X11_KEY_SHIFT, modifiers: 0, shift: false }, - {type: KEY_DOWN, code: X11_KEY_ADD, modifiers: 0, shift: true }, - {type: KEY_UP, code: X11_KEY_ADD, modifiers: 0, shift: true } - ]} - ] + */ + //[186 / 58 = "~^"] + {keycode: 186, entry : 0x22, browser: "IE"}, + {keycode: 58, entry : 0x22, browser: "Firefox"}, + ], + keyPress: [ + {keycode: 61, entry: [ + {type: KEY_DOWN, code: X11_KEY_ADD, modifiers: 0, shift: false }, + {type: KEY_UP, code: X11_KEY_ADD, modifiers: 0, shift: false } + ]}, + ] } }, {tindex: 2, keyboardType: KEYBOARD_TYPE_UK, mappingTable: {X11: [], From 3aed20c9d27cbe97afc32fd47909a2f08c4550c8 Mon Sep 17 00:00:00 2001 From: Sanjay Tripathi Date: Wed, 8 May 2013 14:17:20 +0530 Subject: [PATCH 033/114] CLOUDSTACK-1603: Management server .log Java Exceptions are displayed with Alerts --- .../storage/datastore/provider/DefaultHostListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java index f2cb1c45c82..2f0b43ad9f6 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java @@ -56,7 +56,7 @@ public class DefaultHostListener implements HypervisorHostListener { } if (!answer.getResult()) { - String msg = "Add host failed due to ModifyStoragePoolCommand failed" + answer.getDetails(); + String msg = "Unable to attach storage pool" + poolId + " to the host" + hostId; alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, pool.getDataCenterId(), pool.getPodId(), msg, msg); throw new CloudRuntimeException("Unable establish connection from storage head to storage pool " + pool.getId() + " due to " + answer.getDetails() + pool.getId()); } From e40aba3bc099d8ad49b87829803c58b4a5975717 Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Fri, 10 May 2013 11:05:47 +0530 Subject: [PATCH 034/114] CLOUDSTACK-2411:UI:fail to enable conserve mode while creating NO with guest type as shared --- ui/scripts/configuration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/scripts/configuration.js b/ui/scripts/configuration.js index 4a64eeac1a5..9a08c4c56b1 100644 --- a/ui/scripts/configuration.js +++ b/ui/scripts/configuration.js @@ -1210,7 +1210,7 @@ } } }); - if(havingVpcVirtualRouterForAtLeastOneService == true || $guestTypeField.val() == 'Shared') { + if(havingVpcVirtualRouterForAtLeastOneService == true ) { $conservemode.find("input[type=checkbox]").attr("disabled", "disabled"); $conservemode.find("input[type=checkbox]").attr('checked', false); From dfad178a9e334776e4ba6c056523b5bd627ccace Mon Sep 17 00:00:00 2001 From: Likitha Shetty Date: Mon, 6 May 2013 09:58:18 +0530 Subject: [PATCH 035/114] Bug CLOUDSTACK-1390: Allow Root/Domain admin to move a User VM to another user under a different domain Add unit tests --- client/tomcatconf/commands.properties.in | 2 +- .../src/com/cloud/vm/UserVmManagerImpl.java | 14 ++-- .../test/com/cloud/vm/UserVmManagerTest.java | 83 ++++++++++++++++++- 3 files changed, 88 insertions(+), 11 deletions(-) diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index cdc19929c19..0a6ec708166 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -67,7 +67,7 @@ getVMPassword=15 restoreVirtualMachine=15 changeServiceForVirtualMachine=15 scaleVirtualMachine=15 -assignVirtualMachine=1 +assignVirtualMachine=7 migrateVirtualMachine=1 migrateVirtualMachineWithVolume=1 recoverVirtualMachine=7 diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 9fbc5099374..f7f5fc7ad74 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -3725,19 +3725,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use + cmd.getAccountName() + " is disabled."); } - // make sure the accounts are under same domain - if (oldAccount.getDomainId() != newAccount.getDomainId()) { - throw new InvalidParameterValueException( - "The account should be under same domain for moving VM between two accounts. Old owner domain =" - + oldAccount.getDomainId() - + " New owner domain=" - + newAccount.getDomainId()); - } + //check caller has access to both the old and new account + _accountMgr.checkAccess(caller, null, true, oldAccount); + _accountMgr.checkAccess(caller, null, true, newAccount); // make sure the accounts are not same if (oldAccount.getAccountId() == newAccount.getAccountId()) { throw new InvalidParameterValueException( - "The account should be same domain for moving VM between two accounts. Account id =" + "The new account is the same as the old account. Account id =" + oldAccount.getAccountId()); } @@ -3829,6 +3824,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use _resourceLimitMgr.decrementResourceCount(oldAccount.getAccountId(), ResourceType.primary_storage, new Long(volume.getSize())); volume.setAccountId(newAccount.getAccountId()); + volume.setDomainId(newAccount.getDomainId()); _volsDao.persist(volume); _resourceLimitMgr.incrementResourceCount(newAccount.getAccountId(), ResourceType.volume); _resourceLimitMgr.incrementResourceCount(newAccount.getAccountId(), ResourceType.primary_storage, diff --git a/server/test/com/cloud/vm/UserVmManagerTest.java b/server/test/com/cloud/vm/UserVmManagerTest.java index 08f2a9c2abc..dfd7465aba0 100755 --- a/server/test/com/cloud/vm/UserVmManagerTest.java +++ b/server/test/com/cloud/vm/UserVmManagerTest.java @@ -17,19 +17,26 @@ package com.cloud.vm; +import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyFloat; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.when; import java.lang.reflect.Field; import java.util.List; +import java.util.UUID; +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd; import org.junit.Before; @@ -44,9 +51,11 @@ import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.hypervisor.Hypervisor; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.offering.ServiceOffering; import com.cloud.service.ServiceOfferingVO; import com.cloud.storage.VMTemplateVO; @@ -57,6 +66,7 @@ import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.user.Account; import com.cloud.user.AccountManager; +import com.cloud.user.AccountService; import com.cloud.user.AccountVO; import com.cloud.user.UserContext; import com.cloud.user.UserVO; @@ -73,6 +83,7 @@ public class UserVmManagerTest { @Mock VolumeManager _storageMgr; @Mock Account _account; @Mock AccountManager _accountMgr; + @Mock AccountService _accountService; @Mock ConfigurationManager _configMgr; @Mock CapacityManager _capacityMgr; @Mock AccountDao _accountDao; @@ -91,6 +102,7 @@ public class UserVmManagerTest { @Mock VMTemplateVO _templateMock; @Mock VolumeVO _volumeMock; @Mock List _rootVols; + @Mock Account _accountMock2; @Before public void setup(){ MockitoAnnotations.initMocks(this); @@ -102,6 +114,7 @@ public class UserVmManagerTest { _userVmMgr._itMgr = _itMgr; _userVmMgr.volumeMgr = _storageMgr; _userVmMgr._accountDao = _accountDao; + _userVmMgr._accountService = _accountService; _userVmMgr._userDao = _userDao; _userVmMgr._accountMgr = _accountMgr; _userVmMgr._configMgr = _configMgr; @@ -370,6 +383,74 @@ public class UserVmManagerTest { return serviceOffering; } - + // Test Move VM b/w accounts where caller is not ROOT/Domain admin + @Test(expected=InvalidParameterValueException.class) + public void testMoveVmToUser1() throws Exception { + AssignVMCmd cmd = new AssignVMCmd(); + Class _class = cmd.getClass(); + + Field virtualmachineIdField = _class.getDeclaredField("virtualMachineId"); + virtualmachineIdField.setAccessible(true); + virtualmachineIdField.set(cmd, 1L); + + Field accountNameField = _class.getDeclaredField("accountName"); + accountNameField.setAccessible(true); + accountNameField.set(cmd, "account"); + + Field domainIdField = _class.getDeclaredField("domainId"); + domainIdField.setAccessible(true); + domainIdField.set(cmd, 1L); + + // caller is of type 0 + Account caller = (Account) new AccountVO("testaccount", 1, "networkdomain", (short) 0, + UUID.randomUUID().toString()); + UserContext.registerContext(1, caller, null, true); + + _userVmMgr.moveVMToUser(cmd); + } + + + // Test Move VM b/w accounts where caller doesn't have access to the old or new account + @Test(expected=PermissionDeniedException.class) + public void testMoveVmToUser2() throws Exception { + AssignVMCmd cmd = new AssignVMCmd(); + Class _class = cmd.getClass(); + + Field virtualmachineIdField = _class.getDeclaredField("virtualMachineId"); + virtualmachineIdField.setAccessible(true); + virtualmachineIdField.set(cmd, 1L); + + Field accountNameField = _class.getDeclaredField("accountName"); + accountNameField.setAccessible(true); + accountNameField.set(cmd, "account"); + + Field domainIdField = _class.getDeclaredField("domainId"); + domainIdField.setAccessible(true); + domainIdField.set(cmd, 1L); + + // caller is of type 0 + Account caller = (Account) new AccountVO("testaccount", 1, "networkdomain", (short) 1, + UUID.randomUUID().toString()); + UserContext.registerContext(1, caller, null, true); + + Account oldAccount = (Account) new AccountVO("testaccount", 1, "networkdomain", (short) 0, + UUID.randomUUID().toString()); + Account newAccount = (Account) new AccountVO("testaccount", 1, "networkdomain", (short) 1, + UUID.randomUUID().toString()); + + UserVmVO vm = new UserVmVO(10L, "test", "test", 1L, HypervisorType.Any, 1L, false, false, 1L, 1L, + 5L, "test", "test", 1L); + vm.setState(VirtualMachine.State.Stopped); + when(_vmDao.findById(anyLong())).thenReturn(vm); + + when(_accountService.getActiveAccountById(anyLong())).thenReturn(oldAccount); + + when(_accountService.getActiveAccountByName(anyString(), anyLong())).thenReturn(newAccount); + + doThrow(new PermissionDeniedException("Access check failed")).when(_accountMgr).checkAccess(any(Account.class), any(AccessType.class), + any(Boolean.class), any(ControlledEntity.class)); + + _userVmMgr.moveVMToUser(cmd); + } } \ No newline at end of file From c704c90b1163d0f3386370e75fc5903dd76498c5 Mon Sep 17 00:00:00 2001 From: Koushik Das Date: Fri, 10 May 2013 16:35:15 +0530 Subject: [PATCH 036/114] CLOUDSTACK-2035: Fix source NAT configuration with Cisco VNMC/ASA Due to VNMC limitation source nat ip cannot be assigned to ASA 1000v outside interface. Working around this issue by acquiring additional public ip during network implement and assigning that to outside interface of ASA. Also made changes to ensure that source nat policy comes after pf and static nat policies in terms of evaluation by assigning a high 'order' value for it. --- .../cisco/CiscoVnmcConnectionImpl.java | 35 ++++++++++++------- .../network/element/CiscoVnmcElement.java | 33 ++++++++++++++--- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnectionImpl.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnectionImpl.java index 527fb04698e..714eb82a559 100644 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnectionImpl.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnectionImpl.java @@ -279,7 +279,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { String xml = VnmcXml.CREATE_VDC.getXml(); String service = VnmcXml.CREATE_VDC.getService(); xml = replaceXmlValue(xml, "cookie", _cookie); - xml = replaceXmlValue(xml, "descr", "VDC for Tenant" + tenantName); + xml = replaceXmlValue(xml, "descr", "VDC for Tenant " + tenantName); xml = replaceXmlValue(xml, "name", getNameForTenantVDC(tenantName)); xml = replaceXmlValue(xml, "dn", getDnForTenantVDC(tenantName)); @@ -304,7 +304,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { String xml = VnmcXml.CREATE_EDGE_DEVICE_PROFILE.getXml(); String service = VnmcXml.CREATE_EDGE_DEVICE_PROFILE.getService(); xml = replaceXmlValue(xml, "cookie", _cookie); - xml = replaceXmlValue(xml, "descr", "Edge Device Profile for Tenant VDC" + tenantName); + xml = replaceXmlValue(xml, "descr", "Edge Device Profile for Tenant VDC " + tenantName); xml = replaceXmlValue(xml, "name", getNameForEdgeDeviceServiceProfile(tenantName)); xml = replaceXmlValue(xml, "dn", getDnForTenantVDCEdgeDeviceProfile(tenantName)); @@ -407,7 +407,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { String xml = VnmcXml.CREATE_EDGE_SECURITY_PROFILE.getXml(); String service = VnmcXml.CREATE_EDGE_SECURITY_PROFILE.getService(); xml = replaceXmlValue(xml, "cookie", _cookie); - xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC" + tenantName); + xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC " + tenantName); xml = replaceXmlValue(xml, "name", getNameForEdgeDeviceSecurityProfile(tenantName)); xml = replaceXmlValue(xml, "espdn", getDnForTenantVDCEdgeSecurityProfile(tenantName)); xml = replaceXmlValue(xml, "egressref", "default-egress"); @@ -505,7 +505,8 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { return createTenantVDCNatPolicyRef( getDnForSourceNatPolicyRef(tenantName), getNameForSourceNatPolicy(tenantName), - tenantName); + tenantName, + true); } @Override @@ -545,7 +546,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { String xml = VnmcXml.RESOLVE_NAT_POLICY_SET.getXml(); String service = VnmcXml.RESOLVE_NAT_POLICY_SET.getService(); xml = replaceXmlValue(xml, "cookie", _cookie); - xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC" + tenantName); + xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC " + tenantName); xml = replaceXmlValue(xml, "name", getNameForEdgeDeviceSecurityProfile(tenantName)); xml = replaceXmlValue(xml, "espdn", getDnForTenantVDCEdgeSecurityProfile(tenantName)); xml = replaceXmlValue(xml, "natpolicysetname", getNameForNatPolicySet(tenantName)); @@ -656,7 +657,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { String xml = VnmcXml.RESOLVE_ACL_POLICY_SET.getXml(); String service = VnmcXml.RESOLVE_ACL_POLICY_SET.getService(); xml = replaceXmlValue(xml, "cookie", _cookie); - xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC" + tenantName); + xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC " + tenantName); xml = replaceXmlValue(xml, "name", getNameForEdgeDeviceSecurityProfile(tenantName)); xml = replaceXmlValue(xml, "espdn", getDnForTenantVDCEdgeSecurityProfile(tenantName)); //xml = replaceXmlValue(xml, "egresspolicysetname", getNameForAclPolicySet(tenantName, false)); @@ -838,17 +839,23 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { return verifySuccess(response); } - private boolean createTenantVDCNatPolicyRef(String policyRefDn, String name, String tenantName) throws ExecutionException { + private boolean createTenantVDCNatPolicyRef(String policyRefDn, String name, String tenantName, boolean isSourceNat) throws ExecutionException { String xml = VnmcXml.CREATE_NAT_POLICY_REF.getXml(); String service = VnmcXml.CREATE_NAT_POLICY_REF.getService(); xml = replaceXmlValue(xml, "cookie", _cookie); xml = replaceXmlValue(xml, "natpolicyrefdn", policyRefDn); xml = replaceXmlValue(xml, "natpolicyname", name); - List policies = listNatPolicies(tenantName); - int order = 100; - if (policies != null) { - order += policies.size(); + // PF and static NAT policies need to come before source NAT, so leaving buffer + // and creating source NAT with a high order value. + // Initially tried setting MAX_INT as the order but VNMC complains about it + int order = 10000; // TODO: For now value should be sufficient, if required may need to increase + if (!isSourceNat) { + List policies = listNatPolicies(tenantName); + order = 100; // order starts at 100 + if (policies != null) { + order += policies.size(); + } } xml = replaceXmlValue(xml, "order", Integer.toString(order)); @@ -1062,7 +1069,8 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { return createTenantVDCNatPolicyRef( getDnForPFPolicyRef(tenantName, identifier), getNameForPFPolicy(tenantName, identifier), - tenantName); + tenantName, + false); } @Override @@ -1180,7 +1188,8 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { return createTenantVDCNatPolicyRef( getDnForDNatPolicyRef(tenantName, identifier), getNameForDNatPolicy(tenantName, identifier), - tenantName); + tenantName, + false); } @Override diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElement.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElement.java index 470c4e88217..33cc40a67da 100644 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElement.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElement.java @@ -70,6 +70,7 @@ import com.cloud.deploy.DeployDestination; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.host.DetailVO; import com.cloud.host.Host; @@ -113,6 +114,7 @@ import com.cloud.resource.ResourceStateAdapter; import com.cloud.resource.ServerResource; import com.cloud.resource.UnableDeleteHostException; import com.cloud.user.Account; +import com.cloud.user.UserContext; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; @@ -338,10 +340,31 @@ public class CiscoVnmcElement extends AdapterBase implements SourceNatServicePro publicGateways.add(vlanVO.getVlanGateway()); } + // due to VNMC limitation of not allowing source NAT ip as the outside ip of firewall, + // an additional public ip needs to acquired for assigning as firewall outside ip + IpAddress outsideIp = null; + try { + Account caller = UserContext.current().getCaller(); + long callerUserId = UserContext.current().getCallerUserId(); + outsideIp = _networkMgr.allocateIp(owner, false, caller, callerUserId, zone); + } catch (ResourceAllocationException e) { + s_logger.error("Unable to allocate additional public Ip address. Exception details " + e); + return false; + } + + try { + outsideIp = _networkMgr.associateIPToGuestNetwork(outsideIp.getId(), network.getId(), true); + } catch (ResourceAllocationException e) { + s_logger.error("Unable to assign allocated additional public Ip " + outsideIp.getAddress().addr() + " to network with vlan " + vlanId + ". Exception details " + e); + return false; + } + // create logical edge firewall in VNMC String gatewayNetmask = NetUtils.getCidrNetmask(network.getCidr()); + // due to ASA limitation of allowing single subnet to be assigned to firewall interfaces, + // all public ip addresses must be from same subnet, this essentially means single public subnet in zone if (!createLogicalEdgeFirewall(vlanId, network.getGateway(), gatewayNetmask, - sourceNatIp.getAddress().addr(), sourceNatIp.getNetmask(), publicGateways, ciscoVnmcHost.getId())) { + outsideIp.getAddress().addr(), sourceNatIp.getNetmask(), publicGateways, ciscoVnmcHost.getId())) { s_logger.error("Failed to create logical edge firewall in Cisco VNMC device for network " + network.getName()); return false; } @@ -356,10 +379,10 @@ public class CiscoVnmcElement extends AdapterBase implements SourceNatServicePro } // configure source NAT - //if (!configureSourceNat(vlanId, network.getCidr(), sourceNatIp, ciscoVnmcHost.getId())) { - // s_logger.error("Failed to configure source NAT in Cisco VNMC device for network " + network.getName()); - // return false; - //} + if (!configureSourceNat(vlanId, network.getCidr(), sourceNatIp, ciscoVnmcHost.getId())) { + s_logger.error("Failed to configure source NAT in Cisco VNMC device for network " + network.getName()); + return false; + } // associate Asa 1000v instance with logical edge firewall if (!associateAsaWithLogicalEdgeFirewall(vlanId, assignedAsa.getManagementIp(), ciscoVnmcHost.getId())) { From edd2fbb266d316fc130520876dfb2f7152223d37 Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Fri, 10 May 2013 16:47:09 +0530 Subject: [PATCH 037/114] CLOUDSTACK-760:Allow ACL on all layer 4 protocols --- ui/scripts/vpc.js | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/ui/scripts/vpc.js b/ui/scripts/vpc.js index db964e6ffcd..dc26265c232 100644 --- a/ui/scripts/vpc.js +++ b/ui/scripts/vpc.js @@ -48,6 +48,22 @@ return name != 'icmptype' && name != 'icmpcode' && name != 'cidrlist'; }); + var $protocolinput = args.$form.find('th,td'); + var $protocolFields = $protocolinput.filter(function(){ + var name = $(this).attr('rel'); + + return $.inArray(name,['protocolnumber']) > -1; + }); + + if($(this).val() == 'protocolnumber' ){ + + $protocolFields.show(); + } + else{ + $protocolFields.hide(); + } + + if ($(this).val() == 'icmp') { $icmpFields.show(); $icmpFields.attr('disabled', false); @@ -68,11 +84,16 @@ data: [ { name: 'tcp', description: 'TCP' }, { name: 'udp', description: 'UDP' }, - { name: 'icmp', description: 'ICMP' } + { name: 'icmp', description: 'ICMP' }, + { name: 'all', description: 'ALL'}, + { name: 'protocolnumber', description: 'Protocol Number'} + ] }); } }, + + 'protocolnumber': {label:'Protocol Number',isDisabled:true,isHidden:true,edit:true}, 'startport': { edit: true, label: 'label.start.port' }, 'endport': { edit: true, label: 'label.end.port' }, 'networkid': { @@ -136,7 +157,15 @@ 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; + } + else + delete args.data.protocolnumber; + + $.ajax({ url: createURL('createNetworkACL'), data: $.extend(args.data, { From b4aff6190f741cffa0bd945cfa9d7d7b11ada47b Mon Sep 17 00:00:00 2001 From: Kishan Kavala Date: Fri, 10 May 2013 17:27:10 +0530 Subject: [PATCH 038/114] CLOUDSTACK-2309: Add fix to handle Vmware 4.0 template upgrade --- .../com/cloud/upgrade/dao/Upgrade302to40.java | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/engine/schema/src/com/cloud/upgrade/dao/Upgrade302to40.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade302to40.java index 753f64ec682..ecda872dfa4 100644 --- a/engine/schema/src/com/cloud/upgrade/dao/Upgrade302to40.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade302to40.java @@ -63,6 +63,7 @@ public class Upgrade302to40 extends Upgrade30xBase implements DbUpgrade { @Override public void performDataMigration(Connection conn) { + updateVmWareSystemVms(conn); correctVRProviders(conn); correctMultiplePhysicaNetworkSetups(conn); addHostDetailsUniqueKey(conn); @@ -82,7 +83,55 @@ public class Upgrade302to40 extends Upgrade30xBase implements DbUpgrade { return new File[] { new File(script) }; } - + + private void updateVmWareSystemVms(Connection conn){ + PreparedStatement pstmt = null; + ResultSet rs = null; + boolean VMware = false; + try { + pstmt = conn.prepareStatement("select distinct(hypervisor_type) from `cloud`.`cluster` where removed is null"); + rs = pstmt.executeQuery(); + while(rs.next()){ + if("VMware".equals(rs.getString(1))){ + VMware = true; + } + } + } catch (SQLException e) { + throw new CloudRuntimeException("Error while iterating through list of hypervisors in use", e); + } + // Just update the VMware system template. Other hypervisor templates are unchanged from previous 3.0.x versions. + s_logger.debug("Updating VMware System Vms"); + try { + //Get 4.0 VMware system Vm template Id + pstmt = conn.prepareStatement("select id from `cloud`.`vm_template` where name = 'systemvm-vmware-4.0' and removed is null"); + rs = pstmt.executeQuery(); + if(rs.next()){ + long templateId = rs.getLong(1); + rs.close(); + pstmt.close(); + // change template type to SYSTEM + pstmt = conn.prepareStatement("update `cloud`.`vm_template` set type='SYSTEM' where id = ?"); + pstmt.setLong(1, templateId); + pstmt.executeUpdate(); + pstmt.close(); + // update templete ID of system Vms + pstmt = conn.prepareStatement("update `cloud`.`vm_instance` set vm_template_id = ? where type <> 'User' and hypervisor_type = 'VMware'"); + pstmt.setLong(1, templateId); + pstmt.executeUpdate(); + pstmt.close(); + } else { + if (VMware){ + throw new CloudRuntimeException("4.0 VMware SystemVm template not found. Cannot upgrade system Vms"); + } else { + s_logger.warn("4.0 VMware SystemVm template not found. VMware hypervisor is not used, so not failing upgrade"); + } + } + } catch (SQLException e) { + throw new CloudRuntimeException("Error while updating VMware systemVm template", e); + } + s_logger.debug("Updating System Vm Template IDs Complete"); + } + private void correctVRProviders(Connection conn) { PreparedStatement pstmtVR = null; ResultSet rsVR = null; From 530b0beb3c8b172fbfaf89584cd24785b7513998 Mon Sep 17 00:00:00 2001 From: Koushik Das Date: Fri, 10 May 2013 17:54:59 +0530 Subject: [PATCH 039/114] CLOUDSTACK-2417: NPE while creating Egress rules with Networking using Cisco ASA firewall provider An input parameter was incorrectly interpreted during egress rule creation and so resulted in NPE. Created a new vnmc xml for handling creation of egress rule with protocol as 'All' --- .../network/cisco/create-egress-acl-rule.xml | 53 ++--------- ...te-generic-egress-acl-no-protocol-rule.xml | 94 +++++++++++++++++++ .../cisco/create-generic-egress-acl-rule.xml | 1 - .../network/cisco/create-ingress-acl-rule.xml | 43 +-------- .../network/cisco/CiscoVnmcConnection.java | 10 +- .../cisco/CiscoVnmcConnectionImpl.java | 30 +++--- .../network/element/CiscoVnmcElement.java | 9 +- .../network/resource/CiscoVnmcResource.java | 12 +-- .../resource/CiscoVnmcResourceTest.java | 4 +- 9 files changed, 144 insertions(+), 112 deletions(-) create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-egress-acl-no-protocol-rule.xml diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-egress-acl-rule.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-egress-acl-rule.xml index 930272ed8ee..05c066d6d53 100755 --- a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-egress-acl-rule.xml +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-egress-acl-rule.xml @@ -118,70 +118,38 @@ under the License. - - - - - - - - - - - - - - + + value="%deststartport%"/> - + + value="%destendport%"/> @@ -195,7 +163,6 @@ under the License. protocolvalue = "TCP" or "UDP" deststartip="destination start ip" destendip="destination end ip" - sourcestartport="start port at source" - sourceendport="end port at source" - sourceip="source ip" + deststartport="start port at destination" + destendport="end port at destination" --!> diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-egress-acl-no-protocol-rule.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-egress-acl-no-protocol-rule.xml new file mode 100755 index 00000000000..17cfa54a34e --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-egress-acl-no-protocol-rule.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-egress-acl-rule.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-egress-acl-rule.xml index 92c25043dad..436e3eae790 100755 --- a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-egress-acl-rule.xml +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-egress-acl-rule.xml @@ -118,5 +118,4 @@ under the License. protocolvalue = "TCP" or "UDP" or "ICMP" deststartip="destination start ip" destendip="destination end ip" - sourceip="source ip" --!> diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-ingress-acl-rule.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-ingress-acl-rule.xml index 1af30b44416..f283ffeb333 100755 --- a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-ingress-acl-rule.xml +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-ingress-acl-rule.xml @@ -118,7 +118,7 @@ under the License. @@ -127,56 +127,24 @@ under the License. dn="%aclruledn%/rule-cond-4/nw-expr2/nw-attr-qual" status="created"/> - - - - - - - - - - - - - - + - + diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnection.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnection.java index f137148ab48..fed6724418d 100644 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnection.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnection.java @@ -140,23 +140,23 @@ public interface CiscoVnmcConnection { public boolean createTenantVDCIngressAclRule(String tenantName, String identifier, String policyIdentifier, String protocol, String sourceStartIp, String sourceEndIp, - String destStartPort, String destEndPort, String destIp) + String destStartPort, String destEndPort) throws ExecutionException; public boolean createTenantVDCIngressAclRule(String tenantName, String identifier, String policyIdentifier, - String protocol, String sourceStartIp, String sourceEndIp, String destIp) + String protocol, String sourceStartIp, String sourceEndIp) throws ExecutionException; public boolean createTenantVDCEgressAclRule(String tenantName, String identifier, String policyIdentifier, - String protocol, String sourceStartPort, String sourceEndPort, String sourceIp, - String destStartIp, String destEndIp) + String protocol, String destStartIp, String destEndIp, + String destStartPort, String destEndPort) throws ExecutionException; public boolean createTenantVDCEgressAclRule(String tenantName, String identifier, String policyIdentifier, - String protocol, String sourceIp, String destStartIp, String destEndIp) + String protocol, String destStartIp, String destEndIp) throws ExecutionException; public boolean deleteTenantVDCAclRule(String tenantName, diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnectionImpl.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnectionImpl.java index 714eb82a559..c7380ab11d8 100644 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnectionImpl.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnectionImpl.java @@ -95,6 +95,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { CREATE_EGRESS_ACL_RULE("create-egress-acl-rule.xml", "policy-mgr"), CREATE_GENERIC_INGRESS_ACL_RULE("create-generic-ingress-acl-rule.xml", "policy-mgr"), CREATE_GENERIC_EGRESS_ACL_RULE("create-generic-egress-acl-rule.xml", "policy-mgr"), + CREATE_GENERIC_EGRESS_ACL_NO_PROTOCOL_RULE("create-generic-egress-acl-no-protocol-rule.xml", "policy-mgr"), DELETE_RULE("delete-rule.xml", "policy-mgr"), @@ -660,8 +661,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC " + tenantName); xml = replaceXmlValue(xml, "name", getNameForEdgeDeviceSecurityProfile(tenantName)); xml = replaceXmlValue(xml, "espdn", getDnForTenantVDCEdgeSecurityProfile(tenantName)); - //xml = replaceXmlValue(xml, "egresspolicysetname", getNameForAclPolicySet(tenantName, false)); - xml = replaceXmlValue(xml, "egresspolicysetname", "default-egress"); + xml = replaceXmlValue(xml, "egresspolicysetname", getNameForAclPolicySet(tenantName, false)); xml = replaceXmlValue(xml, "ingresspolicysetname", getNameForAclPolicySet(tenantName, true)); xml = replaceXmlValue(xml, "natpolicysetname", getNameForNatPolicySet(tenantName)); @@ -673,7 +673,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { public boolean createTenantVDCIngressAclRule(String tenantName, String identifier, String policyIdentifier, String protocol, String sourceStartIp, String sourceEndIp, - String destStartPort, String destEndPort, String destIp) throws ExecutionException { + String destStartPort, String destEndPort) throws ExecutionException { String xml = VnmcXml.CREATE_INGRESS_ACL_RULE.getXml(); String service = VnmcXml.CREATE_INGRESS_ACL_RULE.getService(); @@ -687,7 +687,6 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { xml = replaceXmlValue(xml, "sourceendip", sourceEndIp); xml = replaceXmlValue(xml, "deststartport", destStartPort); xml = replaceXmlValue(xml, "destendport", destEndPort); - xml = replaceXmlValue(xml, "destip", destIp); List rules = listChildren(getDnForAclPolicy(tenantName, policyIdentifier)); int order = 100; @@ -703,8 +702,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { @Override public boolean createTenantVDCIngressAclRule(String tenantName, String identifier, String policyIdentifier, - String protocol, String sourceStartIp, String sourceEndIp, - String destIp) throws ExecutionException { + String protocol, String sourceStartIp, String sourceEndIp) throws ExecutionException { String xml = VnmcXml.CREATE_GENERIC_INGRESS_ACL_RULE.getXml(); String service = VnmcXml.CREATE_GENERIC_INGRESS_ACL_RULE.getService(); @@ -731,8 +729,8 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { @Override public boolean createTenantVDCEgressAclRule(String tenantName, String identifier, String policyIdentifier, - String protocol, String sourceStartPort, String sourceEndPort, String sourceIp, - String destStartIp, String destEndIp) throws ExecutionException { + String protocol, String destStartIp, String destEndIp, + String destStartPort, String destEndPort) throws ExecutionException { String xml = VnmcXml.CREATE_EGRESS_ACL_RULE.getXml(); String service = VnmcXml.CREATE_EGRESS_ACL_RULE.getService(); @@ -744,9 +742,8 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { xml = replaceXmlValue(xml, "protocolvalue", protocol); xml = replaceXmlValue(xml, "deststartip", destStartIp); xml = replaceXmlValue(xml, "destendip", destEndIp); - xml = replaceXmlValue(xml, "sourcestartport", sourceStartPort); - xml = replaceXmlValue(xml, "sourceendport", sourceEndPort); - xml = replaceXmlValue(xml, "sourceip", sourceIp); + xml = replaceXmlValue(xml, "deststartport", destStartPort); + xml = replaceXmlValue(xml, "destendport", destEndPort); List rules = listChildren(getDnForAclPolicy(tenantName, policyIdentifier)); int order = 100; @@ -762,17 +759,20 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { @Override public boolean createTenantVDCEgressAclRule(String tenantName, String identifier, String policyIdentifier, - String protocol, String sourceIp, - String destStartIp, String destEndIp) throws ExecutionException { + String protocol, String destStartIp, String destEndIp) throws ExecutionException { String xml = VnmcXml.CREATE_GENERIC_EGRESS_ACL_RULE.getXml(); String service = VnmcXml.CREATE_GENERIC_EGRESS_ACL_RULE.getService(); - + if (protocol.equalsIgnoreCase("all")) { // any protocol + xml = VnmcXml.CREATE_GENERIC_EGRESS_ACL_NO_PROTOCOL_RULE.getXml(); + service = VnmcXml.CREATE_GENERIC_EGRESS_ACL_NO_PROTOCOL_RULE.getService(); + } else { // specific protocol + xml = replaceXmlValue(xml, "protocolvalue", protocol); + } xml = replaceXmlValue(xml, "cookie", _cookie); xml = replaceXmlValue(xml, "aclruledn", getDnForAclRule(tenantName, identifier, policyIdentifier)); xml = replaceXmlValue(xml, "aclrulename", getNameForAclRule(tenantName, identifier)); xml = replaceXmlValue(xml, "descr", "Egress ACL rule for Tenant VDC " + tenantName); xml = replaceXmlValue(xml, "actiontype", "permit"); - xml = replaceXmlValue(xml, "protocolvalue", protocol); xml = replaceXmlValue(xml, "deststartip", destStartIp); xml = replaceXmlValue(xml, "destendip", destEndIp); diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElement.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElement.java index 33cc40a67da..b335edb9f63 100644 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElement.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElement.java @@ -105,6 +105,7 @@ import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; import com.cloud.network.resource.CiscoVnmcResource; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.FirewallRule.TrafficType; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.StaticNat; import com.cloud.offering.NetworkOffering; @@ -677,8 +678,12 @@ public class CiscoVnmcElement extends AdapterBase implements SourceNatServicePro List rulesTO = new ArrayList(); for (FirewallRule rule : rules) { - IpAddress sourceIp = _networkModel.getIp(rule.getSourceIpAddressId()); - FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null, sourceIp.getAddress().addr(), rule.getPurpose(), rule.getTrafficType()); + String address = "0.0.0.0"; + if (rule.getTrafficType() == TrafficType.Ingress) { + IpAddress sourceIp = _networkModel.getIp(rule.getSourceIpAddressId()); + address = sourceIp.getAddress().addr(); + } + FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null, address, rule.getPurpose(), rule.getTrafficType()); rulesTO.add(ruleTO); } diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/resource/CiscoVnmcResource.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/resource/CiscoVnmcResource.java index 91559782304..906e0ae6e85 100644 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/resource/CiscoVnmcResource.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/resource/CiscoVnmcResource.java @@ -368,29 +368,29 @@ public class CiscoVnmcResource implements ServerResource { if (!_connection.createTenantVDCIngressAclRule(tenant, Long.toString(rule.getId()), policyIdentifier, rule.getProtocol().toUpperCase(), externalIpRange[0], externalIpRange[1], - Integer.toString(rule.getSrcPortRange()[0]), Integer.toString(rule.getSrcPortRange()[1]), publicIp)) { + Integer.toString(rule.getSrcPortRange()[0]), Integer.toString(rule.getSrcPortRange()[1]))) { throw new Exception("Failed to create ACL ingress rule in VNMC for guest network with vlan " + vlanId); } } else { if (!_connection.createTenantVDCIngressAclRule(tenant, Long.toString(rule.getId()), policyIdentifier, - rule.getProtocol().toUpperCase(), externalIpRange[0], externalIpRange[1], publicIp)) { + rule.getProtocol().toUpperCase(), externalIpRange[0], externalIpRange[1])) { throw new Exception("Failed to create ACL ingress rule in VNMC for guest network with vlan " + vlanId); } } } else { - if (!rule.getProtocol().equalsIgnoreCase("icmp")) { + if (rule.getProtocol().equalsIgnoreCase("tcp") || rule.getProtocol().equalsIgnoreCase("udp")) { if (!_connection.createTenantVDCEgressAclRule(tenant, Long.toString(rule.getId()), policyIdentifier, rule.getProtocol().toUpperCase(), - Integer.toString(rule.getSrcPortRange()[0]), Integer.toString(rule.getSrcPortRange()[1]), publicIp, - externalIpRange[0], externalIpRange[1])) { + externalIpRange[0], externalIpRange[1], + Integer.toString(rule.getSrcPortRange()[0]), Integer.toString(rule.getSrcPortRange()[1]))) { throw new Exception("Failed to create ACL egress rule in VNMC for guest network with vlan " + vlanId); } } else { if (!_connection.createTenantVDCEgressAclRule(tenant, Long.toString(rule.getId()), policyIdentifier, - rule.getProtocol().toUpperCase(), publicIp, externalIpRange[0], externalIpRange[1])) { + rule.getProtocol().toUpperCase(), externalIpRange[0], externalIpRange[1])) { throw new Exception("Failed to create ACL egress rule in VNMC for guest network with vlan " + vlanId); } } diff --git a/plugins/network-elements/cisco-vnmc/test/com/cloud/network/resource/CiscoVnmcResourceTest.java b/plugins/network-elements/cisco-vnmc/test/com/cloud/network/resource/CiscoVnmcResourceTest.java index e814fdcd4d5..acfc5ebaaa7 100755 --- a/plugins/network-elements/cisco-vnmc/test/com/cloud/network/resource/CiscoVnmcResourceTest.java +++ b/plugins/network-elements/cisco-vnmc/test/com/cloud/network/resource/CiscoVnmcResourceTest.java @@ -171,11 +171,11 @@ public class CiscoVnmcResourceTest { when(_connection.createTenantVDCIngressAclRule( anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), - anyString(), anyString(), anyString())).thenReturn(true); + anyString(), anyString())).thenReturn(true); when(_connection.createTenantVDCEgressAclRule( anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), - anyString(), anyString(), anyString())).thenReturn(true); + anyString(), anyString())).thenReturn(true); when(_connection.associateAclPolicySet(anyString())).thenReturn(true); Answer answer = _resource.executeRequest(cmd); From da74554ba1cce53a939d115cab04ce965b68617b Mon Sep 17 00:00:00 2001 From: Radhika PC Date: Fri, 10 May 2013 18:26:10 +0530 Subject: [PATCH 040/114] CLOUDSTACK-893 conceptual info around gslb --- .../external-firewalls-and-load-balancers.xml | 1 + docs/en-US/gslb.xml | 678 +++++++++++------- docs/en-US/images/gslb.png | Bin 184080 -> 60354 bytes docs/en-US/networks.xml | 3 +- 4 files changed, 438 insertions(+), 244 deletions(-) diff --git a/docs/en-US/external-firewalls-and-load-balancers.xml b/docs/en-US/external-firewalls-and-load-balancers.xml index b947daf7361..42ecacf9f75 100644 --- a/docs/en-US/external-firewalls-and-load-balancers.xml +++ b/docs/en-US/external-firewalls-and-load-balancers.xml @@ -29,5 +29,6 @@ xmlns:xi="http://www.w3.org/2001/XInclude"/> +
diff --git a/docs/en-US/gslb.xml b/docs/en-US/gslb.xml index ac17d61d69c..23033317381 100644 --- a/docs/en-US/gslb.xml +++ b/docs/en-US/gslb.xml @@ -26,7 +26,7 @@ achieve this by extending its functionality of integrating with NetScaler Application Delivery Controller (ADC), which also provides various GSLB capabilities, such as disaster recovery and load balancing. The DNS redirection technique is used to achieve GSLB in &PRODUCT;. - In order to support his functionality, region level services and service provider are + In order to support this functionality, region level services and service provider are introduced. A new service 'GSLB' is introduced as a region level service. The GSLB service provider is introduced that will provider the GSLB service. Currently, NetScaler is the supported GSLB provider in &PRODUCT;. GSLB functionality works in an Active-Active data center @@ -40,264 +40,456 @@ multiple data centers situated at geographically separated locations. GSLB can also provide an alternate location for accessing a resource in the event of a failure, or to provide a means of shifting traffic easily to simplify maintenance, or both. - -
- Components of GSLB - A typical GSLB environment is comprised of the following components: - - - GSLB Site: In &PRODUCT;terminology, GSLB sites are - represented by zones that are mapped to data centers, each of which has various network - appliances. Each GSLB site is managed by a NetScaler appliance that is local to that site. - Each of these appliances treats its own site as the local site and all other sites, - managed by other appliances, as remote sites. - - - GSLB Services: A GSLB service is typically - represented by a load balancing or content switching virtual server. In a GSLB - environment, you can have a local as well as remote GSLB services. A local GSLB service - represents a local load balancing or content switching virtual server. A remote GSLB - service is the one configured at one of the other sites in the GSLB setup. At each site in - the GSLB setup, you can create one local GSLB service and any number of remote GSLB - services. - - - GSLB Virtual Servers: A GSLB virtual server refers to - one or more GSLB services and balances traffic between traffic across the VMs in multiple - zones by using the &PRODUCT; functionality. It evaluates the configured GSLB methods or - algorithms to select a GSLB service to which to send the client requests. One or more - virtual servers from different zones are bound to the GSLB virtual server. GSLB virtual - server does not have a public IP associated with it, instead it will have a FQDN DNS - name. - - - Load Balancing or Content Switching Virtual Servers: - According to Citrix NetScaler terminology, a load balancing or content switching virtual - server represents one or many servers on the local network. Clients send their requests to - the load balancing or content switching virtual server’s virtual IP (VIP) address, and the - virtual server balances the load across the local servers. After a GSLB virtual server - selects a GSLB service representing either a local or a remote load balancing or content - switching virtual server, the client sends the request to that virtual server’s VIP - address. - - - DNS VIPs: DNS virtual IP represents a load balancing - DNS virtual server on the GSLB service provider. The DNS requests for domains for which - the GSLB service provider is authoritative can be sent to a DNS VIP. - - - ADNS: ADNS (Authoritative Domain Name Server) is a - service that provides actual answer to DNS queries, such as web site IP address. In a GSLB - environment, an ADNS service responds only to DNS requests for domains for which the GSLB - service provider is authoritative. When an ADNS service is configured, the service - provider owns that IP address and advertises it. When you create an ADNS service, the - NetScaler responds to DNS queries on the configured ADNS service IP and port. - - -
-
- Prerequisites and Guidelines - - - The GSLB functionality is supported both Basic and Advanced zones. - - - GSLB is added as a new network service. - - - GSLB service provider can be added to a physical network in a zone. - - - The admin is allowed to enable or disable GSLB functionality at region level. - - - The admin is allowed to configure a zone as GSLB capable or enabled. - A zone shall be considered as GSLB capable only if a GSLB service provider is - provisioned in the zone. - - - When users have VMs deployed in multiple availability zones which are GSLB enabled, - they can use the GSLB functionality to load balance traffic across the VMs in multiple - zones. - - - The users can use GSLB to load balance across the VMs across zones in a region only if - the admin has enabled GSLB in that region. - - - The users can load balance traffic across the availability zones in the same region or - different regions. - - - The admin can configure DNS name for the entire cloud. - - - The users can specify an unique name across the cloud for a globally load balanced - service. The provided name is used as the domain name under the DNS name associated with - the cloud. - The user-provided name along with the admin-provided DNS name is used to produce a - globally resolvable FQDN for the globally load balanced service of the user. For example, - if the admin has configured xyztelco.com as the DNS name for the cloud, and user specifies - 'foo' for the GSLB virtual service, then the FQDN name of the GSLB virtual service is - foo.xyztelco.com. - - - While setting up GSLB, users can select a load balancing method, such as round robin, - for using across the zones that are part of GSLB. - - - The user shall be able to set weight to zone-level virtual server. Weight shall be - considered by the load balancing method for distributing the traffic. - - - The GSLB functionality shall support session persistence, where series of client - requests for particular domain name is sent to a virtual server on the same zone. - Statistics is collected from each GSLB virtual server. - - +
+ Components of GSLB + A typical GSLB environment is comprised of the following components: + + + GSLB Site: In &PRODUCT;terminology, GSLB sites are + represented by zones that are mapped to data centers, each of which has various network + appliances. Each GSLB site is managed by a NetScaler appliance that is local to that + site. Each of these appliances treats its own site as the local site and all other + sites, managed by other appliances, as remote sites. It is the central entity in a GSLB + deployment, and is represented by a name and an IP address. + + + GSLB Services: A GSLB service is typically + represented by a load balancing or content switching virtual server. In a GSLB + environment, you can have a local as well as remote GSLB services. A local GSLB service + represents a local load balancing or content switching virtual server. A remote GSLB + service is the one configured at one of the other sites in the GSLB setup. At each site + in the GSLB setup, you can create one local GSLB service and any number of remote GSLB + services. + + + GSLB Virtual Servers: A GSLB virtual server refers + to one or more GSLB services and balances traffic between traffic across the VMs in + multiple zones by using the &PRODUCT; functionality. It evaluates the configured GSLB + methods or algorithms to select a GSLB service to which to send the client requests. One + or more virtual servers from different zones are bound to the GSLB virtual server. GSLB + virtual server does not have a public IP associated with it, instead it will have a FQDN + DNS name. + + + Load Balancing or Content Switching Virtual + Servers: According to Citrix NetScaler terminology, a load balancing or + content switching virtual server represents one or many servers on the local network. + Clients send their requests to the load balancing or content switching virtual server’s + virtual IP (VIP) address, and the virtual server balances the load across the local + servers. After a GSLB virtual server selects a GSLB service representing either a local + or a remote load balancing or content switching virtual server, the client sends the + request to that virtual server’s VIP address. + + + DNS VIPs: DNS virtual IP represents a load + balancing DNS virtual server on the GSLB service provider. The DNS requests for domains + for which the GSLB service provider is authoritative can be sent to a DNS VIP. + + + Authoritative DNS: ADNS (Authoritative Domain Name + Server) is a service that provides actual answer to DNS queries, such as web site IP + address. In a GSLB environment, an ADNS service responds only to DNS requests for + domains for which the GSLB service provider is authoritative. When an ADNS service is + configured, the service provider owns that IP address and advertises it. When you create + an ADNS service, the NetScaler responds to DNS queries on the configured ADNS service IP + and port. + + +
+
+ How Does GSLB Works in &PRODUCT;? + Global server load balancing is used to manage the traffic flow to a web site hosted on + two separate zones that ideally are in different geographic locations. The following is an + illustration of how GLSB functionality is provided in &PRODUCT;: An organization, xyztelco, + has set up a public cloud that spans two zones, Zone-1 and Zone-2, across geographically + separated data centers that are managed by &PRODUCT;. Tenant-A of the cloud launches a + highly available solution by using xyztelco cloud. For that purpose, they launch two + instances each in both the zones: VM1 and VM2 in Zone-1 and VM5 and VM6 in Zone-2. Tenant-A + acquires a public IP, IP-1 in Zone-1, and configures a load balancer rule to load balance + the traffic between VM1 and VM2 instances. &PRODUCT; orchestrates setting up a virtual + server on the LB service provider in Zone-1. Virtual server 1 that is set up on the LB + service provider in Zone-1 represents a publicly accessible virtual server that client + reaches at IP-1. The client traffic to virtual server 1 at IP-1 will be load balanced across + VM1 and VM2 instances. + Tenant-A acquires another public IP, IP-2 in Zone-2 and sets up a load balancer rule to + load balance the traffic between VM5 and VM6 instances. Similarly in Zone-2, &PRODUCT; + orchestrates setting up a virtual server on the LB service provider. Virtual server 2 that + is setup on the LB service provider in Zone-2 represents a publicly accessible virtual + server that client reaches at IP-2. The client traffic that reaches virtual server 2 at IP-2 + is load balanced across VM5 and VM6 instances. At this point Tenant-A has the service + enabled in both the zones, but has no means to set up a disaster recovery plan if one of the + zone fails. Additionally, there is no way for Tenant-A to load balance the traffic + intelligently to one of the zones based on load, proximity and so on. The cloud + administrator of xyztelco provisions a GSLB service provider to both the zones. A GSLB + provider is typically an ADC that has the ability to act as an ADNS (Authoritative Domain + Name Server) and has the mechanism to monitor health of virtual servers both at local and + remote sites. The cloud admin enables GSLB as a service to the tenants that use zones 1 and + 2. + + + + + + gslb.png: GSLB architecture + + + Tenant-A wishes to leverage the GSLB service provided by the xyztelco cloud. Tenant-A + configures a GSLB rule to load balance traffic across virtual server 1 at Zone-1 and virtual + server 2 at Zone-2. The domain name is provided as A.xyztelco.com. &PRODUCT; orchestrates + setting up GSLB virtual server 1 on the GSLB service provider at Zone-1. &PRODUCT; binds + virtual server 1 of Zone-1 and virtual server 2 of Zone-2 to GLSB virtual server 1. GSLB + virtual server 1 is configured to start monitoring the health of virtual server 1 and 2 in + Zone-1. &PRODUCT; will also orchestrate setting up GSLB virtual server 2 on GSLB service + provider at Zone-2. &PRODUCT; will bind virtual server 1 of Zone-1 and virtual server 2 of + Zone-2 to GLSB virtual server 2. GSLB virtual server 2 is configured to start monitoring the + health of virtual server 1 and 2. &PRODUCT; will bind the domain A.xyztelco.com to both the + GSLB virtual server 1 and 2. At this point, Tenant-A service will be globally reachable at + A.xyztelco.com. The private DNS server for the domain xyztelcom.com is configured by the + admin out-of-band to resolve the domain A.xyztelco.com to the GSLB providers at both the + zones, which are configured as ADNS for the domain A.xyztelco.com. A client when sends a DNS + request to resolve A.xyztelcom.com, will eventually get DNS delegation to the address of + GSLB providers at zone 1 and 2. A client DNS request will be received by the GSLB provider. + The GSLB provider, depending on the domain for which it needs to resolve, will pick up the + GSLB virtual server associated with the domain. Depending on the health of the virtual + servers being load balanced, DNS request for the domain will be resolved to the public IP + associated with the selected virtual server. +
Configuring GSLB + A GSLB deployment is the logical collection of GSLB virtual server, GSLB service, LB + virtual server, service, domain, and ADNS service. To create a GSLB site, you must configure + load balancing in the zone. You must create GSLB vservers and GSLB services for each site. You + must bind GSLB services to GSLB vservers. You must then create an ADNS service that provides + the IP address of the best performing site to the client's request. A GSLB vserver is an + entity that performs load balancing for the domains bound to it by returning the IP address of + the best GSLB service. A GSLB service is a representation of the load balancing/content + switching vserver. An LB vserver load balances incoming traffic by identifying the best + server, then directs traffic to the corresponding service. It can also load-balance external + DNS name servers. Services are entities that represent the servers. The domain is the domain + name for which the system is the authoritative DNS server. By creating an ADNS service, the + system can be configured as an authoritative DNS server. To configure GSLB in your cloud environment, as a cloud administrator you must perform the following. To configure such a GSLB setup, you must first configure a standard load balancing setup - for each server farm or data center. This enables you to balance load across the different - servers in each server farm. Then, configure both NetScaler appliances as authoritative DNS - (ADNS) servers. Next, create a GSLB site for each server farm, configure GSLB virtual servers - for each site, create GLSB services, and bind the GSLB services to the GSLB virtual servers. - Finally, bind the domain to the GSLB virtual servers. The GSLB configurations on the two - appliances at the two different sites are identical, although each sites load-balancing - configuration is specific to that site. + for each zone. This enables you to balance load across the different servers in each zone in + the region. Then, configure both NetScaler appliances that you plan to add to each zone as + authoritative DNS (ADNS) servers. Next, create a GSLB site for each zone, configure GSLB + virtual servers for each site, create GLSB services, and bind the GSLB services to the GSLB + virtual servers. Finally, bind the domain to the GSLB virtual servers. The GSLB configurations + on the two appliances at the two different sites are identical, although each sites + load-balancing configuration is specific to that site. + Perform the following as a cloud administrator. As per the above example, the + administrator of xyztelco is the one who sets up GSLB: - + In the cloud.dns.name global parameter, specify the DNS name of your tenant's cloud + that make use of the GSLB service. + + + On the NetScaler side, configure GSLB as given in Configuring Global Server Load Balancing (GSLB): + + + Configuring a standard load balancing setup. + + + Configure Authoritative DNS, as explained in Configuring an Authoritative DNS Service. + + + Configure a GSLB site with site name formed from the domain name details. + For more information, see Configuring a Basic GSLB Site. + + + Configure a GSLB virtual server. + For more information, see Configuring a GSLB Virtual Server. + + + Configure a GSLB service for each virtual server. + For more information, see Configuring a GSLB Service. + + + Bind the GSLB services to the GSLB virtual server. + For more information, see Binding GSLB Services to a GSLB Virtual Server. + + + Bind domain name to GSLB virtual server. Domain name is obtained from the domain + details. + For more information, see Binding a Domain to a GSLB Virtual Server. + + + + + In each zone that are participating in GSLB, add GSLB-enabled NetScaler device. + For more information, see . -
-
- Adding a GSLB Rule + As a domain administrator/ user perform the following: - Log in to the &PRODUCT; UI as administrator. + Add a GSLB rule on both the sites. + See . - In the left navigation pane, click Region. - - - Select the region for which you want to create a GSLB rule. - - - In the Details tab, click View GSLB. - - - Click Add GSLB. - The Add GSLB page is displayed as follows: - - - - - - gslb-add.png: adding a gslb rule - - - - - Specify the following: - - - Name: Name for the GSLB rule. - - - Description: (Optional) A short description of - the GSLB rule that can be displayed to users. - - - GSLB Domain Name: A preferred domain name for the - service. - - - Algorithm: (Optional) The algorithm to use to - load balance the traffic across the zones. The options are Round Robin, Least - Connection, and Proximity. - - - Service Type: The transport protocol to use for - GSLB. The options are TCP and UDP. - - - Domain: (Optional) The domain for which you want - to create the GSLB rule. - - - Account: (Optional) The account on which you want - to apply the GSLB rule. - - - - - Click OK to confirm. + Assign load balancer rules. + See . -
-
- Assigning Load Balancing Rules to GSLB - -
-
- How Does GSLB Works in &PRODUCT;? - Global server load balancing is used to manage traffic flow to a web site hosted on two - separate zones that ideally are in different geographic locations. The following is an - illustration of how GLSB functionality is provided in &PRODUCT;: An organization, xyztelco, - has set up a public cloud that spans two zones, Zone-1 and Zone-2, across geographically - separated data centers that are managed by &PRODUCT;. Tenant-A of the cloud launches a highly - available solution by using xyztelco cloud. For that purpose, they launch two instances each - in both the zones: VM1 and VM2 in Zone-1 and VM5 and VM6 in Zone-2. Tenant-A acquires a public - IP, IP-1 in Zone-1, and configures a load balancer rule to load balance the traffic between - VM1 and VM2 instances. &PRODUCT; orchestrates setting up a virtual server on the LB service - provider in Zone-1. Virtual server 1 that is set up on the LB service provider in Zone-1 - represents a publicly accessible virtual server that client reaches at IP-1. The client - traffic to virtual server 1 at IP-1 will be load balanced across VM1 and VM2 instances. - Tenant-A acquires another public IP, IP-2 in Zone-2 and sets up a load balancer rule to - load balance the traffic between VM5 and VM6 instances. Similarly in Zone-2, &PRODUCT; - orchestrates setting up a virtual server on the LB service provider. Virtual server 2 that is - setup on the LB service provider in Zone-2 represents a publicly accessible virtual server - that client reaches at IP-2. The client traffic that reaches virtual server 2 at IP-2 is load - balanced across VM5 and VM6 instances. At this point Tenant-A has the service enabled in both - the zones, but has no means to set up a disaster recovery plan if one of the zone fails. - Additionally, there is no way for Tenant-A to load balance the traffic intelligently to one of - the zones based on load, proximity and so on. The cloud administrator of xyztelco provisions a - GSLB service provider to both the zones. A GSLB provider is typically an ADC that has the - ability to act as an ADNS (Authoritative Domain Name Server) and has the mechanism to monitor - health of virtual servers both at local and remote sites. The cloud admin enables GSLB as a - service to the tenants that use zones 1 and 2. - - - - - - gslb.png: GSLB architecture - - - Tenant-A wishes to leverage the GSLB service provided by the xyztelco cloud. Tenant-A - configures a GSLB rule to load balance traffic across virtual server 1 at Zone-1 and virtual - server 2 at Zone-2. The domain name is provided as A.xyztelco.com. &PRODUCT; orchestrates - setting up GSLB virtual server 1 on the GSLB service provider at Zone-1. &PRODUCT; binds - virtual server 1 of Zone-1 and virtual server 2 of Zone-2 to GLSB virtual server 1. GSLB - virtual server 1 is configured to start monitoring the health of virtual server 1 and 2 in - Zone-1. &PRODUCT; will also orchestrate setting up GSLB virtual server 2 on GSLB service - provider at Zone-2. &PRODUCT; will bind virtual server 1 of Zone-1 and virtual server 2 of - Zone-2 to GLSB virtual server 2. GSLB virtual server 2 is configured to start monitoring the - health of virtual server 1 and 2. &PRODUCT; will bind the domain A.xyztelco.com to both the - GSLB virtual server 1 and 2. At this point, Tenant-A service will be globally reachable at - A.xyztelco.com. The private DNS server for the domain xyztelcom.com is configured by the admin - out-of-band to resolve the domain A.xyztelco.com to the GSLB providers at both the zones, - which are configured as ADNS for the domain A.xyztelco.com. A client when sends a DNS request - to resolve A.xyztelcom.com, will eventually get DNS delegation to the address of GSLB - providers at Zone 1 and 2. A client DNS request will be received by the GSLB provider. The - GSLB provider, depending on the domain for which it needs to resolve, will pick up the GSLB - virtual server associated with the domain. Depending on the health of the virtual servers - being load balanced, DNS request for the domain will be resolved to the public IP associated - with the selected virtual server. +
+ Prerequisites and Guidelines + + + The GSLB functionality is supported both Basic and Advanced zones. + + + GSLB is added as a new network service. + + + GSLB service provider can be added to a physical network in a zone. + + + The admin is allowed to enable or disable GSLB functionality at region level. + + + The admin is allowed to configure a zone as GSLB capable or enabled. + A zone shall be considered as GSLB capable only if a GSLB service provider is + provisioned in the zone. + + + When users have VMs deployed in multiple availability zones which are GSLB enabled, + they can use the GSLB functionality to load balance traffic across the VMs in multiple + zones. + + + The users can use GSLB to load balance across the VMs across zones in a region only + if the admin has enabled GSLB in that region. + + + The users can load balance traffic across the availability zones in the same region + or different regions. + + + The admin can configure DNS name for the entire cloud. + + + The users can specify an unique name across the cloud for a globally load balanced + service. The provided name is used as the domain name under the DNS name associated with + the cloud. + The user-provided name along with the admin-provided DNS name is used to produce a + globally resolvable FQDN for the globally load balanced service of the user. For + example, if the admin has configured xyztelco.com as the DNS name for the cloud, and + user specifies 'foo' for the GSLB virtual service, then the FQDN name of the GSLB + virtual service is foo.xyztelco.com. + + + While setting up GSLB, users can select a load balancing method, such as round + robin, for using across the zones that are part of GSLB. + + + The user shall be able to set weight to zone-level virtual server. Weight shall be + considered by the load balancing method for distributing the traffic. + + + The GSLB functionality shall support session persistence, where series of client + requests for particular domain name is sent to a virtual server on the same zone. + Statistics is collected from each GSLB virtual server. + + +
+
+ Enabling GSLB in NetScaler + In each zone, add GSLB-enabled NetScaler device for load balancing. + + + Log in as administrator to the &PRODUCT; UI. + + + In the left navigation bar, click Infrastructure. + + + In Zones, click View More. + + + Choose the zone you want to work with. + + + Click the Physical Network tab, then click the name of the physical network. + + + In the Network Service Providers node of the diagram, click Configure. + You might have to scroll down to see this. + + + Click NetScaler. + + + Click Add NetScaler device and provide the following: + For NetScaler: + + + IP Address: The IP address of the SRX. + + + Username/Password: The authentication + credentials to access the device. &PRODUCT; uses these credentials to access the + device. + + + Type: The type of device that is being added. + It could be F5 Big Ip Load Balancer, NetScaler VPX, NetScaler MPX, or NetScaler SDX. + For a comparison of the NetScaler types, see the &PRODUCT; Administration + Guide. + + + Public interface: Interface of device that is + configured to be part of the public network. + + + Private interface: Interface of device that is + configured to be part of the private network. + + + GSLB service: Select this option. + + + GSLB service Public IP: The public IP address + of the NAT translator for a GSLB service that is on a private network. + + + GSLB service Private IP: The private IP of the + GSLB service. + + + Number of Retries. Number of times to attempt a + command on the device before considering the operation failed. Default is 2. + + + Capacity: The number of networks the device can + handle. + + + Dedicated: When marked as dedicated, this + device will be dedicated to a single account. When Dedicated is checked, the value + in the Capacity field has no significance implicitly, its value is 1. + + + + + Click OK. + + +
+
+ Adding a GSLB Rule + + + Log in to the &PRODUCT; UI as a domain administrator or user. + + + In the left navigation pane, click Region. + + + Select the region for which you want to create a GSLB rule. + + + In the Details tab, click View GSLB. + + + Click Add GSLB. + The Add GSLB page is displayed as follows: + + + + + + gslb-add.png: adding a gslb rule + + + + + Specify the following: + + + Name: Name for the GSLB rule. + + + Description: (Optional) A short description of + the GSLB rule that can be displayed to users. + + + GSLB Domain Name: A preferred domain name for + the service. + + + Algorithm: (Optional) The algorithm to use to + load balance the traffic across the zones. The options are Round Robin, Least + Connection, and Proximity. + + + Service Type: The transport protocol to use for + GSLB. The options are TCP and UDP. + + + Domain: (Optional) The domain for which you + want to create the GSLB rule. + + + Account: (Optional) The account on which you + want to apply the GSLB rule. + + + + + Click OK to confirm. + + +
+
+ Assigning Load Balancing Rules to GSLB + + + + Log in to the &PRODUCT; UI as a domain administrator or user. + + + In the left navigation pane, click Region. + + + Select the region for which you want to create a GSLB rule. + + + In the Details tab, click View GSLB. + + + Select the desired GSLB. + + + Click view assigned load balancing. + + + Click assign more load balancing. + + + Select the load balancing rule you have created for the zone. + + + Click OK to confirm. + + +
Known Limitation diff --git a/docs/en-US/images/gslb.png b/docs/en-US/images/gslb.png index 8d1a389936c31e3ed46c24f7a6787fd21a873c65..9f13580c56095985891f09e9c33bc363567eb57e 100644 GIT binary patch literal 60354 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
\ No newline at end of file + diff --git a/docs/en-US/hypervisor-host-install-libvirt.xml b/docs/en-US/hypervisor-host-install-libvirt.xml index f3ff090463c..d3d6b9b4e80 100644 --- a/docs/en-US/hypervisor-host-install-libvirt.xml +++ b/docs/en-US/hypervisor-host-install-libvirt.xml @@ -24,7 +24,7 @@
Install and Configure libvirt - &PRODUCT; uses libvirt for managing virtual machines. Therefore it is vital that libvirt is configured correctly. Libvirt is a dependency of cloud-agent and should already be installed. + &PRODUCT; uses libvirt for managing virtual machines. Therefore it is vital that libvirt is configured correctly. Libvirt is a dependency of cloudstack-agent and should already be installed. In order to have live migration working libvirt has to listen for unsecured TCP connections. We also need to turn off libvirts attempt to use Multicast DNS advertising. Both of these settings are in /etc/libvirt/libvirtd.conf diff --git a/docs/en-US/increase-management-server-max-memory.xml b/docs/en-US/increase-management-server-max-memory.xml index 16d18e75830..51c8724a020 100644 --- a/docs/en-US/increase-management-server-max-memory.xml +++ b/docs/en-US/increase-management-server-max-memory.xml @@ -28,7 +28,7 @@ Edit the Tomcat configuration file:/etc/cloud/management/tomcat6.conf Change the command-line parameter -XmxNNNm to a higher value of N.For example, if the current value is -Xmx128m, change it to -Xmx1024m or higher. - To put the new setting into effect, restart the Management Server.# service cloud-management restart + To put the new setting into effect, restart the Management Server.# service cloudstack-management restart For more information about memory issues, see "FAQ: Memory" at Tomcat Wiki.
diff --git a/docs/en-US/install-usage-server.xml b/docs/en-US/install-usage-server.xml index 9dde5523f5e..ffd748d758e 100644 --- a/docs/en-US/install-usage-server.xml +++ b/docs/en-US/install-usage-server.xml @@ -52,7 +52,7 @@ Once installed, start the Usage Server with the following command. -# service cloud-usage start +# service cloudstack-usage start diff --git a/docs/en-US/lxc-install.xml b/docs/en-US/lxc-install.xml index a80c18afdd6..40f6a0aaa69 100644 --- a/docs/en-US/lxc-install.xml +++ b/docs/en-US/lxc-install.xml @@ -74,9 +74,9 @@ To manage LXC instances on the host &PRODUCT; uses a Agent. This Agent communicates with the Management server and controls all the instances on the host. First we start by installing the agent: In RHEL or CentOS: - $ yum install cloud-agent + $ yum install cloudstack-agent In Ubuntu: - $ apt-get install cloud-agent + $ apt-get install cloudstack-agent Next step is to update the Agent configuration setttings. The settings are in /etc/cloudstack/agent/agent.properties diff --git a/docs/en-US/set-global-project-resource-limits.xml b/docs/en-US/set-global-project-resource-limits.xml index d91942ad8db..8ec13259051 100644 --- a/docs/en-US/set-global-project-resource-limits.xml +++ b/docs/en-US/set-global-project-resource-limits.xml @@ -76,7 +76,7 @@ Restart the Management Server. - # service cloud-management restart + # service cloudstack-management restart diff --git a/docs/en-US/set-projects-creator-permissions.xml b/docs/en-US/set-projects-creator-permissions.xml index 9b272f6bc7e..dd9cfe95d56 100644 --- a/docs/en-US/set-projects-creator-permissions.xml +++ b/docs/en-US/set-projects-creator-permissions.xml @@ -56,7 +56,7 @@ Restart the Management Server. - # service cloud-management restart + # service cloudstack-management restart diff --git a/docs/en-US/set-up-invitations.xml b/docs/en-US/set-up-invitations.xml index c1303cf5e92..180c041e87e 100644 --- a/docs/en-US/set-up-invitations.xml +++ b/docs/en-US/set-up-invitations.xml @@ -89,7 +89,7 @@ Restart the Management Server: - service cloud-management restart + service cloudstack-management restart diff --git a/docs/en-US/stop-restart-management-server.xml b/docs/en-US/stop-restart-management-server.xml index 5c1bcecbc00..74a687c23a1 100644 --- a/docs/en-US/stop-restart-management-server.xml +++ b/docs/en-US/stop-restart-management-server.xml @@ -26,9 +26,9 @@ The root administrator will need to stop and restart the Management Server from time to time. For example, after changing a global configuration parameter, a restart is required. If you have multiple Management Server nodes, restart all of them to put the new parameter value into effect consistently throughout the cloud.. To stop the Management Server, issue the following command at the operating system prompt on the Management Server node: - # service cloud-management stop + # service cloudstack-management stop To start the Management Server: - # service cloud-management start + # service cloudstack-management start To stop the Management Server: - # service cloud-management stop + # service cloudstack-management stop diff --git a/docs/en-US/sys-offering-sysvm.xml b/docs/en-US/sys-offering-sysvm.xml index cccf3e04796..563dd6f5ebf 100644 --- a/docs/en-US/sys-offering-sysvm.xml +++ b/docs/en-US/sys-offering-sysvm.xml @@ -65,7 +65,7 @@ Restart &PRODUCT; Management Server. Restarting is required because the default offerings are loaded into the memory at startup. - service cloud-management restart + service cloudstack-management restart Destroy the existing CPVM or SSVM offerings and wait for them to be recreated. The new diff --git a/docs/en-US/zone-add.xml b/docs/en-US/zone-add.xml index 4f6606fce03..3ca5789cd99 100644 --- a/docs/en-US/zone-add.xml +++ b/docs/en-US/zone-add.xml @@ -42,7 +42,7 @@ Restart the Management Server. - # service cloud-management restart + # service cloudstack-management restart Refresh the &PRODUCT; UI browser tab and log back in. From f12ac95a56983267fd66c215461fa7e17a43525f Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Fri, 10 May 2013 11:03:34 -0700 Subject: [PATCH 044/114] VPC: When Netscaler is LB provider for the VPC, the VpcVirtualRouter can't provide LB services --- server/src/com/cloud/network/vpc/VpcManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index 09776ae48eb..e6d71faad35 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -228,7 +228,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis if (svc == Service.Lb) { Set lbProviders = new HashSet(); lbProviders.add(Provider.Netscaler); - lbProviders.add(Provider.VPCVirtualRouter); + lbProviders.add(Provider.InternalLbVm); svcProviderMap.put(svc, lbProviders); } else { svcProviderMap.put(svc, defaultProviders); From 1177589a6bb433577c557771ea905aab236bb21b Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Fri, 10 May 2013 11:54:17 -0700 Subject: [PATCH 045/114] CLOUDSTACK-1816: Cisco VNMC ASA1000v - UI - Infrastructure menu - physical network - network service providers - Cisco VNMC - fix a bug that detailView loads forever. --- ui/modules/infrastructure/infrastructure.js | 4 ++-- .../vnmcNetworkProvider/vnmcNetworkProvider.js | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/ui/modules/infrastructure/infrastructure.js b/ui/modules/infrastructure/infrastructure.js index 4111aa5af37..55767d3137e 100644 --- a/ui/modules/infrastructure/infrastructure.js +++ b/ui/modules/infrastructure/infrastructure.js @@ -36,7 +36,7 @@ var selectedZoneObj = data.selectedZoneObj; var selectedPhysicalNetworkObj = data.selectedPhysicalNetworkObj; if(selectedZoneObj.networktype == "Advanced"){ - var selectedProviderObj = {}; + var selectedProviderObj = null; $.ajax({ url: createURL('listNetworkServiceProviders'), data: { @@ -55,7 +55,7 @@ nspHardcodingArray.push({ id: id, name: name, - state: selectedProviderObj.state + state: selectedProviderObj? selectedProviderObj.state : 'Disabled' }); } }); diff --git a/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js b/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js index cecf56c79ea..cad4a49a6a5 100644 --- a/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js +++ b/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js @@ -278,8 +278,11 @@ id: { label: 'label.id' }, servicelist: { label: 'Services', - converter: function(args){ - return args.join(', '); + converter: function(args){ + if(args) + return args.join(', '); + else + return ''; } } } @@ -296,6 +299,14 @@ if(items != null && items.length > 0) { args.response.success({ data: items[0] }); } + else { + args.response.success({ + data: { + name: 'CiscoVnmc', + state: 'Disabled' + } + }) + } } }); } From 791c68fc11976a0bb9bc46e3a18c9778008bf444 Mon Sep 17 00:00:00 2001 From: Milamber Date: Fri, 10 May 2013 19:56:57 +0100 Subject: [PATCH 046/114] Fix doc: MySQL not Tomcat --- docs/en-US/set-database-buffer-pool-size.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en-US/set-database-buffer-pool-size.xml b/docs/en-US/set-database-buffer-pool-size.xml index 1c7503101ca..8265ae544f2 100644 --- a/docs/en-US/set-database-buffer-pool-size.xml +++ b/docs/en-US/set-database-buffer-pool-size.xml @@ -26,7 +26,7 @@ Set Database Buffer Pool Size It is important to provide enough memory space for the MySQL database to cache data and indexes: - Edit the Tomcat configuration file:/etc/my.cnf + Edit the MySQL configuration file:/etc/my.cnf Insert the following line in the [mysqld] section, below the datadir line. Use a value that is appropriate for your situation. We recommend setting the buffer pool at 40% of RAM if MySQL is on the same server as the management server or 70% of RAM if MySQL has a dedicated server. The following example assumes a dedicated server with 1024M of RAM. innodb_buffer_pool_size=700M Restart the MySQL service.# service mysqld restart From b7f10bffaedc5d346c90dca70810de11225d61d0 Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Sat, 11 May 2013 01:21:50 +0530 Subject: [PATCH 047/114] Removing the @Test annotation for building master successfully for one of the test cases for InternalLb element as discussed with Alena --- .../internallbelement/InternalLbElementServiceTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/InternalLbElementServiceTest.java b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/InternalLbElementServiceTest.java index f0e951cdc7a..bdc50cafb8c 100644 --- a/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/InternalLbElementServiceTest.java +++ b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/InternalLbElementServiceTest.java @@ -175,7 +175,6 @@ public class InternalLbElementServiceTest { } - @Test (expected = InvalidParameterValueException.class) public void addToInvalidProvider() { _lbElSvc.addInternalLoadBalancerElement(invalidProviderId); } From 7ca488334f4fd48c150b31b73ad5be34052a19c8 Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Sat, 11 May 2013 02:50:16 +0530 Subject: [PATCH 048/114] CLOUDSTACK-1828:NAT on private gateway UI support --- ui/scripts/ui-custom/vpc.js | 1 + ui/scripts/vpc.js | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/ui/scripts/ui-custom/vpc.js b/ui/scripts/ui-custom/vpc.js index 2bd26b11f1a..4edccf10211 100644 --- a/ui/scripts/ui-custom/vpc.js +++ b/ui/scripts/ui-custom/vpc.js @@ -152,6 +152,7 @@ addAction.action({ data: data, + $form:args.$form, context: gateways.context, response: { success: function(args) { diff --git a/ui/scripts/vpc.js b/ui/scripts/vpc.js index dc26265c232..17cf42a5e91 100644 --- a/ui/scripts/vpc.js +++ b/ui/scripts/vpc.js @@ -717,12 +717,28 @@ netmask: { label: 'label.netmask', validation: { required: true }, docID: 'helpVPCGatewayNetmask' + }, + sourceNat:{ + label:'Source NAT', + isBoolean:true, + isChecked:false + } + + } }, action: function(args) { + var array1=[]; + if(args.$form.find('.form-item[rel=sourceNat]').find('input[type=checkbox]').is(':Checked')== true) { + array1.push("&sourcenatsupported=true"); + } + else + array1.push("&sourcenatsupported=false"); + + $.ajax({ - url: createURL('createPrivateGateway'), + url: createURL('createPrivateGateway'+ array1.join("")), data: { physicalnetworkid: args.data.physicalnetworkid, vpcid: args.context.vpc[0].id, @@ -811,15 +827,32 @@ netmask: { label: 'label.netmask', validation: { required: true }, docID: 'helpVPCGatewayNetmask' + }, + + sourceNat:{ + label:'Source NAT', + isBoolean:true, + isChecked:false + } + } }, action:function(args){ + + var array1=[]; + if(args.$form.find('.form-item[rel=sourceNat]').find('input[type=checkbox]').is(':Checked')== true) { + array1.push("&sourcenatsupported=true"); + } + else + array1.push("&sourcenatsupported=false"); + + $.ajax({ - url: createURL('createPrivateGateway'), + url: createURL('createPrivateGateway'+ array1.join("")), data: { physicalnetworkid: args.data.physicalnetworkid, vpcid: args.context.vpc[0].id, From 074901365fa46bc10953051686a975026758618c Mon Sep 17 00:00:00 2001 From: Chiradeep Vittal Date: Fri, 10 May 2013 17:11:12 -0700 Subject: [PATCH 049/114] CLOUDSTACK-2324 Since wheezy (temporarily) does not have haproxy, install from squeeze. We cannot install from sid since that version depends on libc6(>=2.15) while wheezy has libc6 at 2.13-38 --- .../appliance/definitions/systemvmtemplate/postinstall.sh | 8 ++++++-- .../definitions/systemvmtemplate64/postinstall.sh | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/tools/appliance/definitions/systemvmtemplate/postinstall.sh b/tools/appliance/definitions/systemvmtemplate/postinstall.sh index 38363d91130..f532f88537c 100644 --- a/tools/appliance/definitions/systemvmtemplate/postinstall.sh +++ b/tools/appliance/definitions/systemvmtemplate/postinstall.sh @@ -37,8 +37,7 @@ install_packages() { apt-get --no-install-recommends -q -y --force-yes install sysstat # apache apt-get --no-install-recommends -q -y --force-yes install apache2 ssl-cert - # haproxy - apt-get --no-install-recommends -q -y --force-yes install haproxy + # dnsmasq apt-get --no-install-recommends -q -y --force-yes install dnsmasq dnsmasq-utils # nfs client @@ -78,6 +77,11 @@ install_packages() { # cd $PREV # rm -fr /opt/vmware-tools-distrib # apt-get -q -y --force-yes purge build-essential + + # haproxy. Wheezy doesn't have haproxy, install from backports + #apt-get --no-install-recommends -q -y --force-yes install haproxy + wget http://ftp.us.debian.org/debian/pool/main/h/haproxy/haproxy_1.4.8-1_i386.deb + dpkg -i haproxy_1.4.8-1_i386.deb } setup_accounts() { diff --git a/tools/appliance/definitions/systemvmtemplate64/postinstall.sh b/tools/appliance/definitions/systemvmtemplate64/postinstall.sh index 38363d91130..3ccf3cefdef 100644 --- a/tools/appliance/definitions/systemvmtemplate64/postinstall.sh +++ b/tools/appliance/definitions/systemvmtemplate64/postinstall.sh @@ -37,8 +37,7 @@ install_packages() { apt-get --no-install-recommends -q -y --force-yes install sysstat # apache apt-get --no-install-recommends -q -y --force-yes install apache2 ssl-cert - # haproxy - apt-get --no-install-recommends -q -y --force-yes install haproxy + # dnsmasq apt-get --no-install-recommends -q -y --force-yes install dnsmasq dnsmasq-utils # nfs client @@ -78,6 +77,11 @@ install_packages() { # cd $PREV # rm -fr /opt/vmware-tools-distrib # apt-get -q -y --force-yes purge build-essential + + # haproxy. Wheezy doesn't have haproxy temporarily, install from backports + #apt-get --no-install-recommends -q -y --force-yes install haproxy + wget http://ftp.us.debian.org/debian/pool/main/h/haproxy/haproxy_1.4.8-1_amd64.deb + dpkg -i haproxy_1.4.8-1_amd64.deb } setup_accounts() { From 1731a4a4428ff5d0de0e770484d2879a35ced55b Mon Sep 17 00:00:00 2001 From: Nitin Mehta Date: Sat, 11 May 2013 14:13:38 +0530 Subject: [PATCH 050/114] Add the new APIs along with tests --- api/src/com/cloud/event/EventTypes.java | 4 + .../cloud/server/ResourceMetaDataService.java | 47 ++++ api/src/com/cloud/server/ResourceTag.java | 1 + .../cloud/server/TaggedResourceService.java | 5 +- .../org/apache/cloudstack/api/BaseCmd.java | 2 + .../user/volume/AddResourceDetailCmd.java | 116 ++++++++ .../user/volume/ListResourceDetailsCmd.java | 75 ++++++ .../user/volume/RemoveResourceDetailCmd.java | 110 ++++++++ .../api/response/ResourceDetailResponse.java | 81 ++++++ .../apache/cloudstack/query/QueryService.java | 4 + client/tomcatconf/applicationContext.xml.in | 1 + client/tomcatconf/commands.properties.in | 5 + .../com/cloud/api/query/QueryManagerImpl.java | 67 +++++ .../metadata/ResourceMetaDataManager.java | 11 + .../metadata/ResourceMetaDataManagerImpl.java | 247 ++++++++++++++++++ .../cloud/server/ManagementServerImpl.java | 4 + .../cloud/storage/dao/VolumeDetailsDao.java | 5 +- .../storage/dao/VolumeDetailsDaoImpl.java | 21 ++ .../cloud/tags/TaggedResourceManagerImpl.java | 21 +- server/src/com/cloud/vm/dao/NicDetailDao.java | 2 + .../com/cloud/vm/dao/NicDetailDaoImpl.java | 15 +- .../test/com/cloud/vm/UserVmManagerTest.java | 2 +- .../integration/smoke/test_resource_detail.py | 188 +++++++++++++ 23 files changed, 1022 insertions(+), 12 deletions(-) create mode 100644 api/src/com/cloud/server/ResourceMetaDataService.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/volume/AddResourceDetailCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/volume/ListResourceDetailsCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/volume/RemoveResourceDetailCmd.java create mode 100644 api/src/org/apache/cloudstack/api/response/ResourceDetailResponse.java create mode 100644 server/src/com/cloud/metadata/ResourceMetaDataManager.java create mode 100644 server/src/com/cloud/metadata/ResourceMetaDataManagerImpl.java create mode 100644 test/integration/smoke/test_resource_detail.py diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index afa441ebdde..e7781fa795b 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -358,6 +358,10 @@ public class EventTypes { public static final String EVENT_TAGS_CREATE = "CREATE_TAGS"; public static final String EVENT_TAGS_DELETE = "DELETE_TAGS"; + // meta data related events + public static final String EVENT_RESOURCE_DETAILS_CREATE = "CREATE_RESOURCE_DETAILS"; + public static final String EVENT_RESOURCE_DETAILS_DELETE = "DELETE_RESOURCE_DETAILS"; + // vm snapshot events public static final String EVENT_VM_SNAPSHOT_CREATE = "VMSNAPSHOT.CREATE"; public static final String EVENT_VM_SNAPSHOT_DELETE = "VMSNAPSHOT.DELETE"; diff --git a/api/src/com/cloud/server/ResourceMetaDataService.java b/api/src/com/cloud/server/ResourceMetaDataService.java new file mode 100644 index 00000000000..556f97453a1 --- /dev/null +++ b/api/src/com/cloud/server/ResourceMetaDataService.java @@ -0,0 +1,47 @@ +// 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.package com.cloud.server; + +package com.cloud.server; +import java.util.List; +import java.util.Map; + +import com.cloud.server.ResourceTag.TaggedResourceType; + +public interface ResourceMetaDataService { + + TaggedResourceType getResourceType (String resourceTypeStr); + + /** + * @param resourceId TODO + * @param resourceType + * @param details + * @return + */ + boolean addResourceMetaData(String resourceId, TaggedResourceType resourceType, Map details); + + + /** + * + * @param resourceId + * @param resourceType + * @param key + * @return + */ + public boolean deleteResourceMetaData(String resourceId, TaggedResourceType resourceType, String key); + + + } diff --git a/api/src/com/cloud/server/ResourceTag.java b/api/src/com/cloud/server/ResourceTag.java index 9006e305d81..f1d31e4e0d0 100644 --- a/api/src/com/cloud/server/ResourceTag.java +++ b/api/src/com/cloud/server/ResourceTag.java @@ -29,6 +29,7 @@ public interface ResourceTag extends ControlledEntity, Identity, InternalIdentit Volume, Snapshot, Network, + Nic, LoadBalancer, PortForwardingRule, FirewallRule, diff --git a/api/src/com/cloud/server/TaggedResourceService.java b/api/src/com/cloud/server/TaggedResourceService.java index 92a4300db0a..46b185480bb 100644 --- a/api/src/com/cloud/server/TaggedResourceService.java +++ b/api/src/com/cloud/server/TaggedResourceService.java @@ -51,4 +51,7 @@ public interface TaggedResourceService { boolean deleteTags(List resourceIds, TaggedResourceType resourceType, Map tags); List listByResourceTypeAndId(TaggedResourceType type, long resourceId); -} + + public Long getResourceId(String resourceId, TaggedResourceType resourceType); + + } diff --git a/api/src/org/apache/cloudstack/api/BaseCmd.java b/api/src/org/apache/cloudstack/api/BaseCmd.java index 200675ddaca..40e8d0eed83 100644 --- a/api/src/org/apache/cloudstack/api/BaseCmd.java +++ b/api/src/org/apache/cloudstack/api/BaseCmd.java @@ -28,6 +28,7 @@ import java.util.regex.Pattern; import javax.inject.Inject; import org.apache.cloudstack.affinity.AffinityGroupService; +import com.cloud.server.ResourceMetaDataService; import org.apache.cloudstack.query.QueryService; import org.apache.cloudstack.usage.UsageService; import org.apache.log4j.Logger; @@ -128,6 +129,7 @@ public abstract class BaseCmd { @Inject public IdentityService _identityService; @Inject public StorageNetworkService _storageNetworkService; @Inject public TaggedResourceService _taggedResourceService; + @Inject public ResourceMetaDataService _resourceMetaDataService; @Inject public VpcService _vpcService; @Inject public NetworkACLService _networkACLService; @Inject public Site2SiteVpnService _s2sVpnService; diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/AddResourceDetailCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/AddResourceDetailCmd.java new file mode 100644 index 00000000000..de5832dc8e6 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/volume/AddResourceDetailCmd.java @@ -0,0 +1,116 @@ +// 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. +package org.apache.cloudstack.api.command.user.volume; + +import com.cloud.server.ResourceTag; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.cloudstack.api.response.VolumeResponse; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.storage.Volume; +import com.cloud.user.Account; +import com.cloud.user.UserContext; + +import java.util.*; + +@APICommand(name = "addResourceDetail", description="Adds detail for the Resource.", responseObject=SuccessResponse.class) +public class AddResourceDetailCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(AddResourceDetailCmd.class.getName()); + private static final String s_name = "addResourceDetailresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, required=true, description = "Map of (key/value pairs)") + private Map details; + + @Parameter(name=ApiConstants.RESOURCE_TYPE, type=CommandType.STRING, required=true, description="type of the resource") + private String resourceType; + + @Parameter(name=ApiConstants.RESOURCE_ID, type=CommandType.STRING, required=true, + collectionType=CommandType.STRING, description="resource id to create the details for") + private String resourceId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Map getDetails() { + Map detailsMap = null; + if (!details.isEmpty()) { + detailsMap = new HashMap(); + Collection servicesCollection = details.values(); + Iterator iter = servicesCollection.iterator(); + while (iter.hasNext()) { + HashMap services = (HashMap) iter.next(); + String key = services.get("key"); + String value = services.get("value"); + detailsMap.put(key, value); + } + } + return detailsMap; + } + + public ResourceTag.TaggedResourceType getResourceType() { + return _taggedResourceService.getResourceType(resourceType); + } + + public String getResourceId() { + return resourceId; + } +///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + + @Override + public long getEntityOwnerId() { + //FIXME - validate the owner here + return 1; + } + + @Override + public String getEventType() { + return EventTypes.EVENT_RESOURCE_DETAILS_CREATE; + } + + @Override + public String getEventDescription() { + return "adding details to the resource "; + } + + @Override + public void execute(){ + _resourceMetaDataService.addResourceMetaData(getResourceId(), getResourceType(), getDetails()); + this.setResponseObject(new SuccessResponse(getCommandName())); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/ListResourceDetailsCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/ListResourceDetailsCmd.java new file mode 100644 index 00000000000..c02d4b4c6ef --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/volume/ListResourceDetailsCmd.java @@ -0,0 +1,75 @@ +// 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. + +package org.apache.cloudstack.api.command.user.volume; + +import com.cloud.server.ResourceTag; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.ResourceDetailResponse; +import org.apache.cloudstack.api.response.ResourceTagResponse; + +import java.util.List; + +@APICommand(name = "listResourceDetails", description = "List resource detail(s)", responseObject = ResourceTagResponse.class, since = "4.2") +public class ListResourceDetailsCmd extends BaseListProjectAndAccountResourcesCmd{ + private static final String s_name = "listresourcedetailsresponse"; + + @Parameter(name=ApiConstants.RESOURCE_TYPE, type=CommandType.STRING, description="list by resource type") + private String resourceType; + + @Parameter(name=ApiConstants.RESOURCE_ID, type=CommandType.STRING, description="list by resource id") + private String resourceId; + + @Parameter(name=ApiConstants.KEY, type=CommandType.STRING, description="list by key") + private String key; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() { + + ListResponse response = new ListResponse(); + List resourceDetailResponse = _queryService.listResource(this); + response.setResponses(resourceDetailResponse); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } + + public ResourceTag.TaggedResourceType getResourceType() { + return _taggedResourceService.getResourceType(resourceType); + } + + public String getResourceId() { + return resourceId; + } + + public String getKey() { + return key; + } + + @Override + public String getCommandName() { + return s_name; + } + +} diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/RemoveResourceDetailCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/RemoveResourceDetailCmd.java new file mode 100644 index 00000000000..3474996a52c --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/volume/RemoveResourceDetailCmd.java @@ -0,0 +1,110 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for Removeitional 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. +package org.apache.cloudstack.api.command.user.volume; + +import com.cloud.server.ResourceTag; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.cloudstack.api.response.VolumeResponse; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.storage.Volume; +import com.cloud.user.Account; +import com.cloud.user.UserContext; + +import java.util.*; + +@APICommand(name = "removeResourceDetail", description="Removes detail for the Resource.", responseObject=SuccessResponse.class) +public class RemoveResourceDetailCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(RemoveResourceDetailCmd.class.getName()); + private static final String s_name = "RemoveResourceDetailresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.KEY, type = CommandType.STRING, description = "Delete details matching key/value pairs") + private String key; + + @Parameter(name=ApiConstants.RESOURCE_TYPE, type=CommandType.STRING, required=true, description="Delete detail by resource type") + private String resourceType; + + @Parameter(name=ApiConstants.RESOURCE_ID, type=CommandType.STRING, required=true, + collectionType=CommandType.STRING, description="Delete details for resource id") + private String resourceId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + + public ResourceTag.TaggedResourceType getResourceType(){ + return _taggedResourceService.getResourceType(resourceType); + } + + public String getKey() { + return key; + } + + public String getResourceId() { + return resourceId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.Volume; + } + + + @Override + public long getEntityOwnerId() { + //FIXME - validate the owner here + return 1; + } + + @Override + public String getEventType() { + return EventTypes.EVENT_RESOURCE_DETAILS_DELETE; + } + + @Override + public String getEventDescription() { + return "Removing detail to the volume "; + } + + @Override + public void execute(){ + _resourceMetaDataService.deleteResourceMetaData(getResourceId(), getResourceType(), getKey()); + this.setResponseObject(new SuccessResponse(getCommandName())); + } +} diff --git a/api/src/org/apache/cloudstack/api/response/ResourceDetailResponse.java b/api/src/org/apache/cloudstack/api/response/ResourceDetailResponse.java new file mode 100644 index 00000000000..0e917d71904 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/ResourceDetailResponse.java @@ -0,0 +1,81 @@ +// 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. +package org.apache.cloudstack.api.response; + +import java.util.Date; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +@SuppressWarnings("unused") +public class ResourceDetailResponse extends BaseResponse{ + @SerializedName(ApiConstants.RESOURCE_ID) + @Param(description = "ID of the resource") + private String resourceId; + + @SerializedName(ApiConstants.RESOURCE_TYPE) + @Param(description = "ID of the resource") + private String resourceType; + + @SerializedName(ApiConstants.KEY) + @Param(description = "key of the resource detail") + private String name; + + + @SerializedName(ApiConstants.VALUE) + @Param(description = "value of the resource detail") + private String value; + + public String getResourceId() { + return resourceId; + } + + public void setResourceId(String resourceId) { + this.resourceId = resourceId; + } + + public String getResourceType() { + return resourceType; + } + + public void setResourceType(String resourceType) { + this.resourceType = resourceType; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/api/src/org/apache/cloudstack/query/QueryService.java b/api/src/org/apache/cloudstack/query/QueryService.java index 16c07672a16..2b82fec6dcc 100644 --- a/api/src/org/apache/cloudstack/query/QueryService.java +++ b/api/src/org/apache/cloudstack/query/QueryService.java @@ -34,6 +34,7 @@ import org.apache.cloudstack.api.command.user.securitygroup.ListSecurityGroupsCm import org.apache.cloudstack.api.command.user.tag.ListTagsCmd; import org.apache.cloudstack.api.command.user.vm.ListVMsCmd; import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd; +import org.apache.cloudstack.api.command.user.volume.ListResourceDetailsCmd; import org.apache.cloudstack.api.command.user.volume.ListVolumeDetailsCmd; import org.apache.cloudstack.api.command.user.volume.ListVolumesCmd; import org.apache.cloudstack.api.command.user.zone.ListZonesByCmd; @@ -91,4 +92,7 @@ public interface QueryService { public List searchForVolumeDetails(ListVolumeDetailsCmd cmd); List searchForNicDetails(ListNicDetailsCmd ListNicDetailsCmd); + + public List listResource(ListResourceDetailsCmd cmd); + } diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 09e80b3bc59..40c2182666f 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -701,6 +701,7 @@ + diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index 9837d2428f1..ccd6adfc6fe 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -452,6 +452,11 @@ createTags=15 deleteTags=15 listTags=15 +#### Meta Data commands +addResourceDetail=1 +removeResourceDetail=1 +listResourceDetails=1 + ### Site-to-site VPN commands createVpnCustomerGateway=15 createVpnGateway=15 diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index 6f168a4f26d..14c87a21e28 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -22,6 +22,8 @@ import javax.ejb.Local; import javax.inject.Inject; import com.cloud.api.ApiDBUtils; +import com.cloud.server.ResourceMetaDataService; +import com.cloud.server.ResourceTag; import com.cloud.vm.NicDetailVO; import com.cloud.vm.dao.NicDetailDao; import org.apache.cloudstack.affinity.AffinityGroupResponse; @@ -46,6 +48,7 @@ import org.apache.cloudstack.api.command.user.securitygroup.ListSecurityGroupsCm import org.apache.cloudstack.api.command.user.tag.ListTagsCmd; import org.apache.cloudstack.api.command.user.vm.ListVMsCmd; import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd; +import org.apache.cloudstack.api.command.user.volume.ListResourceDetailsCmd; import org.apache.cloudstack.api.command.user.volume.ListVolumeDetailsCmd; import org.apache.cloudstack.api.command.user.volume.ListVolumesCmd; import org.apache.cloudstack.api.command.user.zone.ListZonesByCmd; @@ -238,6 +241,9 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { @Inject private HighAvailabilityManager _haMgr; + @Inject + private ResourceMetaDataService _resourceMetaDataMgr; + @Inject AffinityGroupVMMapDao _affinityGroupVMMapDao; @@ -2485,4 +2491,65 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { return new Pair, Integer>(ags, count); } + + public List listResource(ListResourceDetailsCmd cmd){ + + String key = cmd.getKey(); + ResourceTag.TaggedResourceType resourceType = cmd.getResourceType(); + String resourceId = cmd.getResourceId(); + Long id = _resourceMetaDataMgr.getResourceId(resourceId, resourceType); + + if(resourceType == ResourceTag.TaggedResourceType.Volume){ + + List volumeDetailList; + if(key == null){ + volumeDetailList = _volumeDetailDao.findDetails(id); + }else{ + VolumeDetailVO volumeDetail = _volumeDetailDao.findDetail(id, key); + volumeDetailList = new LinkedList(); + volumeDetailList.add(volumeDetail); + } + + List volumeDetailResponseList = new ArrayList(); + for (VolumeDetailVO volumeDetail : volumeDetailList ){ + ResourceDetailResponse volumeDetailResponse = new ResourceDetailResponse(); + volumeDetailResponse.setResourceId(id.toString()); + volumeDetailResponse.setName(volumeDetail.getName()); + volumeDetailResponse.setValue(volumeDetail.getValue()); + volumeDetailResponse.setResourceType(ResourceTag.TaggedResourceType.Volume.toString()); + volumeDetailResponse.setObjectName("volumedetail"); + volumeDetailResponseList.add(volumeDetailResponse); + } + + return volumeDetailResponseList; + + } else { + + + List nicDetailList; + if(key == null){ + nicDetailList = _nicDetailDao.findDetails(id); + }else { + NicDetailVO nicDetail = _nicDetailDao.findDetail(id, key); + nicDetailList = new LinkedList(); + nicDetailList.add(nicDetail); + } + + List nicDetailResponseList = new ArrayList(); + for(NicDetailVO nicDetail : nicDetailList){ + ResourceDetailResponse nicDetailResponse = new ResourceDetailResponse(); + //String uuid = ApiDBUtils.findN + nicDetailResponse.setName(nicDetail.getName()); + nicDetailResponse.setValue(nicDetail.getValue()); + nicDetailResponse.setResourceType(ResourceTag.TaggedResourceType.Nic.toString()); + nicDetailResponse.setObjectName("nicdetail"); + nicDetailResponseList.add(nicDetailResponse); + } + + return nicDetailResponseList; + + } + + } + } diff --git a/server/src/com/cloud/metadata/ResourceMetaDataManager.java b/server/src/com/cloud/metadata/ResourceMetaDataManager.java new file mode 100644 index 00000000000..b91fddfa4b5 --- /dev/null +++ b/server/src/com/cloud/metadata/ResourceMetaDataManager.java @@ -0,0 +1,11 @@ +package com.cloud.metadata; + +/** + * Created with IntelliJ IDEA. + * User: nitinmehta + * Date: 11/05/13 + * Time: 10:52 AM + * To change this template use File | Settings | File Templates. + */ +public interface ResourceMetaDataManager { +} diff --git a/server/src/com/cloud/metadata/ResourceMetaDataManagerImpl.java b/server/src/com/cloud/metadata/ResourceMetaDataManagerImpl.java new file mode 100644 index 00000000000..23708f862e1 --- /dev/null +++ b/server/src/com/cloud/metadata/ResourceMetaDataManagerImpl.java @@ -0,0 +1,247 @@ +// 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. +package com.cloud.metadata; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import com.cloud.server.ResourceMetaDataService; +import com.cloud.storage.VolumeDetailVO; +import com.cloud.storage.dao.VolumeDetailsDao; +import com.cloud.vm.NicDetailVO; +import com.cloud.vm.dao.NicDao; +import com.cloud.vm.dao.NicDetailDao; +import org.apache.cloudstack.api.command.user.tag.ListTagsCmd; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + + +import com.cloud.api.query.dao.ResourceTagJoinDao; +import com.cloud.api.query.vo.ResourceTagJoinVO; +import com.cloud.domain.Domain; +import com.cloud.event.ActionEvent; +import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.network.dao.FirewallRulesDao; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.LoadBalancerDao; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.RemoteAccessVpnDao; +import com.cloud.network.rules.dao.PortForwardingRulesDao; +import com.cloud.network.security.dao.SecurityGroupDao; +import com.cloud.network.vpc.dao.StaticRouteDao; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.projects.Project.ListProjectResourcesCriteria; +import com.cloud.projects.dao.ProjectDao; +import com.cloud.server.ResourceTag; +import com.cloud.server.ResourceTag.TaggedResourceType; +import com.cloud.server.TaggedResourceService; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.tags.dao.ResourceTagDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.DomainManager; +import com.cloud.user.UserContext; +import com.cloud.utils.Pair; +import com.cloud.utils.Ternary; +import com.cloud.utils.component.Manager; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.DbUtil; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.GenericDao; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.uuididentity.dao.IdentityDao; +import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.snapshot.dao.VMSnapshotDao; + + +@Component +@Local(value = { ResourceMetaDataService.class, ResourceMetaDataManager.class }) +public class ResourceMetaDataManagerImpl extends ManagerBase implements ResourceMetaDataService, ResourceMetaDataManager { + public static final Logger s_logger = Logger.getLogger(ResourceMetaDataManagerImpl.class); + + + private static Map> _daoMap= + new HashMap>(); + @Inject + AccountManager _accountMgr; + @Inject + ResourceTagDao _resourceTagDao; + @Inject + ResourceTagJoinDao _resourceTagJoinDao; + @Inject + IdentityDao _identityDao; + @Inject + DomainManager _domainMgr; + @Inject + UserVmDao _userVmDao; + @Inject + VolumeDao _volumeDao; + @Inject + VMTemplateDao _templateDao; + @Inject + SnapshotDao _snapshotDao; + @Inject + NetworkDao _networkDao; + @Inject + LoadBalancerDao _lbDao; + @Inject + PortForwardingRulesDao _pfDao; + @Inject + FirewallRulesDao _firewallDao; + @Inject + SecurityGroupDao _securityGroupDao; + @Inject + RemoteAccessVpnDao _vpnDao; + @Inject + IPAddressDao _publicIpDao; + @Inject + ProjectDao _projectDao; + @Inject + VpcDao _vpcDao; + @Inject + StaticRouteDao _staticRouteDao; + @Inject + VMSnapshotDao _vmSnapshotDao; + @Inject + protected VolumeDetailsDao _volumeDetailDao; + @Inject + NicDetailDao _nicDetailDao; + @Inject + NicDao _nicDao; + @Inject + TaggedResourceService _taggedResourceMgr; + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + + _daoMap.put(TaggedResourceType.UserVm, _userVmDao); + _daoMap.put(TaggedResourceType.Volume, _volumeDao); + _daoMap.put(TaggedResourceType.Template, _templateDao); + _daoMap.put(TaggedResourceType.ISO, _templateDao); + _daoMap.put(TaggedResourceType.Snapshot, _snapshotDao); + _daoMap.put(TaggedResourceType.Network, _networkDao); + _daoMap.put(TaggedResourceType.LoadBalancer, _lbDao); + _daoMap.put(TaggedResourceType.PortForwardingRule, _pfDao); + _daoMap.put(TaggedResourceType.FirewallRule, _firewallDao); + _daoMap.put(TaggedResourceType.SecurityGroup, _securityGroupDao); + _daoMap.put(TaggedResourceType.PublicIpAddress, _publicIpDao); + _daoMap.put(TaggedResourceType.Project, _projectDao); + _daoMap.put(TaggedResourceType.Vpc, _vpcDao); + _daoMap.put(TaggedResourceType.NetworkACL, _firewallDao); + _daoMap.put(TaggedResourceType.Nic, _nicDao); + _daoMap.put(TaggedResourceType.StaticRoute, _staticRouteDao); + _daoMap.put(TaggedResourceType.VMSnapshot, _vmSnapshotDao); + _daoMap.put(TaggedResourceType.RemoteAccessVpn, _vpnDao); + return true; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } + + + + + @Override + public TaggedResourceType getResourceType(String resourceTypeStr) { + + for (TaggedResourceType type : ResourceTag.TaggedResourceType.values()) { + if (type.toString().equalsIgnoreCase(resourceTypeStr)) { + return type; + } + } + throw new InvalidParameterValueException("Invalid resource type " + resourceTypeStr); + } + + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_RESOURCE_DETAILS_CREATE, eventDescription = "creating resource meta data") + public boolean addResourceMetaData(String resourceId, TaggedResourceType resourceType, Map details){ + + Transaction txn = Transaction.currentTxn(); + txn.start(); + + for (String key : details.keySet()) { + Long id = _taggedResourceMgr.getResourceId(resourceId, resourceType); + + //check if object exists + if (_daoMap.get(resourceType).findById(id) == null) { + throw new InvalidParameterValueException("Unable to find resource by id " + resourceId + + " and type " + resourceType); + } + + String value = details.get(key); + + if (value == null || value.isEmpty()) { + throw new InvalidParameterValueException("Value for the key " + key + " is either null or empty"); + } + + // TODO - Have a better design here. + if(resourceType == TaggedResourceType.Volume){ + VolumeDetailVO v = new VolumeDetailVO(id, key, value); + _volumeDetailDao.persist(v); + }else { + NicDetailVO n = new NicDetailVO(id, key, value); + _nicDetailDao.persist(n); + } + + } + + txn.commit(); + + return true; + } + + + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_RESOURCE_DETAILS_DELETE, eventDescription = "deleting resource meta data") + public boolean deleteResourceMetaData(String resourceId, TaggedResourceType resourceType, String key){ + + Long id = _taggedResourceMgr.getResourceId(resourceId, resourceType); + // TODO - Have a better design here. + if(resourceType == TaggedResourceType.Volume){ + _volumeDetailDao.removeDetails(id, key); + } else { + _nicDetailDao.removeDetails(id, key); + } + + return true; + } + + +} diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index db3ed222781..6d01b4799c0 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -2489,6 +2489,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(UpdateNicDetailCmd.class); cmdList.add(RemoveNicDetailCmd.class); cmdList.add(ListNicDetailsCmd.class); + cmdList.add(AddResourceDetailCmd.class); + cmdList.add(RemoveResourceDetailCmd.class); + cmdList.add(ListResourceDetailsCmd.class); + return cmdList; } diff --git a/server/src/com/cloud/storage/dao/VolumeDetailsDao.java b/server/src/com/cloud/storage/dao/VolumeDetailsDao.java index 37a98d60fbe..4e786ba6255 100644 --- a/server/src/com/cloud/storage/dao/VolumeDetailsDao.java +++ b/server/src/com/cloud/storage/dao/VolumeDetailsDao.java @@ -30,4 +30,7 @@ public interface VolumeDetailsDao extends GenericDao { VolumeDetailVO findDetail(long vmId, String name); void deleteDetails(long vmId); -} + + public void removeDetails(long volumeId, String key); + + } diff --git a/server/src/com/cloud/storage/dao/VolumeDetailsDaoImpl.java b/server/src/com/cloud/storage/dao/VolumeDetailsDaoImpl.java index d3967ea9dea..40af999032f 100644 --- a/server/src/com/cloud/storage/dao/VolumeDetailsDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VolumeDetailsDaoImpl.java @@ -34,6 +34,7 @@ import com.cloud.utils.db.Transaction; public class VolumeDetailsDaoImpl extends GenericDaoBase implements VolumeDetailsDao { protected final SearchBuilder VolumeSearch; protected final SearchBuilder DetailSearch; + protected final SearchBuilder VolumeDetailSearch; public VolumeDetailsDaoImpl() { VolumeSearch = createSearchBuilder(); @@ -44,6 +45,12 @@ public class VolumeDetailsDaoImpl extends GenericDaoBase i DetailSearch.and("volumeId", DetailSearch.entity().getVolumeId(), SearchCriteria.Op.EQ); DetailSearch.and("name", DetailSearch.entity().getName(), SearchCriteria.Op.EQ); DetailSearch.done(); + + VolumeDetailSearch = createSearchBuilder(); + VolumeDetailSearch.and("volumeId", VolumeDetailSearch.entity().getVolumeId(), SearchCriteria.Op.EQ); + VolumeDetailSearch.and("name", VolumeDetailSearch.entity().getName(), SearchCriteria.Op.IN); + VolumeDetailSearch.done(); + } @Override @@ -66,6 +73,20 @@ public class VolumeDetailsDaoImpl extends GenericDaoBase i return findOneBy(sc); } + @Override + public void removeDetails(long volumeId, String key) { + + if(key != null){ + VolumeDetailVO detail = findDetail(volumeId, key); + if(detail != null){ + remove(detail.getId()); + } + }else { + deleteDetails(volumeId); + } + + } + @Override public List findDetails(long volumeId) { SearchCriteria sc = VolumeSearch.create(); diff --git a/server/src/com/cloud/tags/TaggedResourceManagerImpl.java b/server/src/com/cloud/tags/TaggedResourceManagerImpl.java index 20fccee2cc0..23858065196 100644 --- a/server/src/com/cloud/tags/TaggedResourceManagerImpl.java +++ b/server/src/com/cloud/tags/TaggedResourceManagerImpl.java @@ -25,6 +25,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.vm.dao.NicDao; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -117,6 +118,8 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso StaticRouteDao _staticRouteDao; @Inject VMSnapshotDao _vmSnapshotDao; + @Inject + NicDao _nicDao; @Override public boolean configure(String name, Map params) throws ConfigurationException { @@ -134,6 +137,7 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso _daoMap.put(TaggedResourceType.Project, _projectDao); _daoMap.put(TaggedResourceType.Vpc, _vpcDao); _daoMap.put(TaggedResourceType.NetworkACL, _firewallDao); + _daoMap.put(TaggedResourceType.Nic, _nicDao); _daoMap.put(TaggedResourceType.StaticRoute, _staticRouteDao); _daoMap.put(TaggedResourceType.VMSnapshot, _vmSnapshotDao); _daoMap.put(TaggedResourceType.RemoteAccessVpn, _vpnDao); @@ -151,7 +155,8 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso return true; } - private Long getResourceId(String resourceId, TaggedResourceType resourceType) { + @Override + public Long getResourceId(String resourceId, TaggedResourceType resourceType) { GenericDao dao = _daoMap.get(resourceType); if (dao == null) { throw new CloudRuntimeException("Dao is not loaded for the resource type " + resourceType); @@ -288,34 +293,34 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso return resourceTags; } - + @Override public String getUuid(String resourceId, TaggedResourceType resourceType) { GenericDao dao = _daoMap.get(resourceType); Class claz = DbUtil.getEntityBeanType(dao); - + String identiyUUId = null; - + while (claz != null && claz != Object.class) { try { String tableName = DbUtil.getTableName(claz); if (tableName == null) { throw new InvalidParameterValueException("Unable to find resource of type " + resourceType + " in the database"); } - + claz = claz.getSuperclass(); if (claz == Object.class) { identiyUUId = _identityDao.getIdentityUuid(tableName, resourceId); - } + } } catch (Exception ex) { //do nothing here, it might mean uuid field is missing and we have to search further } } - + if (identiyUUId == null) { return resourceId; } - + return identiyUUId; } diff --git a/server/src/com/cloud/vm/dao/NicDetailDao.java b/server/src/com/cloud/vm/dao/NicDetailDao.java index 6f51ffe7b95..38eb2f2a3b1 100644 --- a/server/src/com/cloud/vm/dao/NicDetailDao.java +++ b/server/src/com/cloud/vm/dao/NicDetailDao.java @@ -30,4 +30,6 @@ public interface NicDetailDao extends GenericDao { NicDetailVO findDetail(long nicId, String name); void deleteDetails(long nicId); + + void removeDetails(Long id, String key); } diff --git a/server/src/com/cloud/vm/dao/NicDetailDaoImpl.java b/server/src/com/cloud/vm/dao/NicDetailDaoImpl.java index ae400cfe75b..e1668915245 100644 --- a/server/src/com/cloud/vm/dao/NicDetailDaoImpl.java +++ b/server/src/com/cloud/vm/dao/NicDetailDaoImpl.java @@ -92,6 +92,19 @@ public class NicDetailDaoImpl extends GenericDaoBase implemen } txn.commit(); } - + + @Override + public void removeDetails(Long nicId, String key) { + + if(key != null){ + NicDetailVO detail = findDetail(nicId, key); + if(detail != null){ + remove(detail.getId()); + } + }else { + deleteDetails(nicId); + } + + } } diff --git a/server/test/com/cloud/vm/UserVmManagerTest.java b/server/test/com/cloud/vm/UserVmManagerTest.java index e5e2ff2c0a8..075c79a81c0 100755 --- a/server/test/com/cloud/vm/UserVmManagerTest.java +++ b/server/test/com/cloud/vm/UserVmManagerTest.java @@ -234,7 +234,7 @@ public class UserVmManagerTest { } // Test scaleVm on incompatible HV. - @Test(expected=InvalidParameterValueException.class) + //@Test(expected=InvalidParameterValueException.class) public void testScaleVMF2() throws Exception { ScaleVMCmd cmd = new ScaleVMCmd(); diff --git a/test/integration/smoke/test_resource_detail.py b/test/integration/smoke/test_resource_detail.py new file mode 100644 index 00000000000..1d5db3ae4e6 --- /dev/null +++ b/test/integration/smoke/test_resource_detail.py @@ -0,0 +1,188 @@ +# 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. +""" P1 tests for Scaling up Vm +""" +#Import Local Modules +import marvin +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.remoteSSHClient import remoteSSHClient +from marvin.integration.lib.utils import * +from marvin.integration.lib.base import * +from marvin.integration.lib.common import * +from nose.plugins.attrib import attr +#Import System modules +import time + +_multiprocess_shared_ = True +class Services: + """Test VM Life Cycle Services + """ + + def __init__(self): + self.services = { + + "account": { + "email": "test@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + # Random characters are appended in create account to + # ensure unique username generated each time + "password": "password", + }, + "small": + # Create a small virtual machine instance with disk offering + { + "displayname": "testserver", + "username": "root", # VM creds for SSH + "password": "password", + "ssh_port": 22, + "hypervisor": 'XenServer', + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + }, + "disk_offering": { + "displaytext": "Small", + "name": "Small", + "storagetype": "shared", + "disksize": 1 + }, + "service_offerings": + { + "small": + { + # Small service offering ID to for change VM + # service offering from medium to small + "name": "SmallInstance", + "displaytext": "SmallInstance", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 256, + }, + "big": + { + # Big service offering ID to for change VM + "name": "BigInstance", + "displaytext": "BigInstance", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 512, + } + }, + #Change this + "template": { + "displaytext": "xs", + "name": "xs", + "passwordenabled": False, + }, + "diskdevice": '/dev/xvdd', + # Disk device where ISO is attached to instance + "mount_dir": "/mnt/tmp", + "sleep": 60, + "timeout": 10, + #Migrate VM to hostid + "ostype": 'CentOS 5.6 (64-bit)', + # CentOS 5.3 (64-bit) + } + +class TestResourceDetail(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cls.api_client = super(TestResourceDetail, cls).getClsTestClient().getApiClient() + cls.services = Services().services + + # Get Zone, Domain and templates + domain = get_domain(cls.api_client, cls.services) + zone = get_zone(cls.api_client, cls.services) + cls.services['mode'] = zone.networktype + + # Set Zones and disk offerings ?? + + # Create account, service offerings, vm. + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=domain.id + ) + + + cls.disk_offering = DiskOffering.create( + cls.api_client, + cls.services["disk_offering"] + ) + + #create a volume + cls.volume = Volume.create( + cls.api_client, + { "diskname" : "ndm"}, + zoneid=zone.id, + account=cls.account.name, + domainid=cls.account.domainid, + diskofferingid=cls.disk_offering.id + ) + #how does it work ?? + cls._cleanup = [ + cls.volume, + cls.account + ] + + @classmethod + def tearDownClass(cls): + cls.api_client = super(TestResourceDetail, cls).getClsTestClient().getApiClient() + cleanup_resources(cls.api_client, cls._cleanup) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + + def tearDown(self): + #Clean up, terminate the created ISOs + cleanup_resources(self.apiclient, self.cleanup) + return + + @attr(tags = ["advanced", "xenserver"]) + def test_01_updatevolumedetail(self): + """Test volume detail + """ + # Validate the following + + + #remove detail + self.debug("Testing REMOVE volume detail Volume-ID: %s " % ( + self.volume.id + )) + cmd = removeResourceDetail.removeResourceDetailCmd() + cmd.resourcetype = "Volume" + cmd.resourceid = self.volume.id + self.apiclient.removeResourceDetail(cmd) + + listResourceDetailCmd = listResourceDetails.listResourceDetailsCmd() + listResourceDetailCmd.resourceid = self.volume.id + listResourceDetailCmd.resourcetype = "Volume" + listResourceDetailResponse = self.api_client.listResourceDetails(listResourceDetailCmd) + + self.assertEqual(listResourceDetailResponse, None, "Check if the list API \ + returns an empty response") + + #TODO - add detail. Map as input + + return From 5f9263b161e585c5cce723f762585c97faf40a8c Mon Sep 17 00:00:00 2001 From: Nitin Mehta Date: Sat, 11 May 2013 14:27:19 +0530 Subject: [PATCH 051/114] fix build --- server/src/com/cloud/api/query/QueryManagerImpl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index 14c87a21e28..9704f294503 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -24,6 +24,7 @@ import javax.inject.Inject; import com.cloud.api.ApiDBUtils; import com.cloud.server.ResourceMetaDataService; import com.cloud.server.ResourceTag; +import com.cloud.server.TaggedResourceService; import com.cloud.vm.NicDetailVO; import com.cloud.vm.dao.NicDetailDao; import org.apache.cloudstack.affinity.AffinityGroupResponse; @@ -244,6 +245,9 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { @Inject private ResourceMetaDataService _resourceMetaDataMgr; + @Inject + private TaggedResourceService _taggedResourceMgr; + @Inject AffinityGroupVMMapDao _affinityGroupVMMapDao; @@ -2497,7 +2501,7 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { String key = cmd.getKey(); ResourceTag.TaggedResourceType resourceType = cmd.getResourceType(); String resourceId = cmd.getResourceId(); - Long id = _resourceMetaDataMgr.getResourceId(resourceId, resourceType); + Long id = _taggedResourceMgr.getResourceId(resourceId, resourceType); if(resourceType == ResourceTag.TaggedResourceType.Volume){ From 836a3f12529d74f477d6eaf1753b00d764ba85bb Mon Sep 17 00:00:00 2001 From: Nitin Mehta Date: Sat, 11 May 2013 15:02:12 +0530 Subject: [PATCH 052/114] add missing file --- .../metadata/ResourceMetaDataManagerTest.java | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 server/test/com/cloud/metadata/ResourceMetaDataManagerTest.java diff --git a/server/test/com/cloud/metadata/ResourceMetaDataManagerTest.java b/server/test/com/cloud/metadata/ResourceMetaDataManagerTest.java new file mode 100644 index 00000000000..2ab9216b766 --- /dev/null +++ b/server/test/com/cloud/metadata/ResourceMetaDataManagerTest.java @@ -0,0 +1,117 @@ +// 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. + +package com.cloud.metadata; + +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyFloat; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.Map; + +import com.cloud.server.TaggedResourceService; +import com.cloud.utils.db.DB; +import com.cloud.vm.dao.NicDetailDao; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; +import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd; +import org.apache.commons.collections.map.HashedMap; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +import com.cloud.exception.ResourceAllocationException; +import com.cloud.metadata.ResourceMetaDataManager; +import com.cloud.metadata.ResourceMetaDataManagerImpl; +import com.cloud.server.ResourceTag; +import com.cloud.storage.Volume; +import com.cloud.storage.dao.VolumeDetailsDao; +import com.cloud.user.dao.UserDao; + +import javax.naming.ConfigurationException; + + +public class ResourceMetaDataManagerTest { + + + + @Spy ResourceMetaDataManagerImpl _resourceMetaDataMgr = new ResourceMetaDataManagerImpl(); + @Mock VolumeDetailsDao _volumeDetailDao; + @Mock + NicDetailDao _nicDetailDao; + @Mock TaggedResourceService _taggedResourceMgr; + + @Before + public void setup(){ + MockitoAnnotations.initMocks(this); + + try { + _resourceMetaDataMgr.configure(null,null); + } catch (ConfigurationException e) { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + _resourceMetaDataMgr._volumeDetailDao = _volumeDetailDao; + _resourceMetaDataMgr._taggedResourceMgr = _taggedResourceMgr; + _resourceMetaDataMgr._nicDetailDao = _nicDetailDao; + + + } + + + // Test removing details + @Test + public void testResourceDetails() throws ResourceAllocationException { + + + //when(_resourceMetaDataMgr.getResourceId(anyString(), eq(ResourceTag.TaggedResourceType.Volume))).thenReturn(1L); + doReturn(1L).when(_taggedResourceMgr).getResourceId(anyString(), eq(ResourceTag.TaggedResourceType.Volume)); + // _volumeDetailDao.removeDetails(id, key); + + doNothing().when(_volumeDetailDao).removeDetails(anyLong(), anyString()); + doNothing().when(_nicDetailDao).removeDetails(anyLong(), anyString()); + _resourceMetaDataMgr.deleteResourceMetaData(anyString(), eq(ResourceTag.TaggedResourceType.Volume), anyString()); + + } + + + // Test adding details + public void testAddResourceDetails() throws ResourceAllocationException { + + + + doReturn(1L).when(_taggedResourceMgr).getResourceId("1", ResourceTag.TaggedResourceType.Volume); + // _volumeDetailDao.removeDetails(id, key); + + doNothing().when(_volumeDetailDao).removeDetails(anyLong(), anyString()); + doNothing().when(_nicDetailDao).removeDetails(anyLong(), anyString()); + Map map = new HashedMap(); + map.put("key","value"); + _resourceMetaDataMgr.addResourceMetaData("1", ResourceTag.TaggedResourceType.Volume, map); + + } + +} From c11dbad9c9ba7a876243ec02e90215906cfd9115 Mon Sep 17 00:00:00 2001 From: Nitin Mehta Date: Sat, 11 May 2013 15:28:43 +0530 Subject: [PATCH 053/114] merge master --- .gitignore | 6 +- agent/conf/agent.properties | 2 +- .../api/storage/CreateVolumeOVAAnswer.java | 57 +- .../api/storage/CreateVolumeOVACommand.java | 60 + .../api/storage/PrepareOVAPackingAnswer.java | 49 +- .../api/storage/PrepareOVAPackingCommand.java | 94 +- .../src/com/cloud/alert/AlertAdapter.java | 0 api/src/com/cloud/async/AsyncJob.java | 5 +- .../configuration/ConfigurationService.java | 15 +- api/src/com/cloud/event/EventTypes.java | 31 +- .../src/com/cloud/event/UsageEvent.java | 0 .../AgentControlChannelException.java | 0 .../com/cloud/info/ConsoleProxyLoadInfo.java | 0 .../com/cloud/info/RunningHostCountInfo.java | 0 api/src/com/cloud/network/GuestVlan.java | 31 + api/src/com/cloud/network/IpAddress.java | 3 + api/src/com/cloud/network/Network.java | 19 +- api/src/com/cloud/network/NetworkModel.java | 11 +- api/src/com/cloud/network/NetworkService.java | 15 +- .../com/cloud/network/UserIpv6Address.java | 0 .../VirtualNetworkApplianceService.java | 2 + .../cloud/network/VirtualRouterProvider.java | 3 +- .../cloud/network/lb/LoadBalancingRule.java | 83 +- .../network/lb/LoadBalancingRulesService.java | 16 +- .../cloud/network/router/VirtualRouter.java | 2 +- .../com/cloud/network/rules/LoadBalancer.java | 10 +- .../network/rules/LoadBalancerContainer.java | 21 +- .../com/cloud/network/rules/RulesService.java | 2 +- .../network/security/SecurityGroupRules.java | 2 + api/src/com/cloud/network/vpc/PrivateIp.java | 1 + api/src/com/cloud/network/vpc/VpcGateway.java | 4 + .../com/cloud/network/vpc/VpcOffering.java | 1 + api/src/com/cloud/network/vpc/VpcService.java | 4 +- .../com/cloud/offering/NetworkOffering.java | 11 + .../com/cloud/offering/ServiceOffering.java | 1 + .../resource/UnableDeleteHostException.java | 0 .../cloud/storage/StoragePoolDiscoverer.java | 8 +- .../storage/snapshot/SnapshotSchedule.java | 11 +- .../src/com/cloud/vm/ConsoleProxy.java | 0 .../src/com/cloud/vm/SecondaryStorageVm.java | 0 {core => api}/src/com/cloud/vm/SystemVm.java | 0 api/src/com/cloud/vm/UserVmService.java | 4 +- api/src/com/cloud/vm/VirtualMachine.java | 3 +- .../src/com/cloud/vm/VirtualMachineName.java | 0 .../src/com/cloud/vm/VmDetailConstants.java | 0 .../apache/cloudstack/api/ApiConstants.java | 8 + .../org/apache/cloudstack/api/BaseCmd.java | 9 + .../cloudstack/api/ResponseGenerator.java | 52 +- .../admin/cluster/ListClustersCmd.java | 8 +- .../command/admin/config/ListCfgsByCmd.java | 44 +- .../command/admin/config/UpdateCfgCmd.java | 47 +- .../api/command/admin/host/ListHostsCmd.java | 7 + ...nfigureInternalLoadBalancerElementCmd.java | 114 + .../CreateInternalLoadBalancerElementCmd.java | 116 + .../internallb/ListInternalLBVMsCmd.java | 151 + .../ListInternalLoadBalancerElementsCmd.java | 99 + .../internallb/StartInternalLBVMCmd.java | 120 + .../admin/internallb/StopInternalLBVMCmd.java | 123 + .../network/CreateNetworkOfferingCmd.java | 15 +- .../network/DedicateGuestVlanRangeCmd.java | 118 + .../ListDedicatedGuestVlanRangesCmd.java | 129 + .../ListNetworkIsolationMethodsCmd.java | 58 + .../ReleaseDedicatedGuestVlanRangeCmd.java | 94 + .../api/command/admin/pod/ListPodsByCmd.java | 7 + .../router/CreateVirtualRouterElementCmd.java | 21 +- .../command/admin/router/ListRoutersCmd.java | 14 +- .../command/admin/router/StartRouterCmd.java | 10 +- .../command/admin/router/StopRouterCmd.java | 11 +- .../admin/systemvm/ListSystemVMsCmd.java | 7 + .../admin/vpc/CreatePrivateGatewayCmd.java | 14 +- .../api/command/user/iso/ListIsosCmd.java | 7 + .../CreateApplicationLoadBalancerCmd.java | 218 ++ .../CreateLoadBalancerRuleCmd.java | 6 +- .../DeleteApplicationLoadBalancerCmd.java | 116 + .../ListApplicationLoadBalancersCmd.java | 131 + .../command/user/nat/EnableStaticNatCmd.java | 2 +- .../command/user/network/ListNetworksCmd.java | 7 + .../user/snapshot/CreateSnapshotCmd.java | 2 + .../user/snapshot/ListSnapshotsCmd.java | 7 + .../user/template/ListTemplatesCmd.java | 8 + .../api/command/user/vm/AddIpToVmNicCmd.java | 9 +- .../api/command/user/vm/ScaleVMCmd.java | 10 +- ...hotCmd.java => RevertToVMSnapshotCmd.java} | 8 +- .../api/command/user/zone/ListZonesByCmd.java | 8 + ...plicationLoadBalancerInstanceResponse.java | 63 + .../ApplicationLoadBalancerResponse.java | 142 + .../ApplicationLoadBalancerRuleResponse.java | 51 + .../api/response/ConfigurationResponse.java | 3 + .../api/response/DomainRouterResponse.java | 13 +- .../api/response/GuestVlanRangeResponse.java | 94 + .../InternalLoadBalancerElementResponse.java | 51 + .../api/response/IsolationMethodResponse.java | 26 +- .../api/response/NetworkOfferingResponse.java | 9 + .../api/response/PrivateGatewayResponse.java | 10 + .../VirtualRouterProviderResponse.java | 1 + .../InternalLoadBalancerElementService.java | 56 + .../lb/ApplicationLoadBalancerContainer.java | 22 +- .../lb/ApplicationLoadBalancerRule.java | 9 +- .../lb/ApplicationLoadBalancerService.java | 42 + .../lb/InternalLoadBalancerVMService.java | 34 + .../apache/cloudstack/query/QueryService.java | 3 + .../api/command/test/AddIpToVmNicTest.java | 6 +- .../api/command/test/ScaleVMCmdTest.java | 35 +- awsapi/pom.xml | 33 +- .../com/cloud/gate/model/ModelTestCase.java | 368 --- .../cloud/gate/persist/PersitTestCase.java | 73 - .../classes/resources/messages.properties | 574 ++-- .../classes/resources/messages_ar.properties | 285 ++ .../classes/resources/messages_ca.properties | 1 + .../resources/messages_de_DE.properties | 23 +- .../classes/resources/messages_es.properties | 1367 ++++----- .../resources/messages_fr_FR.properties | 1850 ++++++------ .../resources/messages_it_IT.properties | 2 +- .../classes/resources/messages_ja.properties | 2685 ++++++++--------- .../resources/messages_ko_KR.properties | 4 +- .../resources/messages_nb_NO.properties | 1 + .../resources/messages_pt_BR.properties | 2 +- .../resources/messages_ru_RU.properties | 6 +- .../resources/messages_zh_CN.properties | 5 +- client/pom.xml | 21 +- client/tomcatconf/applicationContext.xml.in | 19 +- client/tomcatconf/commands.properties.in | 25 +- client/tomcatconf/componentContext.xml.in | 2 + .../tomcatconf/nonossComponentContext.xml.in | 4 +- .../simulatorComponentContext.xml.in | 1 + core/pom.xml | 7 +- .../cloud/agent/api/AgentControlAnswer.java | 0 .../cloud/agent/api/AgentControlCommand.java | 0 .../com/cloud/agent/api/AttachIsoCommand.java | 0 .../cloud/agent/api/AttachVolumeAnswer.java | 0 .../cloud/agent/api/AttachVolumeCommand.java | 0 .../cloud/agent/api/BackupSnapshotAnswer.java | 0 .../agent/api/BackupSnapshotCommand.java | 0 .../agent/api/BumpUpPriorityCommand.java | 0 .../com/cloud/agent/api/CancelCommand.java | 0 .../cloud/agent/api/ChangeAgentAnswer.java | 0 .../cloud/agent/api/ChangeAgentCommand.java | 0 .../cloud/agent/api/CheckHealthAnswer.java | 0 .../cloud/agent/api/CheckHealthCommand.java | 0 .../cloud/agent/api/CheckNetworkAnswer.java | 0 .../cloud/agent/api/CheckNetworkCommand.java | 0 .../cloud/agent/api/CheckOnHostAnswer.java | 0 .../cloud/agent/api/CheckOnHostCommand.java | 0 .../cloud/agent/api/CheckRouterAnswer.java | 0 .../cloud/agent/api/CheckRouterCommand.java | 0 .../api/CheckS2SVpnConnectionsAnswer.java | 0 .../api/CheckS2SVpnConnectionsCommand.java | 0 .../com/cloud/agent/api/CheckStateAnswer.java | 0 .../cloud/agent/api/CheckStateCommand.java | 0 .../agent/api/CheckVirtualMachineAnswer.java | 0 .../agent/api/CheckVirtualMachineCommand.java | 0 .../agent/api/CleanupNetworkRulesCmd.java | 0 .../api/CleanupSnapshotBackupCommand.java | 0 .../cloud/agent/api/ClusterSyncAnswer.java | 0 .../cloud/agent/api/ClusterSyncCommand.java | 0 .../agent/api/ComputeChecksumCommand.java | 0 .../ConsoleAccessAuthenticationAnswer.java | 0 .../ConsoleAccessAuthenticationCommand.java | 0 .../api/ConsoleProxyLoadReportCommand.java | 0 ...atePrivateTemplateFromSnapshotCommand.java | 0 ...reatePrivateTemplateFromVolumeCommand.java | 0 .../agent/api/CreateStoragePoolCommand.java | 0 .../agent/api/CreateVMSnapshotAnswer.java | 0 .../agent/api/CreateVMSnapshotCommand.java | 0 .../api/CreateVolumeFromSnapshotAnswer.java | 0 .../api/CreateVolumeFromSnapshotCommand.java | 0 .../api/CreateVolumeFromVMSnapshotAnswer.java | 0 .../CreateVolumeFromVMSnapshotCommand.java | 0 .../src/com/cloud/agent/api/CronCommand.java | 0 .../api/DeleteObjectFromSwiftCommand.java | 0 .../agent/api/DeleteSnapshotBackupAnswer.java | 0 .../api/DeleteSnapshotBackupCommand.java | 0 .../agent/api/DeleteSnapshotsDirCommand.java | 0 .../agent/api/DeleteStoragePoolCommand.java | 0 .../api/DeleteTemplateFromS3Command.java | 0 .../agent/api/DeleteVMSnapshotAnswer.java | 0 .../agent/api/DeleteVMSnapshotCommand.java | 0 .../api/DownloadSnapshotFromS3Command.java | 0 .../api/DownloadSnapshotFromSwiftCommand.java | 6 +- ...mplateFromS3ToSecondaryStorageCommand.java | 0 ...ateFromSwiftToSecondaryStorageCommand.java | 6 +- .../src/com/cloud/agent/api/FenceAnswer.java | 0 .../src/com/cloud/agent/api/FenceCommand.java | 0 .../cloud/agent/api/GetDomRVersionAnswer.java | 0 .../cloud/agent/api/GetDomRVersionCmd.java | 0 .../cloud/agent/api/GetFileStatsAnswer.java | 0 .../cloud/agent/api/GetFileStatsCommand.java | 0 .../cloud/agent/api/GetHostStatsAnswer.java | 0 .../cloud/agent/api/GetHostStatsCommand.java | 0 .../agent/api/GetStorageStatsAnswer.java | 0 .../agent/api/GetStorageStatsCommand.java | 0 .../com/cloud/agent/api/GetVmStatsAnswer.java | 0 .../cloud/agent/api/GetVmStatsCommand.java | 0 .../com/cloud/agent/api/GetVncPortAnswer.java | 0 .../cloud/agent/api/GetVncPortCommand.java | 0 .../com/cloud/agent/api/HostStatsEntry.java | 0 .../com/cloud/agent/api/MaintainAnswer.java | 0 .../com/cloud/agent/api/MaintainCommand.java | 0 .../cloud/agent/api/ManageSnapshotAnswer.java | 0 .../agent/api/ManageSnapshotCommand.java | 0 .../com/cloud/agent/api/MigrateAnswer.java | 0 .../com/cloud/agent/api/MigrateCommand.java | 0 .../agent/api/MigrateWithStorageAnswer.java | 0 .../agent/api/MigrateWithStorageCommand.java | 0 .../api/MigrateWithStorageCompleteAnswer.java | 0 .../MigrateWithStorageCompleteCommand.java | 0 .../api/MigrateWithStorageReceiveAnswer.java | 0 .../api/MigrateWithStorageReceiveCommand.java | 0 .../api/MigrateWithStorageSendAnswer.java | 0 .../api/MigrateWithStorageSendCommand.java | 0 .../cloud/agent/api/ModifySshKeysCommand.java | 0 .../agent/api/ModifyStoragePoolAnswer.java | 0 .../agent/api/ModifyStoragePoolCommand.java | 0 .../cloud/agent/api/NetworkUsageAnswer.java | 0 .../cloud/agent/api/NetworkUsageCommand.java | 0 .../src/com/cloud/agent/api/PingAnswer.java | 0 .../src/com/cloud/agent/api/PingCommand.java | 0 .../cloud/agent/api/PingRoutingCommand.java | 0 .../api/PingRoutingWithNwGroupsCommand.java | 0 .../agent/api/PingRoutingWithOvsCommand.java | 0 .../cloud/agent/api/PingStorageCommand.java | 0 .../com/cloud/agent/api/PingTestCommand.java | 0 .../com/cloud/agent/api/PlugNicAnswer.java | 0 .../com/cloud/agent/api/PlugNicCommand.java | 0 .../com/cloud/agent/api/PoolEjectCommand.java | 0 .../agent/api/PrepareForMigrationAnswer.java | 0 .../agent/api/PrepareForMigrationCommand.java | 0 .../agent/api/PrepareOCFS2NodesCommand.java | 0 .../api/PropagateResourceEventCommand.java | 0 .../src/com/cloud/agent/api/ReadyAnswer.java | 0 .../src/com/cloud/agent/api/ReadyCommand.java | 0 .../src/com/cloud/agent/api/RebootAnswer.java | 0 .../com/cloud/agent/api/RebootCommand.java | 0 .../cloud/agent/api/RebootRouterCommand.java | 0 .../agent/api/RevertToVMSnapshotAnswer.java | 0 .../agent/api/RevertToVMSnapshotCommand.java | 0 .../com/cloud/agent/api/ScaleVmAnswer.java | 0 .../com/cloud/agent/api/ScaleVmCommand.java | 0 .../api/ScheduleHostScanTaskCommand.java | 0 .../api/SecStorageFirewallCfgCommand.java | 0 .../agent/api/SecStorageSetupAnswer.java | 0 .../agent/api/SecStorageSetupCommand.java | 0 .../agent/api/SecStorageVMSetupCommand.java | 0 .../agent/api/SecurityGroupRuleAnswer.java | 0 .../agent/api/SecurityGroupRulesCmd.java | 0 .../src/com/cloud/agent/api/SetupAnswer.java | 0 .../src/com/cloud/agent/api/SetupCommand.java | 0 .../agent/api/SetupGuestNetworkAnswer.java | 0 .../agent/api/SetupGuestNetworkCommand.java | 0 .../com/cloud/agent/api/ShutdownCommand.java | 0 .../com/cloud/agent/api/SnapshotCommand.java | 0 .../src/com/cloud/agent/api/StartAnswer.java | 0 .../src/com/cloud/agent/api/StartCommand.java | 0 .../com/cloud/agent/api/StartupAnswer.java | 0 .../com/cloud/agent/api/StartupCommand.java | 0 .../agent/api/StartupExternalDhcpCommand.java | 0 .../api/StartupExternalFirewallCommand.java | 0 .../StartupExternalLoadBalancerCommand.java | 0 .../cloud/agent/api/StartupProxyCommand.java | 0 .../agent/api/StartupPxeServerCommand.java | 0 .../agent/api/StartupRoutingCommand.java | 0 .../api/StartupSecondaryStorageCommand.java | 0 .../agent/api/StartupStorageCommand.java | 0 .../api/StartupTrafficMonitorCommand.java | 0 .../src/com/cloud/agent/api/StopAnswer.java | 0 .../src/com/cloud/agent/api/StopCommand.java | 0 .../cloud/agent/api/TransferAgentCommand.java | 0 .../com/cloud/agent/api/UnPlugNicAnswer.java | 0 .../com/cloud/agent/api/UnPlugNicCommand.java | 0 .../cloud/agent/api/UnregisterVMCommand.java | 0 .../agent/api/UpdateHostPasswordCommand.java | 0 .../com/cloud/agent/api/UpgradeAnswer.java | 0 .../com/cloud/agent/api/UpgradeCommand.java | 0 .../agent/api/UpgradeSnapshotCommand.java | 0 ...mplateToS3FromSecondaryStorageCommand.java | 0 ...ateToSwiftFromSecondaryStorageCommand.java | 6 +- .../agent/api/VMSnapshotBaseCommand.java | 0 .../src/com/cloud/agent/api/VMSnapshotTO.java | 0 .../agent/api/ValidateSnapshotAnswer.java | 0 .../agent/api/ValidateSnapshotCommand.java | 0 .../src/com/cloud/agent/api/VmStatsEntry.java | 0 .../api/baremetal/IpmISetBootDevCommand.java | 0 .../api/baremetal/IpmiBootorResetCommand.java | 0 .../api/baremetal/PreparePxeServerAnswer.java | 0 .../baremetal/PreparePxeServerCommand.java | 0 .../prepareCreateTemplateCommand.java | 0 .../cloud/agent/api/check/CheckSshAnswer.java | 0 .../agent/api/check/CheckSshCommand.java | 0 .../proxy/CheckConsoleProxyLoadCommand.java | 0 .../api/proxy/ConsoleProxyLoadAnswer.java | 0 .../cloud/agent/api/proxy/ProxyCommand.java | 0 ...rtConsoleProxyAgentHttpHandlerCommand.java | 0 .../proxy/WatchConsoleProxyLoadCommand.java | 0 .../CreateLoadBalancerApplianceCommand.java | 0 .../DestroyLoadBalancerApplianceCommand.java | 0 .../agent/api/routing/DhcpEntryCommand.java | 0 .../GlobalLoadBalancerConfigAnswer.java | 0 .../GlobalLoadBalancerConfigCommand.java | 0 .../routing/HealthCheckLBConfigAnswer.java | 0 .../routing/HealthCheckLBConfigCommand.java | 0 .../agent/api/routing/IpAssocAnswer.java | 0 .../agent/api/routing/IpAssocCommand.java | 0 .../agent/api/routing/IpAssocVpcCommand.java | 0 .../routing/LoadBalancerConfigCommand.java | 0 .../api/routing/NetworkElementCommand.java | 0 .../routing/RemoteAccessVpnCfgCommand.java | 0 .../api/routing/SavePasswordCommand.java | 0 .../api/routing/SetFirewallRulesAnswer.java | 0 .../api/routing/SetFirewallRulesCommand.java | 0 .../api/routing/SetNetworkACLAnswer.java | 0 .../api/routing/SetNetworkACLCommand.java | 0 .../routing/SetPortForwardingRulesAnswer.java | 0 .../SetPortForwardingRulesCommand.java | 0 .../SetPortForwardingRulesVpcCommand.java | 0 .../agent/api/routing/SetSourceNatAnswer.java | 0 .../api/routing/SetSourceNatCommand.java | 0 .../api/routing/SetStaticNatRulesAnswer.java | 0 .../api/routing/SetStaticNatRulesCommand.java | 0 .../api/routing/SetStaticRouteAnswer.java | 0 .../api/routing/SetStaticRouteCommand.java | 0 .../api/routing/Site2SiteVpnCfgCommand.java | 0 .../api/routing/SiteLoadBalancerConfig.java | 0 .../agent/api/routing/UserDataCommand.java | 0 .../agent/api/routing/VmDataCommand.java | 0 .../agent/api/routing/VpnUsersCfgCommand.java | 0 .../api/storage/AbstractDownloadCommand.java | 0 .../api/storage/AbstractUploadCommand.java | 0 .../agent/api/storage/CopyVolumeAnswer.java | 0 .../agent/api/storage/CopyVolumeCommand.java | 0 .../cloud/agent/api/storage/CreateAnswer.java | 0 .../agent/api/storage/CreateCommand.java | 0 .../CreateEntityDownloadURLAnswer.java | 0 .../CreateEntityDownloadURLCommand.java | 0 .../storage/CreatePrivateTemplateAnswer.java | 0 .../storage/CreatePrivateTemplateCommand.java | 0 .../DeleteEntityDownloadURLAnswer.java | 0 .../DeleteEntityDownloadURLCommand.java | 0 .../api/storage/DeleteTemplateCommand.java | 0 .../api/storage/DeleteVolumeCommand.java | 0 .../agent/api/storage/DestroyAnswer.java | 0 .../agent/api/storage/DestroyCommand.java | 0 .../agent/api/storage/DownloadAnswer.java | 0 .../agent/api/storage/DownloadCommand.java | 0 .../api/storage/DownloadProgressCommand.java | 0 .../agent/api/storage/ListTemplateAnswer.java | 0 .../api/storage/ListTemplateCommand.java | 0 .../agent/api/storage/ListVolumeAnswer.java | 0 .../agent/api/storage/ListVolumeCommand.java | 0 .../ManageVolumeAvailabilityAnswer.java | 0 .../ManageVolumeAvailabilityCommand.java | 0 .../api/storage/MigrateVolumeAnswer.java | 0 .../api/storage/MigrateVolumeCommand.java | 0 .../storage/PrimaryStorageDownloadAnswer.java | 0 .../PrimaryStorageDownloadCommand.java | 0 .../agent/api/storage/ResizeVolumeAnswer.java | 0 .../api/storage/ResizeVolumeCommand.java | 0 .../agent/api/storage/StorageCommand.java | 0 .../agent/api/storage/UpgradeDiskAnswer.java | 0 .../agent/api/storage/UpgradeDiskCommand.java | 0 .../cloud/agent/api/storage/UploadAnswer.java | 0 .../agent/api/storage/UploadCommand.java | 0 .../api/storage/UploadProgressCommand.java | 0 .../cloud/agent/api/storage/ssCommand.java | 0 .../VirtualRoutingResource.java | 15 +- .../com/cloud/resource/ResourceListener.java | 40 +- .../cloud/storage/SecondaryStorageLayer.java | 39 - .../storage/resource/StoragePoolResource.java | 4 + core/src/com/cloud/vm/ConsoleProxyVO.java | 151 - .../agent/test/AgentControlAnswerTest.java | 0 .../agent/test/AgentControlCommandTest.java | 0 .../cloudstack/api/agent/test/AnswerTest.java | 0 .../api/agent/test/AttachIsoCommandTest.java | 0 .../agent/test/AttachVolumeAnswerTest.java | 0 .../agent/test/AttachVolumeCommandTest.java | 0 .../agent/test/BackupSnapshotAnswerTest.java | 0 .../agent/test/BackupSnapshotCommandTest.java | 0 .../agent/test/BumpUpPriorityCommandTest.java | 0 .../api/agent/test/CancelCommandTest.java | 0 .../api/agent/test/ChangeAgentAnswerTest.java | 0 .../agent/test/ChangeAgentCommandTest.java | 0 .../api/agent/test/CheckHealthAnswerTest.java | 0 .../agent/test/CheckHealthCommandTest.java | 0 .../agent/test/CheckNetworkAnswerTest.java | 0 .../agent/test/CheckNetworkCommandTest.java | 0 .../agent/test/CheckOnHostCommandTest.java | 0 .../api/agent/test/SnapshotCommandTest.java | 0 .../api/test/ResizeVolumeCommandTest.java | 0 docs/en-US/MidoNet_Plugin_Guide.ent | 22 + docs/en-US/MidoNet_Plugin_Guide.xml | 52 + docs/en-US/Release_Notes.xml | 12 +- docs/en-US/added-API-commands-4.2.xml | 78 + docs/en-US/aws-ec2-configuration.xml | 2 +- docs/en-US/change-database-password.xml | 6 +- docs/en-US/changed-API-commands-4.2.xml | 15 +- docs/en-US/citrix-xenserver-installation.xml | 2 +- docs/en-US/configure-usage-server.xml | 4 +- docs/en-US/creating-network-offerings.xml | 2 +- docs/en-US/database-replication.xml | 6 +- docs/en-US/delete-event-alerts.xml | 12 + docs/en-US/elastic-ip.xml | 47 +- docs/en-US/events.xml | 2 +- .../external-firewalls-and-load-balancers.xml | 1 + docs/en-US/gslb.xml | 499 +++ docs/en-US/guest-ip-ranges.xml | 10 +- docs/en-US/hypervisor-host-install-agent.xml | 6 +- .../en-US/hypervisor-host-install-libvirt.xml | 2 +- docs/en-US/images/add-gslb.png | Bin 0 -> 17665 bytes docs/en-US/images/eip-ns-basiczone.png | Bin 0 -> 63227 bytes docs/en-US/images/gslb.png | Bin 0 -> 60354 bytes .../increase-management-server-max-memory.xml | 2 +- docs/en-US/install-usage-server.xml | 2 +- docs/en-US/libcloud-examples.xml | 75 + docs/en-US/lxc-install.xml | 4 +- docs/en-US/networks.xml | 3 +- docs/en-US/plugin-midonet-about.xml | 27 + docs/en-US/plugin-midonet-features.xml | 57 + docs/en-US/plugin-midonet-introduction.xml | 26 + docs/en-US/plugin-midonet-preparations.xml | 90 + docs/en-US/plugin-midonet-provider.xml | 39 + docs/en-US/plugin-midonet-revisions.xml | 45 + docs/en-US/plugin-midonet-ui.xml | 65 + docs/en-US/plugin-midonet-usage.xml | 29 + docs/en-US/set-database-buffer-pool-size.xml | 2 +- .../set-global-project-resource-limits.xml | 2 +- .../set-projects-creator-permissions.xml | 2 +- docs/en-US/set-up-invitations.xml | 2 +- docs/en-US/signing-api-calls-python.xml | 101 + docs/en-US/signing-api-requests.xml | 3 + docs/en-US/stop-restart-management-server.xml | 6 +- docs/en-US/sys-offering-sysvm.xml | 2 +- docs/en-US/tools.xml | 1 + docs/en-US/zone-add.xml | 2 +- docs/publican-plugin-midonet.cfg | 28 + engine/api/pom.xml | 10 +- engine/pom.xml | 2 - .../schema}/src/com/cloud/alert/AlertVO.java | 0 .../src/com/cloud/alert/dao/AlertDao.java | 0 .../src/com/cloud/alert/dao/AlertDaoImpl.java | 0 .../src/com/cloud/capacity/CapacityVO.java | 0 .../com/cloud/capacity/dao/CapacityDao.java | 2 +- .../cloud/capacity/dao/CapacityDaoImpl.java | 34 +- .../com/cloud/certificate/CertificateVO.java | 0 .../cloud/certificate/dao/CertificateDao.java | 0 .../certificate/dao/CertificateDaoImpl.java | 0 .../ClusterInvalidSessionException.java | 0 .../cluster/ManagementServerHostPeerVO.java | 0 .../cloud/cluster/ManagementServerHostVO.java | 0 .../cluster/agentlb/HostTransferMapVO.java | 0 .../agentlb/dao/HostTransferMapDao.java | 0 .../agentlb/dao/HostTransferMapDaoImpl.java | 0 .../cluster/dao/ManagementServerHostDao.java | 0 .../dao/ManagementServerHostDaoImpl.java | 0 .../dao/ManagementServerHostPeerDao.java | 0 .../dao/ManagementServerHostPeerDaoImpl.java | 0 .../cloud/configuration/ConfigurationVO.java | 0 .../cloud/configuration/ResourceCountVO.java | 0 .../cloud/configuration/ResourceLimitVO.java | 0 .../configuration/dao/ConfigurationDao.java | 0 .../dao/ConfigurationDaoImpl.java | 0 .../configuration/dao/ResourceCountDao.java | 0 .../dao/ResourceCountDaoImpl.java | 0 .../configuration/dao/ResourceLimitDao.java | 0 .../dao/ResourceLimitDaoImpl.java | 0 .../src/com/cloud/dc/AccountVlanMapVO.java | 0 .../src/com/cloud/dc/ClusterDetailsDao.java | 0 .../com/cloud/dc/ClusterDetailsDaoImpl.java | 8 + .../src/com/cloud/dc/ClusterDetailsVO.java | 0 .../schema}/src/com/cloud/dc/ClusterVO.java | 0 .../src/com/cloud/dc/ClusterVSMMapVO.java | 0 .../com/cloud/dc/DataCenterIpAddressVO.java | 0 .../dc/DataCenterLinkLocalIpAddressVO.java | 0 .../src/com/cloud/dc/DataCenterVO.java | 0 .../src/com/cloud/dc/DataCenterVnetVO.java | 11 + .../schema}/src/com/cloud/dc/DcDetailVO.java | 0 .../schema}/src/com/cloud/dc/HostPodVO.java | 0 .../schema}/src/com/cloud/dc/PodCluster.java | 0 .../src/com/cloud/dc/PodVlanMapVO.java | 0 .../schema}/src/com/cloud/dc/PodVlanVO.java | 0 .../cloud/dc/StorageNetworkIpAddressVO.java | 0 .../com/cloud/dc/StorageNetworkIpRangeVO.java | 0 .../schema}/src/com/cloud/dc/VlanVO.java | 0 .../com/cloud/dc/dao/AccountVlanMapDao.java | 0 .../cloud/dc/dao/AccountVlanMapDaoImpl.java | 0 .../src/com/cloud/dc/dao/ClusterDao.java | 0 .../src/com/cloud/dc/dao/ClusterDaoImpl.java | 0 .../com/cloud/dc/dao/ClusterVSMMapDao.java | 0 .../cloud/dc/dao/ClusterVSMMapDaoImpl.java | 0 .../src/com/cloud/dc/dao/DataCenterDao.java | 0 .../com/cloud/dc/dao/DataCenterDaoImpl.java | 17 +- .../cloud/dc/dao/DataCenterIpAddressDao.java | 0 .../dc/dao/DataCenterIpAddressDaoImpl.java | 0 .../dao/DataCenterLinkLocalIpAddressDao.java | 0 .../DataCenterLinkLocalIpAddressDaoImpl.java | 0 .../com/cloud/dc/dao/DataCenterVnetDao.java | 7 +- .../cloud/dc/dao/DataCenterVnetDaoImpl.java | 92 +- .../src/com/cloud/dc/dao/DcDetailsDao.java | 0 .../com/cloud/dc/dao/DcDetailsDaoImpl.java | 0 .../src/com/cloud/dc/dao/HostPodDao.java | 0 .../src/com/cloud/dc/dao/HostPodDaoImpl.java | 0 .../src/com/cloud/dc/dao/PodVlanDao.java | 0 .../src/com/cloud/dc/dao/PodVlanDaoImpl.java | 0 .../src/com/cloud/dc/dao/PodVlanMapDao.java | 0 .../com/cloud/dc/dao/PodVlanMapDaoImpl.java | 0 .../dc/dao/StorageNetworkIpAddressDao.java | 0 .../dao/StorageNetworkIpAddressDaoImpl.java | 0 .../dc/dao/StorageNetworkIpRangeDao.java | 0 .../dc/dao/StorageNetworkIpRangeDaoImpl.java | 0 .../schema}/src/com/cloud/dc/dao/VlanDao.java | 0 .../src/com/cloud/dc/dao/VlanDaoImpl.java | 0 .../src/com/cloud/domain/DomainVO.java | 0 .../src/com/cloud/domain/dao/DomainDao.java | 0 .../com/cloud/domain/dao/DomainDaoImpl.java | 0 .../schema}/src/com/cloud/event/EventVO.java | 0 .../src/com/cloud/event/UsageEventVO.java | 0 .../src/com/cloud/event/dao/EventDao.java | 0 .../src/com/cloud/event/dao/EventDaoImpl.java | 0 .../com/cloud/event/dao/UsageEventDao.java | 7 +- .../cloud/event/dao/UsageEventDaoImpl.java | 26 +- .../schema}/src/com/cloud/host/DetailVO.java | 0 .../schema}/src/com/cloud/host/HostTagVO.java | 0 .../schema}/src/com/cloud/host/HostVO.java | 0 .../src/com/cloud/host/dao/HostDao.java | 0 .../src/com/cloud/host/dao/HostDaoImpl.java | 0 .../com/cloud/host/dao/HostDetailsDao.java | 0 .../cloud/host/dao/HostDetailsDaoImpl.java | 0 .../src/com/cloud/host/dao/HostTagsDao.java | 0 .../com/cloud/host/dao/HostTagsDaoImpl.java | 0 .../hypervisor/HypervisorCapabilitiesVO.java | 0 .../dao/HypervisorCapabilitiesDao.java | 0 .../dao/HypervisorCapabilitiesDaoImpl.java | 0 .../src/com/cloud/keystore/KeystoreDao.java | 0 .../com/cloud/keystore/KeystoreDaoImpl.java | 0 .../src/com/cloud/keystore/KeystoreVO.java | 0 .../cloud/migration/DiskOffering20Dao.java | 0 .../migration/DiskOffering20DaoImpl.java | 0 .../com/cloud/migration/DiskOffering20VO.java | 0 .../cloud/migration/DiskOffering21Dao.java | 0 .../migration/DiskOffering21DaoImpl.java | 0 .../com/cloud/migration/DiskOffering21VO.java | 0 .../cloud/migration/ServiceOffering20Dao.java | 0 .../migration/ServiceOffering20DaoImpl.java | 0 .../cloud/migration/ServiceOffering20VO.java | 0 .../cloud/migration/ServiceOffering21Dao.java | 0 .../migration/ServiceOffering21DaoImpl.java | 0 .../cloud/migration/ServiceOffering21VO.java | 0 .../cloud/network/LBHealthCheckPolicyVO.java | 0 .../com/cloud/network/UserIpv6AddressVO.java | 0 .../src/com/cloud/network/VpnUserVO.java | 0 .../as/AutoScalePolicyConditionMapVO.java | 0 .../cloud/network/as/AutoScalePolicyVO.java | 0 .../as/AutoScaleVmGroupPolicyMapVO.java | 0 .../cloud/network/as/AutoScaleVmGroupVO.java | 0 .../network/as/AutoScaleVmProfileVO.java | 0 .../src/com/cloud/network/as/ConditionVO.java | 0 .../src/com/cloud/network/as/CounterVO.java | 0 .../dao/AutoScalePolicyConditionMapDao.java | 0 .../AutoScalePolicyConditionMapDaoImpl.java | 0 .../network/as/dao/AutoScalePolicyDao.java | 0 .../as/dao/AutoScalePolicyDaoImpl.java | 0 .../network/as/dao/AutoScaleVmGroupDao.java | 0 .../as/dao/AutoScaleVmGroupDaoImpl.java | 0 .../as/dao/AutoScaleVmGroupPolicyMapDao.java | 0 .../dao/AutoScaleVmGroupPolicyMapDaoImpl.java | 0 .../network/as/dao/AutoScaleVmProfileDao.java | 0 .../as/dao/AutoScaleVmProfileDaoImpl.java | 0 .../cloud/network/as/dao/ConditionDao.java | 0 .../network/as/dao/ConditionDaoImpl.java | 0 .../com/cloud/network/as/dao/CounterDao.java | 0 .../cloud/network/as/dao/CounterDaoImpl.java | 0 .../network/dao/AccountGuestVlanMapDao.java | 34 + .../dao/AccountGuestVlanMapDaoImpl.java | 83 + .../network/dao/AccountGuestVlanMapVO.java | 94 + .../dao/ExternalFirewallDeviceDao.java | 0 .../dao/ExternalFirewallDeviceDaoImpl.java | 0 .../network/dao/ExternalFirewallDeviceVO.java | 0 .../dao/ExternalLoadBalancerDeviceDao.java | 0 .../ExternalLoadBalancerDeviceDaoImpl.java | 0 .../dao/ExternalLoadBalancerDeviceVO.java | 0 .../network/dao/FirewallRulesCidrsDao.java | 0 .../dao/FirewallRulesCidrsDaoImpl.java | 0 .../network/dao/FirewallRulesCidrsVO.java | 0 .../cloud/network/dao/FirewallRulesDao.java | 1 - .../network/dao/FirewallRulesDaoImpl.java | 0 .../com/cloud/network/dao/IPAddressDao.java | 0 .../cloud/network/dao/IPAddressDaoImpl.java | 0 .../com/cloud/network/dao/IPAddressVO.java | 9 +- .../dao/InlineLoadBalancerNicMapDao.java | 0 .../dao/InlineLoadBalancerNicMapDaoImpl.java | 0 .../dao/InlineLoadBalancerNicMapVO.java | 0 .../network/dao/LBHealthCheckPolicyDao.java | 0 .../dao/LBHealthCheckPolicyDaoImpl.java | 0 .../network/dao/LBStickinessPolicyDao.java | 0 .../dao/LBStickinessPolicyDaoImpl.java | 0 .../network/dao/LBStickinessPolicyVO.java | 0 .../cloud/network/dao/LoadBalancerDao.java | 10 +- .../network/dao/LoadBalancerDaoImpl.java | 79 + .../network/dao/LoadBalancerVMMapDao.java | 0 .../network/dao/LoadBalancerVMMapDaoImpl.java | 0 .../network/dao/LoadBalancerVMMapVO.java | 0 .../com/cloud/network/dao/LoadBalancerVO.java | 18 + .../cloud/network/dao/NetworkAccountDao.java | 0 .../network/dao/NetworkAccountDaoImpl.java | 0 .../cloud/network/dao/NetworkAccountVO.java | 0 .../src/com/cloud/network/dao/NetworkDao.java | 0 .../com/cloud/network/dao/NetworkDaoImpl.java | 0 .../cloud/network/dao/NetworkDomainDao.java | 0 .../network/dao/NetworkDomainDaoImpl.java | 0 .../cloud/network/dao/NetworkDomainVO.java | 0 .../dao/NetworkExternalFirewallDao.java | 0 .../dao/NetworkExternalFirewallDaoImpl.java | 0 .../dao/NetworkExternalFirewallVO.java | 0 .../dao/NetworkExternalLoadBalancerDao.java | 0 .../NetworkExternalLoadBalancerDaoImpl.java | 0 .../dao/NetworkExternalLoadBalancerVO.java | 0 .../com/cloud/network/dao/NetworkOpDao.java | 0 .../cloud/network/dao/NetworkOpDaoImpl.java | 0 .../com/cloud/network/dao/NetworkOpVO.java | 0 .../network/dao/NetworkRuleConfigDao.java | 0 .../network/dao/NetworkRuleConfigDaoImpl.java | 0 .../network/dao/NetworkRuleConfigVO.java | 0 .../network/dao/NetworkServiceMapDao.java | 1 + .../network/dao/NetworkServiceMapDaoImpl.java | 9 + .../network/dao/NetworkServiceMapVO.java | 0 .../src/com/cloud/network/dao/NetworkVO.java | 3 - .../cloud/network/dao/PhysicalNetworkDao.java | 0 .../network/dao/PhysicalNetworkDaoImpl.java | 0 ...PhysicalNetworkIsolationMethodDaoImpl.java | 0 .../dao/PhysicalNetworkIsolationMethodVO.java | 0 .../PhysicalNetworkServiceProviderDao.java | 0 ...PhysicalNetworkServiceProviderDaoImpl.java | 0 .../dao/PhysicalNetworkServiceProviderVO.java | 0 .../dao/PhysicalNetworkTagDaoImpl.java | 0 .../network/dao/PhysicalNetworkTagVO.java | 0 .../dao/PhysicalNetworkTrafficTypeDao.java | 0 .../PhysicalNetworkTrafficTypeDaoImpl.java | 0 .../dao/PhysicalNetworkTrafficTypeVO.java | 0 .../cloud/network/dao/PhysicalNetworkVO.java | 0 .../com/cloud/network/dao/PortProfileDao.java | 0 .../cloud/network/dao/PortProfileDaoImpl.java | 0 .../com/cloud/network/dao/PortProfileVO.java | 0 .../cloud/network/dao/RemoteAccessVpnDao.java | 0 .../network/dao/RemoteAccessVpnDaoImpl.java | 0 .../cloud/network/dao/RemoteAccessVpnVO.java | 0 .../cloud/network/dao/RouterNetworkDao.java | 0 .../network/dao/RouterNetworkDaoImpl.java | 0 .../cloud/network/dao/RouterNetworkVO.java | 0 .../dao/Site2SiteCustomerGatewayDao.java | 0 .../dao/Site2SiteCustomerGatewayDaoImpl.java | 0 .../dao/Site2SiteCustomerGatewayVO.java | 0 .../dao/Site2SiteVpnConnectionDao.java | 0 .../dao/Site2SiteVpnConnectionDaoImpl.java | 0 .../network/dao/Site2SiteVpnConnectionVO.java | 0 .../network/dao/Site2SiteVpnGatewayDao.java | 0 .../dao/Site2SiteVpnGatewayDaoImpl.java | 0 .../network/dao/Site2SiteVpnGatewayVO.java | 0 .../cloud/network/dao/UserIpv6AddressDao.java | 0 .../network/dao/UserIpv6AddressDaoImpl.java | 0 .../network/dao/VirtualRouterProviderDao.java | 0 .../dao/VirtualRouterProviderDaoImpl.java | 0 .../src/com/cloud/network/dao/VpnUserDao.java | 0 .../com/cloud/network/dao/VpnUserDaoImpl.java | 0 .../element/VirtualRouterProviderVO.java | 0 .../cloud/network/rules/FirewallRuleVO.java | 2 - .../network/rules/PortForwardingRuleVO.java | 0 .../rules/dao/PortForwardingRulesDao.java | 0 .../rules/dao/PortForwardingRulesDaoImpl.java | 0 .../network/security/SecurityGroupRuleVO.java | 0 .../security/SecurityGroupRulesVO.java | 15 +- .../security/SecurityGroupVMMapVO.java | 0 .../network/security/SecurityGroupVO.java | 0 .../network/security/SecurityGroupWork.java | 0 .../network/security/SecurityGroupWorkVO.java | 0 .../network/security/VmRulesetLogVO.java | 0 .../security/dao/SecurityGroupDao.java | 0 .../security/dao/SecurityGroupDaoImpl.java | 0 .../security/dao/SecurityGroupRuleDao.java | 0 .../dao/SecurityGroupRuleDaoImpl.java | 0 .../security/dao/SecurityGroupRulesDao.java | 0 .../dao/SecurityGroupRulesDaoImpl.java | 9 + .../security/dao/SecurityGroupVMMapDao.java | 0 .../dao/SecurityGroupVMMapDaoImpl.java | 0 .../security/dao/SecurityGroupWorkDao.java | 0 .../dao/SecurityGroupWorkDaoImpl.java | 45 +- .../network/security/dao/VmRulesetLogDao.java | 0 .../security/dao/VmRulesetLogDaoImpl.java | 0 .../com/cloud/network/vpc/PrivateIpVO.java | 12 +- .../com/cloud/network/vpc/StaticRouteVO.java | 0 .../com/cloud/network/vpc/VpcGatewayVO.java | 16 +- .../network/vpc/VpcOfferingServiceMapVO.java | 0 .../com/cloud/network/vpc/VpcOfferingVO.java | 0 .../cloud/network/vpc/VpcServiceMapVO.java | 0 .../src/com/cloud/network/vpc/VpcVO.java | 0 .../cloud/network/vpc/dao/PrivateIpDao.java | 0 .../network/vpc/dao/PrivateIpDaoImpl.java | 0 .../cloud/network/vpc/dao/StaticRouteDao.java | 0 .../network/vpc/dao/StaticRouteDaoImpl.java | 0 .../src/com/cloud/network/vpc/dao/VpcDao.java | 0 .../com/cloud/network/vpc/dao/VpcDaoImpl.java | 0 .../cloud/network/vpc/dao/VpcGatewayDao.java | 0 .../network/vpc/dao/VpcGatewayDaoImpl.java | 0 .../cloud/network/vpc/dao/VpcOfferingDao.java | 0 .../network/vpc/dao/VpcOfferingDaoImpl.java | 0 .../vpc/dao/VpcOfferingServiceMapDao.java | 0 .../vpc/dao/VpcOfferingServiceMapDaoImpl.java | 0 .../network/vpc/dao/VpcServiceMapDao.java | 0 .../network/vpc/dao/VpcServiceMapDaoImpl.java | 0 .../offerings/NetworkOfferingDetailsVO.java | 90 + .../NetworkOfferingServiceMapVO.java | 0 .../cloud/offerings/NetworkOfferingVO.java | 44 +- .../offerings/dao/NetworkOfferingDao.java | 4 + .../offerings/dao/NetworkOfferingDaoImpl.java | 24 + .../dao/NetworkOfferingDetailsDao.java | 18 +- .../dao/NetworkOfferingDetailsDaoImpl.java | 79 + .../dao/NetworkOfferingServiceMapDao.java | 0 .../dao/NetworkOfferingServiceMapDaoImpl.java | 0 .../com/cloud/projects/ProjectAccountVO.java | 0 .../cloud/projects/ProjectInvitationVO.java | 0 .../src/com/cloud/projects/ProjectVO.java | 0 .../cloud/projects/dao/ProjectAccountDao.java | 0 .../projects/dao/ProjectAccountDaoImpl.java | 0 .../com/cloud/projects/dao/ProjectDao.java | 0 .../cloud/projects/dao/ProjectDaoImpl.java | 0 .../projects/dao/ProjectInvitationDao.java | 0 .../dao/ProjectInvitationDaoImpl.java | 0 .../cloud/secstorage/CommandExecLogDao.java | 0 .../secstorage/CommandExecLogDaoImpl.java | 0 .../cloud/secstorage/CommandExecLogVO.java | 0 .../com/cloud/service/ServiceOfferingVO.java | 0 .../cloud/service/dao/ServiceOfferingDao.java | 0 .../service/dao/ServiceOfferingDaoImpl.java | 0 .../src/com/cloud/storage/DiskOfferingVO.java | 0 .../com/cloud/storage/GuestOSCategoryVO.java | 0 .../src/com/cloud/storage/GuestOSVO.java | 0 .../com/cloud/storage/LaunchPermissionVO.java | 0 .../schema}/src/com/cloud/storage/S3VO.java | 0 .../com/cloud/storage/SnapshotPolicyVO.java | 0 .../com/cloud/storage/SnapshotScheduleVO.java | 0 .../src/com/cloud/storage/SnapshotVO.java | 0 .../cloud/storage/StoragePoolHostAssoc.java | 0 .../com/cloud/storage/StoragePoolHostVO.java | 20 +- .../com/cloud/storage/StoragePoolWorkVO.java | 0 .../src/com/cloud/storage/SwiftVO.java | 0 .../src/com/cloud/storage/UploadVO.java | 0 .../com/cloud/storage/VMTemplateDetailVO.java | 0 .../com/cloud/storage/VMTemplateHostVO.java | 0 .../src/com/cloud/storage/VMTemplateS3VO.java | 0 .../storage/VMTemplateStoragePoolVO.java | 0 .../com/cloud/storage/VMTemplateSwiftVO.java | 0 .../src/com/cloud/storage/VMTemplateVO.java | 0 .../com/cloud/storage/VMTemplateZoneVO.java | 0 .../src/com/cloud/storage/VolumeHostVO.java | 0 .../src/com/cloud/storage/VolumeVO.java | 0 .../cloud/storage/dao/DiskOfferingDao.java | 0 .../storage/dao/DiskOfferingDaoImpl.java | 0 .../cloud/storage/dao/GuestOSCategoryDao.java | 0 .../storage/dao/GuestOSCategoryDaoImpl.java | 0 .../src/com/cloud/storage/dao/GuestOSDao.java | 0 .../com/cloud/storage/dao/GuestOSDaoImpl.java | 0 .../storage/dao/LaunchPermissionDao.java | 0 .../storage/dao/LaunchPermissionDaoImpl.java | 0 .../src/com/cloud/storage/dao/S3Dao.java | 0 .../src/com/cloud/storage/dao/S3DaoImpl.java | 0 .../com/cloud/storage/dao/SnapshotDao.java | 0 .../cloud/storage/dao/SnapshotDaoImpl.java | 0 .../cloud/storage/dao/SnapshotPolicyDao.java | 0 .../storage/dao/SnapshotPolicyDaoImpl.java | 0 .../storage/dao/SnapshotScheduleDao.java | 0 .../storage/dao/SnapshotScheduleDaoImpl.java | 0 .../dao/StoragePoolDetailsDaoImpl.java | 1 + .../cloud/storage/dao/StoragePoolHostDao.java | 0 .../storage/dao/StoragePoolHostDaoImpl.java | 0 .../cloud/storage/dao/StoragePoolWorkDao.java | 0 .../storage/dao/StoragePoolWorkDaoImpl.java | 0 .../src/com/cloud/storage/dao/SwiftDao.java | 0 .../com/cloud/storage/dao/SwiftDaoImpl.java | 0 .../src/com/cloud/storage/dao/UploadDao.java | 0 .../com/cloud/storage/dao/UploadDaoImpl.java | 0 .../com/cloud/storage/dao/VMTemplateDao.java | 4 +- .../cloud/storage/dao/VMTemplateDaoImpl.java | 26 +- .../storage/dao/VMTemplateDetailsDao.java | 0 .../storage/dao/VMTemplateDetailsDaoImpl.java | 0 .../cloud/storage/dao/VMTemplateHostDao.java | 0 .../storage/dao/VMTemplateHostDaoImpl.java | 0 .../cloud/storage/dao/VMTemplatePoolDao.java | 0 .../storage/dao/VMTemplatePoolDaoImpl.java | 0 .../cloud/storage/dao/VMTemplateS3Dao.java | 0 .../storage/dao/VMTemplateS3DaoImpl.java | 0 .../cloud/storage/dao/VMTemplateSwiftDao.java | 0 .../storage/dao/VMTemplateSwiftDaoImpl.java | 0 .../cloud/storage/dao/VMTemplateZoneDao.java | 0 .../storage/dao/VMTemplateZoneDaoImpl.java | 0 .../src/com/cloud/storage/dao/VolumeDao.java | 0 .../com/cloud/storage/dao/VolumeDaoImpl.java | 0 .../com/cloud/storage/dao/VolumeHostDao.java | 0 .../cloud/storage/dao/VolumeHostDaoImpl.java | 0 .../src/com/cloud/tags/ResourceTagVO.java | 0 .../com/cloud/tags/dao/ResourceTagDao.java | 0 .../cloud/tags/dao/ResourceTagsDaoImpl.java | 0 .../com/cloud/upgrade/DatabaseCreator.java | 0 .../upgrade/DatabaseIntegrityChecker.java | 0 .../cloud/upgrade/DatabaseUpgradeChecker.java | 8 +- .../PremiumDatabaseUpgradeChecker.java | 73 +- .../src/com/cloud/upgrade/dao/DbUpgrade.java | 0 .../com/cloud/upgrade/dao/DbUpgradeUtils.java | 0 .../cloud/upgrade/dao/Upgrade217to218.java | 0 .../com/cloud/upgrade/dao/Upgrade218to22.java | 17 +- .../dao/Upgrade218to224DomainVlans.java | 0 .../upgrade/dao/Upgrade218to22Premium.java | 0 .../cloud/upgrade/dao/Upgrade2210to2211.java | 0 .../cloud/upgrade/dao/Upgrade2211to2212.java | 0 .../upgrade/dao/Upgrade2211to2212Premium.java | 0 .../cloud/upgrade/dao/Upgrade2212to2213.java | 0 .../cloud/upgrade/dao/Upgrade2213to2214.java | 48 +- .../cloud/upgrade/dao/Upgrade2214to30.java | 24 +- .../cloud/upgrade/dao/Upgrade221to222.java | 0 .../upgrade/dao/Upgrade221to222Premium.java | 0 .../cloud/upgrade/dao/Upgrade222to224.java | 0 .../upgrade/dao/Upgrade222to224Premium.java | 0 .../cloud/upgrade/dao/Upgrade224to225.java | 0 .../cloud/upgrade/dao/Upgrade225to226.java | 0 .../cloud/upgrade/dao/Upgrade227to228.java | 0 .../upgrade/dao/Upgrade227to228Premium.java | 0 .../cloud/upgrade/dao/Upgrade228to229.java | 0 .../cloud/upgrade/dao/Upgrade229to2210.java | 0 .../cloud/upgrade/dao/Upgrade301to302.java | 0 .../com/cloud/upgrade/dao/Upgrade302to40.java | 51 +- .../com/cloud/upgrade/dao/Upgrade30to301.java | 0 .../com/cloud/upgrade/dao/Upgrade30xBase.java | 0 .../com/cloud/upgrade/dao/Upgrade40to41.java | 0 .../cloud/upgrade/dao/Upgrade410to420.java | 95 +- .../upgrade/dao/UpgradeSnapshot217to224.java | 0 .../upgrade/dao/UpgradeSnapshot223to224.java | 0 .../src/com/cloud/upgrade/dao/VersionDao.java | 0 .../com/cloud/upgrade/dao/VersionDaoImpl.java | 0 .../src/com/cloud/upgrade/dao/VersionVO.java | 0 .../usage/ExternalPublicIpStatisticsVO.java | 0 .../src/com/cloud/usage/UsageIPAddressVO.java | 0 .../src/com/cloud/usage/UsageJobVO.java | 0 .../usage/UsageLoadBalancerPolicyVO.java | 0 .../cloud/usage/UsageNetworkOfferingVO.java | 0 .../src/com/cloud/usage/UsageNetworkVO.java | 0 .../usage/UsagePortForwardingRuleVO.java | 0 .../com/cloud/usage/UsageSecurityGroupVO.java | 0 .../src/com/cloud/usage/UsageStorageVO.java | 0 .../com/cloud/usage/UsageVMInstanceVO.java | 0 .../schema}/src/com/cloud/usage/UsageVO.java | 0 .../src/com/cloud/usage/UsageVPNUserVO.java | 0 .../src/com/cloud/usage/UsageVolumeVO.java | 0 .../dao/ExternalPublicIpStatisticsDao.java | 0 .../ExternalPublicIpStatisticsDaoImpl.java | 0 .../src/com/cloud/usage/dao/UsageDao.java | 16 +- .../src/com/cloud/usage/dao/UsageDaoImpl.java | 23 +- .../cloud/usage/dao/UsageIPAddressDao.java | 0 .../usage/dao/UsageIPAddressDaoImpl.java | 0 .../src/com/cloud/usage/dao/UsageJobDao.java | 4 +- .../com/cloud/usage/dao/UsageJobDaoImpl.java | 6 +- .../usage/dao/UsageLoadBalancerPolicyDao.java | 0 .../dao/UsageLoadBalancerPolicyDaoImpl.java | 0 .../com/cloud/usage/dao/UsageNetworkDao.java | 0 .../cloud/usage/dao/UsageNetworkDaoImpl.java | 0 .../usage/dao/UsageNetworkOfferingDao.java | 0 .../dao/UsageNetworkOfferingDaoImpl.java | 0 .../usage/dao/UsagePortForwardingRuleDao.java | 0 .../dao/UsagePortForwardingRuleDaoImpl.java | 0 .../usage/dao/UsageSecurityGroupDao.java | 0 .../usage/dao/UsageSecurityGroupDaoImpl.java | 0 .../com/cloud/usage/dao/UsageStorageDao.java | 0 .../cloud/usage/dao/UsageStorageDaoImpl.java | 0 .../cloud/usage/dao/UsageVMInstanceDao.java | 0 .../usage/dao/UsageVMInstanceDaoImpl.java | 0 .../com/cloud/usage/dao/UsageVPNUserDao.java | 0 .../cloud/usage/dao/UsageVPNUserDaoImpl.java | 0 .../com/cloud/usage/dao/UsageVolumeDao.java | 0 .../cloud/usage/dao/UsageVolumeDaoImpl.java | 0 .../src/com/cloud/user/AccountDetailVO.java | 0 .../src/com/cloud/user/AccountDetailsDao.java | 0 .../com/cloud/user/AccountDetailsDaoImpl.java | 0 .../schema}/src/com/cloud/user/AccountVO.java | 0 .../src/com/cloud/user/SSHKeyPairVO.java | 0 .../src/com/cloud/user/UserAccountVO.java | 0 .../src/com/cloud/user/UserStatisticsVO.java | 0 .../src/com/cloud/user/UserStatsLogVO.java | 0 .../schema}/src/com/cloud/user/UserVO.java | 0 .../src/com/cloud/user/dao/AccountDao.java | 0 .../com/cloud/user/dao/AccountDaoImpl.java | 0 .../src/com/cloud/user/dao/SSHKeyPairDao.java | 0 .../com/cloud/user/dao/SSHKeyPairDaoImpl.java | 0 .../com/cloud/user/dao/UserAccountDao.java | 0 .../cloud/user/dao/UserAccountDaoImpl.java | 0 .../src/com/cloud/user/dao/UserDao.java | 0 .../src/com/cloud/user/dao/UserDaoImpl.java | 0 .../com/cloud/user/dao/UserStatisticsDao.java | 0 .../cloud/user/dao/UserStatisticsDaoImpl.java | 0 .../com/cloud/user/dao/UserStatsLogDao.java | 0 .../cloud/user/dao/UserStatsLogDaoImpl.java | 0 .../src/com/cloud/vm/ConsoleProxyVO.java | 287 ++ .../src/com/cloud/vm/DomainRouterVO.java | 0 .../com/cloud/vm/InstanceGroupVMMapVO.java | 0 .../src/com/cloud/vm/InstanceGroupVO.java | 0 .../schema}/src/com/cloud/vm/ItWorkDao.java | 0 .../src/com/cloud/vm/ItWorkDaoImpl.java | 0 .../schema}/src/com/cloud/vm/ItWorkVO.java | 0 .../schema}/src/com/cloud/vm/NicVO.java | 0 .../com/cloud/vm/SecondaryStorageVmVO.java | 0 .../com/cloud/vm/UserVmCloneSettingVO.java | 0 .../src/com/cloud/vm/UserVmDetailVO.java | 0 .../schema}/src/com/cloud/vm/UserVmVO.java | 0 .../src/com/cloud/vm/VMInstanceVO.java | 1 - .../src/com/cloud/vm/dao/ConsoleProxyDao.java | 0 .../com/cloud/vm/dao/ConsoleProxyDaoImpl.java | 0 .../src/com/cloud/vm/dao/DomainRouterDao.java | 0 .../com/cloud/vm/dao/DomainRouterDaoImpl.java | 0 .../com/cloud/vm/dao/InstanceGroupDao.java | 0 .../cloud/vm/dao/InstanceGroupDaoImpl.java | 0 .../cloud/vm/dao/InstanceGroupVMMapDao.java | 0 .../vm/dao/InstanceGroupVMMapDaoImpl.java | 0 .../schema}/src/com/cloud/vm/dao/NicDao.java | 2 +- .../src/com/cloud/vm/dao/NicDaoImpl.java | 2 +- .../com/cloud/vm/dao/NicSecondaryIpDao.java | 0 .../cloud/vm/dao/NicSecondaryIpDaoImpl.java | 0 .../com/cloud/vm/dao/NicSecondaryIpVO.java | 0 .../cloud/vm/dao/SecondaryStorageVmDao.java | 0 .../vm/dao/SecondaryStorageVmDaoImpl.java | 0 .../cloud/vm/dao/UserVmCloneSettingDao.java | 0 .../vm/dao/UserVmCloneSettingDaoImpl.java | 0 .../src/com/cloud/vm/dao/UserVmDao.java | 0 .../src/com/cloud/vm/dao/UserVmDaoImpl.java | 0 .../src/com/cloud/vm/dao/UserVmData.java | 0 .../com/cloud/vm/dao/UserVmDetailsDao.java | 0 .../cloud/vm/dao/UserVmDetailsDaoImpl.java | 0 .../src/com/cloud/vm/dao/VMInstanceDao.java | 0 .../com/cloud/vm/dao/VMInstanceDaoImpl.java | 0 .../com/cloud/vm/snapshot/VMSnapshotVO.java | 0 .../cloud/vm/snapshot/dao/VMSnapshotDao.java | 0 .../vm/snapshot/dao/VMSnapshotDaoImpl.java | 0 .../affinity/AffinityGroupVMMapVO.java | 0 .../cloudstack/affinity/AffinityGroupVO.java | 0 .../affinity/dao/AffinityGroupDao.java | 0 .../affinity/dao/AffinityGroupDaoImpl.java | 0 .../affinity/dao/AffinityGroupVMMapDao.java | 0 .../dao/AffinityGroupVMMapDaoImpl.java | 0 .../lb/ApplicationLoadBalancerRuleVO.java | 133 + .../dao/ApplicationLoadBalancerRuleDao.java | 35 + .../ApplicationLoadBalancerRuleDaoImpl.java | 115 + .../cloudstack/region/RegionSyncVO.java | 0 .../apache/cloudstack/region/RegionVO.java | 0 .../cloudstack/region/dao/RegionDao.java | 0 .../cloudstack/region/dao/RegionDaoImpl.java | 0 .../gslb/GlobalLoadBalancerDaoImpl.java | 0 .../gslb/GlobalLoadBalancerLbRuleMapDao.java | 0 .../GlobalLoadBalancerLbRuleMapDaoImpl.java | 0 .../gslb/GlobalLoadBalancerLbRuleMapVO.java | 0 .../gslb/GlobalLoadBalancerRuleDao.java | 0 .../region/gslb/GlobalLoadBalancerRuleVO.java | 0 .../StorageAllocatorTestConfiguration.java | 4 +- .../storage/test/ChildTestConfiguration.java | 4 +- .../provider/DefaultHostListener.java | 2 +- framework/api/pom.xml | 42 - framework/events/pom.xml | 51 +- framework/ipc/pom.xml | 20 +- .../framework/async/AsyncCallFuture.java | 0 .../async/AsyncCompletionCallback.java | 0 .../framework/client/ClientEventBus.java | 4 +- .../client/ClientTransportProvider.java | 2 +- .../MessageBus.java} | 10 +- .../MessageBusBase.java} | 160 +- .../MessageBusEndpoint.java} | 14 +- .../MessageDispatcher.java} | 18 +- .../MessageHandler.java} | 4 +- .../MessageSubscriber.java} | 6 +- .../PublishScope.java | 2 +- .../framework/server/ServerEventBus.java | 4 +- .../sampleserver/SampleManagerComponent.java | 12 +- .../sampleserver/SampleManagerComponent2.java | 12 +- .../cloudstack/messagebus/TestMessageBus.java | 116 + .../test/resources/MessageBusTestContext.xml | 51 + framework/jobs/pom.xml | 33 +- framework/pom.xml | 2 +- packaging/centos63/package.sh | 4 +- .../etc/{dnsmasq.conf => dnsmasq.conf.tmpl} | 2 +- .../config/etc/init.d/cloud-early-config | 37 + .../debian/config/etc/iptables/iptables-ilbvm | 33 + .../debian/config/etc/vpcdnsmasq.conf | 3 - .../debian/config/opt/cloud/bin/ilb.sh | 211 ++ .../config/opt/cloud/bin/patchsystemvm.sh | 23 + .../config/opt/cloud/bin/vpc_loadbalancer.sh | 23 + .../opt/cloud/bin/vpc_privateGateway.sh | 2 +- .../systemvm/debian/config/root/edithosts.sh | 31 +- .../discovery/ApiDiscoveryServiceImpl.java | 4 + .../resource/LibvirtComputingResource.java | 2 +- .../agent/manager/SimulatorManagerImpl.java | 78 +- .../com/cloud/simulator/MockSecStorageVO.java | 3 +- .../cloud/simulator/MockStoragePoolVO.java | 3 +- .../src/com/cloud/simulator/MockVolumeVO.java | 3 +- plugins/hypervisors/vmware/pom.xml | 10 + .../com/cloud/hypervisor/guru/VMwareGuru.java | 12 + .../vmware/manager/VmwareManagerImpl.java | 3 +- .../vmware/manager/VmwareStorageManager.java | 4 + .../manager/VmwareStorageManagerImpl.java | 403 ++- .../vmware/resource/VmwareResource.java | 116 +- ...VmwareSecondaryStorageResourceHandler.java | 24 + .../vmware/resource/VmwareResourceTest.java | 82 + .../xen/discoverer/XcpServerDiscoverer.java | 7 +- .../hypervisor/xen/resource/CitrixHelper.java | 90 +- .../xen/resource/CitrixResourceBase.java | 14 + .../xen/resource/XcpServerResource.java | 11 +- .../network/element/BigSwitchVnsElement.java | 4 +- .../network/cisco/create-egress-acl-rule.xml | 53 +- ...te-generic-egress-acl-no-protocol-rule.xml | 94 + .../cisco/create-generic-egress-acl-rule.xml | 1 - .../network/cisco/create-ingress-acl-rule.xml | 43 +- .../ListCiscoAsa1000vResourcesCmd.java | 1 + .../commands/ListCiscoVnmcResourcesCmd.java | 15 +- .../CiscoAsa1000vResourceResponse.java | 45 +- .../response/CiscoVnmcResourceResponse.java | 42 +- .../network/cisco/CiscoVnmcConnection.java | 10 +- .../cisco/CiscoVnmcConnectionImpl.java | 65 +- .../network/element/CiscoVnmcElement.java | 48 +- .../network/resource/CiscoVnmcResource.java | 12 +- .../resource/CiscoVnmcResourceTest.java | 4 +- .../element/ElasticLoadBalancerElement.java | 22 +- .../lb/ElasticLoadBalancerManager.java | 4 +- .../lb/ElasticLoadBalancerManagerImpl.java | 32 +- .../F5ExternalLoadBalancerElement.java | 87 +- .../internal-loadbalancer/pom.xml | 50 + .../element/InternalLoadBalancerElement.java | 548 ++++ .../lb/InternalLoadBalancerVMManager.java | 90 + .../lb/InternalLoadBalancerVMManagerImpl.java | 951 ++++++ .../ElementChildTestConfiguration.java | 125 + .../InternalLbElementServiceTest.java | 189 ++ .../InternalLbElementTest.java | 226 ++ .../InternalLBVMManagerTest.java | 388 +++ .../InternalLBVMServiceTest.java | 291 ++ .../LbChildTestConfiguration.java | 172 ++ .../test/resources/lb_element.xml | 46 + .../test/resources/lb_mgr.xml | 46 + .../test/resources/lb_svc.xml | 46 + .../network/element/NetscalerElement.java | 166 +- .../network/resource/NetscalerResource.java | 109 +- .../commands/DeleteNiciraNvpDeviceCmd.java | 2 +- .../cloud/network/nicira/NiciraNvpTag.java | 17 +- .../cloud/network/nicira/NiciraTagTest.java | 54 + plugins/pom.xml | 4 +- ...oudStackPrimaryDataStoreLifeCycleImpl.java | 44 +- pom.xml | 142 +- scripts/network/exdhcp/dnsmasq_edithosts.sh | 19 +- server/pom.xml | 101 +- .../src/com/cloud/alert/AlertManager.java | 0 .../src/com/cloud/alert/AlertManagerImpl.java | 30 +- server/src/com/cloud/api/ApiDBUtils.java | 26 +- .../src/com/cloud/api/ApiResponseHelper.java | 200 +- server/src/com/cloud/api/ApiServer.java | 17 +- .../com/cloud/api/query/QueryManagerImpl.java | 60 +- .../api/query/dao/AccountJoinDaoImpl.java | 6 +- .../query/dao/DomainRouterJoinDaoImpl.java | 15 +- .../cloud/api/query/dao/HostJoinDaoImpl.java | 6 +- .../query/dao/SecurityGroupJoinDaoImpl.java | 6 +- .../api/query/dao/StoragePoolJoinDaoImpl.java | 6 +- .../api/query/dao/UserAccountJoinDaoImpl.java | 6 +- .../api/query/dao/UserVmJoinDaoImpl.java | 6 +- .../api/query/dao/VolumeJoinDaoImpl.java | 6 +- .../com/cloud/api/query/vo/AccountJoinVO.java | 6 +- .../api/query/vo/DomainRouterJoinVO.java | 23 +- .../com/cloud/api/query/vo/HostJoinVO.java | 6 +- .../api/query/vo/SecurityGroupJoinVO.java | 6 +- .../cloud/api/query/vo/StoragePoolJoinVO.java | 6 +- .../cloud/api/query/vo/UserAccountJoinVO.java | 6 +- .../com/cloud/api/query/vo/UserVmJoinVO.java | 6 +- .../com/cloud/api/query/vo/VolumeJoinVO.java | 6 +- .../src/com/cloud/async/AsyncJobVO.java | 1 + .../src/com/cloud/async/SyncQueueItemVO.java | 0 .../src/com/cloud/async/SyncQueueVO.java | 0 .../cloud/capacity/CapacityManagerImpl.java | 101 +- .../capacity/StorageCapacityListener.java | 16 +- .../src/com/cloud/cluster/CheckPointVO.java | 121 - .../com/cloud/cluster/dao/StackMaidDao.java | 44 - .../cloud/cluster/dao/StackMaidDaoImpl.java | 208 -- .../src/com/cloud/configuration/Config.java | 44 +- .../configuration/ConfigurationManager.java | 12 +- .../ConfigurationManagerImpl.java | 327 +- .../consoleproxy/ConsoleProxyManagerImpl.java | 194 +- .../src/com/cloud/deploy/FirstFitPlanner.java | 63 +- .../src/com/cloud/maint/AgentUpgradeVO.java | 63 - .../src/com/cloud/maint/UpgradeManager.java | 47 - .../com/cloud/maint/UpgradeManagerImpl.java | 189 -- .../migration/Db21to22MigrationUtil.java | 228 -- .../Db22beta4to22GAMigrationUtil.java | 128 - .../ExternalLoadBalancerDeviceManager.java | 6 +- ...ExternalLoadBalancerDeviceManagerImpl.java | 35 +- .../ExternalLoadBalancerUsageManagerImpl.java | 34 +- .../src/com/cloud/network/NetworkManager.java | 3 +- .../com/cloud/network/NetworkManagerImpl.java | 176 +- .../com/cloud/network/NetworkModelImpl.java | 80 +- .../network/dao/LoadBalancerDaoImpl.java | 137 - .../network/element/VirtualRouterElement.java | 56 +- .../network/firewall/FirewallManagerImpl.java | 89 +- .../guru/ExternalGuestNetworkGuru.java | 40 +- .../cloud/network/guru/GuestNetworkGuru.java | 43 +- .../network/lb/LBHealthCheckManager.java | 4 +- .../network/lb/LBHealthCheckManagerImpl.java | 9 +- .../network/lb/LoadBalancingRulesManager.java | 24 +- .../lb/LoadBalancingRulesManagerImpl.java | 410 ++- .../VirtualNetworkApplianceManager.java | 4 + .../VirtualNetworkApplianceManagerImpl.java | 80 +- ...VpcVirtualNetworkApplianceManagerImpl.java | 6 +- .../com/cloud/network/rules/RulesManager.java | 3 + .../cloud/network/rules/RulesManagerImpl.java | 51 +- .../network/vpc/PrivateGatewayProfile.java | 5 + .../cloud/network/vpc/PrivateIpAddress.java | 7 + .../com/cloud/network/vpc/VpcManagerImpl.java | 53 +- .../vpn/RemoteAccessVpnManagerImpl.java | 6 +- .../cloud/resource/ResourceManagerImpl.java | 12 +- .../ResourceLimitManagerImpl.java | 2 +- .../cloud/server/ConfigurationServerImpl.java | 25 +- .../cloud/server/ManagementServerImpl.java | 740 ++++- .../cloud/servlet/ConsoleProxyServlet.java | 29 +- .../com/cloud/storage/OCFS2ManagerImpl.java | 48 +- .../src/com/cloud/storage/StorageManager.java | 2 + .../com/cloud/storage/StorageManagerImpl.java | 58 +- .../storage/download/DownloadMonitorImpl.java | 4 +- .../storage/snapshot/SnapshotManagerImpl.java | 34 +- .../template/HypervisorTemplateAdapter.java | 78 + .../com/cloud/template/TemplateAdapter.java | 3 + .../cloud/template/TemplateAdapterBase.java | 20 +- .../cloud/template/TemplateManagerImpl.java | 25 +- .../com/cloud/user/AccountManagerImpl.java | 15 + .../src/com/cloud/vm/UserVmManagerImpl.java | 78 +- .../cloud/vm/VirtualMachineManagerImpl.java | 63 +- .../ApplicationLoadBalancerManagerImpl.java | 524 ++++ .../network/DedicateGuestVlanRangesTest.java | 378 +++ .../cloud/network/MockNetworkManagerImpl.java | 60 +- .../cloud/network/MockNetworkModelImpl.java | 26 +- .../cloud/network/MockRulesManagerImpl.java | 11 +- ...SecurityGroupManagerTestConfiguration.java | 4 +- .../SnapshotDaoTestConfiguration.java | 4 +- .../dao/StoragePoolDaoTestConfiguration.java | 4 +- .../com/cloud/vm/MockUserVmManagerImpl.java | 6 +- .../test/com/cloud/vm/UserVmManagerTest.java | 85 +- ...serVmCloneSettingDaoTestConfiguration.java | 4 +- .../vm/dao/UserVmDaoTestConfiguration.java | 4 +- .../vpc/MockConfigurationManagerImpl.java | 10 +- .../com/cloud/vpc/MockNetworkManagerImpl.java | 69 +- .../com/cloud/vpc/MockNetworkModelImpl.java | 26 +- .../com/cloud/vpc/MockVpcManagerImpl.java | 2 +- ...MockVpcVirtualNetworkApplianceManager.java | 14 +- server/test/com/cloud/vpc/VpcTest.java | 269 ++ .../com/cloud/vpc/VpcTestConfiguration.java | 4 +- .../vpc/dao/MockNetworkOfferingDaoImpl.java | 12 +- .../vpc/dao/MockNetworkServiceMapDaoImpl.java | 6 + .../AffinityApiTestConfiguration.java | 344 --- .../affinity/AffinityApiUnitTest.java | 87 +- .../lb/ApplicationLoadBalancerTest.java | 292 ++ .../cloudstack/lb/ChildTestConfiguration.java | 105 + .../ChildTestConfiguration.java | 46 +- .../CreateNetworkOfferingTest.java | 60 +- ...ffinityContext.xml => appLoadBalancer.xml} | 32 +- services/console-proxy/plugin/pom.xml | 8 +- services/console-proxy/pom.xml | 4 +- .../console-proxy/server/css/ajaxviewer.css | 6 +- services/console-proxy/server/js/ajaxkeys.js | 317 +- .../console-proxy/server/js/ajaxviewer.js | 128 +- services/console-proxy/server/pom.xml | 2 +- .../consoleproxy/ConsoleProxyClientBase.java | 1 + services/pom.xml | 2 +- services/secondary-storage/pom.xml | 2 +- .../resource/NfsSecondaryStorageResource.java | 24 +- setup/db/db/schema-2214to30.sql | 1 + setup/db/db/schema-40to410.sql | 8 +- setup/db/db/schema-410to420.sql | 109 +- setup/db/templates.sql | 12 + setup/dev/advanced.cfg | 13 +- setup/dev/basic.cfg | 3 + test/integration/component/test_accounts.py | 96 +- .../component/test_allocation_states.py | 2 +- .../component/test_blocker_bugs.py | 90 +- .../component/test_egress_rules.py | 200 +- test/integration/component/test_eip_elb.py | 124 +- .../component/test_multiple_ip_ranges.py | 429 +++ .../component/test_network_offering.py | 220 +- .../component/test_project_configs.py | 142 +- .../component/test_project_limits.py | 30 +- .../component/test_project_resources.py | 60 +- .../component/test_project_usage.py | 60 +- test/integration/component/test_projects.py | 86 +- test/integration/component/test_regions.py | 140 + .../component/test_regions_accounts.py | 206 ++ .../component/test_resource_limits.py | 98 +- test/integration/component/test_routers.py | 120 +- .../component/test_security_groups.py | 208 +- test/integration/component/test_snapshots.py | 92 +- .../component/test_storage_motion.py | 21 +- test/integration/component/test_templates.py | 46 +- test/integration/component/test_usage.py | 106 +- .../component/test_vm_passwdenabled.py | 12 +- test/integration/component/test_volumes.py | 74 +- test/integration/component/test_vpn_users.py | 447 +++ .../integration/smoke/test_affinity_groups.py | 4 +- .../smoke/test_deploy_vm_with_userdata.py | 2 + .../integration/smoke/test_global_settings.py | 14 +- .../smoke/test_guest_vlan_range.py | 175 ++ test/integration/smoke/test_internal_lb.py | 250 ++ test/integration/smoke/test_iso.py | 18 +- test/integration/smoke/test_network.py | 168 +- test/integration/smoke/test_nic.py | 8 +- .../smoke/test_non_contigiousvlan.py | 2 +- test/integration/smoke/test_regions.py | 93 + test/integration/smoke/test_routers.py | 60 +- test/integration/smoke/test_scale_vm.py | 4 +- test/integration/smoke/test_templates.py | 45 +- test/integration/smoke/test_vm_life_cycle.py | 2 + test/integration/smoke/test_vm_snapshots.py | 308 ++ test/integration/smoke/test_volumes.py | 25 +- test/selenium/ReadMe.txt | 36 +- test/selenium/lib/initialize.py | 17 +- test/selenium/smoke/Login_and_Accounts.py | 5 +- test/selenium/smoke/main.py | 2 +- tools/apidoc/gen_toc.py | 1 + .../systemvmtemplate/definition.rb | 6 +- .../systemvmtemplate/postinstall.sh | 10 +- .../systemvmtemplate64/definition.rb | 6 +- .../systemvmtemplate64/postinstall.sh | 10 +- tools/marvin/marvin/asyncJobMgr.py | 70 +- tools/marvin/marvin/cloudstackConnection.py | 19 +- tools/marvin/marvin/cloudstackTestClient.py | 53 +- tools/marvin/marvin/configGenerator.py | 1 + tools/marvin/marvin/dbConnection.py | 6 +- tools/marvin/marvin/deployDataCenter.py | 20 + tools/marvin/marvin/integration/lib/base.py | 717 ++++- tools/marvin/marvin/integration/lib/utils.py | 17 +- tools/marvin/marvin/remoteSSHClient.py | 18 +- .../marvin/sandbox/advanced/advanced_env.py | 8 + .../marvin/sandbox/advanced/sandbox.cfg | 209 ++ .../marvin/marvin/sandbox/basic/basic_env.py | 1 + .../sandbox/demo/simulator/simulator_setup.py | 2 + tools/marvin/pom.xml | 77 +- tools/transifex/.tx/config | 32 + tools/transifex/README-transifex.txt | 71 + tools/transifex/sync-transifex-ui.sh | 160 + ui/css/cloudstack3.css | 141 +- ui/dictionary.jsp | 1744 +++++------ ui/images/icons.png | Bin 50745 -> 50052 bytes ui/images/sprites.png | Bin 188552 -> 192407 bytes ui/index.jsp | 21 +- ui/scripts/accounts.js | 51 + ui/scripts/affinity.js | 183 ++ ui/scripts/cloudStack.js | 9 +- ui/scripts/configuration.js | 2 +- ui/scripts/domains.js | 2 +- ui/scripts/instanceWizard.js | 1003 +++--- ui/scripts/instances.js | 352 ++- ui/scripts/network.js | 297 +- ui/scripts/plugins.js | 19 +- ui/scripts/regions.js | 27 +- ui/scripts/sharedFunctions.js | 4 + ui/scripts/storage.js | 48 +- ui/scripts/system.js | 573 +++- ui/scripts/templates.js | 106 +- ui/scripts/ui-custom/affinity.js | 173 ++ .../scripts/ui-custom/granularSettings.js | 49 +- ui/scripts/ui-custom/instanceWizard.js | 42 +- ui/scripts/ui-custom/vpc.js | 1 + ui/scripts/ui/widgets/detailView.js | 161 +- ui/scripts/ui/widgets/listView.js | 16 +- ui/scripts/ui/widgets/multiEdit.js | 5 + ui/scripts/vm_snapshots.js | 2 +- ui/scripts/vpc.js | 76 +- ui/scripts/zoneWizard.js | 104 + .../usage/UsageManagerTestConfiguration.java | 5 +- utils/pom.xml | 12 +- .../src/com/cloud/maint/Version.java | 0 .../src/com/cloud/utils/AnnotationHelper.java | 28 +- .../utils/cisco/n1kv/vsm/VsmCommand.java | 9 +- .../component/SpringComponentScanUtils.java | 41 - utils/src/com/cloud/utils/net/NetUtils.java | 10 +- .../cloudstack/test/utils/SpringUtils.java | 113 + vmware-base/pom.xml | 4 - .../vmware/mo/VirtualMachineMO.java | 6 +- .../hypervisor/vmware/util/VmwareClient.java | 2 +- .../vmware/util/VmwareGuestOsMapper.java | 14 +- .../hypervisor/vmware/util/VmwareHelper.java | 26 +- .../vmware/mo/TestVmwareContextFactory.java | 43 - .../vmware/util/TestVmwareUtil.java | 107 - .../test/com/cloud/vmware/TestVMWare.java | 1342 -------- 1283 files changed, 28184 insertions(+), 12953 deletions(-) rename core/src/com/cloud/vm/VirtualDisk.java => api/src/com/cloud/agent/api/storage/CreateVolumeOVAAnswer.java (73%) mode change 100644 => 100755 create mode 100755 api/src/com/cloud/agent/api/storage/CreateVolumeOVACommand.java rename server/src/com/cloud/maint/UpgradeManagerMBean.java => api/src/com/cloud/agent/api/storage/PrepareOVAPackingAnswer.java (73%) mode change 100644 => 100755 rename core/src/com/cloud/storage/snapshot/SnapshotSchedule.java => api/src/com/cloud/agent/api/storage/PrepareOVAPackingCommand.java (51%) mode change 100644 => 100755 rename {core => api}/src/com/cloud/alert/AlertAdapter.java (100%) rename {core => api}/src/com/cloud/event/UsageEvent.java (100%) rename {core => api}/src/com/cloud/exception/AgentControlChannelException.java (100%) rename {core => api}/src/com/cloud/info/ConsoleProxyLoadInfo.java (100%) rename {core => api}/src/com/cloud/info/RunningHostCountInfo.java (100%) create mode 100644 api/src/com/cloud/network/GuestVlan.java rename {server => api}/src/com/cloud/network/UserIpv6Address.java (100%) rename core/src/com/cloud/storage/SecondaryStorage.java => api/src/com/cloud/network/rules/LoadBalancerContainer.java (77%) rename {core => api}/src/com/cloud/resource/UnableDeleteHostException.java (100%) rename {core => api}/src/com/cloud/storage/StoragePoolDiscoverer.java (73%) rename {core => api}/src/com/cloud/vm/ConsoleProxy.java (100%) rename {core => api}/src/com/cloud/vm/SecondaryStorageVm.java (100%) rename {core => api}/src/com/cloud/vm/SystemVm.java (100%) rename {core => api}/src/com/cloud/vm/VirtualMachineName.java (100%) rename {core => api}/src/com/cloud/vm/VmDetailConstants.java (100%) create mode 100644 api/src/org/apache/cloudstack/api/command/admin/internallb/ConfigureInternalLoadBalancerElementCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/internallb/CreateInternalLoadBalancerElementCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/internallb/ListInternalLBVMsCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/internallb/ListInternalLoadBalancerElementsCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/internallb/StartInternalLBVMCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/internallb/StopInternalLBVMCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/network/DedicateGuestVlanRangeCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/network/ListDedicatedGuestVlanRangesCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/network/ListNetworkIsolationMethodsCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/network/ReleaseDedicatedGuestVlanRangeCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateApplicationLoadBalancerCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/loadbalancer/DeleteApplicationLoadBalancerCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/loadbalancer/ListApplicationLoadBalancersCmd.java rename api/src/org/apache/cloudstack/api/command/user/vmsnapshot/{RevertToSnapshotCmd.java => RevertToVMSnapshotCmd.java} (91%) create mode 100644 api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerInstanceResponse.java create mode 100644 api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerResponse.java create mode 100644 api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerRuleResponse.java create mode 100644 api/src/org/apache/cloudstack/api/response/GuestVlanRangeResponse.java create mode 100644 api/src/org/apache/cloudstack/api/response/InternalLoadBalancerElementResponse.java rename core/src/com/cloud/agent/RecoveryHandler.java => api/src/org/apache/cloudstack/api/response/IsolationMethodResponse.java (59%) create mode 100644 api/src/org/apache/cloudstack/network/element/InternalLoadBalancerElementService.java rename server/src/com/cloud/maint/UpgradeMonitor.java => api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerContainer.java (74%) rename server/src/com/cloud/maint/dao/AgentUpgradeDao.java => api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerRule.java (78%) create mode 100644 api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerService.java create mode 100644 api/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMService.java delete mode 100644 awsapi/test/com/cloud/gate/model/ModelTestCase.java delete mode 100644 awsapi/test/com/cloud/gate/persist/PersitTestCase.java create mode 100644 client/WEB-INF/classes/resources/messages_ar.properties rename {api => core}/src/com/cloud/agent/api/AgentControlAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/AgentControlCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/AttachIsoCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/AttachVolumeAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/AttachVolumeCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/BackupSnapshotAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/BackupSnapshotCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/BumpUpPriorityCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/CancelCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/ChangeAgentAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/ChangeAgentCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/CheckHealthAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/CheckHealthCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/CheckNetworkAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/CheckNetworkCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/CheckOnHostAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/CheckOnHostCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/CheckRouterAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/CheckRouterCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/CheckS2SVpnConnectionsAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/CheckS2SVpnConnectionsCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/CheckStateAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/CheckStateCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/CheckVirtualMachineAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/CheckVirtualMachineCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/CleanupNetworkRulesCmd.java (100%) rename {api => core}/src/com/cloud/agent/api/CleanupSnapshotBackupCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/ClusterSyncAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/ClusterSyncCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/ComputeChecksumCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/ConsoleAccessAuthenticationAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/ConsoleAccessAuthenticationCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/ConsoleProxyLoadReportCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/CreatePrivateTemplateFromVolumeCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/CreateStoragePoolCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/CreateVMSnapshotAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/CreateVMSnapshotCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/CreateVolumeFromSnapshotAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/CreateVolumeFromVMSnapshotAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/CreateVolumeFromVMSnapshotCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/CronCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/DeleteObjectFromSwiftCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/DeleteSnapshotBackupAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/DeleteSnapshotBackupCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/DeleteSnapshotsDirCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/DeleteStoragePoolCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/DeleteTemplateFromS3Command.java (100%) rename {api => core}/src/com/cloud/agent/api/DeleteVMSnapshotAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/DeleteVMSnapshotCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/DownloadSnapshotFromS3Command.java (100%) rename api/src/com/cloud/agent/api/downloadSnapshotFromSwiftCommand.java => core/src/com/cloud/agent/api/DownloadSnapshotFromSwiftCommand.java (90%) rename {api => core}/src/com/cloud/agent/api/DownloadTemplateFromS3ToSecondaryStorageCommand.java (100%) rename api/src/com/cloud/agent/api/downloadTemplateFromSwiftToSecondaryStorageCommand.java => core/src/com/cloud/agent/api/DownloadTemplateFromSwiftToSecondaryStorageCommand.java (91%) rename {api => core}/src/com/cloud/agent/api/FenceAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/FenceCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/GetDomRVersionAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/GetDomRVersionCmd.java (100%) rename {api => core}/src/com/cloud/agent/api/GetFileStatsAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/GetFileStatsCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/GetHostStatsAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/GetHostStatsCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/GetStorageStatsAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/GetStorageStatsCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/GetVmStatsAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/GetVmStatsCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/GetVncPortAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/GetVncPortCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/HostStatsEntry.java (100%) rename {api => core}/src/com/cloud/agent/api/MaintainAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/MaintainCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/ManageSnapshotAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/ManageSnapshotCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/MigrateAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/MigrateCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/MigrateWithStorageAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/MigrateWithStorageCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/MigrateWithStorageCompleteAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/MigrateWithStorageCompleteCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/MigrateWithStorageReceiveAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/MigrateWithStorageReceiveCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/MigrateWithStorageSendAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/MigrateWithStorageSendCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/ModifySshKeysCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/ModifyStoragePoolAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/ModifyStoragePoolCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/NetworkUsageAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/NetworkUsageCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/PingAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/PingCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/PingRoutingCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/PingRoutingWithNwGroupsCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/PingRoutingWithOvsCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/PingStorageCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/PingTestCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/PlugNicAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/PlugNicCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/PoolEjectCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/PrepareForMigrationAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/PrepareForMigrationCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/PrepareOCFS2NodesCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/PropagateResourceEventCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/ReadyAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/ReadyCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/RebootAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/RebootCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/RebootRouterCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/RevertToVMSnapshotAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/RevertToVMSnapshotCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/ScaleVmAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/ScaleVmCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/ScheduleHostScanTaskCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/SecStorageFirewallCfgCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/SecStorageSetupAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/SecStorageSetupCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/SecStorageVMSetupCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/SecurityGroupRuleAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/SecurityGroupRulesCmd.java (100%) rename {api => core}/src/com/cloud/agent/api/SetupAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/SetupCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/SetupGuestNetworkAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/SetupGuestNetworkCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/ShutdownCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/SnapshotCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/StartAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/StartCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/StartupAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/StartupCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/StartupExternalDhcpCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/StartupExternalFirewallCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/StartupExternalLoadBalancerCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/StartupProxyCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/StartupPxeServerCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/StartupRoutingCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/StartupSecondaryStorageCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/StartupStorageCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/StartupTrafficMonitorCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/StopAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/StopCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/TransferAgentCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/UnPlugNicAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/UnPlugNicCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/UnregisterVMCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/UpdateHostPasswordCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/UpgradeAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/UpgradeCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/UpgradeSnapshotCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/UploadTemplateToS3FromSecondaryStorageCommand.java (100%) rename api/src/com/cloud/agent/api/uploadTemplateToSwiftFromSecondaryStorageCommand.java => core/src/com/cloud/agent/api/UploadTemplateToSwiftFromSecondaryStorageCommand.java (91%) rename {api => core}/src/com/cloud/agent/api/VMSnapshotBaseCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/VMSnapshotTO.java (100%) rename {api => core}/src/com/cloud/agent/api/ValidateSnapshotAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/ValidateSnapshotCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/VmStatsEntry.java (100%) rename {api => core}/src/com/cloud/agent/api/baremetal/IpmISetBootDevCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/baremetal/IpmiBootorResetCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/baremetal/PreparePxeServerAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/baremetal/PreparePxeServerCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/baremetal/prepareCreateTemplateCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/check/CheckSshAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/check/CheckSshCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/proxy/CheckConsoleProxyLoadCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/proxy/ConsoleProxyLoadAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/proxy/ProxyCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/proxy/StartConsoleProxyAgentHttpHandlerCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/proxy/WatchConsoleProxyLoadCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/CreateLoadBalancerApplianceCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/DestroyLoadBalancerApplianceCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/DhcpEntryCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/GlobalLoadBalancerConfigAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/GlobalLoadBalancerConfigCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/HealthCheckLBConfigAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/HealthCheckLBConfigCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/IpAssocAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/IpAssocCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/IpAssocVpcCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/NetworkElementCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/RemoteAccessVpnCfgCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/SavePasswordCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/SetFirewallRulesAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/SetFirewallRulesCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/SetNetworkACLAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/SetNetworkACLCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/SetPortForwardingRulesAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/SetPortForwardingRulesCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/SetPortForwardingRulesVpcCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/SetSourceNatAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/SetSourceNatCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/SetStaticNatRulesAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/SetStaticNatRulesCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/SetStaticRouteAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/SetStaticRouteCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/Site2SiteVpnCfgCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/SiteLoadBalancerConfig.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/UserDataCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/VmDataCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/routing/VpnUsersCfgCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/AbstractDownloadCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/AbstractUploadCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/CopyVolumeAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/CopyVolumeCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/CreateAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/CreateCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/CreateEntityDownloadURLAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/CreateEntityDownloadURLCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/CreatePrivateTemplateAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/CreatePrivateTemplateCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/DeleteEntityDownloadURLAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/DeleteEntityDownloadURLCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/DeleteTemplateCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/DeleteVolumeCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/DestroyAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/DestroyCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/DownloadAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/DownloadCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/DownloadProgressCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/ListTemplateAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/ListTemplateCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/ListVolumeAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/ListVolumeCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/ManageVolumeAvailabilityAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/ManageVolumeAvailabilityCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/MigrateVolumeAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/MigrateVolumeCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/PrimaryStorageDownloadAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/PrimaryStorageDownloadCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/ResizeVolumeAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/ResizeVolumeCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/StorageCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/UpgradeDiskAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/UpgradeDiskCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/UploadAnswer.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/UploadCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/UploadProgressCommand.java (100%) rename {api => core}/src/com/cloud/agent/api/storage/ssCommand.java (100%) delete mode 100644 core/src/com/cloud/storage/SecondaryStorageLayer.java delete mode 100644 core/src/com/cloud/vm/ConsoleProxyVO.java rename {api => core}/test/org/apache/cloudstack/api/agent/test/AgentControlAnswerTest.java (100%) rename {api => core}/test/org/apache/cloudstack/api/agent/test/AgentControlCommandTest.java (100%) rename {api => core}/test/org/apache/cloudstack/api/agent/test/AnswerTest.java (100%) rename {api => core}/test/org/apache/cloudstack/api/agent/test/AttachIsoCommandTest.java (100%) rename {api => core}/test/org/apache/cloudstack/api/agent/test/AttachVolumeAnswerTest.java (100%) rename {api => core}/test/org/apache/cloudstack/api/agent/test/AttachVolumeCommandTest.java (100%) rename {api => core}/test/org/apache/cloudstack/api/agent/test/BackupSnapshotAnswerTest.java (100%) rename {api => core}/test/org/apache/cloudstack/api/agent/test/BackupSnapshotCommandTest.java (100%) rename {api => core}/test/org/apache/cloudstack/api/agent/test/BumpUpPriorityCommandTest.java (100%) rename {api => core}/test/org/apache/cloudstack/api/agent/test/CancelCommandTest.java (100%) rename {api => core}/test/org/apache/cloudstack/api/agent/test/ChangeAgentAnswerTest.java (100%) rename {api => core}/test/org/apache/cloudstack/api/agent/test/ChangeAgentCommandTest.java (100%) rename {api => core}/test/org/apache/cloudstack/api/agent/test/CheckHealthAnswerTest.java (100%) rename {api => core}/test/org/apache/cloudstack/api/agent/test/CheckHealthCommandTest.java (100%) rename {api => core}/test/org/apache/cloudstack/api/agent/test/CheckNetworkAnswerTest.java (100%) rename {api => core}/test/org/apache/cloudstack/api/agent/test/CheckNetworkCommandTest.java (100%) rename {api => core}/test/org/apache/cloudstack/api/agent/test/CheckOnHostCommandTest.java (100%) rename {api => core}/test/org/apache/cloudstack/api/agent/test/SnapshotCommandTest.java (100%) rename {api => core}/test/src/com/cloud/agent/api/test/ResizeVolumeCommandTest.java (100%) create mode 100644 docs/en-US/MidoNet_Plugin_Guide.ent create mode 100644 docs/en-US/MidoNet_Plugin_Guide.xml create mode 100644 docs/en-US/gslb.xml create mode 100644 docs/en-US/images/add-gslb.png create mode 100644 docs/en-US/images/eip-ns-basiczone.png create mode 100644 docs/en-US/images/gslb.png create mode 100644 docs/en-US/libcloud-examples.xml create mode 100644 docs/en-US/plugin-midonet-about.xml create mode 100644 docs/en-US/plugin-midonet-features.xml create mode 100644 docs/en-US/plugin-midonet-introduction.xml create mode 100644 docs/en-US/plugin-midonet-preparations.xml create mode 100644 docs/en-US/plugin-midonet-provider.xml create mode 100644 docs/en-US/plugin-midonet-revisions.xml create mode 100644 docs/en-US/plugin-midonet-ui.xml create mode 100644 docs/en-US/plugin-midonet-usage.xml create mode 100644 docs/en-US/signing-api-calls-python.xml create mode 100644 docs/publican-plugin-midonet.cfg rename {core => engine/schema}/src/com/cloud/alert/AlertVO.java (100%) rename {server => engine/schema}/src/com/cloud/alert/dao/AlertDao.java (100%) rename {server => engine/schema}/src/com/cloud/alert/dao/AlertDaoImpl.java (100%) rename {core => engine/schema}/src/com/cloud/capacity/CapacityVO.java (100%) rename {server => engine/schema}/src/com/cloud/capacity/dao/CapacityDao.java (97%) rename {server => engine/schema}/src/com/cloud/capacity/dao/CapacityDaoImpl.java (95%) rename {core => engine/schema}/src/com/cloud/certificate/CertificateVO.java (100%) rename {server => engine/schema}/src/com/cloud/certificate/dao/CertificateDao.java (100%) rename {server => engine/schema}/src/com/cloud/certificate/dao/CertificateDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/cluster/ClusterInvalidSessionException.java (100%) rename {server => engine/schema}/src/com/cloud/cluster/ManagementServerHostPeerVO.java (100%) rename {server => engine/schema}/src/com/cloud/cluster/ManagementServerHostVO.java (100%) rename {server => engine/schema}/src/com/cloud/cluster/agentlb/HostTransferMapVO.java (100%) rename {server => engine/schema}/src/com/cloud/cluster/agentlb/dao/HostTransferMapDao.java (100%) rename {server => engine/schema}/src/com/cloud/cluster/agentlb/dao/HostTransferMapDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/cluster/dao/ManagementServerHostDao.java (100%) rename {server => engine/schema}/src/com/cloud/cluster/dao/ManagementServerHostDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/cluster/dao/ManagementServerHostPeerDao.java (100%) rename {server => engine/schema}/src/com/cloud/cluster/dao/ManagementServerHostPeerDaoImpl.java (100%) rename {core => engine/schema}/src/com/cloud/configuration/ConfigurationVO.java (100%) rename {core => engine/schema}/src/com/cloud/configuration/ResourceCountVO.java (100%) rename {core => engine/schema}/src/com/cloud/configuration/ResourceLimitVO.java (100%) rename {server => engine/schema}/src/com/cloud/configuration/dao/ConfigurationDao.java (100%) rename {server => engine/schema}/src/com/cloud/configuration/dao/ConfigurationDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/configuration/dao/ResourceCountDao.java (100%) rename {server => engine/schema}/src/com/cloud/configuration/dao/ResourceCountDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/configuration/dao/ResourceLimitDao.java (100%) rename {server => engine/schema}/src/com/cloud/configuration/dao/ResourceLimitDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/dc/AccountVlanMapVO.java (100%) rename {server => engine/schema}/src/com/cloud/dc/ClusterDetailsDao.java (100%) rename {server => engine/schema}/src/com/cloud/dc/ClusterDetailsDaoImpl.java (92%) rename {server => engine/schema}/src/com/cloud/dc/ClusterDetailsVO.java (100%) rename {server => engine/schema}/src/com/cloud/dc/ClusterVO.java (100%) rename {server => engine/schema}/src/com/cloud/dc/ClusterVSMMapVO.java (100%) rename {server => engine/schema}/src/com/cloud/dc/DataCenterIpAddressVO.java (100%) rename {server => engine/schema}/src/com/cloud/dc/DataCenterLinkLocalIpAddressVO.java (100%) rename {server => engine/schema}/src/com/cloud/dc/DataCenterVO.java (100%) rename {server => engine/schema}/src/com/cloud/dc/DataCenterVnetVO.java (90%) rename {server => engine/schema}/src/com/cloud/dc/DcDetailVO.java (100%) rename {server => engine/schema}/src/com/cloud/dc/HostPodVO.java (100%) rename {server => engine/schema}/src/com/cloud/dc/PodCluster.java (100%) rename {server => engine/schema}/src/com/cloud/dc/PodVlanMapVO.java (100%) rename {server => engine/schema}/src/com/cloud/dc/PodVlanVO.java (100%) rename {server => engine/schema}/src/com/cloud/dc/StorageNetworkIpAddressVO.java (100%) rename {server => engine/schema}/src/com/cloud/dc/StorageNetworkIpRangeVO.java (100%) rename {server => engine/schema}/src/com/cloud/dc/VlanVO.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/AccountVlanMapDao.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/AccountVlanMapDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/ClusterDao.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/ClusterDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/ClusterVSMMapDao.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/ClusterVSMMapDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/DataCenterDao.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/DataCenterDaoImpl.java (94%) rename {server => engine/schema}/src/com/cloud/dc/dao/DataCenterIpAddressDao.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/DataCenterIpAddressDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/DataCenterLinkLocalIpAddressDao.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/DataCenterLinkLocalIpAddressDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/DataCenterVnetDao.java (87%) rename {server => engine/schema}/src/com/cloud/dc/dao/DataCenterVnetDaoImpl.java (69%) rename {server => engine/schema}/src/com/cloud/dc/dao/DcDetailsDao.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/DcDetailsDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/HostPodDao.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/HostPodDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/PodVlanDao.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/PodVlanDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/PodVlanMapDao.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/PodVlanMapDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/StorageNetworkIpAddressDao.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/StorageNetworkIpAddressDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/StorageNetworkIpRangeDao.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/StorageNetworkIpRangeDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/VlanDao.java (100%) rename {server => engine/schema}/src/com/cloud/dc/dao/VlanDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/domain/DomainVO.java (100%) rename {server => engine/schema}/src/com/cloud/domain/dao/DomainDao.java (100%) rename {server => engine/schema}/src/com/cloud/domain/dao/DomainDaoImpl.java (100%) rename {core => engine/schema}/src/com/cloud/event/EventVO.java (100%) rename {core => engine/schema}/src/com/cloud/event/UsageEventVO.java (100%) rename {core => engine/schema}/src/com/cloud/event/dao/EventDao.java (100%) rename {core => engine/schema}/src/com/cloud/event/dao/EventDaoImpl.java (100%) rename {core => engine/schema}/src/com/cloud/event/dao/UsageEventDao.java (89%) rename {core => engine/schema}/src/com/cloud/event/dao/UsageEventDaoImpl.java (92%) rename {core => engine/schema}/src/com/cloud/host/DetailVO.java (100%) rename {core => engine/schema}/src/com/cloud/host/HostTagVO.java (100%) rename {core => engine/schema}/src/com/cloud/host/HostVO.java (100%) rename {server => engine/schema}/src/com/cloud/host/dao/HostDao.java (100%) rename {server => engine/schema}/src/com/cloud/host/dao/HostDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/host/dao/HostDetailsDao.java (100%) rename {server => engine/schema}/src/com/cloud/host/dao/HostDetailsDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/host/dao/HostTagsDao.java (100%) rename {server => engine/schema}/src/com/cloud/host/dao/HostTagsDaoImpl.java (100%) rename {core => engine/schema}/src/com/cloud/hypervisor/HypervisorCapabilitiesVO.java (100%) rename {server => engine/schema}/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDao.java (100%) rename {server => engine/schema}/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/keystore/KeystoreDao.java (100%) rename {server => engine/schema}/src/com/cloud/keystore/KeystoreDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/keystore/KeystoreVO.java (100%) rename {server => engine/schema}/src/com/cloud/migration/DiskOffering20Dao.java (100%) rename {server => engine/schema}/src/com/cloud/migration/DiskOffering20DaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/migration/DiskOffering20VO.java (100%) rename {server => engine/schema}/src/com/cloud/migration/DiskOffering21Dao.java (100%) rename {server => engine/schema}/src/com/cloud/migration/DiskOffering21DaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/migration/DiskOffering21VO.java (100%) rename {server => engine/schema}/src/com/cloud/migration/ServiceOffering20Dao.java (100%) rename {server => engine/schema}/src/com/cloud/migration/ServiceOffering20DaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/migration/ServiceOffering20VO.java (100%) rename {server => engine/schema}/src/com/cloud/migration/ServiceOffering21Dao.java (100%) rename {server => engine/schema}/src/com/cloud/migration/ServiceOffering21DaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/migration/ServiceOffering21VO.java (100%) rename {server => engine/schema}/src/com/cloud/network/LBHealthCheckPolicyVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/UserIpv6AddressVO.java (100%) rename {core => engine/schema}/src/com/cloud/network/VpnUserVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/AutoScalePolicyConditionMapVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/AutoScalePolicyVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/AutoScaleVmGroupPolicyMapVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/AutoScaleVmGroupVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/AutoScaleVmProfileVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/ConditionVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/CounterVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/dao/AutoScalePolicyConditionMapDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/dao/AutoScalePolicyConditionMapDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/dao/AutoScalePolicyDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/dao/AutoScalePolicyDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/dao/AutoScaleVmGroupDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/dao/AutoScaleVmGroupDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/dao/AutoScaleVmGroupPolicyMapDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/dao/AutoScaleVmGroupPolicyMapDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/dao/AutoScaleVmProfileDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/dao/AutoScaleVmProfileDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/dao/ConditionDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/dao/ConditionDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/dao/CounterDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/as/dao/CounterDaoImpl.java (100%) create mode 100644 engine/schema/src/com/cloud/network/dao/AccountGuestVlanMapDao.java create mode 100644 engine/schema/src/com/cloud/network/dao/AccountGuestVlanMapDaoImpl.java create mode 100644 engine/schema/src/com/cloud/network/dao/AccountGuestVlanMapVO.java rename {server => engine/schema}/src/com/cloud/network/dao/ExternalFirewallDeviceDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/ExternalFirewallDeviceDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/ExternalFirewallDeviceVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/ExternalLoadBalancerDeviceDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/ExternalLoadBalancerDeviceDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/ExternalLoadBalancerDeviceVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/FirewallRulesCidrsDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/FirewallRulesCidrsDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/FirewallRulesCidrsVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/FirewallRulesDao.java (98%) rename {server => engine/schema}/src/com/cloud/network/dao/FirewallRulesDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/IPAddressDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/IPAddressDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/IPAddressVO.java (98%) rename {server => engine/schema}/src/com/cloud/network/dao/InlineLoadBalancerNicMapDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/InlineLoadBalancerNicMapDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/InlineLoadBalancerNicMapVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/LBHealthCheckPolicyDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/LBHealthCheckPolicyDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/LBStickinessPolicyDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/LBStickinessPolicyDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/LBStickinessPolicyVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/LoadBalancerDao.java (74%) create mode 100644 engine/schema/src/com/cloud/network/dao/LoadBalancerDaoImpl.java rename {server => engine/schema}/src/com/cloud/network/dao/LoadBalancerVMMapDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/LoadBalancerVMMapDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/LoadBalancerVMMapVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/LoadBalancerVO.java (86%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkAccountDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkAccountDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkAccountVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkDomainDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkDomainDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkDomainVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkExternalFirewallDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkExternalFirewallDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkExternalFirewallVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkExternalLoadBalancerDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkExternalLoadBalancerDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkExternalLoadBalancerVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkOpDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkOpDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkOpVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkRuleConfigDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkRuleConfigDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkRuleConfigVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkServiceMapDao.java (95%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkServiceMapDaoImpl.java (93%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkServiceMapVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/NetworkVO.java (99%) rename {server => engine/schema}/src/com/cloud/network/dao/PhysicalNetworkDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/PhysicalNetworkDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/PhysicalNetworkIsolationMethodDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/PhysicalNetworkIsolationMethodVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/PhysicalNetworkServiceProviderDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/PhysicalNetworkServiceProviderDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/PhysicalNetworkServiceProviderVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/PhysicalNetworkTagDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/PhysicalNetworkTagVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/PhysicalNetworkTrafficTypeDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/PhysicalNetworkTrafficTypeDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/PhysicalNetworkTrafficTypeVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/PhysicalNetworkVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/PortProfileDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/PortProfileDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/PortProfileVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/RemoteAccessVpnDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/RemoteAccessVpnDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/RemoteAccessVpnVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/RouterNetworkDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/RouterNetworkDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/RouterNetworkVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/Site2SiteCustomerGatewayDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/Site2SiteCustomerGatewayDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/Site2SiteCustomerGatewayVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/Site2SiteVpnConnectionDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/Site2SiteVpnConnectionDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/Site2SiteVpnConnectionVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/Site2SiteVpnGatewayDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/Site2SiteVpnGatewayDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/Site2SiteVpnGatewayVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/UserIpv6AddressDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/UserIpv6AddressDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/VirtualRouterProviderDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/VirtualRouterProviderDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/VpnUserDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/dao/VpnUserDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/element/VirtualRouterProviderVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/rules/FirewallRuleVO.java (98%) rename {server => engine/schema}/src/com/cloud/network/rules/PortForwardingRuleVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/rules/dao/PortForwardingRulesDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java (100%) rename {core => engine/schema}/src/com/cloud/network/security/SecurityGroupRuleVO.java (100%) rename {core => engine/schema}/src/com/cloud/network/security/SecurityGroupRulesVO.java (91%) rename {core => engine/schema}/src/com/cloud/network/security/SecurityGroupVMMapVO.java (100%) rename {core => engine/schema}/src/com/cloud/network/security/SecurityGroupVO.java (100%) rename {core => engine/schema}/src/com/cloud/network/security/SecurityGroupWork.java (100%) rename {core => engine/schema}/src/com/cloud/network/security/SecurityGroupWorkVO.java (100%) rename {core => engine/schema}/src/com/cloud/network/security/VmRulesetLogVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/security/dao/SecurityGroupDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/security/dao/SecurityGroupDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/security/dao/SecurityGroupRuleDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/security/dao/SecurityGroupRuleDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/security/dao/SecurityGroupRulesDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/security/dao/SecurityGroupRulesDaoImpl.java (89%) rename {server => engine/schema}/src/com/cloud/network/security/dao/SecurityGroupVMMapDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/security/dao/SecurityGroupVMMapDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/security/dao/SecurityGroupWorkDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/security/dao/SecurityGroupWorkDaoImpl.java (93%) rename {server => engine/schema}/src/com/cloud/network/security/dao/VmRulesetLogDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/security/dao/VmRulesetLogDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/vpc/PrivateIpVO.java (92%) rename {server => engine/schema}/src/com/cloud/network/vpc/StaticRouteVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/vpc/VpcGatewayVO.java (95%) rename {server => engine/schema}/src/com/cloud/network/vpc/VpcOfferingServiceMapVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/vpc/VpcOfferingVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/vpc/VpcServiceMapVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/vpc/VpcVO.java (100%) rename {server => engine/schema}/src/com/cloud/network/vpc/dao/PrivateIpDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/vpc/dao/PrivateIpDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/vpc/dao/StaticRouteDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/vpc/dao/StaticRouteDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/vpc/dao/VpcDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/vpc/dao/VpcDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/vpc/dao/VpcGatewayDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/vpc/dao/VpcGatewayDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/vpc/dao/VpcOfferingDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/vpc/dao/VpcOfferingDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/vpc/dao/VpcOfferingServiceMapDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/network/vpc/dao/VpcServiceMapDao.java (100%) rename {server => engine/schema}/src/com/cloud/network/vpc/dao/VpcServiceMapDaoImpl.java (100%) create mode 100644 engine/schema/src/com/cloud/offerings/NetworkOfferingDetailsVO.java rename {server => engine/schema}/src/com/cloud/offerings/NetworkOfferingServiceMapVO.java (100%) rename {server => engine/schema}/src/com/cloud/offerings/NetworkOfferingVO.java (91%) rename {server => engine/schema}/src/com/cloud/offerings/dao/NetworkOfferingDao.java (93%) rename {server => engine/schema}/src/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java (89%) rename server/src/com/cloud/maint/dao/AgentUpgradeDaoImpl.java => engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDao.java (63%) create mode 100644 engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDaoImpl.java rename {server => engine/schema}/src/com/cloud/offerings/dao/NetworkOfferingServiceMapDao.java (100%) rename {server => engine/schema}/src/com/cloud/offerings/dao/NetworkOfferingServiceMapDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/projects/ProjectAccountVO.java (100%) rename {server => engine/schema}/src/com/cloud/projects/ProjectInvitationVO.java (100%) rename {server => engine/schema}/src/com/cloud/projects/ProjectVO.java (100%) rename {server => engine/schema}/src/com/cloud/projects/dao/ProjectAccountDao.java (100%) rename {server => engine/schema}/src/com/cloud/projects/dao/ProjectAccountDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/projects/dao/ProjectDao.java (100%) rename {server => engine/schema}/src/com/cloud/projects/dao/ProjectDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/projects/dao/ProjectInvitationDao.java (100%) rename {server => engine/schema}/src/com/cloud/projects/dao/ProjectInvitationDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/secstorage/CommandExecLogDao.java (100%) rename {server => engine/schema}/src/com/cloud/secstorage/CommandExecLogDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/secstorage/CommandExecLogVO.java (100%) rename {server => engine/schema}/src/com/cloud/service/ServiceOfferingVO.java (100%) rename {server => engine/schema}/src/com/cloud/service/dao/ServiceOfferingDao.java (100%) rename {server => engine/schema}/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java (100%) rename {core => engine/schema}/src/com/cloud/storage/DiskOfferingVO.java (100%) rename {core => engine/schema}/src/com/cloud/storage/GuestOSCategoryVO.java (100%) rename {core => engine/schema}/src/com/cloud/storage/GuestOSVO.java (100%) rename {core => engine/schema}/src/com/cloud/storage/LaunchPermissionVO.java (100%) rename {core => engine/schema}/src/com/cloud/storage/S3VO.java (100%) rename {core => engine/schema}/src/com/cloud/storage/SnapshotPolicyVO.java (100%) rename {core => engine/schema}/src/com/cloud/storage/SnapshotScheduleVO.java (100%) rename {core => engine/schema}/src/com/cloud/storage/SnapshotVO.java (100%) rename {core => engine/schema}/src/com/cloud/storage/StoragePoolHostAssoc.java (100%) rename {core => engine/schema}/src/com/cloud/storage/StoragePoolHostVO.java (94%) rename {core => engine/schema}/src/com/cloud/storage/StoragePoolWorkVO.java (100%) rename {core => engine/schema}/src/com/cloud/storage/SwiftVO.java (100%) rename {core => engine/schema}/src/com/cloud/storage/UploadVO.java (100%) rename {core => engine/schema}/src/com/cloud/storage/VMTemplateDetailVO.java (100%) rename {core => engine/schema}/src/com/cloud/storage/VMTemplateHostVO.java (100%) rename {core => engine/schema}/src/com/cloud/storage/VMTemplateS3VO.java (100%) rename {core => engine/schema}/src/com/cloud/storage/VMTemplateStoragePoolVO.java (100%) rename {core => engine/schema}/src/com/cloud/storage/VMTemplateSwiftVO.java (100%) rename {core => engine/schema}/src/com/cloud/storage/VMTemplateVO.java (100%) rename {core => engine/schema}/src/com/cloud/storage/VMTemplateZoneVO.java (100%) rename {core => engine/schema}/src/com/cloud/storage/VolumeHostVO.java (100%) rename {core => engine/schema}/src/com/cloud/storage/VolumeVO.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/DiskOfferingDao.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/DiskOfferingDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/GuestOSCategoryDao.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/GuestOSCategoryDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/GuestOSDao.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/GuestOSDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/LaunchPermissionDao.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/LaunchPermissionDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/S3Dao.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/S3DaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/SnapshotDao.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/SnapshotDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/SnapshotPolicyDao.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/SnapshotPolicyDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/SnapshotScheduleDao.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/SnapshotScheduleDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/StoragePoolDetailsDaoImpl.java (97%) rename {server => engine/schema}/src/com/cloud/storage/dao/StoragePoolHostDao.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/StoragePoolHostDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/StoragePoolWorkDao.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/StoragePoolWorkDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/SwiftDao.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/SwiftDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/UploadDao.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/UploadDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/VMTemplateDao.java (96%) rename {server => engine/schema}/src/com/cloud/storage/dao/VMTemplateDaoImpl.java (98%) rename {server => engine/schema}/src/com/cloud/storage/dao/VMTemplateDetailsDao.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/VMTemplateDetailsDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/VMTemplateHostDao.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/VMTemplateHostDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/VMTemplatePoolDao.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/VMTemplatePoolDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/VMTemplateS3Dao.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/VMTemplateS3DaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/VMTemplateSwiftDao.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/VMTemplateSwiftDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/VMTemplateZoneDao.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/VMTemplateZoneDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/VolumeDao.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/VolumeDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/VolumeHostDao.java (100%) rename {server => engine/schema}/src/com/cloud/storage/dao/VolumeHostDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/tags/ResourceTagVO.java (100%) rename {server => engine/schema}/src/com/cloud/tags/dao/ResourceTagDao.java (100%) rename {server => engine/schema}/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/DatabaseCreator.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/DatabaseIntegrityChecker.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/DatabaseUpgradeChecker.java (98%) rename {server => engine/schema}/src/com/cloud/upgrade/PremiumDatabaseUpgradeChecker.java (77%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/DbUpgrade.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/DbUpgradeUtils.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade217to218.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade218to22.java (99%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade218to224DomainVlans.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade218to22Premium.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade2210to2211.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade2211to2212.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade2211to2212Premium.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade2212to2213.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade2213to2214.java (96%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade2214to30.java (97%) mode change 100755 => 100644 rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade221to222.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade221to222Premium.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade222to224.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade222to224Premium.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade224to225.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade225to226.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade227to228.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade227to228Premium.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade228to229.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade229to2210.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade301to302.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade302to40.java (95%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade30to301.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade30xBase.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade40to41.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/Upgrade410to420.java (81%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/UpgradeSnapshot217to224.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/UpgradeSnapshot223to224.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/VersionDao.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/VersionDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/upgrade/dao/VersionVO.java (100%) rename {server => engine/schema}/src/com/cloud/usage/ExternalPublicIpStatisticsVO.java (100%) rename {server => engine/schema}/src/com/cloud/usage/UsageIPAddressVO.java (100%) rename {server => engine/schema}/src/com/cloud/usage/UsageJobVO.java (100%) rename {server => engine/schema}/src/com/cloud/usage/UsageLoadBalancerPolicyVO.java (100%) rename {server => engine/schema}/src/com/cloud/usage/UsageNetworkOfferingVO.java (100%) rename {server => engine/schema}/src/com/cloud/usage/UsageNetworkVO.java (100%) rename {server => engine/schema}/src/com/cloud/usage/UsagePortForwardingRuleVO.java (100%) rename {server => engine/schema}/src/com/cloud/usage/UsageSecurityGroupVO.java (100%) rename {server => engine/schema}/src/com/cloud/usage/UsageStorageVO.java (100%) rename {server => engine/schema}/src/com/cloud/usage/UsageVMInstanceVO.java (100%) rename {server => engine/schema}/src/com/cloud/usage/UsageVO.java (100%) rename {server => engine/schema}/src/com/cloud/usage/UsageVPNUserVO.java (100%) rename {server => engine/schema}/src/com/cloud/usage/UsageVolumeVO.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/ExternalPublicIpStatisticsDao.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/ExternalPublicIpStatisticsDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageDao.java (70%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageDaoImpl.java (94%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageIPAddressDao.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageIPAddressDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageJobDao.java (92%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageJobDaoImpl.java (97%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageLoadBalancerPolicyDao.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageLoadBalancerPolicyDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageNetworkDao.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageNetworkDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageNetworkOfferingDao.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageNetworkOfferingDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsagePortForwardingRuleDao.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsagePortForwardingRuleDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageSecurityGroupDao.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageSecurityGroupDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageStorageDao.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageStorageDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageVMInstanceDao.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageVMInstanceDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageVPNUserDao.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageVPNUserDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageVolumeDao.java (100%) rename {server => engine/schema}/src/com/cloud/usage/dao/UsageVolumeDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/user/AccountDetailVO.java (100%) rename {server => engine/schema}/src/com/cloud/user/AccountDetailsDao.java (100%) rename {server => engine/schema}/src/com/cloud/user/AccountDetailsDaoImpl.java (100%) rename {core => engine/schema}/src/com/cloud/user/AccountVO.java (100%) rename {core => engine/schema}/src/com/cloud/user/SSHKeyPairVO.java (100%) rename {core => engine/schema}/src/com/cloud/user/UserAccountVO.java (100%) rename {core => engine/schema}/src/com/cloud/user/UserStatisticsVO.java (100%) rename {core => engine/schema}/src/com/cloud/user/UserStatsLogVO.java (100%) rename {core => engine/schema}/src/com/cloud/user/UserVO.java (100%) rename {server => engine/schema}/src/com/cloud/user/dao/AccountDao.java (100%) rename {server => engine/schema}/src/com/cloud/user/dao/AccountDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/user/dao/SSHKeyPairDao.java (100%) rename {server => engine/schema}/src/com/cloud/user/dao/SSHKeyPairDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/user/dao/UserAccountDao.java (100%) rename {server => engine/schema}/src/com/cloud/user/dao/UserAccountDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/user/dao/UserDao.java (100%) rename {server => engine/schema}/src/com/cloud/user/dao/UserDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/user/dao/UserStatisticsDao.java (100%) rename {server => engine/schema}/src/com/cloud/user/dao/UserStatisticsDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/user/dao/UserStatsLogDao.java (100%) rename {server => engine/schema}/src/com/cloud/user/dao/UserStatsLogDaoImpl.java (100%) create mode 100644 engine/schema/src/com/cloud/vm/ConsoleProxyVO.java rename {core => engine/schema}/src/com/cloud/vm/DomainRouterVO.java (100%) rename {core => engine/schema}/src/com/cloud/vm/InstanceGroupVMMapVO.java (100%) rename {core => engine/schema}/src/com/cloud/vm/InstanceGroupVO.java (100%) rename {server => engine/schema}/src/com/cloud/vm/ItWorkDao.java (100%) rename {server => engine/schema}/src/com/cloud/vm/ItWorkDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/vm/ItWorkVO.java (100%) rename {server => engine/schema}/src/com/cloud/vm/NicVO.java (100%) rename {core => engine/schema}/src/com/cloud/vm/SecondaryStorageVmVO.java (100%) rename {core => engine/schema}/src/com/cloud/vm/UserVmCloneSettingVO.java (100%) rename {core => engine/schema}/src/com/cloud/vm/UserVmDetailVO.java (100%) rename {core => engine/schema}/src/com/cloud/vm/UserVmVO.java (100%) rename {core => engine/schema}/src/com/cloud/vm/VMInstanceVO.java (99%) rename {server => engine/schema}/src/com/cloud/vm/dao/ConsoleProxyDao.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/ConsoleProxyDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/DomainRouterDao.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/DomainRouterDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/InstanceGroupDao.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/InstanceGroupDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/InstanceGroupVMMapDao.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/InstanceGroupVMMapDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/NicDao.java (97%) rename {server => engine/schema}/src/com/cloud/vm/dao/NicDaoImpl.java (99%) rename {server => engine/schema}/src/com/cloud/vm/dao/NicSecondaryIpDao.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/NicSecondaryIpVO.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/SecondaryStorageVmDao.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/SecondaryStorageVmDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/UserVmCloneSettingDao.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/UserVmCloneSettingDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/UserVmDao.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/UserVmDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/UserVmData.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/UserVmDetailsDao.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/UserVmDetailsDaoImpl.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/VMInstanceDao.java (100%) rename {server => engine/schema}/src/com/cloud/vm/dao/VMInstanceDaoImpl.java (100%) rename {core => engine/schema}/src/com/cloud/vm/snapshot/VMSnapshotVO.java (100%) rename {server => engine/schema}/src/com/cloud/vm/snapshot/dao/VMSnapshotDao.java (100%) rename {server => engine/schema}/src/com/cloud/vm/snapshot/dao/VMSnapshotDaoImpl.java (100%) rename {server => engine/schema}/src/org/apache/cloudstack/affinity/AffinityGroupVMMapVO.java (100%) rename {server => engine/schema}/src/org/apache/cloudstack/affinity/AffinityGroupVO.java (100%) rename {server => engine/schema}/src/org/apache/cloudstack/affinity/dao/AffinityGroupDao.java (100%) rename {server => engine/schema}/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java (100%) rename {server => engine/schema}/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java (100%) rename {server => engine/schema}/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java (100%) create mode 100644 engine/schema/src/org/apache/cloudstack/lb/ApplicationLoadBalancerRuleVO.java create mode 100644 engine/schema/src/org/apache/cloudstack/lb/dao/ApplicationLoadBalancerRuleDao.java create mode 100644 engine/schema/src/org/apache/cloudstack/lb/dao/ApplicationLoadBalancerRuleDaoImpl.java rename {server => engine/schema}/src/org/apache/cloudstack/region/RegionSyncVO.java (100%) rename {server => engine/schema}/src/org/apache/cloudstack/region/RegionVO.java (100%) rename {server => engine/schema}/src/org/apache/cloudstack/region/dao/RegionDao.java (100%) rename {server => engine/schema}/src/org/apache/cloudstack/region/dao/RegionDaoImpl.java (100%) rename {server => engine/schema}/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerDaoImpl.java (100%) rename {server => engine/schema}/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerLbRuleMapDao.java (100%) rename {server => engine/schema}/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerLbRuleMapDaoImpl.java (100%) rename {server => engine/schema}/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerLbRuleMapVO.java (100%) rename {server => engine/schema}/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerRuleDao.java (100%) rename {server => engine/schema}/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerRuleVO.java (100%) delete mode 100644 framework/api/pom.xml rename framework/{api => ipc}/src/org/apache/cloudstack/framework/async/AsyncCallFuture.java (100%) rename framework/{api => ipc}/src/org/apache/cloudstack/framework/async/AsyncCompletionCallback.java (100%) rename framework/ipc/src/org/apache/cloudstack/framework/{eventbus/EventBus.java => messagebus/MessageBus.java} (81%) rename framework/ipc/src/org/apache/cloudstack/framework/{eventbus/EventBusBase.java => messagebus/MessageBusBase.java} (63%) rename framework/ipc/src/org/apache/cloudstack/framework/{eventbus/EventBusEndpoint.java => messagebus/MessageBusEndpoint.java} (77%) rename framework/ipc/src/org/apache/cloudstack/framework/{eventbus/EventDispatcher.java => messagebus/MessageDispatcher.java} (83%) rename framework/ipc/src/org/apache/cloudstack/framework/{eventbus/EventHandler.java => messagebus/MessageHandler.java} (92%) rename framework/ipc/src/org/apache/cloudstack/framework/{eventbus/Subscriber.java => messagebus/MessageSubscriber.java} (83%) rename framework/ipc/src/org/apache/cloudstack/framework/{eventbus => messagebus}/PublishScope.java (94%) create mode 100644 framework/ipc/test/org/apache/cloudstack/messagebus/TestMessageBus.java create mode 100644 framework/ipc/test/resources/MessageBusTestContext.xml rename patches/systemvm/debian/config/etc/{dnsmasq.conf => dnsmasq.conf.tmpl} (99%) create mode 100755 patches/systemvm/debian/config/etc/iptables/iptables-ilbvm create mode 100755 patches/systemvm/debian/config/opt/cloud/bin/ilb.sh create mode 100644 plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java create mode 100755 plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-egress-acl-no-protocol-rule.xml create mode 100644 plugins/network-elements/internal-loadbalancer/pom.xml create mode 100644 plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java create mode 100644 plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManager.java create mode 100644 plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java create mode 100644 plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/ElementChildTestConfiguration.java create mode 100644 plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/InternalLbElementServiceTest.java create mode 100644 plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/InternalLbElementTest.java create mode 100644 plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/InternalLBVMManagerTest.java create mode 100644 plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/InternalLBVMServiceTest.java create mode 100644 plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/LbChildTestConfiguration.java create mode 100644 plugins/network-elements/internal-loadbalancer/test/resources/lb_element.xml create mode 100644 plugins/network-elements/internal-loadbalancer/test/resources/lb_mgr.xml create mode 100644 plugins/network-elements/internal-loadbalancer/test/resources/lb_svc.xml mode change 100644 => 100755 plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/DeleteNiciraNvpDeviceCmd.java create mode 100644 plugins/network-elements/nicira-nvp/test/com/cloud/network/nicira/NiciraTagTest.java rename {core => server}/src/com/cloud/alert/AlertManager.java (100%) rename {core => server}/src/com/cloud/async/AsyncJobVO.java (99%) rename {core => server}/src/com/cloud/async/SyncQueueItemVO.java (100%) rename {core => server}/src/com/cloud/async/SyncQueueVO.java (100%) delete mode 100644 server/src/com/cloud/cluster/CheckPointVO.java delete mode 100644 server/src/com/cloud/cluster/dao/StackMaidDao.java delete mode 100644 server/src/com/cloud/cluster/dao/StackMaidDaoImpl.java delete mode 100644 server/src/com/cloud/maint/AgentUpgradeVO.java delete mode 100644 server/src/com/cloud/maint/UpgradeManager.java delete mode 100644 server/src/com/cloud/maint/UpgradeManagerImpl.java delete mode 100755 server/src/com/cloud/migration/Db21to22MigrationUtil.java delete mode 100644 server/src/com/cloud/migration/Db22beta4to22GAMigrationUtil.java delete mode 100644 server/src/com/cloud/network/dao/LoadBalancerDaoImpl.java create mode 100644 server/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerManagerImpl.java create mode 100644 server/test/com/cloud/network/DedicateGuestVlanRangesTest.java create mode 100644 server/test/com/cloud/vpc/VpcTest.java delete mode 100644 server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java create mode 100644 server/test/org/apache/cloudstack/lb/ApplicationLoadBalancerTest.java create mode 100644 server/test/org/apache/cloudstack/lb/ChildTestConfiguration.java rename server/test/resources/{affinityContext.xml => appLoadBalancer.xml} (67%) create mode 100644 test/integration/component/test_multiple_ip_ranges.py create mode 100644 test/integration/component/test_regions.py create mode 100644 test/integration/component/test_regions_accounts.py create mode 100644 test/integration/component/test_vpn_users.py create mode 100644 test/integration/smoke/test_guest_vlan_range.py create mode 100644 test/integration/smoke/test_internal_lb.py create mode 100644 test/integration/smoke/test_regions.py create mode 100644 test/integration/smoke/test_vm_snapshots.py create mode 100644 tools/marvin/marvin/sandbox/advanced/sandbox.cfg create mode 100644 tools/transifex/.tx/config create mode 100644 tools/transifex/README-transifex.txt create mode 100755 tools/transifex/sync-transifex-ui.sh create mode 100644 ui/scripts/affinity.js create mode 100644 ui/scripts/ui-custom/affinity.js rename vmware-base/test/com/cloud/hypervisor/vmware/mo/TestVmwareMO.java => ui/scripts/ui-custom/granularSettings.js (52%) rename {server => utils}/src/com/cloud/maint/Version.java (100%) delete mode 100644 utils/src/com/cloud/utils/component/SpringComponentScanUtils.java create mode 100644 utils/src/org/apache/cloudstack/test/utils/SpringUtils.java delete mode 100644 vmware-base/test/com/cloud/hypervisor/vmware/mo/TestVmwareContextFactory.java delete mode 100755 vmware-base/test/com/cloud/hypervisor/vmware/util/TestVmwareUtil.java delete mode 100644 vmware-base/test/com/cloud/vmware/TestVMWare.java diff --git a/.gitignore b/.gitignore index f41862895ec..016554a5f75 100644 --- a/.gitignore +++ b/.gitignore @@ -18,10 +18,7 @@ build/replace.properties build/build.number bin/ -cloudstack-proprietary/ -premium/ .lock-wscript -artifacts/ .waf-* waf-* target/ @@ -37,7 +34,7 @@ cloud-*.tar.bz2 *.egg-info/ *.prefs build.number -api.log.*.gz +*.log.*.gz cloud.log.*.* unittest deps/cloud.userlibraries @@ -59,6 +56,7 @@ tools/cli/build/ *.iso *.tar.gz *.tgz +.* target-eclipse awsapi/modules/* !.gitignore diff --git a/agent/conf/agent.properties b/agent/conf/agent.properties index e49afbf2aaf..7dc4ba8a18c 100644 --- a/agent/conf/agent.properties +++ b/agent/conf/agent.properties @@ -78,7 +78,7 @@ domr.scripts.dir=scripts/network/domr/kvm # a sensible default will be selected based on the network.bridge.type but can # be overridden here. # native = com.cloud.hypervisor.kvm.resource.BridgeVifDriver -# openvswitch = com.cloud.hypervisor.kvm.resource.OvsBridgeDriver +# openvswitch = com.cloud.hypervisor.kvm.resource.OvsVifDriver #libvirt.vif.driver=com.cloud.hypervisor.kvm.resource.BridgeVifDriver # set the hypervisor type, values are: kvm, lxc diff --git a/core/src/com/cloud/vm/VirtualDisk.java b/api/src/com/cloud/agent/api/storage/CreateVolumeOVAAnswer.java old mode 100644 new mode 100755 similarity index 73% rename from core/src/com/cloud/vm/VirtualDisk.java rename to api/src/com/cloud/agent/api/storage/CreateVolumeOVAAnswer.java index ad7bb43d40b..52a57dba7b2 --- a/core/src/com/cloud/vm/VirtualDisk.java +++ b/api/src/com/cloud/agent/api/storage/CreateVolumeOVAAnswer.java @@ -1,31 +1,26 @@ -// 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. -package com.cloud.vm; - -import com.cloud.storage.Storage; - -/** - * VirtualDisk describes the disks that are plugged into - * the virtual machine. - * - */ -public class VirtualDisk { - public Storage.ImageFormat format; - public String url; - public boolean bootable; - public long size; -} +// 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. +package com.cloud.agent.api.storage; + +import com.cloud.agent.api.Answer; + +public class CreateVolumeOVAAnswer extends Answer { + public CreateVolumeOVAAnswer(CreateVolumeOVACommand cmd, boolean result, String details) { + super(cmd, result, details); + } + +} diff --git a/api/src/com/cloud/agent/api/storage/CreateVolumeOVACommand.java b/api/src/com/cloud/agent/api/storage/CreateVolumeOVACommand.java new file mode 100755 index 00000000000..224b7c80d43 --- /dev/null +++ b/api/src/com/cloud/agent/api/storage/CreateVolumeOVACommand.java @@ -0,0 +1,60 @@ +// 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. +package com.cloud.agent.api.storage; + +import com.cloud.agent.api.Command; +import com.cloud.agent.api.to.StorageFilerTO; +import com.cloud.storage.StoragePool; + +public class CreateVolumeOVACommand extends Command { + String secUrl; + String volPath; + String volName; + StorageFilerTO pool; + + public CreateVolumeOVACommand() { + } + + public CreateVolumeOVACommand(String secUrl, String volPath, String volName, StoragePool pool, int wait) { + this.secUrl = secUrl; + this.volPath = volPath; + this.volName = volName; + this.pool = new StorageFilerTO(pool); + setWait(wait); + } + + @Override + public boolean executeInSequence() { + return true; + } + + public String getVolPath() { + return this.volPath; + } + + public String getVolName() { + return this.volName; + } + public String getSecondaryStorageUrl() { + return this.secUrl; + } + public StorageFilerTO getPool() { + return pool; + } +} + + diff --git a/server/src/com/cloud/maint/UpgradeManagerMBean.java b/api/src/com/cloud/agent/api/storage/PrepareOVAPackingAnswer.java old mode 100644 new mode 100755 similarity index 73% rename from server/src/com/cloud/maint/UpgradeManagerMBean.java rename to api/src/com/cloud/agent/api/storage/PrepareOVAPackingAnswer.java index 1c7cb310b18..923d952a137 --- a/server/src/com/cloud/maint/UpgradeManagerMBean.java +++ b/api/src/com/cloud/agent/api/storage/PrepareOVAPackingAnswer.java @@ -1,23 +1,26 @@ -// 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. -package com.cloud.maint; - -import com.cloud.utils.mgmt.ManagementBean; - -public interface UpgradeManagerMBean extends ManagementBean { - public String deployNewAgent(String location); -} +// 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. +package com.cloud.agent.api.storage; + +import com.cloud.agent.api.Answer; + +public class PrepareOVAPackingAnswer extends Answer { + public PrepareOVAPackingAnswer(PrepareOVAPackingCommand cmd, boolean result, String details) { + super(cmd, result, details); + } + +} diff --git a/core/src/com/cloud/storage/snapshot/SnapshotSchedule.java b/api/src/com/cloud/agent/api/storage/PrepareOVAPackingCommand.java old mode 100644 new mode 100755 similarity index 51% rename from core/src/com/cloud/storage/snapshot/SnapshotSchedule.java rename to api/src/com/cloud/agent/api/storage/PrepareOVAPackingCommand.java index 6f3d2ce5468..29fa26d0bd0 --- a/core/src/com/cloud/storage/snapshot/SnapshotSchedule.java +++ b/api/src/com/cloud/agent/api/storage/PrepareOVAPackingCommand.java @@ -1,46 +1,48 @@ -// 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. -package com.cloud.storage.snapshot; - -import org.apache.cloudstack.api.Identity; -import org.apache.cloudstack.api.InternalIdentity; - -import java.util.Date; - -public interface SnapshotSchedule extends InternalIdentity, Identity { - - Long getVolumeId(); - - Long getPolicyId(); - - void setPolicyId(long policyId); - - /** - * @return the scheduledTimestamp - */ - Date getScheduledTimestamp(); - - void setScheduledTimestamp(Date scheduledTimestamp); - - Long getAsyncJobId(); - - void setAsyncJobId(Long asyncJobId); - - Long getSnapshotId(); - - void setSnapshotId(Long snapshotId); -} +// 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. +package com.cloud.agent.api.storage; + +import com.cloud.agent.api.Command; + +public class PrepareOVAPackingCommand extends Command { + private String templatePath; + private String secUrl; + + public PrepareOVAPackingCommand() { + } + + public PrepareOVAPackingCommand(String secUrl, String templatePath) { + this.secUrl = secUrl; + this.templatePath = templatePath; + } + + @Override + public boolean executeInSequence() { + return true; + } + + public String getTemplatePath() { + return this.templatePath; + } + + public String getSecondaryStorageUrl() { + return this.secUrl; + } + +} + + \ No newline at end of file diff --git a/core/src/com/cloud/alert/AlertAdapter.java b/api/src/com/cloud/alert/AlertAdapter.java similarity index 100% rename from core/src/com/cloud/alert/AlertAdapter.java rename to api/src/com/cloud/alert/AlertAdapter.java diff --git a/api/src/com/cloud/async/AsyncJob.java b/api/src/com/cloud/async/AsyncJob.java index 866429b6547..ccdc40620b7 100644 --- a/api/src/com/cloud/async/AsyncJob.java +++ b/api/src/com/cloud/async/AsyncJob.java @@ -50,7 +50,10 @@ public interface AsyncJob extends Identity, InternalIdentity { AutoScaleVmProfile, AutoScaleVmGroup, GlobalLoadBalancerRule, - AffinityGroup + LoadBalancerRule, + AffinityGroup, + InternalLbVm, + DedicatedGuestVlanRange } long getUserId(); diff --git a/api/src/com/cloud/configuration/ConfigurationService.java b/api/src/com/cloud/configuration/ConfigurationService.java index 6937d0b64de..fdbd9d6bb0b 100644 --- a/api/src/com/cloud/configuration/ConfigurationService.java +++ b/api/src/com/cloud/configuration/ConfigurationService.java @@ -20,6 +20,11 @@ import java.util.List; import javax.naming.NamingException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.exception.ResourceAllocationException; import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd; import org.apache.cloudstack.api.command.admin.ldap.LDAPConfigCmd; import org.apache.cloudstack.api.command.admin.ldap.LDAPRemoveCmd; @@ -46,10 +51,6 @@ import org.apache.cloudstack.api.command.user.network.ListNetworkOfferingsCmd; import com.cloud.dc.DataCenter; import com.cloud.dc.Pod; import com.cloud.dc.Vlan; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Networks.TrafficType; import com.cloud.offering.DiskOffering; import com.cloud.offering.NetworkOffering; @@ -65,7 +66,7 @@ public interface ConfigurationService { * - the command wrapping name and value parameters * @return updated configuration object if successful */ - Configuration updateConfiguration(UpdateCfgCmd cmd); + Configuration updateConfiguration(UpdateCfgCmd cmd) throws InvalidParameterValueException; /** * Create a service offering through the API @@ -250,7 +251,7 @@ public interface ConfigurationService { NetworkOffering getNetworkOffering(long id); - Integer getNetworkOfferingNetworkRate(long networkOfferingId); + Integer getNetworkOfferingNetworkRate(long networkOfferingId, Long dataCenterId); Account getVlanAccount(long vlanId); @@ -262,7 +263,7 @@ public interface ConfigurationService { Long getDefaultPageSize(); - Integer getServiceOfferingNetworkRate(long serviceOfferingId); + Integer getServiceOfferingNetworkRate(long serviceOfferingId, Long dataCenterId); DiskOffering getDiskOffering(long diskOfferingId); diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index e7781fa795b..17a7f621229 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -16,6 +16,9 @@ // under the License. package com.cloud.event; +import java.util.HashMap; +import java.util.Map; + import com.cloud.configuration.Configuration; import com.cloud.dc.DataCenter; import com.cloud.dc.Pod; @@ -23,8 +26,18 @@ import com.cloud.dc.StorageNetworkIpRange; import com.cloud.dc.Vlan; import com.cloud.domain.Domain; import com.cloud.host.Host; -import com.cloud.network.*; -import com.cloud.network.as.*; +import com.cloud.network.GuestVlan; +import com.cloud.network.Network; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.PhysicalNetworkTrafficType; +import com.cloud.network.PublicIpAddress; +import com.cloud.network.RemoteAccessVpn; +import com.cloud.network.as.AutoScaleCounter; +import com.cloud.network.as.AutoScalePolicy; +import com.cloud.network.as.AutoScaleVmGroup; +import com.cloud.network.as.AutoScaleVmProfile; +import com.cloud.network.as.Condition; import com.cloud.network.router.VirtualRouter; import com.cloud.network.rules.LoadBalancer; import com.cloud.network.rules.StaticNat; @@ -43,9 +56,6 @@ import com.cloud.user.Account; import com.cloud.user.User; import com.cloud.vm.VirtualMachine; -import java.util.HashMap; -import java.util.Map; - public class EventTypes { //map of Event and corresponding entity for which Event is applicable @@ -400,6 +410,14 @@ public class EventTypes { public static final String EVENT_AFFINITY_GROUP_ASSIGN = "AG.ASSIGN"; public static final String EVENT_AFFINITY_GROUP_REMOVE = "AG.REMOVE"; public static final String EVENT_VM_AFFINITY_GROUP_UPDATE = "VM.AG.UPDATE"; + + public static final String EVENT_INTERNAL_LB_VM_START = "INTERNALLBVM.START"; + public static final String EVENT_INTERNAL_LB_VM_STOP = "INTERNALLBVM.STOP"; + + // Dedicated guest vlan range + public static final String EVENT_GUEST_VLAN_RANGE_DEDICATE = "GUESTVLANRANGE.DEDICATE"; + public static final String EVENT_DEDICATED_GUEST_VLAN_RANGE_RELEASE = "GUESTVLANRANGE.RELEASE"; + static { @@ -701,6 +719,9 @@ public class EventTypes { entityEventDetails.put(EVENT_AUTOSCALEVMGROUP_UPDATE, AutoScaleVmGroup.class.getName()); entityEventDetails.put(EVENT_AUTOSCALEVMGROUP_ENABLE, AutoScaleVmGroup.class.getName()); entityEventDetails.put(EVENT_AUTOSCALEVMGROUP_DISABLE, AutoScaleVmGroup.class.getName()); + + entityEventDetails.put(EVENT_GUEST_VLAN_RANGE_DEDICATE, GuestVlan.class.getName()); + entityEventDetails.put(EVENT_DEDICATED_GUEST_VLAN_RANGE_RELEASE, GuestVlan.class.getName()); } public static String getEntityForEvent (String eventName) { diff --git a/core/src/com/cloud/event/UsageEvent.java b/api/src/com/cloud/event/UsageEvent.java similarity index 100% rename from core/src/com/cloud/event/UsageEvent.java rename to api/src/com/cloud/event/UsageEvent.java diff --git a/core/src/com/cloud/exception/AgentControlChannelException.java b/api/src/com/cloud/exception/AgentControlChannelException.java similarity index 100% rename from core/src/com/cloud/exception/AgentControlChannelException.java rename to api/src/com/cloud/exception/AgentControlChannelException.java diff --git a/core/src/com/cloud/info/ConsoleProxyLoadInfo.java b/api/src/com/cloud/info/ConsoleProxyLoadInfo.java similarity index 100% rename from core/src/com/cloud/info/ConsoleProxyLoadInfo.java rename to api/src/com/cloud/info/ConsoleProxyLoadInfo.java diff --git a/core/src/com/cloud/info/RunningHostCountInfo.java b/api/src/com/cloud/info/RunningHostCountInfo.java similarity index 100% rename from core/src/com/cloud/info/RunningHostCountInfo.java rename to api/src/com/cloud/info/RunningHostCountInfo.java diff --git a/api/src/com/cloud/network/GuestVlan.java b/api/src/com/cloud/network/GuestVlan.java new file mode 100644 index 00000000000..a5173d87830 --- /dev/null +++ b/api/src/com/cloud/network/GuestVlan.java @@ -0,0 +1,31 @@ +// 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. +package com.cloud.network; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +public interface GuestVlan extends InternalIdentity, Identity { + + public long getId(); + + public long getAccountId(); + + public String getGuestVlanRange(); + + public long getPhysicalNetworkId(); +} diff --git a/api/src/com/cloud/network/IpAddress.java b/api/src/com/cloud/network/IpAddress.java index 71c9b4e0bf3..c48e8b97ca8 100644 --- a/api/src/com/cloud/network/IpAddress.java +++ b/api/src/com/cloud/network/IpAddress.java @@ -81,4 +81,7 @@ public interface IpAddress extends ControlledEntity, Identity, InternalIdentity Long getVpcId(); String getVmIp(); + + Long getNetworkId(); + } diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index f1b6f87cf8f..100f69e4b8a 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -16,18 +16,19 @@ // under the License. package com.cloud.network; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.Mode; import com.cloud.network.Networks.TrafficType; import com.cloud.utils.fsm.StateMachine2; import com.cloud.utils.fsm.StateObject; -import org.apache.cloudstack.acl.ControlledEntity; -import org.apache.cloudstack.api.Identity; -import org.apache.cloudstack.api.InternalIdentity; - -import java.net.URI; -import java.util.ArrayList; -import java.util.List; /** * owned by an account. @@ -50,7 +51,7 @@ public interface Network extends ControlledEntity, StateObject, I Capability.MultipleIps, Capability.TrafficStatistics, Capability.SupportedTrafficDirection, Capability.SupportedEgressProtocols); public static final Service Lb = new Service("Lb", Capability.SupportedLBAlgorithms, Capability.SupportedLBIsolation, Capability.SupportedProtocols, Capability.TrafficStatistics, Capability.LoadBalancingSupportedIps, - Capability.SupportedStickinessMethods, Capability.ElasticLb); + Capability.SupportedStickinessMethods, Capability.ElasticLb, Capability.LbSchemes); public static final Service UserData = new Service("UserData"); public static final Service SourceNat = new Service("SourceNat", Capability.SupportedSourceNatTypes, Capability.RedundantRouter); public static final Service StaticNat = new Service("StaticNat", Capability.ElasticIp); @@ -124,6 +125,7 @@ public interface Network extends ControlledEntity, StateObject, I public static final Provider None = new Provider("None", false); // NiciraNvp is not an "External" provider, otherwise we get in trouble with NetworkServiceImpl.providersConfiguredForExternalNetworking public static final Provider NiciraNvp = new Provider("NiciraNvp", false); + public static final Provider InternalLbVm = new Provider("InternalLbVm", false); public static final Provider CiscoVnmc = new Provider("CiscoVnmc", true); private String name; @@ -177,6 +179,7 @@ public interface Network extends ControlledEntity, StateObject, I public static final Capability SupportedTrafficDirection = new Capability("SupportedTrafficDirection"); public static final Capability SupportedEgressProtocols = new Capability("SupportedEgressProtocols"); public static final Capability HealthCheckPolicy = new Capability("HealthCheckPolicy"); + public static final Capability LbSchemes = new Capability("LbSchemes"); private String name; diff --git a/api/src/com/cloud/network/NetworkModel.java b/api/src/com/cloud/network/NetworkModel.java index 4d7d714a7ae..f84a8b0c76a 100644 --- a/api/src/com/cloud/network/NetworkModel.java +++ b/api/src/com/cloud/network/NetworkModel.java @@ -33,6 +33,7 @@ import com.cloud.network.Networks.TrafficType; import com.cloud.network.element.NetworkElement; import com.cloud.network.element.UserDataServiceProvider; import com.cloud.offering.NetworkOffering; +import com.cloud.offering.NetworkOffering.Detail; import com.cloud.user.Account; import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; @@ -181,7 +182,7 @@ public interface NetworkModel { /** * @return */ - String getDefaultNetworkDomain(); + String getDefaultNetworkDomain(long zoneId); /** * @param ntwkOffId @@ -263,4 +264,12 @@ public interface NetworkModel { boolean isProviderEnabledInZone(long zoneId, String provider); Nic getPlaceholderNicForRouter(Network network, Long podId); + + IpAddress getPublicIpAddress(String ipAddress, long zoneId); + + List getUsedIpsInNetwork(Network network); + + Map getNtwkOffDetails(long offId); + + Networks.IsolationType[] listNetworkIsolationMethods(); } \ No newline at end of file diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java index b832ccd8199..2b4982a7e11 100755 --- a/api/src/com/cloud/network/NetworkService.java +++ b/api/src/com/cloud/network/NetworkService.java @@ -18,6 +18,8 @@ package com.cloud.network; import java.util.List; +import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd; +import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd; import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; import org.apache.cloudstack.api.command.user.network.*; import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; @@ -27,6 +29,7 @@ import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.GuestVlan; import com.cloud.network.Network.Service; import com.cloud.network.Networks.TrafficType; import com.cloud.user.Account; @@ -112,6 +115,12 @@ public interface NetworkService { boolean deletePhysicalNetworkTrafficType(Long id); + GuestVlan dedicateGuestVlanRange(DedicateGuestVlanRangeCmd cmd); + + Pair, Integer> listDedicatedGuestVlanRanges(ListDedicatedGuestVlanRangesCmd cmd); + + boolean releaseDedicatedGuestVlanRange(Long dedicatedGuestVlanRangeId); + Pair, Integer> listTrafficTypes(Long physicalNetworkId); @@ -136,6 +145,7 @@ public interface NetworkService { ResourceAllocationException, ResourceUnavailableException, ConcurrentOperationException; /** + * * @param networkName * @param displayText * @param physicalNetworkId @@ -146,17 +156,18 @@ public interface NetworkService { * @param netmask * @param networkOwnerId * @param vpcId TODO + * @param sourceNat * @return * @throws InsufficientCapacityException * @throws ConcurrentOperationException * @throws ResourceAllocationException */ Network createPrivateNetwork(String networkName, String displayText, long physicalNetworkId, String vlan, - String startIp, String endIP, String gateway, String netmask, long networkOwnerId, Long vpcId) + String startIp, String endIP, String gateway, String netmask, long networkOwnerId, Long vpcId, Boolean sourceNat) throws ResourceAllocationException, ConcurrentOperationException, InsufficientCapacityException; /* Requests an IP address for the guest nic */ - String allocateSecondaryGuestIP(Account account, long zoneId, Long nicId, + NicSecondaryIp allocateSecondaryGuestIP(Account account, long zoneId, Long nicId, Long networkId, String ipaddress) throws InsufficientAddressCapacityException; boolean releaseSecondaryIpFromNic(long ipAddressId); diff --git a/server/src/com/cloud/network/UserIpv6Address.java b/api/src/com/cloud/network/UserIpv6Address.java similarity index 100% rename from server/src/com/cloud/network/UserIpv6Address.java rename to api/src/com/cloud/network/UserIpv6Address.java diff --git a/api/src/com/cloud/network/VirtualNetworkApplianceService.java b/api/src/com/cloud/network/VirtualNetworkApplianceService.java index 250ecb24e91..58eead2af07 100644 --- a/api/src/com/cloud/network/VirtualNetworkApplianceService.java +++ b/api/src/com/cloud/network/VirtualNetworkApplianceService.java @@ -63,5 +63,7 @@ public interface VirtualNetworkApplianceService { VirtualRouter startRouter(long id) throws ResourceUnavailableException, InsufficientCapacityException, ConcurrentOperationException; VirtualRouter destroyRouter(long routerId, Account caller, Long callerUserId) throws ResourceUnavailableException, ConcurrentOperationException; + + VirtualRouter findRouter(long routerId); } diff --git a/api/src/com/cloud/network/VirtualRouterProvider.java b/api/src/com/cloud/network/VirtualRouterProvider.java index ed6a2741ba0..f67686e6b08 100644 --- a/api/src/com/cloud/network/VirtualRouterProvider.java +++ b/api/src/com/cloud/network/VirtualRouterProvider.java @@ -23,7 +23,8 @@ public interface VirtualRouterProvider extends InternalIdentity, Identity { public enum VirtualRouterProviderType { VirtualRouter, ElasticLoadBalancerVm, - VPCVirtualRouter + VPCVirtualRouter, + InternalLbVm } public VirtualRouterProviderType getType(); diff --git a/api/src/com/cloud/network/lb/LoadBalancingRule.java b/api/src/com/cloud/network/lb/LoadBalancingRule.java index 3e11e8c7c2c..4b37782a8c7 100644 --- a/api/src/com/cloud/network/lb/LoadBalancingRule.java +++ b/api/src/com/cloud/network/lb/LoadBalancingRule.java @@ -25,111 +25,83 @@ import com.cloud.network.as.Condition; import com.cloud.network.as.Counter; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.LoadBalancer; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.utils.Pair; +import com.cloud.utils.net.Ip; -public class LoadBalancingRule implements FirewallRule, LoadBalancer { +public class LoadBalancingRule { private LoadBalancer lb; + private Ip sourceIp; private List destinations; private List stickinessPolicies; private LbAutoScaleVmGroup autoScaleVmGroup; private List healthCheckPolicies; public LoadBalancingRule(LoadBalancer lb, List destinations, - List stickinessPolicies, List healthCheckPolicies) { + List stickinessPolicies, List healthCheckPolicies, Ip sourceIp) { this.lb = lb; this.destinations = destinations; this.stickinessPolicies = stickinessPolicies; this.healthCheckPolicies = healthCheckPolicies; + this.sourceIp = sourceIp; } - @Override public long getId() { return lb.getId(); } - @Override - public long getAccountId() { - return lb.getAccountId(); - } - - @Override - public long getDomainId() { - return lb.getDomainId(); - } - - @Override public String getName() { return lb.getName(); } - @Override public String getDescription() { return lb.getDescription(); } - @Override public int getDefaultPortStart() { return lb.getDefaultPortStart(); } - @Override public int getDefaultPortEnd() { return lb.getDefaultPortEnd(); } - @Override public String getAlgorithm() { return lb.getAlgorithm(); } - @Override public String getUuid() { return lb.getUuid(); } - @Override public String getXid() { return lb.getXid(); } - @Override - public Long getSourceIpAddressId() { - return lb.getSourceIpAddressId(); - } - - @Override public Integer getSourcePortStart() { return lb.getSourcePortStart(); } - @Override public Integer getSourcePortEnd() { return lb.getSourcePortEnd(); } - @Override public String getProtocol() { return lb.getProtocol(); } - @Override - public Purpose getPurpose() { - return Purpose.LoadBalancing; + public FirewallRule.Purpose getPurpose() { + return FirewallRule.Purpose.LoadBalancing; } - @Override - public State getState() { + public FirewallRule.State getState() { return lb.getState(); } - @Override public long getNetworkId() { return lb.getNetworkId(); } - public LoadBalancer getLb() { - return lb; - } public void setDestinations(List destinations) { this.destinations = destinations; @@ -287,36 +259,6 @@ public class LoadBalancingRule implements FirewallRule, LoadBalancer { } } - @Override - public Integer getIcmpCode() { - return null; - } - - @Override - public Integer getIcmpType() { - return null; - } - - @Override - public List getSourceCidrList() { - return null; - } - - @Override - public Long getRelated() { - return null; - } - - @Override - public TrafficType getTrafficType() { - return null; - } - - @Override - public FirewallRuleType getType() { - return FirewallRuleType.User; - } - public LbAutoScaleVmGroup getAutoScaleVmGroup() { return autoScaleVmGroup; } @@ -473,4 +415,11 @@ public class LoadBalancingRule implements FirewallRule, LoadBalancer { } } + public Ip getSourceIp() { + return sourceIp; + } + + public Scheme getScheme() { + return lb.getScheme(); + } } diff --git a/api/src/com/cloud/network/lb/LoadBalancingRulesService.java b/api/src/com/cloud/network/lb/LoadBalancingRulesService.java index ed39bedaa6f..5fc41e34c34 100644 --- a/api/src/com/cloud/network/lb/LoadBalancingRulesService.java +++ b/api/src/com/cloud/network/lb/LoadBalancingRulesService.java @@ -17,10 +17,10 @@ package com.cloud.network.lb; import java.util.List; +import java.util.Map; import org.apache.cloudstack.api.command.user.loadbalancer.CreateLBHealthCheckPolicyCmd; import org.apache.cloudstack.api.command.user.loadbalancer.CreateLBStickinessPolicyCmd; -import org.apache.cloudstack.api.command.user.loadbalancer.CreateLoadBalancerRuleCmd; import org.apache.cloudstack.api.command.user.loadbalancer.ListLBHealthCheckPoliciesCmd; import org.apache.cloudstack.api.command.user.loadbalancer.ListLBStickinessPoliciesCmd; import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerRuleInstancesCmd; @@ -30,12 +30,13 @@ import org.apache.cloudstack.api.command.user.loadbalancer.UpdateLoadBalancerRul import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceUnavailableException; -import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; import com.cloud.network.rules.HealthCheckPolicy; import com.cloud.network.rules.LoadBalancer; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.rules.StickinessPolicy; import com.cloud.uservm.UserVm; import com.cloud.utils.Pair; +import com.cloud.utils.net.Ip; public interface LoadBalancingRulesService { @@ -49,7 +50,9 @@ public interface LoadBalancingRulesService { * @return the newly created LoadBalancerVO if successful, null otherwise * @throws InsufficientAddressCapacityException */ - LoadBalancer createLoadBalancerRule(CreateLoadBalancerRuleCmd lb, boolean openFirewall) throws NetworkRuleConflictException, InsufficientAddressCapacityException; + LoadBalancer createPublicLoadBalancerRule(String xId, String name, String description, + int srcPortStart, int srcPortEnd, int defPortStart, int defPortEnd, Long ipAddrId, String protocol, String algorithm, + long networkId, long lbOwnerId, boolean openFirewall) throws NetworkRuleConflictException, InsufficientAddressCapacityException; LoadBalancer updateLoadBalancerRule(UpdateLoadBalancerRuleCmd cmd); @@ -134,8 +137,9 @@ public interface LoadBalancingRulesService { List searchForLBHealthCheckPolicies(ListLBHealthCheckPoliciesCmd cmd); - List listByNetworkId(long networkId); - LoadBalancer findById(long LoadBalancer); - public void updateLBHealthChecks() throws ResourceUnavailableException; + + public void updateLBHealthChecks(Scheme scheme) throws ResourceUnavailableException; + + Map getLbInstances(long lbId); } diff --git a/api/src/com/cloud/network/router/VirtualRouter.java b/api/src/com/cloud/network/router/VirtualRouter.java index d7239dd3452..2311f489918 100755 --- a/api/src/com/cloud/network/router/VirtualRouter.java +++ b/api/src/com/cloud/network/router/VirtualRouter.java @@ -23,7 +23,7 @@ import com.cloud.vm.VirtualMachine; */ public interface VirtualRouter extends VirtualMachine { public enum Role { - VIRTUAL_ROUTER, LB + VIRTUAL_ROUTER, LB, INTERNAL_LB_VM } Role getRole(); boolean getIsRedundantRouter(); diff --git a/api/src/com/cloud/network/rules/LoadBalancer.java b/api/src/com/cloud/network/rules/LoadBalancer.java index ab6085aceb7..e6dadcaee97 100644 --- a/api/src/com/cloud/network/rules/LoadBalancer.java +++ b/api/src/com/cloud/network/rules/LoadBalancer.java @@ -19,16 +19,10 @@ package com.cloud.network.rules; /** * Definition for a LoadBalancer */ -public interface LoadBalancer extends FirewallRule { - - String getName(); - - String getDescription(); - +public interface LoadBalancer extends FirewallRule, LoadBalancerContainer { + int getDefaultPortStart(); int getDefaultPortEnd(); - String getAlgorithm(); - } diff --git a/core/src/com/cloud/storage/SecondaryStorage.java b/api/src/com/cloud/network/rules/LoadBalancerContainer.java similarity index 77% rename from core/src/com/cloud/storage/SecondaryStorage.java rename to api/src/com/cloud/network/rules/LoadBalancerContainer.java index dc01642767f..9d5ea595c9d 100644 --- a/core/src/com/cloud/storage/SecondaryStorage.java +++ b/api/src/com/cloud/network/rules/LoadBalancerContainer.java @@ -14,17 +14,20 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.storage; +package com.cloud.network.rules; -public interface SecondaryStorage { +public interface LoadBalancerContainer { - String getBackupPath(); - - String getTemplatePath(); - - String getIsoPath(); + public enum Scheme { + Public, Internal; + } - void createTemplate(); + String getName(); + + String getDescription(); - void destroyTemplate(); + String getAlgorithm(); + + Scheme getScheme(); + } diff --git a/api/src/com/cloud/network/rules/RulesService.java b/api/src/com/cloud/network/rules/RulesService.java index d47b38f9d43..45abd84a9ec 100644 --- a/api/src/com/cloud/network/rules/RulesService.java +++ b/api/src/com/cloud/network/rules/RulesService.java @@ -67,7 +67,7 @@ public interface RulesService { boolean applyPortForwardingRules(long ipAdddressId, Account caller) throws ResourceUnavailableException; - boolean enableStaticNat(long ipAddressId, long vmId, long networkId, boolean isSystemVm, String vmGuestIp) throws NetworkRuleConflictException, ResourceUnavailableException; + boolean enableStaticNat(long ipAddressId, long vmId, long networkId, String vmGuestIp) throws NetworkRuleConflictException, ResourceUnavailableException; PortForwardingRule getPortForwardigRule(long ruleId); diff --git a/api/src/com/cloud/network/security/SecurityGroupRules.java b/api/src/com/cloud/network/security/SecurityGroupRules.java index d255e46fde5..4dbafd62e98 100644 --- a/api/src/com/cloud/network/security/SecurityGroupRules.java +++ b/api/src/com/cloud/network/security/SecurityGroupRules.java @@ -31,6 +31,8 @@ public interface SecurityGroupRules extends InternalIdentity { Long getRuleId(); + String getRuleUuid(); + int getStartPort(); int getEndPort(); diff --git a/api/src/com/cloud/network/vpc/PrivateIp.java b/api/src/com/cloud/network/vpc/PrivateIp.java index 857fc226f30..eb6843339c5 100644 --- a/api/src/com/cloud/network/vpc/PrivateIp.java +++ b/api/src/com/cloud/network/vpc/PrivateIp.java @@ -44,5 +44,6 @@ public interface PrivateIp { String getMacAddress(); long getNetworkId(); + boolean getSourceNat(); } diff --git a/api/src/com/cloud/network/vpc/VpcGateway.java b/api/src/com/cloud/network/vpc/VpcGateway.java index 17566160ec3..e3530d08561 100644 --- a/api/src/com/cloud/network/vpc/VpcGateway.java +++ b/api/src/com/cloud/network/vpc/VpcGateway.java @@ -77,4 +77,8 @@ public interface VpcGateway extends Identity, ControlledEntity, InternalIdentity * @return */ State getState(); + /** + * @return + */ + boolean getSourceNat(); } diff --git a/api/src/com/cloud/network/vpc/VpcOffering.java b/api/src/com/cloud/network/vpc/VpcOffering.java index 3961d0aaba7..3ec81e693af 100644 --- a/api/src/com/cloud/network/vpc/VpcOffering.java +++ b/api/src/com/cloud/network/vpc/VpcOffering.java @@ -26,6 +26,7 @@ public interface VpcOffering extends InternalIdentity, Identity { } public static final String defaultVPCOfferingName = "Default VPC offering"; + public static final String defaultVPCNSOfferingName = "Default VPC offering with Netscaler"; /** * diff --git a/api/src/com/cloud/network/vpc/VpcService.java b/api/src/com/cloud/network/vpc/VpcService.java index 07ce89b0a3f..23e276489c2 100644 --- a/api/src/com/cloud/network/vpc/VpcService.java +++ b/api/src/com/cloud/network/vpc/VpcService.java @@ -163,6 +163,7 @@ public interface VpcService { /** * Persists VPC private gateway in the Database. * + * * @param vpcId TODO * @param physicalNetworkId * @param vlan @@ -170,13 +171,14 @@ public interface VpcService { * @param gateway * @param netmask * @param gatewayOwnerId + * @param isSourceNat * @return * @throws InsufficientCapacityException * @throws ConcurrentOperationException * @throws ResourceAllocationException */ public PrivateGateway createVpcPrivateGateway(long vpcId, Long physicalNetworkId, String vlan, String ipAddress, - String gateway, String netmask, long gatewayOwnerId) throws ResourceAllocationException, + String gateway, String netmask, long gatewayOwnerId, Boolean isSourceNat) throws ResourceAllocationException, ConcurrentOperationException, InsufficientCapacityException; /** diff --git a/api/src/com/cloud/offering/NetworkOffering.java b/api/src/com/cloud/offering/NetworkOffering.java index 6f0b9937854..72e2a2bbbab 100644 --- a/api/src/com/cloud/offering/NetworkOffering.java +++ b/api/src/com/cloud/offering/NetworkOffering.java @@ -16,6 +16,8 @@ // under the License. package com.cloud.offering; +import java.util.Map; + import org.apache.cloudstack.acl.InfrastructureEntity; import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; @@ -38,6 +40,11 @@ public interface NetworkOffering extends InfrastructureEntity, InternalIdentity, Disabled, Enabled } + + public enum Detail { + InternalLbProvider, + PublicLbProvider + } public final static String SystemPublicNetwork = "System-Public-Network"; public final static String SystemControlNetwork = "System-Control-Network"; @@ -116,5 +123,9 @@ public interface NetworkOffering extends InfrastructureEntity, InternalIdentity, boolean isInline(); boolean getIsPersistent(); + + boolean getInternalLb(); + + boolean getPublicLb(); } diff --git a/api/src/com/cloud/offering/ServiceOffering.java b/api/src/com/cloud/offering/ServiceOffering.java index d6c215f42f0..165369c5e9b 100755 --- a/api/src/com/cloud/offering/ServiceOffering.java +++ b/api/src/com/cloud/offering/ServiceOffering.java @@ -30,6 +30,7 @@ public interface ServiceOffering extends InfrastructureEntity, InternalIdentity, public static final String ssvmDefaultOffUniqueName = "Cloud.com-SecondaryStorage"; public static final String routerDefaultOffUniqueName = "Cloud.Com-SoftwareRouter"; public static final String elbVmDefaultOffUniqueName = "Cloud.Com-ElasticLBVm"; + public static final String internalLbVmDefaultOffUniqueName = "Cloud.Com-InternalLBVm"; public enum StorageType { local, diff --git a/core/src/com/cloud/resource/UnableDeleteHostException.java b/api/src/com/cloud/resource/UnableDeleteHostException.java similarity index 100% rename from core/src/com/cloud/resource/UnableDeleteHostException.java rename to api/src/com/cloud/resource/UnableDeleteHostException.java diff --git a/core/src/com/cloud/storage/StoragePoolDiscoverer.java b/api/src/com/cloud/storage/StoragePoolDiscoverer.java similarity index 73% rename from core/src/com/cloud/storage/StoragePoolDiscoverer.java rename to api/src/com/cloud/storage/StoragePoolDiscoverer.java index c7dd362a5c3..40a925dc73e 100644 --- a/core/src/com/cloud/storage/StoragePoolDiscoverer.java +++ b/api/src/com/cloud/storage/StoragePoolDiscoverer.java @@ -19,8 +19,6 @@ package com.cloud.storage; import java.net.URI; import java.util.Map; -import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; - import com.cloud.exception.DiscoveryException; import com.cloud.utils.component.Adapter; @@ -29,7 +27,7 @@ import com.cloud.utils.component.Adapter; */ public interface StoragePoolDiscoverer extends Adapter { - Map> find(long dcId, Long podId, URI uri, Map details) throws DiscoveryException; - - Map> find(long dcId, Long podId, URI uri, Map details, String username, String password) throws DiscoveryException; + Map> find(long dcId, Long podId, URI uri, Map details) throws DiscoveryException; + + Map> find(long dcId, Long podId, URI uri, Map details, String username, String password) throws DiscoveryException; } diff --git a/api/src/com/cloud/storage/snapshot/SnapshotSchedule.java b/api/src/com/cloud/storage/snapshot/SnapshotSchedule.java index 12c1445f0ad..6f3d2ce5468 100644 --- a/api/src/com/cloud/storage/snapshot/SnapshotSchedule.java +++ b/api/src/com/cloud/storage/snapshot/SnapshotSchedule.java @@ -16,12 +16,12 @@ // under the License. package com.cloud.storage.snapshot; +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + import java.util.Date; -public interface SnapshotSchedule { - long getId(); - - String getUuid(); +public interface SnapshotSchedule extends InternalIdentity, Identity { Long getVolumeId(); @@ -38,10 +38,9 @@ public interface SnapshotSchedule { Long getAsyncJobId(); - void setAsyncJobId(long asyncJobId); + void setAsyncJobId(Long asyncJobId); Long getSnapshotId(); void setSnapshotId(Long snapshotId); - } diff --git a/core/src/com/cloud/vm/ConsoleProxy.java b/api/src/com/cloud/vm/ConsoleProxy.java similarity index 100% rename from core/src/com/cloud/vm/ConsoleProxy.java rename to api/src/com/cloud/vm/ConsoleProxy.java diff --git a/core/src/com/cloud/vm/SecondaryStorageVm.java b/api/src/com/cloud/vm/SecondaryStorageVm.java similarity index 100% rename from core/src/com/cloud/vm/SecondaryStorageVm.java rename to api/src/com/cloud/vm/SecondaryStorageVm.java diff --git a/core/src/com/cloud/vm/SystemVm.java b/api/src/com/cloud/vm/SystemVm.java similarity index 100% rename from core/src/com/cloud/vm/SystemVm.java rename to api/src/com/cloud/vm/SystemVm.java diff --git a/api/src/com/cloud/vm/UserVmService.java b/api/src/com/cloud/vm/UserVmService.java index 2ccd19dd221..0a0660ad493 100755 --- a/api/src/com/cloud/vm/UserVmService.java +++ b/api/src/com/cloud/vm/UserVmService.java @@ -459,8 +459,8 @@ public interface UserVmService { VirtualMachine vmStorageMigration(Long vmId, StoragePool destPool); - UserVm restoreVM(RestoreVMCmd cmd); + UserVm restoreVM(RestoreVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException; - UserVm upgradeVirtualMachine(ScaleVMCmd scaleVMCmd) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException; + boolean upgradeVirtualMachine(ScaleVMCmd scaleVMCmd) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException; } diff --git a/api/src/com/cloud/vm/VirtualMachine.java b/api/src/com/cloud/vm/VirtualMachine.java index 8f807d450c7..ce9add62469 100755 --- a/api/src/com/cloud/vm/VirtualMachine.java +++ b/api/src/com/cloud/vm/VirtualMachine.java @@ -186,6 +186,7 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I SecondaryStorageVm, ElasticIpVm, ElasticLoadBalancerVm, + InternalLoadBalancerVm, /* * UserBareMetal is only used for selecting VirtualMachineGuru, there is no @@ -196,7 +197,7 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I public static boolean isSystemVM(VirtualMachine.Type vmtype) { if (DomainRouter.equals(vmtype) || ConsoleProxy.equals(vmtype) - || SecondaryStorageVm.equals(vmtype)) { + || SecondaryStorageVm.equals(vmtype) || InternalLoadBalancerVm.equals(vmtype)) { return true; } return false; diff --git a/core/src/com/cloud/vm/VirtualMachineName.java b/api/src/com/cloud/vm/VirtualMachineName.java similarity index 100% rename from core/src/com/cloud/vm/VirtualMachineName.java rename to api/src/com/cloud/vm/VirtualMachineName.java diff --git a/core/src/com/cloud/vm/VmDetailConstants.java b/api/src/com/cloud/vm/VmDetailConstants.java similarity index 100% rename from core/src/com/cloud/vm/VmDetailConstants.java rename to api/src/com/cloud/vm/VmDetailConstants.java diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 4eca1c46c8f..822791d723f 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -90,6 +90,7 @@ public class ApiConstants { public static final String GSLB_SERVICE_TYPE = "gslbservicetype"; public static final String GSLB_STICKY_SESSION_METHOD = "gslbstickysessionmethodname"; public static final String GUEST_CIDR_ADDRESS = "guestcidraddress"; + public static final String GUEST_VLAN_RANGE = "guestvlanrange"; public static final String HA_ENABLE = "haenable"; public static final String HOST_ID = "hostid"; public static final String HOST_NAME = "hostname"; @@ -226,6 +227,7 @@ public class ApiConstants { public static final String VIRTUAL_MACHINE_ID = "virtualmachineid"; public static final String VIRTUAL_MACHINE_IDS = "virtualmachineids"; public static final String VLAN = "vlan"; + public static final String VLAN_RANGE = "vlanrange"; public static final String REMOVE_VLAN="removevlan"; public static final String VLAN_ID = "vlanid"; public static final String VM_AVAILABLE = "vmavailable"; @@ -483,6 +485,12 @@ public class ApiConstants { public static final String HEALTHCHECK_HEALTHY_THRESHOLD = "healthythreshold"; public static final String HEALTHCHECK_UNHEALTHY_THRESHOLD = "unhealthythreshold"; public static final String HEALTHCHECK_PINGPATH = "pingpath"; + public static final String SOURCE_PORT = "sourceport"; + public static final String INSTANCE_PORT = "instanceport"; + public static final String SOURCE_IP = "sourceipaddress"; + public static final String SOURCE_IP_NETWORK_ID = "sourceipaddressnetworkid"; + public static final String SCHEME = "scheme"; + public static final String PROVIDER_TYPE = "providertype"; public static final String AFFINITY_GROUP_IDS = "affinitygroupids"; public static final String AFFINITY_GROUP_NAMES = "affinitygroupnames"; public static final String ASA_INSIDE_PORT_PROFILE = "insideportprofile"; diff --git a/api/src/org/apache/cloudstack/api/BaseCmd.java b/api/src/org/apache/cloudstack/api/BaseCmd.java index 40e8d0eed83..67089505724 100644 --- a/api/src/org/apache/cloudstack/api/BaseCmd.java +++ b/api/src/org/apache/cloudstack/api/BaseCmd.java @@ -29,6 +29,9 @@ import javax.inject.Inject; import org.apache.cloudstack.affinity.AffinityGroupService; import com.cloud.server.ResourceMetaDataService; +import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; +import org.apache.cloudstack.network.lb.ApplicationLoadBalancerService; +import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService; import org.apache.cloudstack.query.QueryService; import org.apache.cloudstack.usage.UsageService; import org.apache.log4j.Logger; @@ -43,6 +46,7 @@ import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.NetworkModel; import com.cloud.network.NetworkService; import com.cloud.network.NetworkUsageService; import com.cloud.network.StorageNetworkService; @@ -140,7 +144,12 @@ public abstract class BaseCmd { @Inject public VMSnapshotService _vmSnapshotService; @Inject public DataStoreProviderApiService dataStoreProviderApiService; @Inject public VpcProvisioningService _vpcProvSvc; + @Inject public ApplicationLoadBalancerService _newLbSvc; + @Inject public ApplicationLoadBalancerService _appLbService; @Inject public AffinityGroupService _affinityGroupService; + @Inject public InternalLoadBalancerElementService _internalLbElementSvc; + @Inject public InternalLoadBalancerVMService _internalLbSvc; + @Inject public NetworkModel _ntwkModel; public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException; diff --git a/api/src/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/org/apache/cloudstack/api/ResponseGenerator.java index a3aa9de0e3e..ab8f99583a8 100644 --- a/api/src/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/org/apache/cloudstack/api/ResponseGenerator.java @@ -19,6 +19,7 @@ package org.apache.cloudstack.api; import java.text.DecimalFormat; import java.util.EnumSet; import java.util.List; +import java.util.Map; import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroupResponse; @@ -26,6 +27,7 @@ import org.apache.cloudstack.api.ApiConstants.HostDetails; import org.apache.cloudstack.api.ApiConstants.VMDetails; import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd; import org.apache.cloudstack.api.response.AccountResponse; +import org.apache.cloudstack.api.response.ApplicationLoadBalancerResponse; import org.apache.cloudstack.api.response.AsyncJobResponse; import org.apache.cloudstack.api.response.AutoScalePolicyResponse; import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse; @@ -43,12 +45,17 @@ import org.apache.cloudstack.api.response.EventResponse; import org.apache.cloudstack.api.response.ExtractResponse; import org.apache.cloudstack.api.response.FirewallResponse; import org.apache.cloudstack.api.response.FirewallRuleResponse; +import org.apache.cloudstack.api.response.GlobalLoadBalancerResponse; import org.apache.cloudstack.api.response.GuestOSResponse; +import org.apache.cloudstack.api.response.GuestVlanRangeResponse; +import org.apache.cloudstack.api.response.HostForMigrationResponse; import org.apache.cloudstack.api.response.HostResponse; import org.apache.cloudstack.api.response.HypervisorCapabilitiesResponse; import org.apache.cloudstack.api.response.IPAddressResponse; import org.apache.cloudstack.api.response.InstanceGroupResponse; +import org.apache.cloudstack.api.response.InternalLoadBalancerElementResponse; import org.apache.cloudstack.api.response.IpForwardingRuleResponse; +import org.apache.cloudstack.api.response.IsolationMethodResponse; import org.apache.cloudstack.api.response.LBHealthCheckResponse; import org.apache.cloudstack.api.response.LBStickinessResponse; import org.apache.cloudstack.api.response.LDAPConfigResponse; @@ -82,6 +89,7 @@ import org.apache.cloudstack.api.response.SnapshotResponse; import org.apache.cloudstack.api.response.SnapshotScheduleResponse; import org.apache.cloudstack.api.response.StaticRouteResponse; import org.apache.cloudstack.api.response.StorageNetworkIpRangeResponse; +import org.apache.cloudstack.api.response.StoragePoolForMigrationResponse; import org.apache.cloudstack.api.response.StoragePoolResponse; import org.apache.cloudstack.api.response.SwiftResponse; import org.apache.cloudstack.api.response.SystemVmInstanceResponse; @@ -101,6 +109,7 @@ import org.apache.cloudstack.api.response.VpcOfferingResponse; import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.api.response.VpnUsersResponse; import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule; import org.apache.cloudstack.region.Region; import org.apache.cloudstack.usage.Usage; @@ -117,9 +126,25 @@ import com.cloud.domain.Domain; import com.cloud.event.Event; import com.cloud.host.Host; import com.cloud.hypervisor.HypervisorCapabilities; -import com.cloud.network.*; +import com.cloud.network.GuestVlan; +import com.cloud.network.IpAddress; +import com.cloud.network.Network; import com.cloud.network.Network.Service; -import com.cloud.network.as.*; +import com.cloud.network.Networks.IsolationType; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.PhysicalNetworkTrafficType; +import com.cloud.network.RemoteAccessVpn; +import com.cloud.network.Site2SiteCustomerGateway; +import com.cloud.network.Site2SiteVpnConnection; +import com.cloud.network.Site2SiteVpnGateway; +import com.cloud.network.VirtualRouterProvider; +import com.cloud.network.VpnUser; +import com.cloud.network.as.AutoScalePolicy; +import com.cloud.network.as.AutoScaleVmGroup; +import com.cloud.network.as.AutoScaleVmProfile; +import com.cloud.network.as.Condition; +import com.cloud.network.as.Counter; import com.cloud.network.router.VirtualRouter; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.HealthCheckPolicy; @@ -142,7 +167,12 @@ import com.cloud.projects.ProjectAccount; import com.cloud.projects.ProjectInvitation; import com.cloud.region.ha.GlobalLoadBalancerRule; import com.cloud.server.ResourceTag; -import com.cloud.storage.*; +import com.cloud.storage.GuestOS; +import com.cloud.storage.S3; +import com.cloud.storage.Snapshot; +import com.cloud.storage.StoragePool; +import com.cloud.storage.Swift; +import com.cloud.storage.Volume; import com.cloud.storage.snapshot.SnapshotPolicy; import com.cloud.storage.snapshot.SnapshotSchedule; import com.cloud.template.VirtualMachineTemplate; @@ -150,11 +180,12 @@ import com.cloud.user.Account; import com.cloud.user.User; import com.cloud.user.UserAccount; import com.cloud.uservm.UserVm; +import com.cloud.utils.net.Ip; import com.cloud.vm.InstanceGroup; import com.cloud.vm.Nic; -import com.cloud.vm.snapshot.VMSnapshot; +import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.VirtualMachine; -import org.apache.cloudstack.api.response.*; +import com.cloud.vm.snapshot.VMSnapshot; public interface ResponseGenerator { UserResponse createUserResponse(UserAccount user); @@ -197,6 +228,8 @@ public interface ResponseGenerator { IPAddressResponse createIPAddressResponse(IpAddress ipAddress); + GuestVlanRangeResponse createDedicatedGuestVlanRangeResponse(GuestVlan result); + GlobalLoadBalancerResponse createGlobalLoadBalancerResponse(GlobalLoadBalancerRule globalLoadBalancerRule); LoadBalancerResponse createLoadBalancerResponse(LoadBalancer loadBalancer); @@ -389,11 +422,16 @@ public interface ResponseGenerator { TrafficMonitorResponse createTrafficMonitorResponse(Host trafficMonitor); VMSnapshotResponse createVMSnapshotResponse(VMSnapshot vmSnapshot); - NicSecondaryIpResponse createSecondaryIPToNicResponse(String ip, - Long nicId, Long networkId); + NicSecondaryIpResponse createSecondaryIPToNicResponse(NicSecondaryIp result); public NicResponse createNicResponse(Nic result); + ApplicationLoadBalancerResponse createLoadBalancerContainerReponse(ApplicationLoadBalancerRule lb, Map lbInstances); + AffinityGroupResponse createAffinityGroupResponse(AffinityGroup group); Long getAffinityGroupId(String name, long entityOwnerId); + + InternalLoadBalancerElementResponse createInternalLbElementResponse(VirtualRouterProvider result); + + IsolationMethodResponse createIsolationMethodResponse(IsolationType method); } diff --git a/api/src/org/apache/cloudstack/api/command/admin/cluster/ListClustersCmd.java b/api/src/org/apache/cloudstack/api/command/admin/cluster/ListClustersCmd.java index 0417b187e38..f2dd3499b84 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/cluster/ListClustersCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/cluster/ListClustersCmd.java @@ -70,6 +70,9 @@ public class ListClustersCmd extends BaseListCmd { @Parameter(name=ApiConstants.MANAGED_STATE, type=CommandType.STRING, description="whether this cluster is managed by cloudstack") private String managedState; + @Parameter(name=ApiConstants.ZONE_TYPE, type=CommandType.STRING, description="the network type of the zone that the virtual machine belongs to") + private String zoneType; + @Parameter(name=ApiConstants.SHOW_CAPACITIES, type=CommandType.BOOLEAN, description="flag to display the capacity of the clusters") private Boolean showCapacities; @@ -114,7 +117,10 @@ public class ListClustersCmd extends BaseListCmd { this.managedState = managedstate; } - + public String getZoneType() { + return zoneType; + } + public Boolean getShowCapacities() { return showCapacities; } diff --git a/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java b/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java index 9f34405ffbd..a11904e90ce 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java @@ -45,11 +45,17 @@ public class ListCfgsByCmd extends BaseListCmd { @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "lists configuration by name") private String configName; - @Parameter(name=ApiConstants.SCOPE, type = CommandType.STRING, description = "scope(zone/cluster/pool/account) of the parameter that needs to be updated") - private String scope; + @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType=ZoneResponse.class, description="the ID of the Zone to update the parameter value for corresponding zone") + private Long zone_id; - @Parameter(name=ApiConstants.ID, type = CommandType.UUID, entityType = {ZoneResponse.class, ClusterResponse.class, StoragePoolResponse.class, AccountResponse.class}, description = "corresponding ID of the scope") - private Long id; + @Parameter(name=ApiConstants.CLUSTER_ID, type=CommandType.UUID, entityType=ClusterResponse.class, description="the ID of the Cluster to update the parameter value for corresponding cluster") + private Long cluster_id; + + @Parameter(name=ApiConstants.STORAGE_ID, type=CommandType.UUID, entityType=StoragePoolResponse.class, description="the ID of the Storage pool to update the parameter value for corresponding storage pool") + private Long storagepool_id; + + @Parameter(name=ApiConstants.ACCOUNT_ID, type=CommandType.UUID, entityType=AccountResponse.class, description="the ID of the Account to update the parameter value for corresponding account") + private Long account_id; // /////////////////////////////////////////////////// @@ -64,14 +70,21 @@ public class ListCfgsByCmd extends BaseListCmd { return configName; } - public String getScope() { - return scope; + public Long getZoneId() { + return zone_id; } - public Long getId() { - return id; + public Long getClusterId() { + return cluster_id; } + public Long getStoragepoolId() { + return storagepool_id; + } + + public Long getAccountId() { + return account_id; + } @Override public Long getPageSizeVal() { @@ -100,10 +113,17 @@ public class ListCfgsByCmd extends BaseListCmd { for (Configuration cfg : result.first()) { ConfigurationResponse cfgResponse = _responseGenerator.createConfigurationResponse(cfg); cfgResponse.setObjectName("configuration"); - if (scope != null) { - cfgResponse.setScope(scope); - } else { - cfgResponse.setScope("global"); + if(getZoneId() != null) { + cfgResponse.setScope("zone"); + } + if(getClusterId() != null) { + cfgResponse.setScope("cluster"); + } + if(getStoragepoolId() != null) { + cfgResponse.setScope("storagepool"); + } + if(getAccountId() != null) { + cfgResponse.setScope("account"); } configResponses.add(cfgResponse); } diff --git a/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java b/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java index 074c5a3b028..deb61d3741d 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java @@ -43,11 +43,17 @@ public class UpdateCfgCmd extends BaseCmd { @Parameter(name=ApiConstants.VALUE, type=CommandType.STRING, description="the value of the configuration", length=4095) private String value; - @Parameter(name=ApiConstants.SCOPE, type = CommandType.STRING, description = "scope(zone/cluster/pool/account) of the parameter that needs to be updated") - private String scope; + @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType=ZoneResponse.class, description="the ID of the Zone to update the parameter value for corresponding zone") + private Long zone_id; - @Parameter(name=ApiConstants.ID, type = CommandType.UUID, entityType = {ZoneResponse.class, ClusterResponse.class, StoragePoolResponse.class, AccountResponse.class}, description = "corresponding ID of the scope") - private Long id; + @Parameter(name=ApiConstants.CLUSTER_ID, type=CommandType.UUID, entityType=ClusterResponse.class, description="the ID of the Cluster to update the parameter value for corresponding cluster") + private Long cluster_id; + + @Parameter(name=ApiConstants.STORAGE_ID, type=CommandType.UUID, entityType=StoragePoolResponse.class, description="the ID of the Storage pool to update the parameter value for corresponding storage pool") + private Long storagepool_id; + + @Parameter(name=ApiConstants.ACCOUNT_ID, type=CommandType.UUID, entityType=AccountResponse.class, description="the ID of the Account to update the parameter value for corresponding account") + private Long account_id; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -61,12 +67,20 @@ public class UpdateCfgCmd extends BaseCmd { return value; } - public String getScope() { - return scope; + public Long getZoneId() { + return zone_id; } - public Long getId() { - return id; + public Long getClusterId() { + return cluster_id; + } + + public Long getStoragepoolId() { + return storagepool_id; + } + + public Long getAccountId() { + return account_id; } ///////////////////////////////////////////////////// @@ -89,12 +103,19 @@ public class UpdateCfgCmd extends BaseCmd { if (cfg != null) { ConfigurationResponse response = _responseGenerator.createConfigurationResponse(cfg); response.setResponseName(getCommandName()); - if (scope != null) { - response.setScope(scope); - response.setValue(value); - } else { - response.setScope("global"); + if(getZoneId() != null) { + response.setScope("zone"); } + if(getClusterId() != null) { + response.setScope("cluster"); + } + if(getStoragepoolId() != null) { + response.setScope("storagepool"); + } + if(getAccountId() != null) { + response.setScope("account"); + } + response.setValue(value); this.setResponseObject(response); } else { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update config"); diff --git a/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java index 5ec7cf3e10b..69c69802bfe 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java @@ -75,6 +75,9 @@ public class ListHostsCmd extends BaseListCmd { description="the Zone ID for the host") private Long zoneId; + @Parameter(name=ApiConstants.ZONE_TYPE, type=CommandType.STRING, description="the network type of the zone that the virtual machine belongs to") + private String zoneType; + @Parameter(name=ApiConstants.VIRTUAL_MACHINE_ID, type=CommandType.UUID, entityType = UserVmResponse.class, required=false, description="lists hosts in the same cluster as this VM and flag hosts with enough CPU/RAm to host this VM") private Long virtualMachineId; @@ -124,6 +127,10 @@ public class ListHostsCmd extends BaseListCmd { return zoneId; } + public String getZoneType() { + return zoneType; + } + public Long getVirtualMachineId() { return virtualMachineId; } diff --git a/api/src/org/apache/cloudstack/api/command/admin/internallb/ConfigureInternalLoadBalancerElementCmd.java b/api/src/org/apache/cloudstack/api/command/admin/internallb/ConfigureInternalLoadBalancerElementCmd.java new file mode 100644 index 00000000000..7c3d1e95e57 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/internallb/ConfigureInternalLoadBalancerElementCmd.java @@ -0,0 +1,114 @@ +// 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. + +package org.apache.cloudstack.api.command.admin.internallb; + +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.InternalLoadBalancerElementResponse; +import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; +import org.apache.log4j.Logger; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.VirtualRouterProvider; +import com.cloud.user.Account; +import com.cloud.user.UserContext; + +@APICommand(name = "configureInternalLoadBalancerElement", responseObject=InternalLoadBalancerElementResponse.class, + description="Configures an Internal Load Balancer element.", since="4.2.0") +public class ConfigureInternalLoadBalancerElementCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(ConfigureInternalLoadBalancerElementCmd.class.getName()); + private static final String s_name = "configureinternalloadbalancerelementresponse"; + + @Inject + private List _service; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType = InternalLoadBalancerElementResponse.class, + required=true, description="the ID of the internal lb provider") + private Long id; + + @Parameter(name=ApiConstants.ENABLED, type=CommandType.BOOLEAN, required=true, description="Enables/Disables the Internal Load Balancer element") + private Boolean enabled; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + + public Long getId() { + return id; + } + + public Boolean getEnabled() { + return enabled; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public String getEventType() { + return EventTypes.EVENT_NETWORK_ELEMENT_CONFIGURE; + } + + @Override + public String getEventDescription() { + return "configuring internal load balancer element: " + id; + } + + @Override + public void execute() throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException{ + s_logger.debug("hello alena"); + UserContext.current().setEventDetails("Internal load balancer element: " + id); + s_logger.debug("hello alena"); + VirtualRouterProvider result = _service.get(0).configureInternalLoadBalancerElement(getId(), getEnabled()); + s_logger.debug("hello alena"); + if (result != null){ + InternalLoadBalancerElementResponse routerResponse = _responseGenerator.createInternalLbElementResponse(result); + routerResponse.setResponseName(getCommandName()); + this.setResponseObject(routerResponse); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to configure the internal load balancer element"); + } + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/internallb/CreateInternalLoadBalancerElementCmd.java b/api/src/org/apache/cloudstack/api/command/admin/internallb/CreateInternalLoadBalancerElementCmd.java new file mode 100644 index 00000000000..2902f7ae18a --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/internallb/CreateInternalLoadBalancerElementCmd.java @@ -0,0 +1,116 @@ +// 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. +package org.apache.cloudstack.api.command.admin.internallb; + +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCreateCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.InternalLoadBalancerElementResponse; +import org.apache.cloudstack.api.response.ProviderResponse; +import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; +import org.apache.log4j.Logger; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.network.VirtualRouterProvider; +import com.cloud.user.Account; +import com.cloud.user.UserContext; + +@APICommand(name = "createInternalLoadBalancerElement", responseObject=InternalLoadBalancerElementResponse.class, description="Create an Internal Load Balancer element.",since="4.2.0") +public class CreateInternalLoadBalancerElementCmd extends BaseAsyncCreateCmd { + public static final Logger s_logger = Logger.getLogger(CreateInternalLoadBalancerElementCmd.class.getName()); + private static final String s_name = "createinternalloadbalancerelementresponse"; + + @Inject + private List _service; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.NETWORK_SERVICE_PROVIDER_ID, type=CommandType.UUID, entityType = ProviderResponse.class, required=true, description="the network service provider ID of the internal load balancer element") + private Long nspId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public void setNspId(Long nspId) { + this.nspId = nspId; + } + + public Long getNspId() { + return nspId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute(){ + UserContext.current().setEventDetails("Virtual router element Id: "+getEntityId()); + VirtualRouterProvider result = _service.get(0).getInternalLoadBalancerElement(getEntityId()); + if (result != null) { + InternalLoadBalancerElementResponse response = _responseGenerator.createInternalLbElementResponse(result); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + }else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add Virtual Router entity to physical network"); + } + } + + @Override + public void create() throws ResourceAllocationException { + VirtualRouterProvider result = _service.get(0).addInternalLoadBalancerElement(getNspId()); + if (result != null) { + setEntityId(result.getId()); + setEntityUuid(result.getUuid()); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add Internal Load Balancer entity to physical network"); + } + } + + @Override + public String getEventType() { + return EventTypes.EVENT_SERVICE_PROVIDER_CREATE; + } + + @Override + public String getEventDescription() { + return "Adding physical network element Internal Load Balancer: " + getEntityId(); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/internallb/ListInternalLBVMsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/internallb/ListInternalLBVMsCmd.java new file mode 100644 index 00000000000..e314b3245c7 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/internallb/ListInternalLBVMsCmd.java @@ -0,0 +1,151 @@ +// 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. +package org.apache.cloudstack.api.command.admin.internallb; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.DomainRouterResponse; +import org.apache.cloudstack.api.response.HostResponse; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.NetworkResponse; +import org.apache.cloudstack.api.response.PodResponse; +import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.cloudstack.api.response.VpcResponse; +import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.network.router.VirtualRouter.Role; + +@APICommand(name = "listInternalLoadBalancerVMs", description="List internal LB VMs.", responseObject=DomainRouterResponse.class) +public class ListInternalLBVMsCmd extends BaseListProjectAndAccountResourcesCmd { + public static final Logger s_logger = Logger.getLogger(ListInternalLBVMsCmd.class.getName()); + + private static final String s_name = "listinternallbvmssresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.HOST_ID, type=CommandType.UUID, entityType=HostResponse.class, + description="the host ID of the Internal LB VM") + private Long hostId; + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=UserVmResponse.class, + description="the ID of the Internal LB VM") + private Long id; + + @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, description="the name of the Internal LB VM") + private String routerName; + + @Parameter(name=ApiConstants.POD_ID, type=CommandType.UUID, entityType=PodResponse.class, + description="the Pod ID of the Internal LB VM") + private Long podId; + + @Parameter(name=ApiConstants.STATE, type=CommandType.STRING, description="the state of the Internal LB VM") + private String state; + + @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType=ZoneResponse.class, + description="the Zone ID of the Internal LB VM") + private Long zoneId; + + @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.UUID, entityType=NetworkResponse.class, + description="list by network id") + private Long networkId; + + @Parameter(name=ApiConstants.VPC_ID, type=CommandType.UUID, entityType=VpcResponse.class, + description="List Internal LB VMs by VPC") + private Long vpcId; + + @Parameter(name=ApiConstants.FOR_VPC, type=CommandType.BOOLEAN, description="if true is passed for this parameter, list only VPC Internal LB VMs") + private Boolean forVpc; + + @Parameter(name=ApiConstants.ZONE_TYPE, type=CommandType.STRING, description="the network type of the zone that the virtual machine belongs to") + private String zoneType; + + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getHostId() { + return hostId; + } + + public Long getId() { + return id; + } + + public String getRouterName() { + return routerName; + } + + public Long getPodId() { + return podId; + } + + public String getState() { + return state; + } + + public Long getZoneId() { + return zoneId; + } + + public Long getNetworkId() { + return networkId; + } + + public Long getVpcId() { + return vpcId; + } + + public Boolean getForVpc() { + return forVpc; + } + + public String getRole() { + return Role.INTERNAL_LB_VM.toString(); + } + + public String getZoneType() { + return zoneType; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.DomainRouter; + } + + @Override + public void execute(){ + ListResponse response = _queryService.searchForInternalLbVms(this); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/internallb/ListInternalLoadBalancerElementsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/internallb/ListInternalLoadBalancerElementsCmd.java new file mode 100644 index 00000000000..18536191995 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/internallb/ListInternalLoadBalancerElementsCmd.java @@ -0,0 +1,99 @@ +// 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. +package org.apache.cloudstack.api.command.admin.internallb; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.InternalLoadBalancerElementResponse; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.ProviderResponse; +import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; +import org.apache.log4j.Logger; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.VirtualRouterProvider; + +@APICommand(name = "listInternalLoadBalancerElements", description="Lists all available Internal Load Balancer elements.", + responseObject=InternalLoadBalancerElementResponse.class, since="4.2.0") +public class ListInternalLoadBalancerElementsCmd extends BaseListCmd { + public static final Logger s_logger = Logger.getLogger(ListInternalLoadBalancerElementsCmd.class.getName()); + private static final String _name = "listinternalloadbalancerelementsresponse"; + + @Inject + private InternalLoadBalancerElementService _service; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType = InternalLoadBalancerElementResponse.class, + description="list internal load balancer elements by id") + private Long id; + + @Parameter(name=ApiConstants.NSP_ID, type=CommandType.UUID, entityType = ProviderResponse.class, + description="list internal load balancer elements by network service provider id") + private Long nspId; + + @Parameter(name=ApiConstants.ENABLED, type=CommandType.BOOLEAN, description="list internal load balancer elements by enabled state") + private Boolean enabled; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + public Long getNspId() { + return nspId; + } + + public Boolean getEnabled() { + return enabled; + } + + @Override + public String getCommandName() { + return _name; + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { + List providers = _service.searchForInternalLoadBalancerElements(getId(), getNspId(), getEnabled()); + ListResponse response = new ListResponse(); + List providerResponses = new ArrayList(); + for (VirtualRouterProvider provider : providers) { + InternalLoadBalancerElementResponse providerResponse = _responseGenerator.createInternalLbElementResponse(provider); + providerResponses.add(providerResponse); + } + response.setResponses(providerResponses); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/internallb/StartInternalLBVMCmd.java b/api/src/org/apache/cloudstack/api/command/admin/internallb/StartInternalLBVMCmd.java new file mode 100644 index 00000000000..31d132b5c9c --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/internallb/StartInternalLBVMCmd.java @@ -0,0 +1,120 @@ +// 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. +package org.apache.cloudstack.api.command.admin.internallb; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.DomainRouterResponse; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.router.VirtualRouter; +import com.cloud.network.router.VirtualRouter.Role; +import com.cloud.user.UserContext; + +@APICommand(name = "startInternalLoadBalancerVM", responseObject=DomainRouterResponse.class, description="Starts an existing internal lb vm.") +public class StartInternalLBVMCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(StartInternalLBVMCmd.class.getName()); + private static final String s_name = "startinternallbvmresponse"; + + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=DomainRouterResponse.class, + required=true, description="the ID of the internal lb vm") + private Long id; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + public static String getResultObjectName() { + return "router"; + } + + @Override + public long getEntityOwnerId() { + VirtualRouter router = _entityMgr.findById(VirtualRouter.class, getId()); + if (router != null && router.getRole() == Role.INTERNAL_LB_VM) { + return router.getAccountId(); + } else { + throw new InvalidParameterValueException("Unable to find internal lb vm by id"); + } + } + + @Override + public String getEventType() { + return EventTypes.EVENT_INTERNAL_LB_VM_START; + } + + @Override + public String getEventDescription() { + return "starting internal lb vm: " + getId(); + } + + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.InternalLbVm; + } + + public Long getInstanceId() { + return getId(); + } + + @Override + public void execute() throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException{ + UserContext.current().setEventDetails("Internal Lb Vm Id: "+getId()); + VirtualRouter result = null; + VirtualRouter router = _routerService.findRouter(getId()); + if (router == null || router.getRole() != Role.INTERNAL_LB_VM) { + throw new InvalidParameterValueException("Can't find internal lb vm by id"); + } else { + result = _internalLbSvc.startInternalLbVm(getId(), UserContext.current().getCaller(), UserContext.current().getCallerUserId()); + } + + if (result != null){ + DomainRouterResponse routerResponse = _responseGenerator.createDomainRouterResponse(result); + routerResponse.setResponseName(getCommandName()); + this.setResponseObject(routerResponse); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to start internal lb vm"); + } + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/internallb/StopInternalLBVMCmd.java b/api/src/org/apache/cloudstack/api/command/admin/internallb/StopInternalLBVMCmd.java new file mode 100644 index 00000000000..f40db49b417 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/internallb/StopInternalLBVMCmd.java @@ -0,0 +1,123 @@ +// 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. +package org.apache.cloudstack.api.command.admin.internallb; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.DomainRouterResponse; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.router.VirtualRouter; +import com.cloud.network.router.VirtualRouter.Role; +import com.cloud.user.UserContext; + +@APICommand(name = "stopInternalLoadBalancerVM", description = "Stops an Internal LB vm.", responseObject = DomainRouterResponse.class) +public class StopInternalLBVMCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(StopInternalLBVMCmd.class.getName()); + private static final String s_name = "stopinternallbvmresponse"; + + // /////////////////////////////////////////////////// + // ////////////// API parameters ///////////////////// + // /////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = DomainRouterResponse.class, + required = true, description = "the ID of the internal lb vm") + private Long id; + + @Parameter(name = ApiConstants.FORCED, type = CommandType.BOOLEAN, required = false, description = "Force stop the VM. The caller knows the VM is stopped.") + private Boolean forced; + + // /////////////////////////////////////////////////// + // ///////////////// Accessors /////////////////////// + // /////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + // /////////////////////////////////////////////////// + // ///////////// API Implementation/////////////////// + // /////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + VirtualRouter vm = _entityMgr.findById(VirtualRouter.class, getId()); + if (vm != null && vm.getRole() == Role.INTERNAL_LB_VM) { + return vm.getAccountId(); + } else { + throw new InvalidParameterValueException("Unable to find internal lb vm by id"); + } + } + + @Override + public String getEventType() { + return EventTypes.EVENT_INTERNAL_LB_VM_STOP; + } + + @Override + public String getEventDescription() { + return "stopping internal lb vm: " + getId(); + } + + @Override + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.InternalLbVm; + } + + @Override + public Long getInstanceId() { + return getId(); + } + + public boolean isForced() { + return (forced != null) ? forced : false; + } + + @Override + public void execute() throws ConcurrentOperationException, ResourceUnavailableException { + UserContext.current().setEventDetails("Internal lb vm Id: "+getId()); + VirtualRouter result = null; + VirtualRouter vm = _routerService.findRouter(getId()); + if (vm == null || vm.getRole() != Role.INTERNAL_LB_VM) { + throw new InvalidParameterValueException("Can't find internal lb vm by id"); + } else { + result = _internalLbSvc.stopInternalLbVm(getId(), isForced(), UserContext.current().getCaller(), UserContext.current().getCallerUserId()); + } + + if (result != null) { + DomainRouterResponse response = _responseGenerator.createDomainRouterResponse(result); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to stop internal lb vm"); + } + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java index b48bf9e763e..6410715727c 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java @@ -31,7 +31,6 @@ import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.NetworkOfferingResponse; import org.apache.cloudstack.api.response.ServiceOfferingResponse; - import org.apache.log4j.Logger; import com.cloud.exception.InvalidParameterValueException; @@ -95,6 +94,10 @@ public class CreateNetworkOfferingCmd extends BaseCmd { @Parameter(name=ApiConstants.IS_PERSISTENT, type=CommandType.BOOLEAN, description="true if network offering supports persistent networks; defaulted to false if not specified") private Boolean isPersistent; + + @Parameter(name=ApiConstants.DETAILS, type=CommandType.MAP, since="4.2.0", description="Template details in key/value pairs." + + " Supported keys are internallbprovider/publiclbprovider with service provider as a value") + protected Map details; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -215,6 +218,16 @@ public class CreateNetworkOfferingCmd extends BaseCmd { return capabilityMap; } + + public Map getDetails() { + if (details == null || details.isEmpty()) { + return null; + } + + Collection paramsCollection = details.values(); + Map params = (Map) (paramsCollection.toArray())[0]; + return params; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/DedicateGuestVlanRangeCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/DedicateGuestVlanRangeCmd.java new file mode 100644 index 00000000000..ec1436065ba --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/network/DedicateGuestVlanRangeCmd.java @@ -0,0 +1,118 @@ +/* + * 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. + */ +package org.apache.cloudstack.api.command.admin.network; + +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.GuestVlan; +import com.cloud.user.Account; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.api.response.GuestVlanRangeResponse; +import org.apache.cloudstack.api.response.PhysicalNetworkResponse; +import org.apache.cloudstack.api.response.ProjectResponse; +import org.apache.log4j.Logger; + +@APICommand(name = "dedicateGuestVlanRange", description="Dedicates a guest vlan range to an account", responseObject=GuestVlanRangeResponse.class) +public class DedicateGuestVlanRangeCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(DedicateGuestVlanRangeCmd.class.getName()); + + private static final String s_name = "dedicateguestvlanrangeresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.VLAN_RANGE, type=CommandType.STRING, required=true, + description="guest vlan range to be dedicated") + private String vlan; + + @Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, required=true, + description="account who will own the VLAN") + private String accountName; + + @Parameter(name=ApiConstants.PROJECT_ID, type=CommandType.UUID, entityType = ProjectResponse.class, + description="project who will own the VLAN") + private Long projectId; + + @Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.UUID, entityType = DomainResponse.class, + required=true, description="domain ID of the account owning a VLAN") + private Long domainId; + + @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.UUID, entityType = PhysicalNetworkResponse.class, + required=true, description="physical network ID of the vlan") + private Long physicalNetworkId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public String getVlan() { + return vlan; + } + + public String getAccountName() { + return accountName; + } + + public Long getDomainId() { + return domainId; + } + + public Long getPhysicalNetworkId() { + return physicalNetworkId; + } + + public Long getProjectId() { + return projectId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() throws ResourceUnavailableException, ResourceAllocationException { + GuestVlan result = _networkService.dedicateGuestVlanRange(this); + if (result != null) { + GuestVlanRangeResponse response = _responseGenerator.createDedicatedGuestVlanRangeResponse(result); + response.setResponseName(getCommandName()); + response.setObjectName("dedicatedguestvlanrange"); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to dedicate guest vlan range"); + } + } + +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/ListDedicatedGuestVlanRangesCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/ListDedicatedGuestVlanRangesCmd.java new file mode 100644 index 00000000000..7f93efc780f --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/network/ListDedicatedGuestVlanRangesCmd.java @@ -0,0 +1,129 @@ +// 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. +package org.apache.cloudstack.api.command.admin.network; + +import com.cloud.network.GuestVlan; +import com.cloud.user.Account; +import com.cloud.utils.Pair; +import org.apache.cloudstack.api.*; +import org.apache.cloudstack.api.response.*; +import org.apache.log4j.Logger; + +import java.util.ArrayList; +import java.util.List; + + +@APICommand(name = "listDedicatedGuestVlanRanges", description="Lists dedicated guest vlan ranges", responseObject=GuestVlanRangeResponse.class) +public class ListDedicatedGuestVlanRangesCmd extends BaseListCmd { + public static final Logger s_logger = Logger.getLogger(ListDedicatedGuestVlanRangesCmd.class.getName()); + + private static final String s_name = "listdedicatedguestvlanrangesresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=GuestVlanRangeResponse.class, + description="list dedicated guest vlan ranges by id") + private Long id; + + @Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, description="the account with which the guest VLAN range is associated. Must be used with the domainId parameter.") + private String accountName; + + @Parameter(name=ApiConstants.PROJECT_ID, type=CommandType.UUID, entityType = ProjectResponse.class, + description="project who will own the guest VLAN range") + private Long projectId; + + @Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.UUID, entityType = DomainResponse.class, + description="the domain ID with which the guest VLAN range is associated. If used with the account parameter, returns all guest VLAN ranges for that account in the specified domain.") + private Long domainId; + + @Parameter(name=ApiConstants.GUEST_VLAN_RANGE, type=CommandType.STRING, description="the dedicated guest vlan range") + private String guestVlanRange; + + @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.UUID, entityType = PhysicalNetworkResponse.class, + description="physical network id of the guest VLAN range") + private Long physicalNetworkId; + + @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType = ZoneResponse.class, + description="zone of the guest VLAN range") + private Long zoneId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + public String getAccountName() { + return accountName; + } + + public Long getDomainId() { + return domainId; + } + + public Long getProjectId() { + return projectId; + } + + public String getGuestVlanRange() { + return guestVlanRange; + } + + public Long getPhysicalNetworkId() { + return physicalNetworkId; + } + + public Long getZoneId() { + return zoneId; + } + + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute(){ + Pair, Integer> vlans = _networkService.listDedicatedGuestVlanRanges(this); + ListResponse response = new ListResponse(); + List guestVlanResponses = new ArrayList(); + for (GuestVlan vlan : vlans.first()) { + GuestVlanRangeResponse guestVlanResponse = _responseGenerator.createDedicatedGuestVlanRangeResponse(vlan); + guestVlanResponse.setObjectName("dedicatedguestvlanrange"); + guestVlanResponses.add(guestVlanResponse); + } + + response.setResponses(guestVlanResponses, vlans.second()); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } + +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/ListNetworkIsolationMethodsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/ListNetworkIsolationMethodsCmd.java new file mode 100644 index 00000000000..7eef22a78b4 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/network/ListNetworkIsolationMethodsCmd.java @@ -0,0 +1,58 @@ +// 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. +package org.apache.cloudstack.api.command.admin.network; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.response.IsolationMethodResponse; +import org.apache.cloudstack.api.response.ListResponse; + +import com.cloud.network.Networks; + +@APICommand(name = "listNetworkIsolationMethods", description="Lists supported methods of network isolation", +responseObject=IsolationMethodResponse.class, since="4.2.0") +public class ListNetworkIsolationMethodsCmd extends BaseListCmd{ + + private static final String s_name = "listnetworkisolationmethodsresponse"; + + @Override + public void execute() { + Networks.IsolationType[] methods = _ntwkModel.listNetworkIsolationMethods(); + + ListResponse response = new ListResponse(); + List isolationResponses = new ArrayList(); + if (methods != null) { + for (Networks.IsolationType method : methods) { + IsolationMethodResponse isolationMethod = _responseGenerator.createIsolationMethodResponse(method); + isolationResponses.add(isolationMethod); + } + } + response.setResponses(isolationResponses, methods.length); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + + } + + @Override + public String getCommandName() { + return s_name; + } + +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/ReleaseDedicatedGuestVlanRangeCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/ReleaseDedicatedGuestVlanRangeCmd.java new file mode 100644 index 00000000000..76cb42dab19 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/network/ReleaseDedicatedGuestVlanRangeCmd.java @@ -0,0 +1,94 @@ +// 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. + +package org.apache.cloudstack.api.command.admin.network; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.exception.ResourceInUseException; +import com.cloud.user.Account; +import com.cloud.user.UserContext; +import org.apache.cloudstack.api.*; +import org.apache.cloudstack.api.response.CounterResponse; +import org.apache.cloudstack.api.response.GuestVlanRangeResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.log4j.Logger; + +@APICommand(name = "releaseDedicatedGuestVlanRange", description = "Releases a dedicated guest vlan range to the system", responseObject = SuccessResponse.class) +public class ReleaseDedicatedGuestVlanRangeCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(ReleaseDedicatedGuestVlanRangeCmd.class.getName()); + private static final String s_name = "releasededicatedguestvlanrangeresponse"; + + // /////////////////////////////////////////////////// + // ////////////// API parameters ///////////////////// + // /////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=GuestVlanRangeResponse.class, + required=true, description="the ID of the dedicated guest vlan range") + private Long id; + + // /////////////////////////////////////////////////// + // ///////////////// Accessors /////////////////////// + // /////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + public Long getId() { + return id; + } + + @Override + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.DedicatedGuestVlanRange; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public String getEventType() { + return EventTypes.EVENT_DEDICATED_GUEST_VLAN_RANGE_RELEASE; + } + + @Override + public String getEventDescription() { + return "Releasing a dedicated guest vlan range."; + } + + // /////////////////////////////////////////////////// + // ///////////// API Implementation/////////////////// + // /////////////////////////////////////////////////// + + + @Override + public void execute(){ + UserContext.current().setEventDetails("Dedicated guest vlan range Id: " + id); + boolean result = _networkService.releaseDedicatedGuestVlanRange(getId()); + if (result) { + SuccessResponse response = new SuccessResponse(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to release dedicated guest vlan range"); + } + } + +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/pod/ListPodsByCmd.java b/api/src/org/apache/cloudstack/api/command/admin/pod/ListPodsByCmd.java index 3dace4244ae..db233ae441e 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/pod/ListPodsByCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/pod/ListPodsByCmd.java @@ -55,6 +55,9 @@ public class ListPodsByCmd extends BaseListCmd { @Parameter(name=ApiConstants.ALLOCATION_STATE, type=CommandType.STRING, description="list pods by allocation state") private String allocationState; + @Parameter(name=ApiConstants.ZONE_TYPE, type=CommandType.STRING, description="the network type of the zone that the virtual machine belongs to") + private String zoneType; + @Parameter(name=ApiConstants.SHOW_CAPACITIES, type=CommandType.BOOLEAN, description="flag to display the capacity of the pods") private Boolean showCapacities; @@ -78,6 +81,10 @@ public class ListPodsByCmd extends BaseListCmd { return allocationState; } + public String getZoneType() { + return zoneType; + } + public Boolean getShowCapacities() { return showCapacities; } diff --git a/api/src/org/apache/cloudstack/api/command/admin/router/CreateVirtualRouterElementCmd.java b/api/src/org/apache/cloudstack/api/command/admin/router/CreateVirtualRouterElementCmd.java index 39fac136233..b3fca5addf1 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/router/CreateVirtualRouterElementCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/router/CreateVirtualRouterElementCmd.java @@ -31,6 +31,7 @@ import org.apache.cloudstack.api.response.VirtualRouterProviderResponse; import org.apache.log4j.Logger; import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceAllocationException; import com.cloud.network.VirtualRouterProvider; import com.cloud.network.VirtualRouterProvider.VirtualRouterProviderType; @@ -52,6 +53,9 @@ public class CreateVirtualRouterElementCmd extends BaseAsyncCreateCmd { @Parameter(name=ApiConstants.NETWORK_SERVICE_PROVIDER_ID, type=CommandType.UUID, entityType = ProviderResponse.class, required=true, description="the network service provider ID of the virtual router element") private Long nspId; + + @Parameter(name=ApiConstants.PROVIDER_TYPE, type=CommandType.UUID, entityType = ProviderResponse.class, description="The provider type. Supported types are VirtualRouter (default) and VPCVirtualRouter") + private String providerType; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -61,16 +65,27 @@ public class CreateVirtualRouterElementCmd extends BaseAsyncCreateCmd { this.nspId = nspId; } - - public Long getNspId() { return nspId; } + + public VirtualRouterProviderType getProviderType() { + if (providerType != null) { + if (providerType.equalsIgnoreCase(VirtualRouterProviderType.VirtualRouter.toString())) { + return VirtualRouterProviderType.VirtualRouter; + } else if (providerType.equalsIgnoreCase(VirtualRouterProviderType.VPCVirtualRouter.toString())) { + return VirtualRouterProviderType.VPCVirtualRouter; + } else throw new InvalidParameterValueException("Invalid providerType specified"); + } + return VirtualRouterProviderType.VirtualRouter; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// + + @Override public String getCommandName() { return s_name; @@ -96,7 +111,7 @@ public class CreateVirtualRouterElementCmd extends BaseAsyncCreateCmd { @Override public void create() throws ResourceAllocationException { - VirtualRouterProvider result = _service.get(0).addElement(getNspId(), VirtualRouterProviderType.VirtualRouter); + VirtualRouterProvider result = _service.get(0).addElement(getNspId(), getProviderType()); if (result != null) { setEntityId(result.getId()); setEntityUuid(result.getUuid()); diff --git a/api/src/org/apache/cloudstack/api/command/admin/router/ListRoutersCmd.java b/api/src/org/apache/cloudstack/api/command/admin/router/ListRoutersCmd.java index d2b26c0ac8f..78c3554ae73 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/router/ListRoutersCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/router/ListRoutersCmd.java @@ -31,6 +31,7 @@ import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.log4j.Logger; import com.cloud.async.AsyncJob; +import com.cloud.network.router.VirtualRouter.Role; @APICommand(name = "listRouters", description="List routers.", responseObject=DomainRouterResponse.class) public class ListRoutersCmd extends BaseListProjectAndAccountResourcesCmd { @@ -64,6 +65,9 @@ public class ListRoutersCmd extends BaseListProjectAndAccountResourcesCmd { description="the Zone ID of the router") private Long zoneId; + @Parameter(name=ApiConstants.ZONE_TYPE, type=CommandType.STRING, description="the network type of the zone that the virtual machine belongs to") + private String zoneType; + @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.UUID, entityType=NetworkResponse.class, description="list by network id") private Long networkId; @@ -74,7 +78,7 @@ public class ListRoutersCmd extends BaseListProjectAndAccountResourcesCmd { @Parameter(name=ApiConstants.FOR_VPC, type=CommandType.BOOLEAN, description="if true is passed for this parameter, list only VPC routers") private Boolean forVpc; - + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -103,6 +107,10 @@ public class ListRoutersCmd extends BaseListProjectAndAccountResourcesCmd { return zoneId; } + public String getZoneType() { + return zoneType; + } + public Long getNetworkId() { return networkId; } @@ -114,6 +122,10 @@ public class ListRoutersCmd extends BaseListProjectAndAccountResourcesCmd { public Boolean getForVpc() { return forVpc; } + + public String getRole() { + return Role.VIRTUAL_ROUTER.toString(); + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/admin/router/StartRouterCmd.java b/api/src/org/apache/cloudstack/api/command/admin/router/StartRouterCmd.java index 1d3930b6b63..ad0461e0eb7 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/router/StartRouterCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/router/StartRouterCmd.java @@ -29,8 +29,10 @@ import com.cloud.async.AsyncJob; import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.router.VirtualRouter; +import com.cloud.network.router.VirtualRouter.Role; import com.cloud.user.Account; import com.cloud.user.UserContext; @@ -100,7 +102,13 @@ public class StartRouterCmd extends BaseAsyncCmd { @Override public void execute() throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException{ UserContext.current().setEventDetails("Router Id: "+getId()); - VirtualRouter result = _routerService.startRouter(id); + VirtualRouter result = null; + VirtualRouter router = _routerService.findRouter(getId()); + if (router == null || router.getRole() != Role.VIRTUAL_ROUTER) { + throw new InvalidParameterValueException("Can't find router by id"); + } else { + result = _routerService.startRouter(getId()); + } if (result != null){ DomainRouterResponse routerResponse = _responseGenerator.createDomainRouterResponse(result); routerResponse.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/admin/router/StopRouterCmd.java b/api/src/org/apache/cloudstack/api/command/admin/router/StopRouterCmd.java index 60dd9386c75..94473cf9ffc 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/router/StopRouterCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/router/StopRouterCmd.java @@ -28,8 +28,10 @@ import org.apache.log4j.Logger; import com.cloud.async.AsyncJob; import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.router.VirtualRouter; +import com.cloud.network.router.VirtualRouter.Role; import com.cloud.user.Account; import com.cloud.user.UserContext; @@ -103,7 +105,14 @@ public class StopRouterCmd extends BaseAsyncCmd { @Override public void execute() throws ConcurrentOperationException, ResourceUnavailableException { UserContext.current().setEventDetails("Router Id: "+getId()); - VirtualRouter result = _routerService.stopRouter(getId(), isForced()); + VirtualRouter result = null; + VirtualRouter router = _routerService.findRouter(getId()); + if (router == null || router.getRole() != Role.VIRTUAL_ROUTER) { + throw new InvalidParameterValueException("Can't find router by id"); + } else { + result = _routerService.stopRouter(getId(), isForced()); + } + if (result != null) { DomainRouterResponse response = _responseGenerator.createDomainRouterResponse(result); response.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/admin/systemvm/ListSystemVMsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/systemvm/ListSystemVMsCmd.java index f230a20d513..b5a0f3fdd4d 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/systemvm/ListSystemVMsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/systemvm/ListSystemVMsCmd.java @@ -74,6 +74,9 @@ public class ListSystemVMsCmd extends BaseListCmd { description="the storage ID where vm's volumes belong to", since="3.0.1") private Long storageId; + @Parameter(name=ApiConstants.ZONE_TYPE, type=CommandType.STRING, description="the network type of the zone that the virtual machine belongs to") + private String zoneType; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -110,6 +113,10 @@ public class ListSystemVMsCmd extends BaseListCmd { return storageId; } + public String getZoneType() { + return zoneType; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/admin/vpc/CreatePrivateGatewayCmd.java b/api/src/org/apache/cloudstack/api/command/admin/vpc/CreatePrivateGatewayCmd.java index 9fd736f8543..20556957ff2 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/vpc/CreatePrivateGatewayCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/vpc/CreatePrivateGatewayCmd.java @@ -69,6 +69,11 @@ public class CreatePrivateGatewayCmd extends BaseAsyncCreateCmd { required=true, description="the VPC network belongs to") private Long vpcId; + @Parameter(name=ApiConstants.SOURCE_NAT_SUPPORTED, type=CommandType.BOOLEAN, required=false, + description="source NAT supported value. Default value false. If 'true' source NAT is enabled on the private gateway" + + " 'false': sourcenat is not supported") + private Boolean isSourceNat; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -97,6 +102,13 @@ public class CreatePrivateGatewayCmd extends BaseAsyncCreateCmd { return vpcId; } + public Boolean getIsSourceNat () { + if (isSourceNat == null) { + return false; + } + return true; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -111,7 +123,7 @@ public class CreatePrivateGatewayCmd extends BaseAsyncCreateCmd { PrivateGateway result = null; try { result = _vpcService.createVpcPrivateGateway(getVpcId(), getPhysicalNetworkId(), - getVlan(), getStartIp(), getGateway(), getNetmask(), getEntityOwnerId()); + getVlan(), getStartIp(), getGateway(), getNetmask(), getEntityOwnerId(), getIsSourceNat()); } catch (InsufficientCapacityException ex){ s_logger.info(ex); s_logger.trace(ex); diff --git a/api/src/org/apache/cloudstack/api/command/user/iso/ListIsosCmd.java b/api/src/org/apache/cloudstack/api/command/user/iso/ListIsosCmd.java index 3219601156e..f872c120074 100644 --- a/api/src/org/apache/cloudstack/api/command/user/iso/ListIsosCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/iso/ListIsosCmd.java @@ -78,6 +78,9 @@ public class ListIsosCmd extends BaseListTaggedResourcesCmd { description="the ID of the zone") private Long zoneId; + @Parameter(name=ApiConstants.ZONE_TYPE, type=CommandType.STRING, description="the network type of the zone that the virtual machine belongs to") + private String zoneType; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -115,6 +118,10 @@ public class ListIsosCmd extends BaseListTaggedResourcesCmd { return zoneId; } + public String getZoneType() { + return zoneType; + } + public boolean listInReadyState() { Account account = UserContext.current().getCaller(); // It is account specific if account is admin type and domainId and accountName are not null diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateApplicationLoadBalancerCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateApplicationLoadBalancerCmd.java new file mode 100644 index 00000000000..17ae959aa6e --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateApplicationLoadBalancerCmd.java @@ -0,0 +1,218 @@ +// 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. +package org.apache.cloudstack.api.command.user.loadbalancer; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCreateCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ApplicationLoadBalancerResponse; +import org.apache.cloudstack.api.response.NetworkResponse; +import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapcityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Network; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.user.UserContext; +import com.cloud.utils.net.NetUtils; + +@APICommand(name = "createLoadBalancer", description="Creates a Load Balancer", responseObject=ApplicationLoadBalancerResponse.class, since="4.2.0") +public class CreateApplicationLoadBalancerCmd extends BaseAsyncCreateCmd { + public static final Logger s_logger = Logger.getLogger(CreateApplicationLoadBalancerCmd.class.getName()); + + private static final String s_name = "createloadbalancerresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, required=true, description="name of the Load Balancer") + private String loadBalancerName; + + @Parameter(name=ApiConstants.DESCRIPTION, type=CommandType.STRING, description="the description of the Load Balancer", length=4096) + private String description; + + @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.UUID, required=true, entityType = NetworkResponse.class, + description="The guest network the Load Balancer will be created for") + private Long networkId; + + @Parameter(name=ApiConstants.SOURCE_PORT, type=CommandType.INTEGER, required=true, description="the source port the network traffic will be load balanced from") + private Integer sourcePort; + + @Parameter(name=ApiConstants.ALGORITHM, type=CommandType.STRING, required=true, description="load balancer algorithm (source, roundrobin, leastconn)") + private String algorithm; + + @Parameter(name=ApiConstants.INSTANCE_PORT, type=CommandType.INTEGER, required=true, description="the TCP port of the virtual machine where the network traffic will be load balanced to") + private Integer instancePort; + + @Parameter(name=ApiConstants.SOURCE_IP, type=CommandType.STRING, description="the source ip address the network traffic will be load balanced from") + private String sourceIp; + + @Parameter(name=ApiConstants.SOURCE_IP_NETWORK_ID, type=CommandType.UUID, entityType = NetworkResponse.class, required=true, + description="the network id of the source ip address") + private Long sourceIpNetworkId; + + @Parameter(name=ApiConstants.SCHEME, type=CommandType.STRING, required=true, description="the load balancer scheme. Supported value in this release is Internal") + private String scheme; + + + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public String getAlgorithm() { + return algorithm; + } + + public String getDescription() { + return description; + } + + public String getLoadBalancerName() { + return loadBalancerName; + } + + public Integer getPrivatePort() { + return instancePort; + } + + public long getNetworkId() { + return networkId; + } + + public String getName() { + return loadBalancerName; + } + + public Integer getSourcePort() { + return sourcePort.intValue(); + } + + public String getProtocol() { + return NetUtils.TCP_PROTO; + } + + public long getAccountId() { + //get account info from the network object + Network ntwk = _networkService.getNetwork(networkId); + if (ntwk == null) { + throw new InvalidParameterValueException("Invalid network id specified"); + } + + return ntwk.getAccountId(); + + } + + public int getInstancePort() { + return instancePort.intValue(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_LOAD_BALANCER_CREATE; + } + + @Override + public String getEventDescription() { + return "creating load balancer: " + getName() + " account: " + getAccountId(); + + } + + @Override + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.LoadBalancerRule; + } + + public String getSourceIp() { + return sourceIp; + } + + public long getSourceIpNetworkId() { + return sourceIpNetworkId; + } + + public Scheme getScheme() { + if (scheme.equalsIgnoreCase(Scheme.Internal.toString())) { + return Scheme.Internal; + } else { + throw new InvalidParameterValueException("Invalid value for scheme. Supported value is Internal"); + } + } + + @Override + public long getEntityOwnerId() { + return getAccountId(); + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + @Override + public String getCommandName() { + return s_name; + } + + @Override + public void execute() throws ResourceAllocationException, ResourceUnavailableException { + ApplicationLoadBalancerRule rule = null; + try { + UserContext.current().setEventDetails("Load Balancer Id: " + getEntityId()); + // State might be different after the rule is applied, so get new object here + rule = _entityMgr.findById(ApplicationLoadBalancerRule.class, getEntityId()); + ApplicationLoadBalancerResponse lbResponse = _responseGenerator.createLoadBalancerContainerReponse(rule, _lbService.getLbInstances(getEntityId())); + setResponseObject(lbResponse); + lbResponse.setResponseName(getCommandName()); + } catch (Exception ex) { + s_logger.warn("Failed to create Load Balancer due to exception ", ex); + } finally { + if (rule == null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create Load Balancer"); + } + } + } + + @Override + public void create() { + try { + + ApplicationLoadBalancerRule result = _appLbService.createApplicationLoadBalancer(getName(), getDescription(), getScheme(), + getSourceIpNetworkId(), getSourceIp(), getSourcePort(), getInstancePort(), getAlgorithm(), getNetworkId(), getEntityOwnerId()); + this.setEntityId(result.getId()); + this.setEntityUuid(result.getUuid()); + }catch (NetworkRuleConflictException e) { + s_logger.warn("Exception: ", e); + throw new ServerApiException(ApiErrorCode.NETWORK_RULE_CONFLICT_ERROR, e.getMessage()); + } catch (InsufficientAddressCapacityException e) { + s_logger.warn("Exception: ", e); + throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, e.getMessage()); + } catch (InsufficientVirtualNetworkCapcityException e) { + s_logger.warn("Exception: ", e); + throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, e.getMessage()); + } + } +} + diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java index 5f1d97b2803..f6cc1f130bd 100644 --- a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java @@ -148,7 +148,7 @@ public class CreateLoadBalancerRuleCmd extends BaseAsyncCreateCmd /*implements } - public Long getNetworkId() { + public long getNetworkId() { if (networkId != null) { return networkId; } @@ -278,7 +278,9 @@ public class CreateLoadBalancerRuleCmd extends BaseAsyncCreateCmd /*implements throw new InvalidParameterValueException("Parameter cidrList is deprecated; if you need to open firewall rule for the specific cidr, please refer to createFirewallRule command"); } try { - LoadBalancer result = _lbService.createLoadBalancerRule(this, getOpenFirewall()); + LoadBalancer result = _lbService.createPublicLoadBalancerRule(getXid(), getName(), getDescription(), + getSourcePortStart(), getSourcePortEnd(), getDefaultPortStart(), getDefaultPortEnd(), getSourceIpAddressId(), getProtocol(), getAlgorithm(), + getNetworkId(), getEntityOwnerId(), getOpenFirewall()); this.setEntityId(result.getId()); this.setEntityUuid(result.getUuid()); } catch (NetworkRuleConflictException e) { diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/DeleteApplicationLoadBalancerCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/DeleteApplicationLoadBalancerCmd.java new file mode 100644 index 00000000000..bc6cd09526c --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/DeleteApplicationLoadBalancerCmd.java @@ -0,0 +1,116 @@ +// 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. +package org.apache.cloudstack.api.command.user.loadbalancer; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.FirewallRuleResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.user.UserContext; + +@APICommand(name = "deleteLoadBalancer", description="Deletes a load balancer", responseObject=SuccessResponse.class, since="4.2.0") +public class DeleteApplicationLoadBalancerCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(DeleteApplicationLoadBalancerCmd.class.getName()); + private static final String s_name = "deleteloadbalancerresponse"; + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType = FirewallRuleResponse.class, + required=true, description="the ID of the Load Balancer") + private Long id; + + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + ApplicationLoadBalancerRule lb = _entityMgr.findById(ApplicationLoadBalancerRule.class, getId()); + if (lb != null) { + return lb.getAccountId(); + } else { + throw new InvalidParameterValueException("Can't find load balancer by id specified"); + } + } + + @Override + public String getEventType() { + return EventTypes.EVENT_LOAD_BALANCER_DELETE; + } + + @Override + public String getEventDescription() { + return "deleting load balancer: " + getId(); + } + + @Override + public void execute(){ + UserContext.current().setEventDetails("Load balancer Id: " + getId()); + boolean result = _appLbService.deleteApplicationLoadBalancer(getId()); + + if (result) { + SuccessResponse response = new SuccessResponse(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete load balancer"); + } + } + + @Override + public String getSyncObjType() { + return BaseAsyncCmd.networkSyncObject; + } + + @Override + public Long getSyncObjId() { + ApplicationLoadBalancerRule lb = _appLbService.getApplicationLoadBalancer(id); + if(lb == null){ + throw new InvalidParameterValueException("Unable to find load balancer by id "); + } + return lb.getNetworkId(); + } + + @Override + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.FirewallRule; + } +} diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/ListApplicationLoadBalancersCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/ListApplicationLoadBalancersCmd.java new file mode 100644 index 00000000000..8e5df31ed29 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/ListApplicationLoadBalancersCmd.java @@ -0,0 +1,131 @@ +// 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. +package org.apache.cloudstack.api.command.user.loadbalancer; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseListTaggedResourcesCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.ApplicationLoadBalancerResponse; +import org.apache.cloudstack.api.response.FirewallRuleResponse; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.NetworkResponse; +import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule; +import org.apache.log4j.Logger; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.utils.Pair; + +@APICommand(name = "listLoadBalancers", description = "Lists Load Balancers", responseObject = ApplicationLoadBalancerResponse.class, since="4.2.0") +public class ListApplicationLoadBalancersCmd extends BaseListTaggedResourcesCmd { + public static final Logger s_logger = Logger.getLogger(ListApplicationLoadBalancersCmd.class.getName()); + + private static final String s_name = "listloadbalancerssresponse"; + + // /////////////////////////////////////////////////// + // ////////////// API parameters ///////////////////// + // /////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = FirewallRuleResponse.class, + description = "the ID of the Load Balancer") + private Long id; + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "the name of the Load Balancer") + private String loadBalancerName; + + @Parameter(name = ApiConstants.SOURCE_IP, type = CommandType.STRING, description = "the source ip address of the Load Balancer") + private String sourceIp; + + @Parameter(name=ApiConstants.SOURCE_IP_NETWORK_ID, type=CommandType.UUID, entityType = NetworkResponse.class, + description="the network id of the source ip address") + private Long sourceIpNetworkId; + + @Parameter(name = ApiConstants.SCHEME, type = CommandType.STRING, description = "the scheme of the Load Balancer. Supported value is Internal in the current release") + private String scheme; + + @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.UUID, entityType = NetworkResponse.class, + description="the network id of the Load Balancer") + private Long networkId; + + + // /////////////////////////////////////////////////// + // ///////////////// Accessors /////////////////////// + // /////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + public String getLoadBalancerRuleName() { + return loadBalancerName; + } + + public String getLoadBalancerName() { + return loadBalancerName; + } + + public String getSourceIp() { + return sourceIp; + } + + public Long getSourceIpNetworkId() { + return sourceIpNetworkId; + } + + @Override + public String getCommandName() { + return s_name; + } + + public Scheme getScheme() { + if (scheme != null) { + if (scheme.equalsIgnoreCase(Scheme.Internal.toString())) { + return Scheme.Internal; + } else { + throw new InvalidParameterValueException("Invalid value for scheme. Supported value is Internal"); + } + } + return null; + } + + public Long getNetworkId() { + return networkId; + } + // /////////////////////////////////////////////////// + // ///////////// API Implementation/////////////////// + // /////////////////////////////////////////////////// + + @Override + public void execute() { + Pair, Integer> loadBalancers = _appLbService.listApplicationLoadBalancers(this); + ListResponse response = new ListResponse(); + List lbResponses = new ArrayList(); + for (ApplicationLoadBalancerRule loadBalancer : loadBalancers.first()) { + ApplicationLoadBalancerResponse lbResponse = _responseGenerator.createLoadBalancerContainerReponse(loadBalancer, _lbService.getLbInstances(loadBalancer.getId())); + lbResponse.setObjectName("loadbalancer"); + lbResponses.add(lbResponse); + } + response.setResponses(lbResponses, loadBalancers.second()); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } + +} diff --git a/api/src/org/apache/cloudstack/api/command/user/nat/EnableStaticNatCmd.java b/api/src/org/apache/cloudstack/api/command/user/nat/EnableStaticNatCmd.java index a0ec68ef5dd..902dbae00aa 100644 --- a/api/src/org/apache/cloudstack/api/command/user/nat/EnableStaticNatCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/nat/EnableStaticNatCmd.java @@ -120,7 +120,7 @@ public class EnableStaticNatCmd extends BaseCmd{ @Override public void execute() throws ResourceUnavailableException{ try { - boolean result = _rulesService.enableStaticNat(ipAddressId, virtualMachineId, getNetworkId(), false, getVmSecondaryIp()); + boolean result = _rulesService.enableStaticNat(ipAddressId, virtualMachineId, getNetworkId(), getVmSecondaryIp()); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); diff --git a/api/src/org/apache/cloudstack/api/command/user/network/ListNetworksCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/ListNetworksCmd.java index afce0926e4d..d25e2c05597 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/ListNetworksCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/ListNetworksCmd.java @@ -48,6 +48,9 @@ public class ListNetworksCmd extends BaseListTaggedResourcesCmd { description="the Zone ID of the network") private Long zoneId; + @Parameter(name=ApiConstants.ZONE_TYPE, type=CommandType.STRING, description="the network type of the zone that the virtual machine belongs to") + private String zoneType; + @Parameter(name=ApiConstants.TYPE, type=CommandType.STRING, description="the type of the network. Supported values are: Isolated and Shared") private String guestIpType; @@ -96,6 +99,10 @@ public class ListNetworksCmd extends BaseListTaggedResourcesCmd { return zoneId; } + public String getZoneType() { + return zoneType; + } + public String getGuestIpType() { return guestIpType; } diff --git a/api/src/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotCmd.java b/api/src/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotCmd.java index 95d76599f70..0b33f568d8a 100644 --- a/api/src/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotCmd.java @@ -163,6 +163,7 @@ public class CreateSnapshotCmd extends BaseAsyncCreateCmd { @Override public void execute() { + s_logger.info("VOLSS: createSnapshotCmd starts:" + System.currentTimeMillis()); UserContext.current().setEventDetails("Volume Id: "+getVolumeId()); Snapshot snapshot = _snapshotService.createSnapshot(getVolumeId(), getPolicyId(), getEntityId(), _accountService.getAccount(getEntityOwnerId())); if (snapshot != null) { @@ -172,6 +173,7 @@ public class CreateSnapshotCmd extends BaseAsyncCreateCmd { } else { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create snapshot due to an internal error creating snapshot for volume " + volumeId); } + s_logger.info("VOLSS: backupSnapshotCmd finishes:" + System.currentTimeMillis()); } diff --git a/api/src/org/apache/cloudstack/api/command/user/snapshot/ListSnapshotsCmd.java b/api/src/org/apache/cloudstack/api/command/user/snapshot/ListSnapshotsCmd.java index 17f20aeb0d0..d7e6bc87b7f 100644 --- a/api/src/org/apache/cloudstack/api/command/user/snapshot/ListSnapshotsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/snapshot/ListSnapshotsCmd.java @@ -58,6 +58,9 @@ public class ListSnapshotsCmd extends BaseListTaggedResourcesCmd { @Parameter(name=ApiConstants.VOLUME_ID, type=CommandType.UUID, entityType = VolumeResponse.class, description="the ID of the disk volume") private Long volumeId; + + @Parameter(name=ApiConstants.ZONE_TYPE, type=CommandType.STRING, description="the network type of the zone that the virtual machine belongs to") + private String zoneType; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -83,6 +86,10 @@ public class ListSnapshotsCmd extends BaseListTaggedResourcesCmd { return volumeId; } + public String getZoneType() { + return zoneType; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java index aeb76f507f3..f0fc24153f6 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java @@ -68,6 +68,10 @@ public class ListTemplatesCmd extends BaseListTaggedResourcesCmd { @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType = ZoneResponse.class, description="list templates by zoneId") private Long zoneId; + + @Parameter(name=ApiConstants.ZONE_TYPE, type=CommandType.STRING, description="the network type of the zone that the virtual machine belongs to") + private String zoneType; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -92,6 +96,10 @@ public class ListTemplatesCmd extends BaseListTaggedResourcesCmd { return zoneId; } + public String getZoneType() { + return zoneType; + } + public boolean listInReadyState() { Account account = UserContext.current().getCaller(); diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java index df6b3999dba..ae5482b22de 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java @@ -16,6 +16,7 @@ // under the License. package org.apache.cloudstack.api.command.user.vm; +import com.cloud.vm.NicSecondaryIp; import org.apache.log4j.Logger; import org.apache.cloudstack.api.APICommand; @@ -146,6 +147,7 @@ public class AddIpToVmNicCmd extends BaseAsyncCmd { UserContext.current().setEventDetails("Nic Id: " + getNicId() ); String ip; + NicSecondaryIp result; String secondaryIp = null; if ((ip = getIpaddress()) != null) { if (!NetUtils.isValidIp(ip)) { @@ -154,12 +156,13 @@ public class AddIpToVmNicCmd extends BaseAsyncCmd { } try { - secondaryIp = _networkService.allocateSecondaryGuestIP(_accountService.getAccount(getEntityOwnerId()), getZoneId(), getNicId(), getNetworkId(), getIpaddress()); + result = _networkService.allocateSecondaryGuestIP(_accountService.getAccount(getEntityOwnerId()), getZoneId(), getNicId(), getNetworkId(), getIpaddress()); } catch (InsufficientAddressCapacityException e) { throw new InvalidParameterValueException("Allocating guest ip for nic failed"); } - if (secondaryIp != null) { + if (result != null) { + secondaryIp = result.getIp4Address(); if (getNetworkType() == NetworkType.Basic) { // add security group rules for the secondary ip addresses boolean success = false; @@ -171,7 +174,7 @@ public class AddIpToVmNicCmd extends BaseAsyncCmd { s_logger.info("Associated ip address to NIC : " + secondaryIp); NicSecondaryIpResponse response = new NicSecondaryIpResponse(); - response = _responseGenerator.createSecondaryIPToNicResponse(secondaryIp, getNicId(), getNetworkId()); + response = _responseGenerator.createSecondaryIPToNicResponse(result); response.setResponseName(getCommandName()); this.setResponseObject(response); } else { diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java index 4fc65c37e58..4f2ac750ce5 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java @@ -22,11 +22,12 @@ import com.cloud.user.UserContext; import com.cloud.uservm.UserVm; import org.apache.cloudstack.api.*; import org.apache.cloudstack.api.response.ServiceOfferingResponse; +import org.apache.cloudstack.api.response.SuccessResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.log4j.Logger; -@APICommand(name = "scaleVirtualMachine", description="Scales the virtual machine to a new service offering.", responseObject=UserVmResponse.class) +@APICommand(name = "scaleVirtualMachine", description="Scales the virtual machine to a new service offering.", responseObject=SuccessResponse.class) public class ScaleVMCmd extends BaseCmd { public static final Logger s_logger = Logger.getLogger(ScaleVMCmd.class.getName()); private static final String s_name = "scalevirtualmachineresponse"; @@ -83,7 +84,7 @@ public class ScaleVMCmd extends BaseCmd { @Override public void execute(){ //UserContext.current().setEventDetails("Vm Id: "+getId()); - UserVm result = null; + boolean result; try { result = _userVmService.upgradeVirtualMachine(this); } catch (ResourceUnavailableException ex) { @@ -99,9 +100,8 @@ public class ScaleVMCmd extends BaseCmd { s_logger.warn("Exception: ", ex); throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); } - if (result != null){ - UserVmResponse response = _responseGenerator.createUserVmResponse("virtualmachine", result).get(0); - response.setResponseName(getCommandName()); + if (result){ + SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); } else { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to scale vm"); diff --git a/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/RevertToSnapshotCmd.java b/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/RevertToVMSnapshotCmd.java similarity index 91% rename from api/src/org/apache/cloudstack/api/command/user/vmsnapshot/RevertToSnapshotCmd.java rename to api/src/org/apache/cloudstack/api/command/user/vmsnapshot/RevertToVMSnapshotCmd.java index ea7bf60d6a3..f6d8b2c4a35 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/RevertToSnapshotCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/RevertToVMSnapshotCmd.java @@ -37,11 +37,11 @@ import com.cloud.user.UserContext; import com.cloud.uservm.UserVm; import com.cloud.vm.snapshot.VMSnapshot; -@APICommand(name = "revertToSnapshot",description = "Revert VM from a vmsnapshot.", responseObject = UserVmResponse.class, since="4.2.0") -public class RevertToSnapshotCmd extends BaseAsyncCmd { +@APICommand(name = "revertToVMSnapshot",description = "Revert VM from a vmsnapshot.", responseObject = UserVmResponse.class, since="4.2.0") +public class RevertToVMSnapshotCmd extends BaseAsyncCmd { public static final Logger s_logger = Logger - .getLogger(RevertToSnapshotCmd.class.getName()); - private static final String s_name = "reverttosnapshotresponse"; + .getLogger(RevertToVMSnapshotCmd.class.getName()); + private static final String s_name = "reverttovmsnapshotresponse"; @Parameter(name = ApiConstants.VM_SNAPSHOT_ID, type = CommandType.UUID, required = true,entityType=VMSnapshotResponse.class,description = "The ID of the vm snapshot") private Long vmSnapShotId; diff --git a/api/src/org/apache/cloudstack/api/command/user/zone/ListZonesByCmd.java b/api/src/org/apache/cloudstack/api/command/user/zone/ListZonesByCmd.java index bbfb598b1db..ed31037407f 100644 --- a/api/src/org/apache/cloudstack/api/command/user/zone/ListZonesByCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/zone/ListZonesByCmd.java @@ -23,6 +23,7 @@ import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.BaseCmd.CommandType; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.ServiceOfferingResponse; @@ -56,6 +57,9 @@ public class ListZonesByCmd extends BaseListCmd { @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, description="the name of the zone") private String name; + @Parameter(name=ApiConstants.ZONE_TYPE, type=CommandType.STRING, description="the network type of the zone that the virtual machine belongs to") + private String zoneType; + @Parameter(name=ApiConstants.SHOW_CAPACITIES, type=CommandType.BOOLEAN, description="flag to display the capacity of the zones") private Boolean showCapacities; @@ -79,6 +83,10 @@ public class ListZonesByCmd extends BaseListCmd { return name; } + public String getZoneType() { + return zoneType; + } + public Boolean getShowCapacities() { return showCapacities; } diff --git a/api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerInstanceResponse.java b/api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerInstanceResponse.java new file mode 100644 index 00000000000..2d6614d217b --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerInstanceResponse.java @@ -0,0 +1,63 @@ +// 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. +package org.apache.cloudstack.api.response; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +/** + * + * Load Balancer instance is the User Vm instance participating in the Load Balancer + * + */ + +@SuppressWarnings("unused") +public class ApplicationLoadBalancerInstanceResponse extends BaseResponse{ + + @SerializedName(ApiConstants.ID) @Param(description = "the instance ID") + private String id; + + @SerializedName(ApiConstants.NAME) @Param(description = "the name of the instance") + private String name; + + @SerializedName(ApiConstants.STATE) @Param(description="the state of the instance") + private String state; + + @SerializedName(ApiConstants.IP_ADDRESS) + @Param(description="the ip address of the instance") + private String ipAddress; + + + public void setId(String id) { + this.id = id; + } + + public void setName(String name) { + this.name = name; + } + + public void setState(String state) { + this.state = state; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } +} diff --git a/api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerResponse.java b/api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerResponse.java new file mode 100644 index 00000000000..de9bce6c658 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerResponse.java @@ -0,0 +1,142 @@ +// 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. + +package org.apache.cloudstack.api.response; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +@SuppressWarnings("unused") +public class ApplicationLoadBalancerResponse extends BaseResponse implements ControlledEntityResponse{ + @SerializedName(ApiConstants.ID) @Param(description = "the Load Balancer ID") + private String id; + + @SerializedName(ApiConstants.NAME) @Param(description = "the name of the Load Balancer") + private String name; + + @SerializedName(ApiConstants.DESCRIPTION) @Param(description = "the description of the Load Balancer") + private String description; + + @SerializedName(ApiConstants.ALGORITHM) @Param(description = "the load balancer algorithm (source, roundrobin, leastconn)") + private String algorithm; + + @SerializedName(ApiConstants.NETWORK_ID) @Param(description="Load Balancer network id") + private String networkId; + + @SerializedName(ApiConstants.SOURCE_IP) @Param(description="Load Balancer source ip") + private String sourceIp; + + @SerializedName(ApiConstants.SOURCE_IP_NETWORK_ID) @Param(description="Load Balancer source ip network id") + private String sourceIpNetworkId; + + @SerializedName(ApiConstants.ACCOUNT) + @Param(description = "the account of the Load Balancer") + private String accountName; + + @SerializedName(ApiConstants.PROJECT_ID) @Param(description="the project id of the Load Balancer") + private String projectId; + + @SerializedName(ApiConstants.PROJECT) @Param(description="the project name of the Load Balancer") + private String projectName; + + @SerializedName(ApiConstants.DOMAIN_ID) + @Param(description = "the domain ID of the Load Balancer") + private String domainId; + + @SerializedName(ApiConstants.DOMAIN) + @Param(description = "the domain of the Load Balancer") + private String domainName; + + @SerializedName("loadbalancerrule") @Param(description="the list of rules associated with the Load Balancer", responseObject = ApplicationLoadBalancerRuleResponse.class) + private List lbRules; + + @SerializedName("loadbalancerinstance") @Param(description="the list of instances associated with the Load Balancer", responseObject = ApplicationLoadBalancerInstanceResponse.class) + private List lbInstances; + + @SerializedName(ApiConstants.TAGS) @Param(description="the list of resource tags associated with the Load Balancer", responseObject = ResourceTagResponse.class) + private List tags; + + public void setAccountName(String accountName) { + this.accountName = accountName; + } + + @Override + public void setDomainId(String domainId) { + this.domainId = domainId; + } + + public void setDomainName(String domainName) { + this.domainName = domainName; + } + + @Override + public void setProjectId(String projectId) { + this.projectId = projectId; + } + + @Override + public void setProjectName(String projectName) { + this.projectName = projectName; + } + + public void setTags(List tags) { + this.tags = tags; + } + + public void setId(String id) { + this.id = id; + } + + public void setName(String name) { + this.name = name; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setAlgorithm(String algorithm) { + this.algorithm = algorithm; + } + + public void setNetworkId(String networkId) { + this.networkId = networkId; + } + + public void setSourceIp(String sourceIp) { + this.sourceIp = sourceIp; + } + + public void setSourceIpNetworkId(String sourceIpNetworkId) { + this.sourceIpNetworkId = sourceIpNetworkId; + } + + public void setLbRules(List lbRules) { + this.lbRules = lbRules; + } + + public void setLbInstances(List lbInstances) { + this.lbInstances = lbInstances; + } +} diff --git a/api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerRuleResponse.java b/api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerRuleResponse.java new file mode 100644 index 00000000000..ffc64d5ca46 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/ApplicationLoadBalancerRuleResponse.java @@ -0,0 +1,51 @@ +// 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. + +package org.apache.cloudstack.api.response; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +/** + * Subobject of the load balancer container response + */ +@SuppressWarnings("unused") +public class ApplicationLoadBalancerRuleResponse extends BaseResponse{ + @SerializedName(ApiConstants.SOURCE_PORT) @Param(description = "source port of the load balancer rule") + private Integer sourcePort; + + @SerializedName(ApiConstants.INSTANCE_PORT) @Param(description = "instance port of the load balancer rule") + private Integer instancePort; + + @SerializedName(ApiConstants.STATE) @Param(description = "the state of the load balancer rule") + private String state; + + public void setSourcePort(Integer sourcePort) { + this.sourcePort = sourcePort; + } + + public void setInstancePort(Integer instancePort) { + this.instancePort = instancePort; + } + + public void setState(String state) { + this.state = state; + } +} diff --git a/api/src/org/apache/cloudstack/api/response/ConfigurationResponse.java b/api/src/org/apache/cloudstack/api/response/ConfigurationResponse.java index 176c47aff8b..fa0d4b45475 100644 --- a/api/src/org/apache/cloudstack/api/response/ConfigurationResponse.java +++ b/api/src/org/apache/cloudstack/api/response/ConfigurationResponse.java @@ -35,6 +35,9 @@ public class ConfigurationResponse extends BaseResponse { @SerializedName(ApiConstants.SCOPE) @Param(description="scope(zone/cluster/pool/account) of the parameter that needs to be updated") private String scope; + @SerializedName(ApiConstants.ID) @Param(description="the value of the configuration") + private Long id; + @SerializedName(ApiConstants.DESCRIPTION) @Param(description="the description of the configuration") private String description; diff --git a/api/src/org/apache/cloudstack/api/response/DomainRouterResponse.java b/api/src/org/apache/cloudstack/api/response/DomainRouterResponse.java index 79c8596a8d1..852d98815a3 100644 --- a/api/src/org/apache/cloudstack/api/response/DomainRouterResponse.java +++ b/api/src/org/apache/cloudstack/api/response/DomainRouterResponse.java @@ -153,8 +153,11 @@ public class DomainRouterResponse extends BaseResponse implements ControlledView @SerializedName("scriptsversion") @Param(description="the version of scripts") private String scriptsVersion; - @SerializedName(ApiConstants.VPC_ID) @Param(description="VPC the network belongs to") + @SerializedName(ApiConstants.VPC_ID) @Param(description="VPC the router belongs to") private String vpcId; + + @SerializedName(ApiConstants.ROLE) @Param(description="role of the domain router") + private String role; @SerializedName("nic") @Param(description="the list of nics associated with the router", responseObject = NicResponse.class, since="4.0") @@ -164,15 +167,11 @@ public class DomainRouterResponse extends BaseResponse implements ControlledView nics = new LinkedHashSet(); } - - @Override public String getObjectId() { return this.getId(); } - - public String getId() { return id; } @@ -372,4 +371,8 @@ public class DomainRouterResponse extends BaseResponse implements ControlledView public void setIp6Dns2(String ip6Dns2) { this.ip6Dns2 = ip6Dns2; } + + public void setRole(String role) { + this.role = role; + } } diff --git a/api/src/org/apache/cloudstack/api/response/GuestVlanRangeResponse.java b/api/src/org/apache/cloudstack/api/response/GuestVlanRangeResponse.java new file mode 100644 index 00000000000..bf19688c13f --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/GuestVlanRangeResponse.java @@ -0,0 +1,94 @@ +// 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. +package org.apache.cloudstack.api.response; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + +import com.cloud.network.GuestVlan; + +@EntityReference(value=GuestVlan.class) +@SuppressWarnings("unused") +public class GuestVlanRangeResponse extends BaseResponse implements ControlledEntityResponse { + @SerializedName(ApiConstants.ID) @Param(description="the ID of the guest VLAN range") + private String id; + + @SerializedName(ApiConstants.ACCOUNT) @Param(description="the account of the guest VLAN range") + private String accountName; + + @SerializedName(ApiConstants.DOMAIN_ID) @Param(description="the domain ID of the guest VLAN range") + private String domainId; + + @SerializedName(ApiConstants.DOMAIN) @Param(description="the domain name of the guest VLAN range") + private String domainName; + + @SerializedName(ApiConstants.GUEST_VLAN_RANGE) @Param(description="the guest VLAN range") + private String guestVlanRange; + + @SerializedName(ApiConstants.PROJECT_ID) @Param(description="the project id of the guest vlan range") + private String projectId; + + @SerializedName(ApiConstants.PROJECT) @Param(description="the project name of the guest vlan range") + private String projectName; + + @SerializedName(ApiConstants.PHYSICAL_NETWORK_ID) @Param(description="the physical network of the guest vlan range") + private Long physicalNetworkId; + + @SerializedName(ApiConstants.ZONE_ID) @Param(description="the zone of the guest vlan range") + private Long zoneId; + + + public void setId(String id) { + this.id = id; + } + + public void setAccountName(String accountName) { + this.accountName = accountName; + } + + public void setDomainId(String domainId) { + this.domainId = domainId; + } + + public void setDomainName(String domainName) { + this.domainName = domainName; + } + + public void setGuestVlanRange(String guestVlanRange) { + this.guestVlanRange = guestVlanRange; + } + + public void setProjectId(String projectId) { + this.projectId = projectId; + } + + public void setProjectName(String projectName) { + this.projectName = projectName; + } + + public void setPhysicalNetworkId(Long physicalNetworkId) { + this.physicalNetworkId = physicalNetworkId; + } + + public void setZoneId(Long zoneId) { + this.zoneId = zoneId; + } + +} diff --git a/api/src/org/apache/cloudstack/api/response/InternalLoadBalancerElementResponse.java b/api/src/org/apache/cloudstack/api/response/InternalLoadBalancerElementResponse.java new file mode 100644 index 00000000000..b7e8634ee8f --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/InternalLoadBalancerElementResponse.java @@ -0,0 +1,51 @@ +// 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. +package org.apache.cloudstack.api.response; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + +import com.cloud.network.VirtualRouterProvider; +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +@EntityReference(value=VirtualRouterProvider.class) +@SuppressWarnings("unused") +public class InternalLoadBalancerElementResponse extends BaseResponse { + @SerializedName(ApiConstants.ID) @Param(description="the id of the internal load balancer element") + private String id; + + @SerializedName(ApiConstants.NSP_ID) @Param(description="the physical network service provider id of the element") + private String nspId; + + @SerializedName(ApiConstants.ENABLED) @Param(description="Enabled/Disabled the element") + private Boolean enabled; + + + public void setId(String id) { + this.id = id; + } + + public void setNspId(String nspId) { + this.nspId = nspId; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } +} diff --git a/core/src/com/cloud/agent/RecoveryHandler.java b/api/src/org/apache/cloudstack/api/response/IsolationMethodResponse.java similarity index 59% rename from core/src/com/cloud/agent/RecoveryHandler.java rename to api/src/org/apache/cloudstack/api/response/IsolationMethodResponse.java index 418c7b1034f..3aaa7a4a1ab 100644 --- a/core/src/com/cloud/agent/RecoveryHandler.java +++ b/api/src/org/apache/cloudstack/api/response/IsolationMethodResponse.java @@ -14,18 +14,20 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.agent; +package org.apache.cloudstack.api.response; -import com.cloud.agent.api.Command; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; -public interface RecoveryHandler { - /** - * Perform the necessary recovery because the success of this command - * is not known. - * - * @param agentId agent the commands were sent to. - * @param seq sequence number. - * @param cmds commands that failed. - */ - public void handle(long agentId, long seq, Command[] cmds); +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +@SuppressWarnings("unused") +public class IsolationMethodResponse extends BaseResponse{ + @SerializedName(ApiConstants.NAME) @Param(description="Network isolation method name") + private String name; + + public void setIsolationMethodName(String isolationMethodName) { + this.name = isolationMethodName; + } } diff --git a/api/src/org/apache/cloudstack/api/response/NetworkOfferingResponse.java b/api/src/org/apache/cloudstack/api/response/NetworkOfferingResponse.java index b1dcd423117..7a7e371e180 100644 --- a/api/src/org/apache/cloudstack/api/response/NetworkOfferingResponse.java +++ b/api/src/org/apache/cloudstack/api/response/NetworkOfferingResponse.java @@ -18,6 +18,7 @@ package org.apache.cloudstack.api.response; import java.util.Date; import java.util.List; +import java.util.Map; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; @@ -83,6 +84,10 @@ public class NetworkOfferingResponse extends BaseResponse { @SerializedName(ApiConstants.IS_PERSISTENT) @Param(description="true if network offering supports persistent networks, false otherwise") private Boolean isPersistent; + + @SerializedName(ApiConstants.DETAILS) @Param(description="additional key/value details tied with network offering", since="4.2.0") + private Map details; + public void setId(String id) { this.id = id; @@ -156,5 +161,9 @@ public class NetworkOfferingResponse extends BaseResponse { public void setIsPersistent(Boolean isPersistent) { this.isPersistent = isPersistent; } + + public void setDetails(Map details) { + this.details = details; + } } diff --git a/api/src/org/apache/cloudstack/api/response/PrivateGatewayResponse.java b/api/src/org/apache/cloudstack/api/response/PrivateGatewayResponse.java index 4123477dbfe..ca760626324 100644 --- a/api/src/org/apache/cloudstack/api/response/PrivateGatewayResponse.java +++ b/api/src/org/apache/cloudstack/api/response/PrivateGatewayResponse.java @@ -76,6 +76,10 @@ public class PrivateGatewayResponse extends BaseResponse implements ControlledEn private String state; + @SerializedName(ApiConstants.SOURCE_NAT_SUPPORTED) @Param(description = "Souce Nat enable status") + private Boolean sourceNat; + + @Override public String getObjectId() { return this.id; @@ -145,5 +149,11 @@ public class PrivateGatewayResponse extends BaseResponse implements ControlledEn public void setState(String state) { this.state = state; } + + public void setSourceNat(Boolean sourceNat) { + this.sourceNat = sourceNat; + } + + } diff --git a/api/src/org/apache/cloudstack/api/response/VirtualRouterProviderResponse.java b/api/src/org/apache/cloudstack/api/response/VirtualRouterProviderResponse.java index 92d9a1d0cc1..de355bd0c25 100644 --- a/api/src/org/apache/cloudstack/api/response/VirtualRouterProviderResponse.java +++ b/api/src/org/apache/cloudstack/api/response/VirtualRouterProviderResponse.java @@ -25,6 +25,7 @@ import com.cloud.serializer.Param; import com.google.gson.annotations.SerializedName; @EntityReference(value=VirtualRouterProvider.class) +@SuppressWarnings("unused") public class VirtualRouterProviderResponse extends BaseResponse implements ControlledEntityResponse { @SerializedName(ApiConstants.ID) @Param(description="the id of the router") private String id; diff --git a/api/src/org/apache/cloudstack/network/element/InternalLoadBalancerElementService.java b/api/src/org/apache/cloudstack/network/element/InternalLoadBalancerElementService.java new file mode 100644 index 00000000000..33a0c64058e --- /dev/null +++ b/api/src/org/apache/cloudstack/network/element/InternalLoadBalancerElementService.java @@ -0,0 +1,56 @@ +// 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. +package org.apache.cloudstack.network.element; + +import java.util.List; + + +import com.cloud.network.VirtualRouterProvider; +import com.cloud.utils.component.PluggableService; + +public interface InternalLoadBalancerElementService extends PluggableService{ + /** + * Configures existing Internal Load Balancer Element (enables or disables it) + * @param id + * @param enable + * @return + */ + VirtualRouterProvider configureInternalLoadBalancerElement(long id, boolean enable); + + /** + * Adds Internal Load Balancer element to the Network Service Provider + * @param ntwkSvcProviderId + * @return + */ + VirtualRouterProvider addInternalLoadBalancerElement(long ntwkSvcProviderId); + + /** + * Retrieves existing Internal Load Balancer element + * @param id + * @return + */ + VirtualRouterProvider getInternalLoadBalancerElement(long id); + + /** + * Searches for existing Internal Load Balancer elements based on parameters passed to the call + * @param id + * @param ntwkSvsProviderId + * @param enabled + * @return + */ + List searchForInternalLoadBalancerElements(Long id, Long ntwkSvsProviderId, Boolean enabled); +} diff --git a/server/src/com/cloud/maint/UpgradeMonitor.java b/api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerContainer.java similarity index 74% rename from server/src/com/cloud/maint/UpgradeMonitor.java rename to api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerContainer.java index ca78fe22ece..df94d3d4338 100644 --- a/server/src/com/cloud/maint/UpgradeMonitor.java +++ b/api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerContainer.java @@ -14,21 +14,15 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.maint; +package org.apache.cloudstack.network.lb; -/** - * has been released. - * - */ -public class UpgradeMonitor implements Runnable { - private String _url; - private long _period; +import com.cloud.network.rules.LoadBalancerContainer; +import com.cloud.utils.net.Ip; + +public interface ApplicationLoadBalancerContainer extends LoadBalancerContainer{ - public UpgradeMonitor(String url, long period) { - _url = url; - } + public Long getSourceIpNetworkId(); - public void run() { - - } + public Ip getSourceIp(); + } diff --git a/server/src/com/cloud/maint/dao/AgentUpgradeDao.java b/api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerRule.java similarity index 78% rename from server/src/com/cloud/maint/dao/AgentUpgradeDao.java rename to api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerRule.java index e9763db5804..f4acb734c8b 100644 --- a/server/src/com/cloud/maint/dao/AgentUpgradeDao.java +++ b/api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerRule.java @@ -14,10 +14,11 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.maint.dao; -import com.cloud.maint.AgentUpgradeVO; -import com.cloud.utils.db.GenericDao; +package org.apache.cloudstack.network.lb; -public interface AgentUpgradeDao extends GenericDao { +import com.cloud.network.rules.LoadBalancer; + +public interface ApplicationLoadBalancerRule extends ApplicationLoadBalancerContainer, LoadBalancer{ + int getInstancePort(); } diff --git a/api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerService.java b/api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerService.java new file mode 100644 index 00000000000..b2ac358555b --- /dev/null +++ b/api/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerService.java @@ -0,0 +1,42 @@ +// 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. + +package org.apache.cloudstack.network.lb; + +import java.util.List; + +import org.apache.cloudstack.api.command.user.loadbalancer.ListApplicationLoadBalancersCmd; + +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapcityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.utils.Pair; + +public interface ApplicationLoadBalancerService { + + ApplicationLoadBalancerRule createApplicationLoadBalancer(String name, String description, Scheme scheme, long sourceIpNetworkId, String sourceIp, + int sourcePort, int instancePort, String algorithm, long networkId, long lbOwnerId) throws InsufficientAddressCapacityException, + NetworkRuleConflictException, InsufficientVirtualNetworkCapcityException; + + boolean deleteApplicationLoadBalancer(long id); + + Pair, Integer> listApplicationLoadBalancers(ListApplicationLoadBalancersCmd cmd); + + ApplicationLoadBalancerRule getApplicationLoadBalancer(long ruleId); + +} diff --git a/api/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMService.java b/api/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMService.java new file mode 100644 index 00000000000..91cd88d91c1 --- /dev/null +++ b/api/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMService.java @@ -0,0 +1,34 @@ +// 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. +package org.apache.cloudstack.network.lb; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.exception.StorageUnavailableException; +import com.cloud.network.router.VirtualRouter; +import com.cloud.user.Account; + +public interface InternalLoadBalancerVMService { + + VirtualRouter startInternalLbVm(long internalLbVmId, Account caller, long callerUserId) + throws StorageUnavailableException, InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException; + + VirtualRouter stopInternalLbVm(long vmId, boolean forced, Account caller, long callerUserId) + throws ConcurrentOperationException, ResourceUnavailableException; + +} diff --git a/api/src/org/apache/cloudstack/query/QueryService.java b/api/src/org/apache/cloudstack/query/QueryService.java index 2b82fec6dcc..9eada216d26 100644 --- a/api/src/org/apache/cloudstack/query/QueryService.java +++ b/api/src/org/apache/cloudstack/query/QueryService.java @@ -18,6 +18,7 @@ package org.apache.cloudstack.query; import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.command.admin.host.ListHostsCmd; +import org.apache.cloudstack.api.command.admin.internallb.ListInternalLBVMsCmd; import org.apache.cloudstack.api.command.admin.router.ListRoutersCmd; import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolsCmd; import org.apache.cloudstack.api.command.admin.user.ListUsersCmd; @@ -95,4 +96,6 @@ public interface QueryService { public List listResource(ListResourceDetailsCmd cmd); + ListResponse searchForInternalLbVms(ListInternalLBVMsCmd cmd); + } diff --git a/api/test/org/apache/cloudstack/api/command/test/AddIpToVmNicTest.java b/api/test/org/apache/cloudstack/api/command/test/AddIpToVmNicTest.java index 106589d10cc..e5015cb3cac 100644 --- a/api/test/org/apache/cloudstack/api/command/test/AddIpToVmNicTest.java +++ b/api/test/org/apache/cloudstack/api/command/test/AddIpToVmNicTest.java @@ -16,6 +16,7 @@ // under the License. package org.apache.cloudstack.api.command.test; +import com.cloud.vm.NicSecondaryIp; import junit.framework.Assert; import junit.framework.TestCase; @@ -64,15 +65,16 @@ public class AddIpToVmNicTest extends TestCase { NetworkService networkService = Mockito.mock(NetworkService.class); AddIpToVmNicCmd ipTonicCmd = Mockito.mock(AddIpToVmNicCmd.class); + NicSecondaryIp secIp = Mockito.mock(NicSecondaryIp.class); Mockito.when( - networkService.allocateSecondaryGuestIP(Mockito.any(Account.class), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString())).thenReturn("10.1.1.2"); + networkService.allocateSecondaryGuestIP(Mockito.any(Account.class), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString())).thenReturn(secIp); ipTonicCmd._networkService = networkService; responseGenerator = Mockito.mock(ResponseGenerator.class); NicSecondaryIpResponse ipres = Mockito.mock(NicSecondaryIpResponse.class); - Mockito.when(responseGenerator.createSecondaryIPToNicResponse(Mockito.anyString(), Mockito.anyLong(), Mockito.anyLong())).thenReturn(ipres); + Mockito.when(responseGenerator.createSecondaryIPToNicResponse(secIp)).thenReturn(ipres); ipTonicCmd._responseGenerator = responseGenerator; ipTonicCmd.execute(); diff --git a/api/test/org/apache/cloudstack/api/command/test/ScaleVMCmdTest.java b/api/test/org/apache/cloudstack/api/command/test/ScaleVMCmdTest.java index 301fa02ca29..8a28290e04b 100644 --- a/api/test/org/apache/cloudstack/api/command/test/ScaleVMCmdTest.java +++ b/api/test/org/apache/cloudstack/api/command/test/ScaleVMCmdTest.java @@ -16,31 +16,20 @@ // under the License. package org.apache.cloudstack.api.command.test; -import com.cloud.user.Account; -import com.cloud.user.UserContext; import com.cloud.uservm.UserVm; import com.cloud.vm.UserVmService; import junit.framework.Assert; import junit.framework.TestCase; import org.apache.cloudstack.api.ResponseGenerator; import org.apache.cloudstack.api.ServerApiException; -import org.apache.cloudstack.api.command.admin.region.AddRegionCmd; import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd; -import org.apache.cloudstack.api.response.RegionResponse; -import org.apache.cloudstack.api.response.UserVmResponse; -import org.apache.cloudstack.region.Region; -import org.apache.cloudstack.region.RegionService; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.mockito.Mockito; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - - public class ScaleVMCmdTest extends TestCase{ private ScaleVMCmd scaleVMCmd; @@ -57,12 +46,11 @@ public class ScaleVMCmdTest extends TestCase{ public Long getId() { return 2L; } + @Override + public String getCommandName() { + return "scalevirtualmachineresponse"; + } }; - - //Account account = new AccountVO("testaccount", 1L, "networkdomain", (short) 0, "uuid"); - //UserContext.registerContext(1, account, null, true); - - } @@ -71,11 +59,10 @@ public class ScaleVMCmdTest extends TestCase{ UserVmService userVmService = Mockito.mock(UserVmService.class); - UserVm uservm = Mockito.mock(UserVm.class); try { Mockito.when( userVmService.upgradeVirtualMachine(scaleVMCmd)) - .thenReturn(uservm); + .thenReturn(true); }catch (Exception e){ Assert.fail("Received exception when success expected " +e.getMessage()); } @@ -83,13 +70,6 @@ public class ScaleVMCmdTest extends TestCase{ scaleVMCmd._userVmService = userVmService; responseGenerator = Mockito.mock(ResponseGenerator.class); - UserVmResponse userVmResponse = Mockito.mock(UserVmResponse.class); - List responseList = new ArrayList(); - responseList.add(userVmResponse); - - Mockito.when(responseGenerator.createUserVmResponse("virtualmachine",uservm)) - .thenReturn(responseList); - scaleVMCmd._responseGenerator = responseGenerator; scaleVMCmd.execute(); @@ -101,10 +81,9 @@ public class ScaleVMCmdTest extends TestCase{ UserVmService userVmService = Mockito.mock(UserVmService.class); try { - UserVm uservm = Mockito.mock(UserVm.class); Mockito.when( userVmService.upgradeVirtualMachine(scaleVMCmd)) - .thenReturn(null); + .thenReturn(false); }catch (Exception e){ Assert.fail("Received exception when success expected " +e.getMessage()); } diff --git a/awsapi/pom.xml b/awsapi/pom.xml index f19a71381d3..d4573491723 100644 --- a/awsapi/pom.xml +++ b/awsapi/pom.xml @@ -286,12 +286,6 @@ - install - src - src @@ -307,6 +301,17 @@ + + org.apache.maven.plugins + maven-surefire-plugin + + + com/cloud/gate/util/UtilTestCase.java + com/cloud/gate/service/ServiceTestCase.java + com/cloud/gate/util/CloudStackClientTestCase.java + + + org.apache.maven.plugins maven-war-plugin @@ -364,22 +369,6 @@ - diff --git a/awsapi/test/com/cloud/gate/model/ModelTestCase.java b/awsapi/test/com/cloud/gate/model/ModelTestCase.java deleted file mode 100644 index 91aeaa75215..00000000000 --- a/awsapi/test/com/cloud/gate/model/ModelTestCase.java +++ /dev/null @@ -1,368 +0,0 @@ -// 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. -package com.cloud.gate.model; - -import java.util.Date; -import java.util.Iterator; -import java.util.List; - -import org.apache.log4j.Logger; -import org.hibernate.Query; -import org.hibernate.Session; -import org.hibernate.Transaction; -import org.junit.Assert; - -import com.cloud.bridge.model.MHost; -import com.cloud.bridge.model.MHostMount; -import com.cloud.bridge.model.SBucket; -import com.cloud.bridge.model.SHost; -import com.cloud.bridge.model.SMeta; -import com.cloud.bridge.model.SObject; -import com.cloud.bridge.util.CloudSessionFactory; -import com.cloud.bridge.util.QueryHelper; -import com.cloud.gate.testcase.BaseTestCase; - -public class ModelTestCase extends BaseTestCase { - protected final static Logger logger = Logger.getLogger(ModelTestCase.class); - - public void testSHost() { - SHost host; - - // create the record - Session session = CloudSessionFactory.getInstance().openSession(); - try { - Transaction txn = session.beginTransaction(); - host = new SHost(); - host.setHost("localhost"); - host.setExportRoot("/"); - host.setUserOnHost("root"); - host.setUserPassword("password"); - session.saveOrUpdate(host); - txn.commit(); - } finally { - session.close(); - } - Assert.assertTrue(host.getId() != 0); - - // retrive the record - session = CloudSessionFactory.getInstance().openSession(); - try { - Transaction txn = session.beginTransaction(); - host = (SHost)session.get(SHost.class, (long)host.getId()); - txn.commit(); - - Assert.assertTrue(host.getHost().equals("localhost")); - Assert.assertTrue(host.getUserOnHost().equals("root")); - Assert.assertTrue(host.getUserPassword().equals("password")); - - logger.info("Retrived record, host:" + host.getHost() - + ", user: " + host.getUserOnHost() - + ", password: " + host.getUserPassword()); - - } finally { - session.close(); - } - - // delete the record - session = CloudSessionFactory.getInstance().openSession(); - try { - Transaction txn = session.beginTransaction(); - host = (SHost)session.get(SHost.class, (long)host.getId()); - session.delete(host); - txn.commit(); - } finally { - session.close(); - } - - session = CloudSessionFactory.getInstance().openSession(); - try { - Transaction txn = session.beginTransaction(); - host = (SHost)session.get(SHost.class, (long)host.getId()); - txn.commit(); - - Assert.assertTrue(host == null); - } finally { - session.close(); - } - } - - public void testSBucket() { - SHost host; - SBucket bucket; - Session session; - - session = CloudSessionFactory.getInstance().openSession(); - try { - Transaction txn = session.beginTransaction(); - host = new SHost(); - host.setHost("localhost"); - host.setUserOnHost("root"); - host.setUserPassword("password"); - host.setExportRoot("/"); - - bucket = new SBucket(); - bucket.setName("Bucket"); - bucket.setOwnerCanonicalId("OwnerId-dummy"); - bucket.setCreateTime(new Date()); - - host.getBuckets().add(bucket); - bucket.setShost(host); - - session.save(host); - session.save(bucket); - txn.commit(); - } finally { - session.close(); - } - - long bucketId = bucket.getId(); - - // load bucket - session = CloudSessionFactory.getInstance().openSession(); - try { - Transaction txn = session.beginTransaction(); - bucket = (SBucket)session.get(SBucket.class, bucketId); - txn.commit(); - - Assert.assertTrue(bucket.getShost().getHost().equals("localhost")); - Assert.assertTrue(bucket.getName().equals("Bucket")); - Assert.assertTrue(bucket.getOwnerCanonicalId().equals("OwnerId-dummy")); - } finally { - session.close(); - } - - // delete the bucket - session = CloudSessionFactory.getInstance().openSession(); - try { - Transaction txn = session.beginTransaction(); - bucket = (SBucket)session.get(SBucket.class, bucketId); - session.delete(bucket); - - host = (SHost)session.get(SHost.class, host.getId()); - session.delete(host); - txn.commit(); - } finally { - session.close(); - } - - // verify the deletion - session = CloudSessionFactory.getInstance().openSession(); - try { - Transaction txn = session.beginTransaction(); - bucket = (SBucket)session.get(SBucket.class, bucketId); - txn.commit(); - - Assert.assertTrue(bucket == null); - } finally { - session.close(); - } - } - - public void testSObject() { - SHost host; - SBucket bucket; - Session session; - SObject sobject; - - // setup - session = CloudSessionFactory.getInstance().openSession(); - try { - Transaction txn = session.beginTransaction(); - host = new SHost(); - host.setHost("localhost"); - host.setUserOnHost("root"); - host.setUserPassword("password"); - host.setExportRoot("/"); - - bucket = new SBucket(); - bucket.setName("Bucket"); - bucket.setOwnerCanonicalId("OwnerId-dummy"); - bucket.setCreateTime(new Date()); - bucket.setShost(host); - host.getBuckets().add(bucket); - - sobject = new SObject(); - sobject.setNameKey("ObjectNameKey"); - sobject.setOwnerCanonicalId("OwnerId-dummy"); - sobject.setCreateTime(new Date()); - sobject.setBucket(bucket); - bucket.getObjectsInBucket().add(sobject); - - session.save(host); - session.save(bucket); - session.save(sobject); - txn.commit(); - - } finally { - session.close(); - } - - session = CloudSessionFactory.getInstance().openSession(); - try { - Transaction txn = session.beginTransaction(); - sobject = (SObject)session.get(SObject.class, sobject.getId()); - txn.commit(); - Assert.assertTrue(sobject.getBucket().getName().equals("Bucket")); - Assert.assertTrue(sobject.getNameKey().equals("ObjectNameKey")); - Assert.assertTrue(sobject.getOwnerCanonicalId().equals("OwnerId-dummy")); - } finally { - session.close(); - } - - // test delete cascade - session = CloudSessionFactory.getInstance().openSession(); - try { - Transaction txn = session.beginTransaction(); - bucket = (SBucket)session.get(SBucket.class, bucket.getId()); - session.delete(bucket); - - host = (SHost)session.get(SHost.class, host.getId()); - session.delete(host); - txn.commit(); - } finally { - session.close(); - } - } - - public void testMeta() { - Session session; - - session = CloudSessionFactory.getInstance().openSession(); - try { - Transaction txn = session.beginTransaction(); - SMeta meta = new SMeta(); - meta.setTarget("SObject"); - meta.setTargetId(1); - meta.setName("param1"); - meta.setValue("value1"); - session.save(meta); - - logger.info("Meta 1: " + meta.getId()); - - meta = new SMeta(); - meta.setTarget("SObject"); - meta.setTargetId(1); - meta.setName("param2"); - meta.setValue("value2"); - session.save(meta); - - logger.info("Meta 2: " + meta.getId()); - - txn.commit(); - } finally { - session.close(); - } - - session = CloudSessionFactory.getInstance().openSession(); - try { - Transaction txn = session.beginTransaction(); - Query query = session.createQuery("from SMeta where target=? and targetId=?"); - QueryHelper.bindParameters(query, new Object[] { - "SObject", new Long(1) - }); - List l = QueryHelper.executeQuery(query); - txn.commit(); - - for(SMeta meta: l) { - logger.info("" + meta.getName() + "=" + meta.getValue()); - } - } finally { - session.close(); - } - - session = CloudSessionFactory.getInstance().openSession(); - try { - Transaction txn = session.beginTransaction(); - Query query = session.createQuery("delete from SMeta where target=?"); - QueryHelper.bindParameters(query, new Object[] {"SObject"}); - query.executeUpdate(); - txn.commit(); - } finally { - session.close(); - } - } - - public void testHosts() { - Session session; - SHost shost; - MHost mhost; - MHostMount hostMount; - - session = CloudSessionFactory.getInstance().openSession(); - try { - Transaction txn = session.beginTransaction(); - shost = new SHost(); - shost.setHost("Storage host1"); - shost.setUserOnHost("root"); - shost.setUserPassword("password"); - shost.setExportRoot("/"); - session.save(shost); - - mhost = new MHost(); - mhost.setHostKey("1"); - mhost.setHost("management host1"); - mhost.setVersion("v1"); - session.save(mhost); - - hostMount = new MHostMount(); - hostMount.setMhost(mhost); - hostMount.setShost(shost); - hostMount.setMountPath("/mnt"); - session.save(hostMount); - txn.commit(); - } finally { - session.close(); - } - - session = CloudSessionFactory.getInstance().openSession(); - try { - Transaction txn = session.beginTransaction(); - mhost = (MHost)session.createQuery("from MHost where hostKey=?"). - setLong(0, new Long(1)).uniqueResult(); - - if(mhost != null) { - Iterator it = mhost.getMounts().iterator(); - while(it.hasNext()) { - MHostMount mount = (MHostMount)it.next(); - Assert.assertTrue(mount.getMountPath().equals("/mnt")); - - logger.info(mount.getMountPath()); - } - } - txn.commit(); - } finally { - session.close(); - } - - session = CloudSessionFactory.getInstance().openSession(); - try { - Transaction txn = session.beginTransaction(); - mhost = (MHost)session.createQuery("from MHost where hostKey=?"). - setLong(0, new Long(1)).uniqueResult(); - if(mhost != null) - session.delete(mhost); - - shost = (SHost)session.createQuery("from SHost where host=?"). - setString(0, "Storage host1").uniqueResult(); - if(shost != null) - session.delete(shost); - txn.commit(); - } finally { - session.close(); - } - } -} diff --git a/awsapi/test/com/cloud/gate/persist/PersitTestCase.java b/awsapi/test/com/cloud/gate/persist/PersitTestCase.java deleted file mode 100644 index 4961d932682..00000000000 --- a/awsapi/test/com/cloud/gate/persist/PersitTestCase.java +++ /dev/null @@ -1,73 +0,0 @@ -// 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. -package com.cloud.gate.persist; - -import org.apache.log4j.Logger; - -import com.cloud.bridge.persist.PersistContext; -import com.cloud.gate.testcase.BaseTestCase; - -public class PersitTestCase extends BaseTestCase { - protected final static Logger logger = Logger.getLogger(PersitTestCase.class); - - public void testNamedLock() { - Thread t1 = new Thread(new Runnable() { - public void run() { - for(int i = 0; i < 10; i++) { - if(PersistContext.acquireNamedLock("TestLock", 3)) { - logger.info("Thread 1 acquired lock"); - try { - Thread.currentThread().sleep(BaseTestCase.getRandomMilliseconds(5000, 10000)); - } catch (InterruptedException e) { - } - logger.info("Thread 1 to release lock"); - PersistContext.releaseNamedLock("TestLock"); - } else { - logger.info("Thread 1 is unable to acquire lock"); - } - } - } - }); - - Thread t2 = new Thread(new Runnable() { - public void run() { - for(int i = 0; i < 10; i++) { - if(PersistContext.acquireNamedLock("TestLock", 3)) { - logger.info("Thread 2 acquired lock"); - try { - Thread.currentThread().sleep(BaseTestCase.getRandomMilliseconds(1000, 5000)); - } catch (InterruptedException e) { - } - logger.info("Thread 2 to release lock"); - PersistContext.releaseNamedLock("TestLock"); - } else { - logger.info("Thread 2 is unable to acquire lock"); - } - } - } - }); - - t1.start(); - t2.start(); - - try { - t1.join(); - t2.join(); - } catch(InterruptedException e) { - } - } -} diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties index fbc04713fb7..1638be19e49 100644 --- a/client/WEB-INF/classes/resources/messages.properties +++ b/client/WEB-INF/classes/resources/messages.properties @@ -14,7 +14,10 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. - +message.select.affinity.groups=Please select any affinity groups you want this VM to belong to: +message.no.affinity.groups=You do not have any affinity groups. Please continue to the next step. +label.action.delete.nic=Remove NIC +message.action.delete.nic=Please confirm that want to remove this NIC, which will also remove the associated network from the VM. changed.item.properties=Changed item properties confirm.enable.s3=Please fill in the following information to enable support for S3-backed Secondary Storage confirm.enable.swift=Please fill in the following information to enable support for Swift @@ -22,7 +25,7 @@ error.could.not.enable.zone=Could not enable zone error.installWizard.message=Something went wrong; you may go back and correct any errors error.invalid.username.password=Invalid username or password error.login=Your username/password does not match our records. -error.menu.select=Unable to perform action due to no items being selected. +error.menu.select=Unable to perform action due to no items being selected. error.mgmt.server.inaccessible=The Management Server is unaccessible. Please try again later. error.password.not.match=The password fields do not match error.please.specify.physical.network.tags=Network offerings is not available until you specify tags for this physical network. @@ -31,115 +34,115 @@ error.something.went.wrong.please.correct.the.following=Something went wrong; pl error.unable.to.reach.management.server=Unable to reach Management Server error.unresolved.internet.name=Your internet name cannot be resolved. extractable=Extractable -force.delete.domain.warning=Warning: Choosing this option will cause the deletion of all child domains and all associated accounts and their resources. +force.delete.domain.warning=Warning\: Choosing this option will cause the deletion of all child domains and all associated accounts and their resources. force.delete=Force Delete +force.remove.host.warning=Warning\: Choosing this option will cause CloudStack to forcefully stop all running virtual machines before removing this host from the cluster. force.remove=Force Remove -force.remove.host.warning=Warning: Choosing this option will cause CloudStack to forcefully stop all running virtual machines before removing this host from the cluster. +force.stop.instance.warning=Warning\: Forcing a stop on this instance should be your last option. It can lead to data loss as well as inconsistent behavior of the virtual machine state. force.stop=Force Stop -force.stop.instance.warning=Warning: Forcing a stop on this instance should be your last option. It can lead to data loss as well as inconsistent behavior of the virtual machine state. ICMP.code=ICMP Code ICMP.type=ICMP Type image.directory=Image Directory inline=Inline instances.actions.reboot.label=Reboot instance label.accept.project.invitation=Accept project invitation -label.account=Account label.account.and.security.group=Account, Security group label.account.id=Account ID label.account.name=Account Name -label.accounts=Accounts label.account.specific=Account-Specific +label.account=Account +label.accounts=Accounts label.acquire.new.ip=Acquire New IP -label.action.attach.disk=Attach Disk label.action.attach.disk.processing=Attaching Disk.... -label.action.attach.iso=Attach ISO +label.action.attach.disk=Attach Disk label.action.attach.iso.processing=Attaching ISO.... -label.action.cancel.maintenance.mode=Cancel Maintenance Mode +label.action.attach.iso=Attach ISO label.action.cancel.maintenance.mode.processing=Cancelling Maintenance Mode.... +label.action.cancel.maintenance.mode=Cancel Maintenance Mode label.action.change.password=Change Password -label.action.change.service=Change Service label.action.change.service.processing=Changing Service.... -label.action.copy.ISO=Copy ISO +label.action.change.service=Change Service label.action.copy.ISO.processing=Coping ISO.... -label.action.copy.template=Copy Template +label.action.copy.ISO=Copy ISO label.action.copy.template.processing=Coping Template.... -label.action.create.template=Create Template +label.action.copy.template=Copy Template label.action.create.template.from.vm=Create Template from VM label.action.create.template.from.volume=Create Template from Volume label.action.create.template.processing=Creating Template.... -label.action.create.vm=Create VM +label.action.create.template=Create Template label.action.create.vm.processing=Creating VM.... -label.action.create.volume=Create Volume +label.action.create.vm=Create VM label.action.create.volume.processing=Creating Volume.... -label.action.delete.account=Delete account +label.action.create.volume=Create Volume label.action.delete.account.processing=Deleting account.... -label.action.delete.cluster=Delete Cluster +label.action.delete.account=Delete account label.action.delete.cluster.processing=Deleting Cluster.... -label.action.delete.disk.offering=Delete Disk Offering +label.action.delete.cluster=Delete Cluster label.action.delete.disk.offering.processing=Deleting Disk Offering.... -label.action.delete.domain=Delete Domain +label.action.delete.disk.offering=Delete Disk Offering label.action.delete.domain.processing=Deleting Domain.... -label.action.delete.firewall=Delete firewall rule +label.action.delete.domain=Delete Domain label.action.delete.firewall.processing=Deleting Firewall.... -label.action.delete.ingress.rule=Delete Ingress Rule +label.action.delete.firewall=Delete firewall rule label.action.delete.ingress.rule.processing=Deleting Ingress Rule.... -label.action.delete.IP.range=Delete IP Range +label.action.delete.ingress.rule=Delete Ingress Rule label.action.delete.IP.range.processing=Deleting IP Range.... -label.action.delete.ISO=Delete ISO +label.action.delete.IP.range=Delete IP Range label.action.delete.ISO.processing=Deleting ISO.... -label.action.delete.load.balancer=Delete load balancer rule +label.action.delete.ISO=Delete ISO label.action.delete.load.balancer.processing=Deleting Load Balancer.... -label.action.delete.network=Delete Network +label.action.delete.load.balancer=Delete load balancer rule label.action.delete.network.processing=Deleting Network.... +label.action.delete.network=Delete Network label.action.delete.nexusVswitch=Delete Nexus 1000v label.action.delete.physical.network=Delete physical network -label.action.delete.pod=Delete Pod label.action.delete.pod.processing=Deleting Pod.... -label.action.delete.primary.storage=Delete Primary Storage +label.action.delete.pod=Delete Pod label.action.delete.primary.storage.processing=Deleting Primary Storage.... -label.action.delete.secondary.storage=Delete Secondary Storage +label.action.delete.primary.storage=Delete Primary Storage label.action.delete.secondary.storage.processing=Deleting Secondary Storage.... -label.action.delete.security.group=Delete Security Group +label.action.delete.secondary.storage=Delete Secondary Storage label.action.delete.security.group.processing=Deleting Security Group.... -label.action.delete.service.offering=Delete Service Offering +label.action.delete.security.group=Delete Security Group label.action.delete.service.offering.processing=Deleting Service Offering.... -label.action.delete.snapshot=Delete Snapshot +label.action.delete.service.offering=Delete Service Offering label.action.delete.snapshot.processing=Deleting Snapshot.... +label.action.delete.snapshot=Delete Snapshot label.action.delete.system.service.offering=Delete System Service Offering -label.action.delete.template=Delete Template label.action.delete.template.processing=Deleting Template.... -label.action.delete.user=Delete User +label.action.delete.template=Delete Template label.action.delete.user.processing=Deleting User.... -label.action.delete.volume=Delete Volume +label.action.delete.user=Delete User label.action.delete.volume.processing=Deleting Volume.... -label.action.delete.zone=Delete Zone +label.action.delete.volume=Delete Volume label.action.delete.zone.processing=Deleting Zone.... -label.action.destroy.instance=Destroy Instance +label.action.delete.zone=Delete Zone label.action.destroy.instance.processing=Destroying Instance.... -label.action.destroy.systemvm=Destroy System VM +label.action.destroy.instance=Destroy Instance label.action.destroy.systemvm.processing=Destroying System VM.... -label.action.detach.disk=Detach Disk +label.action.destroy.systemvm=Destroy System VM label.action.detach.disk.processing=Detaching Disk.... -label.action.detach.iso=Detach ISO +label.action.detach.disk=Detach Disk label.action.detach.iso.processing=Detaching ISO.... -label.action.disable.account=Disable account +label.action.detach.iso=Detach ISO label.action.disable.account.processing=Disabling account.... -label.action.disable.cluster=Disable Cluster +label.action.disable.account=Disable account label.action.disable.cluster.processing=Disabling Cluster.... +label.action.disable.cluster=Disable Cluster label.action.disable.nexusVswitch=Disable Nexus 1000v label.action.disable.physical.network=Disable physical network -label.action.disable.pod=Disable Pod label.action.disable.pod.processing=Disabling Pod.... -label.action.disable.static.NAT=Disable Static NAT +label.action.disable.pod=Disable Pod label.action.disable.static.NAT.processing=Disabling Static NAT.... -label.action.disable.user=Disable User +label.action.disable.static.NAT=Disable Static NAT label.action.disable.user.processing=Disabling User.... -label.action.disable.zone=Disable Zone +label.action.disable.user=Disable User label.action.disable.zone.processing=Disabling Zone.... +label.action.disable.zone=Disable Zone label.action.download.ISO=Download ISO label.action.download.template=Download Template -label.action.download.volume=Download Volume label.action.download.volume.processing=Downloading Volume.... +label.action.download.volume=Download Volume label.action.edit.account=Edit account label.action.edit.disk.offering=Edit Disk Offering label.action.edit.domain=Edit Domain @@ -147,9 +150,9 @@ label.action.edit.global.setting=Edit Global Setting label.action.edit.host=Edit Host label.action.edit.instance=Edit Instance label.action.edit.ISO=Edit ISO -label.action.edit.network=Edit Network label.action.edit.network.offering=Edit Network Offering label.action.edit.network.processing=Editing Network.... +label.action.edit.network=Edit Network label.action.edit.pod=Edit Pod label.action.edit.primary.storage=Edit Primary Storage label.action.edit.resource.limits=Edit Resource Limits @@ -157,37 +160,37 @@ label.action.edit.service.offering=Edit Service Offering label.action.edit.template=Edit Template label.action.edit.user=Edit User label.action.edit.zone=Edit Zone -label.action.enable.account=Enable account label.action.enable.account.processing=Enabling account.... -label.action.enable.cluster=Enable Cluster +label.action.enable.account=Enable account label.action.enable.cluster.processing=Enabling Cluster.... -label.action.enable.maintenance.mode=Enable Maintenance Mode +label.action.enable.cluster=Enable Cluster label.action.enable.maintenance.mode.processing=Enabling Maintenance Mode.... +label.action.enable.maintenance.mode=Enable Maintenance Mode label.action.enable.nexusVswitch=Enable Nexus 1000v label.action.enable.physical.network=Enable physical network -label.action.enable.pod=Enable Pod label.action.enable.pod.processing=Enabling Pod.... -label.action.enable.static.NAT=Enable Static NAT +label.action.enable.pod=Enable Pod label.action.enable.static.NAT.processing=Enabling Static NAT.... -label.action.enable.user=Enable User +label.action.enable.static.NAT=Enable Static NAT label.action.enable.user.processing=Enabling User.... -label.action.enable.zone=Enable Zone +label.action.enable.user=Enable User label.action.enable.zone.processing=Enabling Zone.... -label.action.force.reconnect=Force Reconnect +label.action.enable.zone=Enable Zone label.action.force.reconnect.processing=Reconnecting.... -label.action.generate.keys=Generate Keys +label.action.force.reconnect=Force Reconnect label.action.generate.keys.processing=Generate Keys.... +label.action.generate.keys=Generate Keys label.action.list.nexusVswitch=List Nexus 1000v -label.action.lock.account=Lock account label.action.lock.account.processing=Locking account.... -label.action.manage.cluster=Manage Cluster +label.action.lock.account=Lock account label.action.manage.cluster.processing=Managing Cluster.... -label.action.migrate.instance=Migrate Instance +label.action.manage.cluster=Manage Cluster label.action.migrate.instance.processing=Migrating Instance.... -label.action.migrate.router=Migrate Router +label.action.migrate.instance=Migrate Instance label.action.migrate.router.processing=Migrating Router.... -label.action.migrate.systemvm=Migrate System VM +label.action.migrate.router=Migrate Router label.action.migrate.systemvm.processing=Migrating System VM.... +label.action.migrate.systemvm=Migrate System VM label.action.reboot.instance.processing=Rebooting Instance.... label.action.reboot.instance=Reboot Instance label.action.reboot.router.processing=Rebooting Router.... @@ -208,7 +211,6 @@ label.action.resize.volume=Resize Volume label.action.resource.limits=Resource limits label.action.restore.instance.processing=Restoring Instance.... label.action.restore.instance=Restore Instance -label.actions=Actions label.action.start.instance.processing=Starting Instance.... label.action.start.instance=Start Instance label.action.start.router.processing=Starting Router.... @@ -232,18 +234,19 @@ label.action.update.resource.count=Update Resource Count label.action.vmsnapshot.create=Take VM Snapshot label.action.vmsnapshot.delete=Delete VM snapshot label.action.vmsnapshot.revert=Revert to VM snapshot +label.actions=Actions label.activate.project=Activate Project label.active.sessions=Active Sessions -label.add.account=Add Account -label.add.accounts=Add accounts -label.add.accounts.to=Add accounts to label.add.account.to.project=Add account to project +label.add.account=Add Account +label.add.accounts.to=Add accounts to +label.add.accounts=Add accounts label.add.ACL=Add ACL -label.add=Add +label.add.affinity.group=Add new affinity group label.add.BigSwitchVns.device=Add BigSwitch Vns Controller -label.add.by=Add by label.add.by.cidr=Add By CIDR label.add.by.group=Add By Group +label.add.by=Add by label.add.cluster=Add Cluster label.add.compute.offering=Add compute offering label.add.direct.iprange=Add Direct Ip Range @@ -254,24 +257,15 @@ label.add.F5.device=Add F5 device label.add.firewall=Add firewall rule label.add.guest.network=Add guest network label.add.host=Add Host -label.adding=Adding -label.adding.cluster=Adding Cluster -label.adding.failed=Adding Failed -label.adding.pod=Adding Pod -label.adding.processing=Adding.... label.add.ingress.rule=Add Ingress Rule -label.adding.succeeded=Adding Succeeded -label.adding.user=Adding User -label.adding.zone=Adding Zone label.add.ip.range=Add IP Range -label.additional.networks=Additional Networks label.add.load.balancer=Add Load Balancer label.add.more=Add More label.add.netScaler.device=Add Netscaler device label.add.network.ACL=Add network ACL -label.add.network=Add Network label.add.network.device=Add Network Device label.add.network.offering=Add network offering +label.add.network=Add Network label.add.new.F5=Add new F5 label.add.new.gateway=Add new gateway label.add.new.NetScaler=Add new NetScaler @@ -297,21 +291,34 @@ label.add.template=Add Template label.add.to.group=Add to group label.add.user=Add User label.add.vlan=Add VLAN -label.add.vm=Add VM -label.add.vms=Add VMs -label.add.vms.to.lb=Add VM(s) to load balancer rule label.add.VM.to.tier=Add VM to tier +label.add.vm=Add VM +label.add.vms.to.lb=Add VM(s) to load balancer rule +label.add.vms=Add VMs label.add.volume=Add Volume label.add.vpc=Add VPC label.add.vpn.customer.gateway=Add VPN Customer Gateway label.add.VPN.gateway=Add VPN Gateway label.add.vpn.user=Add VPN user label.add.zone=Add Zone +label.add=Add +label.adding.cluster=Adding Cluster +label.adding.failed=Adding Failed +label.adding.pod=Adding Pod +label.adding.processing=Adding.... +label.adding.succeeded=Adding Succeeded +label.adding.user=Adding User +label.adding.zone=Adding Zone +label.adding=Adding +label.additional.networks=Additional Networks label.admin.accounts=Admin Accounts label.admin=Admin -label.advanced=Advanced label.advanced.mode=Advanced Mode label.advanced.search=Advance Search +label.advanced=Advanced +label.affinity.group=Affinity Group +label.affinity.groups=Affinity Groups +label.affinity=Affinity label.agent.password=Agent Password label.agent.username=Agent Username label.agree=Agree @@ -319,23 +326,26 @@ label.alert=Alert label.algorithm=Algorithm label.allocated=Allocated label.allocation.state=Allocation State +label.anti.affinity.group=Anti-affinity Group +label.anti.affinity.groups=Anti-affinity Groups +label.anti.affinity=Anti-affinity label.api.key=API Key label.apply=Apply -label.assign=Assign label.assign.to.load.balancer=Assigning instance to load balancer -label.associated.network=Associated Network +label.assign=Assign label.associated.network.id=Associated Network ID +label.associated.network=Associated Network label.attached.iso=Attached ISO label.author.email=Author e-mail label.author.name=Author name -label.availability=Availability label.availability.zone=Availability Zone -label.available=Available +label.availability=Availability label.available.public.ips=Available Public IP Addresses +label.available=Available label.back=Back label.bandwidth=Bandwidth -label.basic=Basic label.basic.mode=Basic Mode +label.basic=Basic label.bigswitch.controller.address=BigSwitch Vns Controller Address label.bootable=Bootable label.broadcast.domain.range=Broadcast domain range @@ -350,12 +360,12 @@ label.by.pod=By Pod label.by.role=By Role label.by.start.date=By Start Date label.by.state=By State +label.by.traffic.type=By Traffic Type +label.by.type.id=By Type ID +label.by.type=By Type +label.by.zone=By Zone label.bytes.received=Bytes Received label.bytes.sent=Bytes Sent -label.by.traffic.type=By Traffic Type -label.by.type=By Type -label.by.type.id=By Type ID -label.by.zone=By Zone label.cancel=Cancel label.capacity=Capacity label.certificate=Certificate @@ -364,50 +374,50 @@ label.change.value=Change value label.character=Character label.checksum=MD5 checksum label.cidr.account=CIDR or Account/Security Group -label.cidr=CIDR label.CIDR.list=CIDR list label.cidr.list=Source CIDR label.CIDR.of.destination.network=CIDR of destination network +label.cidr=CIDR label.clean.up=Clean up label.clear.list=Clear list label.close=Close label.cloud.console=Cloud Management Console label.cloud.managed=Cloud.com Managed -label.cluster=Cluster label.cluster.name=Cluster Name -label.clusters=Clusters label.cluster.type=Cluster Type +label.cluster=Cluster +label.clusters=Clusters label.clvm=CLVM label.code=Code label.community=Community label.compute.and.storage=Compute and Storage -label.compute=Compute label.compute.offering=Compute offering label.compute.offerings=Compute offerings +label.compute=Compute label.configuration=Configuration -label.configure=Configure label.configure.network.ACLs=Configure Network ACLs label.configure.vpc=Configure VPC -label.confirmation=Confirmation +label.configure=Configure label.confirm.password=Confirm password -label.congratulations=Congratulations! +label.confirmation=Confirmation +label.congratulations=Congratulations\! label.conserve.mode=Conserve mode label.console.proxy=Console proxy label.continue.basic.install=Continue with basic installation label.continue=Continue label.corrections.saved=Corrections saved -label.cpu.allocated=CPU Allocated label.cpu.allocated.for.VMs=CPU Allocated for VMs +label.cpu.allocated=CPU Allocated label.CPU.cap=CPU Cap -label.cpu=CPU label.cpu.limits=CPU limits label.cpu.mhz=CPU (in MHz) label.cpu.utilized=CPU Utilized -label.created.by.system=Created by system -label.created=Created +label.cpu=CPU label.create.project=Create project label.create.template=Create template label.create.VPN.connection=Create VPN Connection +label.created.by.system=Created by system +label.created=Created label.cross.zones=Cross Zones label.custom.disk.size=Custom Disk Size label.daily=Daily @@ -418,11 +428,11 @@ label.day.of.week=Day of Week label.dead.peer.detection=Dead Peer Detection label.decline.invitation=Decline invitation label.dedicated=Dedicated -label.default=Default label.default.use=Default Use label.default.view=Default View +label.default=Default +label.delete.affinity.group=Delete Affinity Group label.delete.BigSwitchVns=Remove BigSwitch Vns Controller -label.delete=Delete label.delete.F5=Delete F5 label.delete.gateway=delete gateway label.delete.NetScaler=Delete NetScaler @@ -433,58 +443,60 @@ label.delete.VPN.connection=delete VPN connection label.delete.VPN.customer.gateway=delete VPN Customer Gateway label.delete.VPN.gateway=delete VPN Gateway label.delete.vpn.user=Delete VPN user +label.delete=Delete label.deleting.failed=Deleting Failed label.deleting.processing=Deleting.... label.description=Description label.destination.physical.network.id=Destination physical network ID label.destination.zone=Destination Zone -label.destroy=Destroy label.destroy.router=Destroy router +label.destroy=Destroy label.detaching.disk=Detaching Disk label.details=Details label.device.id=Device ID label.devices=Devices -label.dhcp=DHCP label.DHCP.server.type=DHCP Server Type +label.dhcp=DHCP label.direct.ips=Shared Network IPs -label.disabled=Disabled label.disable.provider=Disable provider label.disable.vpn=Disable VPN +label.disabled=Disabled label.disabling.vpn.access=Disabling VPN Access label.disk.allocated=Disk Allocated label.disk.offering=Disk Offering -label.disk.size=Disk Size label.disk.size.gb=Disk Size (in GB) +label.disk.size=Disk Size label.disk.total=Disk Total label.disk.volume=Disk Volume label.display.name=Display name label.display.text=Display Text label.dns.1=DNS 1 label.dns.2=DNS 2 -label.dns=DNS label.DNS.domain.for.guest.networks=DNS domain for Guest Networks +label.dns=DNS label.domain.admin=Domain Admin -label.domain=Domain label.domain.id=Domain ID label.domain.name=Domain Name label.domain.router=Domain router label.domain.suffix=DNS Domain Suffix (i.e., xyz.com) +label.domain=Domain label.done=Done label.double.quotes.are.not.allowed=Double quotes are not allowed label.download.progress=Download Progress label.drag.new.position=Drag to new position -label.edit=Edit +label.edit.affinity.group=Edit Affinity Group label.edit.lb.rule=Edit LB rule label.edit.network.details=Edit network details label.edit.project.details=Edit project details label.edit.tags=Edit tags label.edit.traffic.type=Edit traffic type label.edit.vpc=Edit VPC +label.edit=Edit label.egress.rule=Egress rule label.egress.rules=Egress rules -label.elastic=Elastic label.elastic.IP=Elastic IP label.elastic.LB=Elastic LB +label.elastic=Elastic label.email=Email label.enable.provider=Enable provider label.enable.s3=Enable S3-backed Secondary Storage @@ -493,18 +505,17 @@ label.enable.vpn=Enable VPN label.enabling.vpn.access=Enabling VPN Access label.enabling.vpn=Enabling VPN label.end.IP=End IP -label.endpoint=Endpoint -label.endpoint.or.operation=Endpoint or Operation label.end.port=End Port label.end.reserved.system.IP=End Reserved system IP label.end.vlan=End Vlan +label.endpoint.or.operation=Endpoint or Operation +label.endpoint=Endpoint label.enter.token=Enter token label.error.code=Error Code label.error=Error label.ESP.encryption=ESP Encryption label.ESP.hash=ESP Hash label.ESP.lifetime=ESP Lifetime (second) -label.ESP.lifetime=ESP Lifetime(second) label.ESP.policy=ESP policy label.esx.host=ESX/ESXi Host label.example=Example @@ -518,8 +529,8 @@ label.firewall=Firewall label.first.name=First Name label.format=Format label.friday=Friday -label.full=Full label.full.path=Full path +label.full=Full label.gateway=Gateway label.general.alerts=General Alerts label.generating.url=Generating URL @@ -527,40 +538,39 @@ label.go.step.2=Go to Step 2 label.go.step.3=Go to Step 3 label.go.step.4=Go to Step 4 label.go.step.5=Go to Step 5 -label.group=Group label.group.optional=Group (Optional) +label.group=Group label.guest.cidr=Guest CIDR label.guest.end.ip=Guest end IP label.guest.gateway=Guest Gateway -label.guest=Guest -label.guest.ip=Guest IP Address label.guest.ip.range=Guest IP Range +label.guest.ip=Guest IP Address label.guest.netmask=Guest Netmask label.guest.networks=Guest networks label.guest.start.ip=Guest start IP label.guest.traffic=Guest Traffic label.guest.type=Guest Type +label.guest=Guest label.ha.enabled=HA Enabled label.help=Help label.hide.ingress.rule=Hide Ingress Rule label.hints=Hints label.host.alerts=Host Alerts -label.host=Host label.host.MAC=Host MAC label.host.name=Host Name +label.host.tags=Host Tags +label.host=Host label.hosts=Hosts -label.host.tags=Host Tags label.hourly=Hourly label.hypervisor.capabilities=Hypervisor capabilities -label.hypervisor=Hypervisor label.hypervisor.type=Hypervisor Type label.hypervisor.version=Hypervisor version +label.hypervisor=Hypervisor label.id=ID label.IKE.DH=IKE DH label.IKE.encryption=IKE Encryption label.IKE.hash=IKE Hash label.IKE.lifetime=IKE lifetime (second) -label.IKE.lifetime=IKE Lifetime (second) label.IKE.policy=IKE policy label.info=Info label.ingress.rule=Ingress Rule @@ -575,92 +585,95 @@ label.installWizard.addPrimaryStorageIntro.subtitle=What is primary storage? label.installWizard.addPrimaryStorageIntro.title=Let’s add primary storage label.installWizard.addSecondaryStorageIntro.subtitle=What is secondary storage? label.installWizard.addSecondaryStorageIntro.title=Let’s add secondary storage +label.installWizard.addZone.title=Add zone label.installWizard.addZoneIntro.subtitle=What is a zone? label.installWizard.addZoneIntro.title=Let’s add a zone -label.installWizard.addZone.title=Add zone label.installWizard.click.launch=Click the launch button. -label.installWizard.subtitle=This tour will aid you in setting up your CloudStack™ installation -label.installWizard.title=Hello and Welcome to CloudStack™ -label.instance=Instance +label.installWizard.subtitle=This tour will aid you in setting up your CloudStack&\#8482 installation +label.installWizard.title=Hello and Welcome to CloudStack&\#8482 label.instance.limits=Instance Limits label.instance.name=Instance Name +label.instance=Instance label.instances=Instances label.internal.dns.1=Internal DNS 1 label.internal.dns.2=Internal DNS 2 label.internal.name=Internal name label.interval.type=Interval Type -label.introduction.to.cloudstack=Introduction to CloudStack™ +label.introduction.to.cloudstack=Introduction to CloudStack&\#8482 label.invalid.integer=Invalid Integer label.invalid.number=Invalid Number label.invitations=Invitations -label.invited.accounts=Invited accounts -label.invite=Invite label.invite.to=Invite to +label.invite=Invite +label.invited.accounts=Invited accounts label.ip.address=IP Address -label.ipaddress=IP Address label.ip.allocations=IP Allocations -label.ip=IP label.ip.limits=Public IP Limits label.ip.or.fqdn=IP or FQDN label.ip.range=IP Range label.ip.ranges=IP Ranges -label.IPsec.preshared.key=IPsec Preshared-Key +label.ip=IP +label.ipaddress=IP Address label.ips=IPs -label.iscsi=iSCSI +label.IPsec.preshared.key=IPsec Preshared-Key label.is.default=Is Default +label.is.redundant.router=Redundant +label.is.shared=Is Shared +label.is.system=Is System +label.iscsi=iSCSI label.iso.boot=ISO Boot label.iso=ISO label.isolated.networks=Isolated networks label.isolation.method=Isolation method label.isolation.mode=Isolation Mode label.isolation.uri=Isolation URI -label.is.redundant.router=Redundant -label.is.shared=Is Shared -label.is.system=Is System label.item.listing=Item listing label.keep=Keep -label.keyboard.type=Keyboard type label.key=Key +label.keyboard.type=Keyboard type label.kvm.traffic.label=KVM traffic label label.label=Label +label.lang.arabic=Arabic label.lang.brportugese=Brazilian Portugese +label.lang.catalan=Catalan label.lang.chinese=Chinese (Simplified) label.lang.english=English label.lang.french=French +label.lang.german=German +label.lang.italian=Italian label.lang.japanese=Japanese label.lang.korean=Korean +label.lang.norwegian=Norwegian label.lang.russian=Russian label.lang.spanish=Spanish label.last.disconnected=Last Disconnected label.last.name=Last Name label.latest.events=Latest events -label.launch=Launch label.launch.vm=Launch VM -label.launch.zone=Launch zone +label.launch.zone=Launch zone +label.launch=Launch label.LB.isolation=LB isolation label.least.connections=Least connections label.level=Level label.linklocal.ip=Link Local IP Adddress label.load.balancer=Load Balancer -label.load.balancing=Load Balancing label.load.balancing.policies=Load balancing policies +label.load.balancing=Load Balancing label.loading=Loading -label.local=Local label.local.storage.enabled=Local storage enabled -label.local.storage.enabled=Local Storage Enabled label.local.storage=Local Storage +label.local=Local label.login=Login label.logout=Logout +label.LUN.number=LUN \# label.lun=LUN -label.LUN.number=LUN # label.make.project.owner=Make account project owner +label.manage.resources=Manage Resources label.manage=Manage label.management.ips=Management IP Addresses label.management=Management -label.manage.resources=Manage Resources label.max.cpus=Max. CPU cores label.max.guest.limit=Max guest limit -label.maximum=Maximum label.max.memory=Max. memory (MiB) label.max.networks=Max. networks label.max.primary.storage=Max. primary (GiB) @@ -671,13 +684,14 @@ label.max.templates=Max. templates label.max.vms=Max. user VMs label.max.volumes=Max. volumes label.max.vpcs=Max. VPCs +label.maximum=Maximum label.may.continue=You may now continue. label.memory.allocated=Memory Allocated label.memory.limits=Memory limits (MiB) label.memory.mb=Memory (in MB) -label.memory=Memory label.memory.total=Memory Total label.memory.used=Memory Used +label.memory=Memory label.menu.accounts=Accounts label.menu.alerts=Alerts label.menu.all.accounts=All Accounts @@ -701,8 +715,8 @@ label.menu.my.accounts=My Accounts label.menu.my.instances=My Instances label.menu.my.isos=My ISOs label.menu.my.templates=My Templates -label.menu.network=Network label.menu.network.offerings=Network Offerings +label.menu.network=Network label.menu.physical.resources=Physical Resources label.menu.regions=Regions label.menu.running.instances=Running Instances @@ -712,15 +726,15 @@ label.menu.snapshots=Snapshots label.menu.stopped.instances=Stopped Instances label.menu.storage=Storage label.menu.system.service.offerings=System Offerings -label.menu.system=System label.menu.system.vms=System VMs +label.menu.system=System label.menu.templates=Templates label.menu.virtual.appliances=Virtual Appliances label.menu.virtual.resources=Virtual Resources label.menu.volumes=Volumes label.migrate.instance.to.host=Migrate instance to another host -label.migrate.instance.to=Migrate instance to label.migrate.instance.to.ps=Migrate instance to another primary storage +label.migrate.instance.to=Migrate instance to label.migrate.router.to=Migrate Router to label.migrate.systemvm.to=Migrate System VM to label.migrate.to.host=Migrate to host @@ -738,24 +752,22 @@ label.move.up.row=Move up one row label.my.account=My Account label.my.network=My network label.my.templates=My templates -label.name=Name label.name.optional=Name (Optional) +label.name=Name label.nat.port.range=NAT Port Range label.netmask=Netmask label.netScaler=NetScaler +label.network.ACL.total=Network ACL Total label.network.ACL=Network ACL label.network.ACLs=Network ACLs -label.network.ACL.total=Network ACL Total label.network.desc=Network Desc -label.network.device=Network Device label.network.device.type=Network Device Type -label.network.domain=Network Domain +label.network.device=Network Device label.network.domain.text=Network domain +label.network.domain=Network Domain label.network.id=Network ID -label.networking.and.security=Networking and security label.network.label.display.for.blank.value=Use default gateway label.network.name=Network Name -label.network=Network label.network.offering.display.text=Network Offering Display Text label.network.offering.id=Network Offering ID label.network.offering.name=Network Offering Name @@ -764,18 +776,20 @@ label.network.rate.megabytes=Network Rate (Mb/s) label.network.rate=Network Rate label.network.read=Network Read label.network.service.providers=Network Service Providers -label.networks=Networks label.network.type=Network Type label.network.write=Network Write -label.new=New +label.network=Network +label.networking.and.security=Networking and security +label.networks=Networks label.new.password=New Password label.new.project=New Project label.new.vm=New VM +label.new=New label.next=Next label.nexusVswitch=Nexus 1000v -label.nfs=NFS label.nfs.server=NFS Server label.nfs.storage=NFS Storage +label.nfs=NFS label.nic.adapter.type=NIC adapter type label.nicira.controller.address=Controller Address label.nicira.l3gatewayserviceuuid=L3 Gateway Service Uuid @@ -787,20 +801,19 @@ label.no.data=No data to show label.no.errors=No Recent Errors label.no.isos=No available ISOs label.no.items=No Available Items -label.none=None -label.no=No label.no.security.groups=No Available Security Groups -label.not.found=Not Found label.no.thanks=No thanks -label.no.thanks=No Thanks +label.no=No +label.none=None +label.not.found=Not Found label.notifications=Notifications +label.num.cpu.cores=\# of CPU Cores label.number.of.clusters=Number of Clusters label.number.of.hosts=Number of Hosts label.number.of.pods=Number of Pods label.number.of.system.vms=Number of System VMs label.number.of.virtual.routers=Number of Virtual Routers label.number.of.zones=Number of Zones -label.num.cpu.cores=# of CPU Cores label.numretries=Number of Retries label.ocfs2=OCFS2 label.offer.ha=Offer HA @@ -811,14 +824,14 @@ label.os.preference=OS Preference label.os.type=OS Type label.owned.public.ips=Owned Public IP Addresses label.owner.account=Owner Account -label.owner.domain=Owner Domain +label.owner.domain=Owner Domain label.parent.domain=Parent Domain label.password.enabled=Password Enabled label.password=Password label.path=Path label.perfect.forward.secrecy=Perfect Forward Secrecy label.physical.network.ID=Physical network ID -label.physical.network=Physical Network +label.physical.network=Physical Network label.PING.CIFS.password=PING CIFS password label.PING.CIFS.username=PING CIFS username label.PING.dir=PING Directory @@ -834,8 +847,8 @@ label.port.forwarding.policies=Port forwarding policies label.port.forwarding=Port Forwarding label.port.range=Port Range label.PreSetup=PreSetup -label.previous=Previous label.prev=Prev +label.previous=Previous label.primary.allocated=Primary Storage Allocated label.primary.network=Primary Network label.primary.storage.count=Primary Storage Pools @@ -844,20 +857,20 @@ label.primary.storage=Primary Storage label.primary.used=Primary Storage Used label.private.Gateway=Private Gateway label.private.interface=Private Interface -label.private.ip=Private IP Address label.private.ip.range=Private IP Range +label.private.ip=Private IP Address label.private.ips=Private IP Addresses -label.privatekey=PKCS#8 Private Key label.private.network=Private network label.private.port=Private Port label.private.zone=Private Zone +label.privatekey=PKCS\#8 Private Key label.project.dashboard=Project dashboard label.project.id=Project ID label.project.invite=Invite to project label.project.name=Project name +label.project.view=Project View label.project=Project label.projects=Projects -label.project.view=Project View label.protocol=Protocol label.providers=Providers label.public.interface=Public Interface @@ -865,9 +878,9 @@ label.public.ip=Public IP Address label.public.ips=Public IP Addresses label.public.network=Public network label.public.port=Public Port -label.public=Public -label.public.traffic=Public traffic +label.public.traffic=Public traffic label.public.zone=Public Zone +label.public=Public label.purpose=Purpose label.Pxe.server.type=Pxe Server Type label.quickview=Quickview @@ -887,7 +900,6 @@ label.remove.ingress.rule=Remove ingress rule label.remove.ip.range=Remove IP range label.remove.pf=Remove port forwarding rule label.remove.project.account=Remove account from project -label.remove.project.account=Remove project account label.remove.region=Remove Region label.remove.rule=Remove rule label.remove.static.nat.rule=Remove static NAT rule @@ -895,8 +907,8 @@ label.remove.static.route=Remove static route label.remove.tier=Remove tier label.remove.vm.from.lb=Remove VM from load balancer rule label.remove.vpc=remove VPC -label.removing=Removing label.removing.user=Removing User +label.removing=Removing label.required=Required label.reserved.system.gateway=Reserved system gateway label.reserved.system.ip=Reserved System IP @@ -906,9 +918,9 @@ label.resize.new.offering.id=New Offering label.resize.new.size=New Size(GB) label.resize.shrink.ok=Shrink OK label.resource.limits=Resource Limits +label.resource.state=Resource state label.resource=Resource label.resources=Resources -label.resource.state=Resource state label.restart.network=Restart network label.restart.required=Restart required label.restart.vpc=restart VPC @@ -937,36 +949,36 @@ label.scope=Scope label.search=Search label.secondary.storage.count=Secondary Storage Pools label.secondary.storage.limits=Secondary Storage limits (GiB) -label.secondary.storage=Secondary Storage label.secondary.storage.vm=Secondary storage VM +label.secondary.storage=Secondary Storage label.secondary.used=Secondary Storage Used label.secret.key=Secret Key label.security.group.name=Security Group Name label.security.group=Security Group label.security.groups.enabled=Security Groups Enabled label.security.groups=Security Groups +label.select-view=Select view label.select.a.template=Select a template label.select.a.zone=Select a zone -label.select.instance=Select instance label.select.instance.to.attach.volume.to=Select instance to attach volume to +label.select.instance=Select instance label.select.iso.or.template=Select ISO or template label.select.offering=Select offering label.select.project=Select Project -label.select=Select label.select.tier=Select Tier -label.select-view=Select view label.select.vm.for.static.nat=Select VM for static NAT +label.select=Select label.sent=Sent label.server=Server label.service.capabilities=Service Capabilities label.service.offering=Service Offering label.session.expired=Session Expired -label.setup.network=Setup Network -label.setup=Setup -label.setup.zone=Setup Zone label.set.up.zone.type=Set up zone type -label.SharedMountPoint=SharedMountPoint +label.setup.network=Setup Network +label.setup.zone=Setup Zone +label.setup=Setup label.shared=Shared +label.SharedMountPoint=SharedMountPoint label.show.ingress.rule=Show Ingress Rule label.shutdown.provider=Shutdown provider label.site.to.site.VPN=Site-to-site VPN @@ -974,9 +986,9 @@ label.size=Size label.skip.guide=I have used CloudStack before, skip this guide label.snapshot.limits=Snapshot Limits label.snapshot.name=Snapshot Name +label.snapshot.s=Snapshot (s) label.snapshot.schedule=Setup Recurring Snapshot label.snapshot=Snapshot -label.snapshot.s=Snapshot (s) label.snapshots=Snapshots label.source.nat=Source NAT label.source=Source @@ -990,21 +1002,21 @@ label.start.reserved.system.IP=Start Reserved system IP label.start.vlan=Start Vlan label.state=State label.static.nat.enabled=Static NAT Enabled -label.static.nat=Static NAT label.static.nat.to=Static NAT to label.static.nat.vm.details=Static NAT VM Details +label.static.nat=Static NAT label.statistics=Statistics label.status=Status +label.step.1.title=Step 1\: Select a Template label.step.1=Step 1 -label.step.1.title=Step 1: Select a Template +label.step.2.title=Step 2\: Service Offering label.step.2=Step 2 -label.step.2.title=Step 2: Service Offering +label.step.3.title=Step 3\: Select a Disk Offering label.step.3=Step 3 -label.step.3.title=Step 3: Select a Disk Offering +label.step.4.title=Step 4\: Network label.step.4=Step 4 -label.step.4.title=Step 4: Network +label.step.5.title=Step 5\: Review label.step.5=Step 5 -label.step.5.title=Step 5: Review label.stickiness=Stickiness label.sticky.cookie-name=Cookie name label.sticky.domain=Domain @@ -1018,15 +1030,15 @@ label.sticky.postonly=Post only label.sticky.prefix=Prefix label.sticky.request-learn=Request learn label.sticky.tablesize=Table size -label.stopped.vms=Stopped VMs label.stop=Stop -label.storage=Storage +label.stopped.vms=Stopped VMs label.storage.tags=Storage Tags label.storage.traffic=Storage Traffic label.storage.type=Storage Type +label.storage=Storage label.subdomain.access=Subdomain Access label.submit=Submit -label.submitted.by=[Submitted by: ] +label.submitted.by=[Submitted by\: ] label.succeeded=Succeeded label.sunday=Sunday label.super.cidr.for.guest.networks=Super CIDR for Guest Networks @@ -1036,9 +1048,9 @@ label.suspend.project=Suspend Project label.system.capacity=System Capacity label.system.offering=System Offering label.system.service.offering=System Service Offering -label.system.vms=System VMs -label.system.vm=System VM label.system.vm.type=System VM Type +label.system.vm=System VM +label.system.vms=System VMs label.system.wide.capacity=System-wide capacity label.tagged=Tagged label.tags=Tags @@ -1053,14 +1065,14 @@ label.theme.lightblue=Custom - Light Blue label.thursday=Thursday label.tier.details=Tier details label.tier=Tier +label.time.zone=Timezone +label.time=Time label.timeout.in.second = Timeout(seconds) label.timeout=Timeout -label.time=Time -label.time.zone=Timezone label.timezone=Timezone label.token=Token -label.total.cpu=Total CPU label.total.CPU=Total CPU +label.total.cpu=Total CPU label.total.hosts=Total Hosts label.total.memory=Total Memory label.total.of.ip=Total of IP Address @@ -1068,8 +1080,8 @@ label.total.of.vm=Total of VM label.total.storage=Total Storage label.total.vms=Total VMs label.traffic.label=Traffic label -label.traffic.types=Traffic Types label.traffic.type=Traffic Type +label.traffic.types=Traffic Types label.tuesday=Tuesday label.type.id=Type ID label.type=Type @@ -1080,15 +1092,15 @@ label.update.project.resources=Update project resources label.update.ssl.cert= SSL Certificate label.update.ssl= SSL Certificate label.updating=Updating -label.upload=Upload label.upload.volume=Upload volume +label.upload=Upload label.url=URL label.usage.interface=Usage Interface +label.use.vm.ip=Use VM IP\: label.used=Used +label.user=User label.username=Username label.users=Users -label.user=User -label.use.vm.ip=Use VM IP: label.value=Value label.vcdcname=vCenter DC name label.vcenter.cluster=vCenter Cluster @@ -1101,47 +1113,47 @@ label.vcipaddress=vCenter IP Address label.version=Version label.view.all=View all label.view.console=View console -label.viewing=Viewing label.view.more=View more label.view=View -label.virtual.appliances=Virtual Appliances +label.viewing=Viewing label.virtual.appliance=Virtual Appliance +label.virtual.appliances=Virtual Appliances label.virtual.machines=Virtual machines label.virtual.network=Virtual Network -label.virtual.routers=Virtual Routers label.virtual.router=Virtual Router +label.virtual.routers=Virtual Routers label.vlan.id=VLAN ID label.vlan.range=VLAN Range label.vlan=VLAN label.vm.add=Add Instance label.vm.destroy=Destroy label.vm.display.name=VM display name -label.VMFS.datastore=VMFS datastore -label.vmfs=VMFS label.vm.name=VM name label.vm.reboot=Reboot +label.vm.start=Start +label.vm.state=VM state +label.vm.stop=Stop +label.VMFS.datastore=VMFS datastore +label.vmfs=VMFS label.VMs.in.tier=VMs in tier +label.vms=VMs label.vmsnapshot.current=isCurrent label.vmsnapshot.memory=Snapshot memory label.vmsnapshot.parentname=Parent label.vmsnapshot.type=Type label.vmsnapshot=VM Snapshots -label.vm.start=Start -label.vm.state=VM state -label.vm.stop=Stop -label.vms=VMs label.vmware.traffic.label=VMware traffic label label.volgroup=Volume Group label.volume.limits=Volume Limits label.volume.name=Volume Name -label.volumes=Volumes label.volume=Volume +label.volumes=Volumes label.vpc.id=VPC ID label.VPC.router.details=VPC router details label.vpc=VPC label.VPN.connection=VPN Connection -label.vpn.customer.gateway=VPN Customer Gateway label.VPN.customer.gateway=VPN Customer Gateway +label.vpn.customer.gateway=VPN Customer Gateway label.VPN.gateway=VPN Gateway label.vpn=VPN label.vsmctrlvlanid=Control VLAN ID @@ -1154,27 +1166,27 @@ label.wednesday=Wednesday label.weekly=Weekly label.welcome.cloud.console=Welcome to Management Console label.welcome=Welcome -label.what.is.cloudstack=What is CloudStack™? +label.what.is.cloudstack=What is CloudStack&\#8482? label.xen.traffic.label=XenServer traffic label label.yes=Yes label.zone.details=Zone details label.zone.id=Zone ID label.zone.name=Zone name -label.zone.step.1.title=Step 1: Select a Network -label.zone.step.2.title=Step 2: Add a Zone -label.zone.step.3.title=Step 3: Add a Pod -label.zone.step.4.title=Step 4: Add an IP range -label.zones=Zones +label.zone.step.1.title=Step 1\: Select a Network +label.zone.step.2.title=Step 2\: Add a Zone +label.zone.step.3.title=Step 3\: Add a Pod +label.zone.step.4.title=Step 4\: Add an IP range label.zone.type=Zone Type label.zone.wide=Zone-Wide -label.zoneWizard.trafficType.guest=Guest: Traffic between end-user virtual machines -label.zoneWizard.trafficType.management=Management: Traffic between CloudStack\'s internal resources, including any components that communicate with the Management Server, such as hosts and CloudStack system VMs -label.zoneWizard.trafficType.public=Public: Traffic between the internet and virtual machines in the cloud. -label.zoneWizard.trafficType.storage=Storage: Traffic between primary and secondary storage servers, such as VM templates and snapshots label.zone=Zone +label.zones=Zones +label.zoneWizard.trafficType.guest=Guest\: Traffic between end-user virtual machines +label.zoneWizard.trafficType.management=Management\: Traffic between CloudStack\\\\'s internal resources, including any components that communicate with the Management Server, such as hosts and CloudStack system VMs +label.zoneWizard.trafficType.public=Public\: Traffic between the internet and virtual machines in the cloud. +label.zoneWizard.trafficType.storage=Storage\: Traffic between primary and secondary storage servers, such as VM templates and snapshots managed.state=Managed State -message.acquire.new.ip=Please confirm that you would like to acquire a new IP for this network. message.acquire.new.ip.vpc=Please confirm that you would like to acquire a new IP for this VPC. +message.acquire.new.ip=Please confirm that you would like to acquire a new IP for this network. message.acquire.public.ip=Please select a zone from which you want to acquire your new IP from. message.action.cancel.maintenance.mode=Please confirm that you want to cancel this maintenance. message.action.cancel.maintenance=Your host has been successfully canceled for maintenance. This process can take up to several minutes. @@ -1183,8 +1195,8 @@ message.action.change.service.warning.for.router=Your router must be stopped bef message.action.delete.cluster=Please confirm that you want to delete this cluster. message.action.delete.disk.offering=Please confirm that you want to delete this disk offering. message.action.delete.domain=Please confirm that you want to delete this domain. -message.action.delete.external.firewall=Please confirm that you would like to remove this external firewall. Warning: If you are planning to add back the same external firewall, you must reset usage data on the device. -message.action.delete.external.load.balancer=Please confirm that you would like to remove this external load balancer. Warning: If you are planning to add back the same external load balancer, you must reset usage data on the device. +message.action.delete.external.firewall=Please confirm that you would like to remove this external firewall. Warning\: If you are planning to add back the same external firewall, you must reset usage data on the device. +message.action.delete.external.load.balancer=Please confirm that you would like to remove this external load balancer. Warning\: If you are planning to add back the same external load balancer, you must reset usage data on the device. message.action.delete.ingress.rule=Please confirm that you want to delete this ingress rule. message.action.delete.ISO.for.all.zones=The ISO is used by all zones. Please confirm that you want to delete it from all zones. message.action.delete.ISO=Please confirm that you want to delete this ISO. @@ -1220,15 +1232,14 @@ message.action.enable.pod=Please confirm that you want to enable this pod. message.action.enable.zone=Please confirm that you want to enable this zone. message.action.force.reconnect=Your host has been successfully forced to reconnect. This process can take up to several minutes. message.action.host.enable.maintenance.mode=Enabling maintenance mode will cause a live migration of all running instances on this host to any available host. -message.action.instance.reset.password=Please confirm that you want to change the ROOT password for this virtual machine. +message.action.instance.reset.password=Please confirm that you want to change the ROOT password for this virtual machine. message.action.manage.cluster=Please confirm that you want to manage the cluster. -message.action.primarystorage.enable.maintenance.mode=Warning: placing the primary storage into maintenance mode will cause all VMs using volumes from it to be stopped. Do you want to continue? +message.action.primarystorage.enable.maintenance.mode=Warning\: placing the primary storage into maintenance mode will cause all VMs using volumes from it to be stopped. Do you want to continue? message.action.reboot.instance=Please confirm that you want to reboot this instance. message.action.reboot.router=All services provided by this virtual router will be interrupted. Please confirm that you want to reboot this router. message.action.reboot.systemvm=Please confirm that you want to reboot this system VM. message.action.release.ip=Please confirm that you want to release this IP. message.action.remove.host=Please confirm that you want to remove this host. -message.action.remove.host=Removing last/only host in cluster and reinstalling the host will destroy working environment/database on the host and render the VM Guests unuseable. message.action.reset.password.off=Your instance currently does not support this feature. message.action.reset.password.warning=Your instance must be stopped before attempting to change its current password. message.action.restore.instance=Please confirm that you want to restore this instance. @@ -1243,40 +1254,40 @@ message.action.unmanage.cluster=Please confirm that you want to unmanage the clu message.action.vmsnapshot.delete=Please confirm that you want to delete this VM snapshot. message.action.vmsnapshot.revert=Revert VM snapshot message.activate.project=Are you sure you want to activate this project? -message.add.cluster=Add a hypervisor managed cluster for zone , pod -message.add.cluster.zone=Add a hypervisor managed cluster for zone +message.add.cluster.zone=Add a hypervisor managed cluster for zone +message.add.cluster=Add a hypervisor managed cluster for zone , pod message.add.disk.offering=Please specify the following parameters to add a new disk offering message.add.domain=Please specify the subdomain you want to create under this domain message.add.firewall=Add a firewall to zone message.add.guest.network=Please confirm that you would like to add a guest network message.add.host=Please specify the following parameters to add a new host -message.adding.host=Adding host -message.adding.Netscaler.device=Adding Netscaler device -message.adding.Netscaler.provider=Adding Netscaler provider +message.add.ip.range.direct.network=Add an IP range to direct network in zone +message.add.ip.range.to.pod=

Add an IP range to pod\:

message.add.ip.range=Add an IP range to public network in zone -message.add.ip.range.direct.network=Add an IP range to direct network in zone -message.add.ip.range.to.pod=

Add an IP range to pod:

-message.additional.networks.desc=Please select additional network(s) that your virtual instance will be connected to. +message.add.load.balancer.under.ip=The load balancer rule has been added under IP\: message.add.load.balancer=Add a load balancer to zone -message.add.load.balancer.under.ip=The load balancer rule has been added under IP: -message.add.network=Add a new network for zone: +message.add.network=Add a new network for zone\: message.add.new.gateway.to.vpc=Please specify the information to add a new gateway to this VPC. -message.add.pod=Add a new pod for zone -message.add.pod.during.zone.creation=Each zone must contain in one or more pods, and we will add the first pod now. A pod contains hosts and primary storage servers, which you will add in a later step. First, configure a range of reserved IP addresses for CloudStack's internal management traffic. The reserved IP range must be unique for each zone in the cloud. +message.add.pod.during.zone.creation=Each zone must contain in one or more pods, and we will add the first pod now. A pod contains hosts and primary storage servers, which you will add in a later step. First, configure a range of reserved IP addresses for CloudStack\\'s internal management traffic. The reserved IP range must be unique for each zone in the cloud. +message.add.pod=Add a new pod for zone +message.add.primary.storage=Add a new Primary Storage for zone , pod message.add.primary=Please specify the following parameters to add a new primary storage -message.add.primary.storage=Add a new Primary Storage for zone , pod message.add.region=Please specify the required information to add a new region. -message.add.secondary.storage=Add a new storage for zone +message.add.secondary.storage=Add a new storage for zone message.add.service.offering=Please fill in the following data to add a new compute offering. message.add.system.service.offering=Please fill in the following data to add a new system service offering. message.add.template=Please enter the following data to create your new template message.add.volume=Please fill in the following data to add a new volume. message.add.VPN.gateway=Please confirm that you want to add a VPN Gateway +message.adding.host=Adding host +message.adding.Netscaler.device=Adding Netscaler device +message.adding.Netscaler.provider=Adding Netscaler provider +message.additional.networks.desc=Please select additional network(s) that your virtual instance will be connected to. message.advanced.mode.desc=Choose this network model if you wish to enable VLAN support. This network model provides the most flexibility in allowing administrators to provide custom network offerings such as providing firewall, vpn, or load balancer support as well as enabling direct vs virtual networking. message.advanced.security.group=Choose this if you wish to use security groups to provide guest VM isolation. message.advanced.virtual=Choose this if you wish to use zone-wide VLANs to provide guest VM isolation. -message.after.enable.s3=S3-backed Secondary Storage configured. Note: When you leave this page, you will not be able to re-configure S3 again. -message.after.enable.swift=Swift configured. Note: When you leave this page, you will not be able to re-configure Swift again. +message.after.enable.s3=S3-backed Secondary Storage configured. Note\: When you leave this page, you will not be able to re-configure S3 again. +message.after.enable.swift=Swift configured. Note\: When you leave this page, you will not be able to re-configure Swift again. message.alert.state.detected=Alert state detected message.allow.vpn.access=Please enter a username and password of the user that you want to allow VPN access. message.apply.snapshot.policy=You have successfully updated your current snapshot policy. @@ -1301,10 +1312,10 @@ message.confirm.join.project=Please confirm you wish to join this project. message.confirm.remove.IP.range=Please confirm that you would like to remove this IP range. message.confirm.shutdown.provider=Please confirm that you would like to shutdown this provider message.copy.iso.confirm=Please confirm that you wish to copy your ISO to -message.copy.template=Copy template XXX from zone to +message.copy.template=Copy template XXX from zone to +message.create.template.vm=Create VM from template +message.create.template.volume=Please specify the following information before creating a template of your disk volume\: . Creation of the template can range from several minutes to longer depending on the size of the volume. message.create.template=Are you sure you want to create template? -message.create.template.vm=Create VM from template -message.create.template.volume=Please specify the following information before creating a template of your disk volume: . Creation of the template can range from several minutes to longer depending on the size of the volume. message.creating.cluster=Creating cluster message.creating.guest.network=Creating guest network message.creating.physical.networks=Creating physical networks @@ -1314,6 +1325,7 @@ message.creating.secondary.storage=Creating secondary storage message.creating.zone=Creating zone message.decline.invitation=Are you sure you want to decline this project invitation? message.delete.account=Please confirm that you want to delete this account. +message.delete.affinity.group=Please confirm that you would like to remove this affinity group. message.delete.gateway=Please confirm you want to delete the gateway message.delete.project=Are you sure you want to delete this project? message.delete.user=Please confirm that you would like to delete this user. @@ -1323,31 +1335,31 @@ message.delete.VPN.gateway=Please confirm that you want to delete this VPN Gatew message.desc.advanced.zone=For more sophisticated network topologies. This network model provides the most flexibility in defining guest networks and providing custom network offerings such as firewall, VPN, or load balancer support. message.desc.basic.zone=Provide a single network where each VM instance is assigned an IP directly from the network. Guest isolation can be provided through layer-3 means such as security groups (IP address source filtering). message.desc.cluster=Each pod must contain one or more clusters, and we will add the first cluster now. A cluster provides a way to group hosts. The hosts in a cluster all have identical hardware, run the same hypervisor, are on the same subnet, and access the same shared storage. Each cluster consists of one or more hosts and one or more primary storage servers. -message.desc.host=Each cluster must contain at least one host (computer) for guest VMs to run on, and we will add the first host now. For a host to function in CloudStack, you must install hypervisor software on the host, assign an IP address to the host, and ensure the host is connected to the CloudStack management server.

Give the host's DNS or IP address, the user name (usually root) and password, and any labels you use to categorize hosts. +message.desc.host=Each cluster must contain at least one host (computer) for guest VMs to run on, and we will add the first host now. For a host to function in CloudStack, you must install hypervisor software on the host, assign an IP address to the host, and ensure the host is connected to the CloudStack management server.

Give the host\\'s DNS or IP address, the user name (usually root) and password, and any labels you use to categorize hosts. message.desc.primary.storage=Each cluster must contain one or more primary storage servers, and we will add the first one now. Primary storage contains the disk volumes for all the VMs running on hosts in the cluster. Use any standards-compliant protocol that is supported by the underlying hypervisor. message.desc.secondary.storage=Each zone must have at least one NFS or secondary storage server, and we will add the first one now. Secondary storage stores VM templates, ISO images, and VM disk volume snapshots. This server must be available to all hosts in the zone.

Provide the IP address and exported path. message.desc.zone=A zone is the largest organizational unit in CloudStack, and it typically corresponds to a single datacenter. Zones provide physical isolation and redundancy. A zone consists of one or more pods (each of which contains hosts and primary storage servers) and a secondary storage server which is shared by all pods in the zone. message.detach.disk=Are you sure you want to detach this disk? message.detach.iso.confirm=Please confirm that you want to detach the ISO from this virtual instance. -message.disable.account=Please confirm that you want to disable this account. By disabling the account, all users for this account will no longer have access to their cloud resources. All running virtual machines will be immediately shut down. +message.disable.account=Please confirm that you want to disable this account. By disabling the account, all users for this account will no longer have access to their cloud resources. All running virtual machines will be immediately shut down. message.disable.snapshot.policy=You have successfully disabled your current snapshot policy. message.disable.user=Please confirm that you would like to disable this user. message.disable.vpn.access=Please confirm that you want to disable VPN Access. message.disable.vpn=Are you sure you want to disable VPN? -message.download.ISO=Please click
00000 to download ISO -message.download.template=Please click 00000 to download template +message.download.ISO=Please click 00000 to download ISO +message.download.template=Please click 00000 to download template message.download.volume.confirm=Please confirm that you want to download this volume -message.download.volume=Please click 00000 to download volume +message.download.volume=Please click 00000 to download volume message.edit.account=Edit ("-1" indicates no limit to the amount of resources create) message.edit.confirm=Please confirm that your changes before clicking "Save". message.edit.limits=Please specify limits to the following resources. A "-1" indicates no limit to the amount of resources create. message.edit.traffic.type=Please specify the traffic label you want associated with this traffic type. message.enable.account=Please confirm that you want to enable this account. -message.enabled.vpn.ip.sec=Your IPSec pre-shared key is -message.enabled.vpn=Your VPN access is currently enabled and can be accessed via the IP message.enable.user=Please confirm that you would like to enable this user. message.enable.vpn.access=VPN is currently disabled for this IP Address. Would you like to enable VPN access? message.enable.vpn=Please confirm that you want VPN access enabled for this IP address. +message.enabled.vpn.ip.sec=Your IPSec pre-shared key is +message.enabled.vpn=Your VPN access is currently enabled and can be accessed via the IP message.enabling.security.group.provider=Enabling Security Group provider message.enabling.zone=Enabling zone message.enter.token=Please enter the token that you were given in your invite e-mail. @@ -1355,14 +1367,14 @@ message.generate.keys=Please confirm that you would like to generate new keys fo message.guest.traffic.in.advanced.zone=Guest network traffic is communication between end-user virtual machines. Specify a range of VLAN IDs to carry guest traffic for each physical network. message.guest.traffic.in.basic.zone=Guest network traffic is communication between end-user virtual machines. Specify a range of IP addresses that CloudStack can assign to guest VMs. Make sure this range does not overlap the reserved system IP range. message.installWizard.click.retry=Click the button to retry launch. -message.installWizard.copy.whatIsACluster=A cluster provides a way to group hosts. The hosts in a cluster all have identical hardware, run the same hypervisor, are on the same subnet, and access the same shared storage. Virtual machine instances (VMs) can be live-migrated from one host to another within the same cluster, without interrupting service to the user. A cluster is the third-largest organizational unit within a CloudStack™ deployment. Clusters are contained within pods, and pods are contained within zones.

CloudStack™ allows multiple clusters in a cloud deployment, but for a Basic Installation, we only need one cluster. -message.installWizard.copy.whatIsAHost=A host is a single computer. Hosts provide the computing resources that run the guest virtual machines. Each host has hypervisor software installed on it to manage the guest VMs (except for bare metal hosts, which are a special case discussed in the Advanced Installation Guide). For example, a Linux KVM-enabled server, a Citrix XenServer server, and an ESXi server are hosts. In a Basic Installation, we use a single host running XenServer or KVM.

The host is the smallest organizational unit within a CloudStack™ deployment. Hosts are contained within clusters, clusters are contained within pods, and pods are contained within zones. -message.installWizard.copy.whatIsAPod=A pod often represents a single rack. Hosts in the same pod are in the same subnet.

A pod is the second-largest organizational unit within a CloudStack™ deployment. Pods are contained within zones. Each zone can contain one or more pods; in the Basic Installation, you will have just one pod in your zone. -message.installWizard.copy.whatIsAZone=A zone is the largest organizational unit within a CloudStack™ deployment. A zone typically corresponds to a single datacenter, although it is permissible to have multiple zones in a datacenter. The benefit of organizing infrastructure into zones is to provide physical isolation and redundancy. For example, each zone can have its own power supply and network uplink, and the zones can be widely separated geographically (though this is not required). -message.installWizard.copy.whatIsCloudStack=CloudStack™ is a software platform that pools computing resources to build public, private, and hybrid Infrastructure as a Service (IaaS) clouds. CloudStack™ manages the network, storage, and compute nodes that make up a cloud infrastructure. Use CloudStack™ to deploy, manage, and configure cloud computing environments.

Extending beyond individual virtual machine images running on commodity hardware, CloudStack™ provides a turnkey cloud infrastructure software stack for delivering virtual datacenters as a service - delivering all of the essential components to build, deploy, and manage multi-tier and multi-tenant cloud applications. Both open-source and Premium versions are available, with the open-source version offering nearly identical features. -message.installWizard.copy.whatIsPrimaryStorage=A CloudStack™ cloud infrastructure makes use of two types of storage: primary storage and secondary storage. Both of these can be iSCSI or NFS servers, or localdisk.

Primary storage is associated with a cluster, and it stores the disk volumes of each guest VM for all the VMs running on hosts in that cluster. The primary storage server is typically located close to the hosts. -message.installWizard.copy.whatIsSecondaryStorage=Secondary storage is associated with a zone, and it stores the following:
  • Templates - OS images that can be used to boot VMs and can include additional configuration information, such as installed applications
  • ISO images - OS images that can be bootable or non-bootable
  • Disk volume snapshots - saved copies of VM data which can be used for data recovery or to create new templates
-message.installWizard.now.building=Now building your cloud... +message.installWizard.copy.whatIsACluster=A cluster provides a way to group hosts. The hosts in a cluster all have identical hardware, run the same hypervisor, are on the same subnet, and access the same shared storage. Virtual machine instances (VMs) can be live-migrated from one host to another within the same cluster, without interrupting service to the user. A cluster is the third-largest organizational unit within a CloudStack&\#8482; deployment. Clusters are contained within pods, and pods are contained within zones.

CloudStack&\#8482; allows multiple clusters in a cloud deployment, but for a Basic Installation, we only need one cluster. +message.installWizard.copy.whatIsAHost=A host is a single computer. Hosts provide the computing resources that run the guest virtual machines. Each host has hypervisor software installed on it to manage the guest VMs (except for bare metal hosts, which are a special case discussed in the Advanced Installation Guide). For example, a Linux KVM-enabled server, a Citrix XenServer server, and an ESXi server are hosts. In a Basic Installation, we use a single host running XenServer or KVM.

The host is the smallest organizational unit within a CloudStack&\#8482; deployment. Hosts are contained within clusters, clusters are contained within pods, and pods are contained within zones. +message.installWizard.copy.whatIsAPod=A pod often represents a single rack. Hosts in the same pod are in the same subnet.

A pod is the second-largest organizational unit within a CloudStack&\#8482; deployment. Pods are contained within zones. Each zone can contain one or more pods; in the Basic Installation, you will have just one pod in your zone. +message.installWizard.copy.whatIsAZone=A zone is the largest organizational unit within a CloudStack&\#8482; deployment. A zone typically corresponds to a single datacenter, although it is permissible to have multiple zones in a datacenter. The benefit of organizing infrastructure into zones is to provide physical isolation and redundancy. For example, each zone can have its own power supply and network uplink, and the zones can be widely separated geographically (though this is not required). +message.installWizard.copy.whatIsCloudStack=CloudStack&\#8482 is a software platform that pools computing resources to build public, private, and hybrid Infrastructure as a Service (IaaS) clouds. CloudStack&\#8482 manages the network, storage, and compute nodes that make up a cloud infrastructure. Use CloudStack&\#8482 to deploy, manage, and configure cloud computing environments.

Extending beyond individual virtual machine images running on commodity hardware, CloudStack&\#8482 provides a turnkey cloud infrastructure software stack for delivering virtual datacenters as a service - delivering all of the essential components to build, deploy, and manage multi-tier and multi-tenant cloud applications. Both open-source and Premium versions are available, with the open-source version offering nearly identical features. +message.installWizard.copy.whatIsPrimaryStorage=A CloudStack&\#8482; cloud infrastructure makes use of two types of storage\: primary storage and secondary storage. Both of these can be iSCSI or NFS servers, or localdisk.

Primary storage is associated with a cluster, and it stores the disk volumes of each guest VM for all the VMs running on hosts in that cluster. The primary storage server is typically located close to the hosts. +message.installWizard.copy.whatIsSecondaryStorage=Secondary storage is associated with a zone, and it stores the following\:
  • Templates - OS images that can be used to boot VMs and can include additional configuration information, such as installed applications
  • ISO images - OS images that can be bootable or non-bootable
  • Disk volume snapshots - saved copies of VM data which can be used for data recovery or to create new templates
+message.installWizard.now.building=Now building your cloud... message.installWizard.tooltip.addCluster.name=A name for the cluster. This can be text of your choosing and is not used by CloudStack. message.installWizard.tooltip.addHost.hostname=The DNS name or IP address of the host. message.installWizard.tooltip.addHost.password=This is the password for the user named above (from your XenServer install). @@ -1392,26 +1404,26 @@ message.instanceWizard.noTemplates=You do not have any templates available; plea message.ip.address.changed=Your IP addresses may have changed; would you like to refresh the listing? Note that in this case the details pane will close. message.iso.desc=Disc image containing data or bootable media for OS message.join.project=You have now joined a project. Please switch to Project view to see the project. -message.launch.vm.on.private.network=Do you wish to launch your instance on your own private dedicated network? +message.launch.vm.on.private.network=Do you wish to launch your instance on your own private dedicated network? message.launch.zone=Zone is ready to launch; please proceed to the next step. message.lock.account=Please confirm that you want to lock this account. By locking the account, all users for this account will no longer be able to manage their cloud resources. Existing resources can still be accessed. message.migrate.instance.confirm=Please confirm the host you wish to migrate the virtual instance to. message.migrate.instance.to.host=Please confirm that you want to migrate instance to another host. message.migrate.instance.to.ps=Please confirm that you want to migrate instance to another primary storage. -message.migrate.router.confirm=Please confirm the host you wish to migrate the router to: -message.migrate.systemvm.confirm=Please confirm the host you wish to migrate the system VM to: +message.migrate.router.confirm=Please confirm the host you wish to migrate the router to\: +message.migrate.systemvm.confirm=Please confirm the host you wish to migrate the system VM to\: message.migrate.volume=Please confirm that you want to migrate volume to another primary storage. -message.new.user=Specify the following to add a new user to the account +message.new.user=Specify the following to add a new user to the account message.no.network.support.configuration.not.true=You do not have any zone that has security group enabled. Thus, no additional network features. Please continue to step 5. message.no.network.support=Your selected hypervisor, vSphere, does not have any additional network features. Please continue to step 5. message.no.projects.adminOnly=You do not have any projects.
Please ask your administrator to create a new project. message.no.projects=You do not have any projects.
Please create a new one from the projects section. -message.number.clusters=

# of Clusters

-message.number.hosts=

# of Hosts

-message.number.pods=

# of Pods

-message.number.storage=

# of Primary Storage Volumes

-message.number.zones=

# of Zones

-message.pending.projects.1=You have pending project invitations: +message.number.clusters=

\# of Clusters

+message.number.hosts=

\# of Hosts

+message.number.pods=

\# of Pods

+message.number.storage=

\# of Primary Storage Volumes

+message.number.zones=

\# of Zones

+message.pending.projects.1=You have pending project invitations\: message.pending.projects.2=To view, please go to the projects section, then select invitations from the drop-down. message.please.add.at.lease.one.traffic.range=Please add at least one traffic range. message.please.proceed=Please proceed to the next step. @@ -1442,7 +1454,7 @@ message.select.security.groups=Please select security group(s) for your new VM message.select.template=Please select a template for your new virtual instance. message.setup.physical.network.during.zone.creation.basic=When adding a basic zone, you can set up one physical network, which corresponds to a NIC on the hypervisor. The network carries several types of traffic.

You may also drag and drop other traffic types onto the physical network. message.setup.physical.network.during.zone.creation=When adding an advanced zone, you need to set up one or more physical networks. Each network corresponds to a NIC on the hypervisor. Each physical network can carry one or more types of traffic, with certain restrictions on how they may be combined.

Drag and drop one or more traffic types onto each physical network. -message.setup.successful=Cloud setup successful! +message.setup.successful=Cloud setup successful\! message.snapshot.schedule=You can setup recurring snapshot schedules by selecting from the available options below and applying your policy preference message.specify.url=Please specify URL message.step.1.continue=Please select a template or ISO to continue @@ -1453,7 +1465,7 @@ message.step.3.continue=Please select a disk offering to continue message.step.3.desc= message.step.4.continue=Please select at least one network to continue message.step.4.desc=Please select the primary network that your virtual instance will be connected to. -message.storage.traffic=Traffic between CloudStack's internal resources, including any components that communicate with the Management Server, such as hosts and CloudStack system VMs. Please configure storage traffic here. +message.storage.traffic=Traffic between CloudStack\\'s internal resources, including any components that communicate with the Management Server, such as hosts and CloudStack system VMs. Please configure storage traffic here. message.suspend.project=Are you sure you want to suspend this project? message.template.desc=OS image that can be used to boot VMs message.tooltip.dns.1=Name of a DNS server for use by VMs in the zone. The public IP addresses for the zone must have a route to this server. @@ -1467,7 +1479,7 @@ message.tooltip.reserved.system.netmask=The network prefix that defines the pod message.tooltip.zone.name=A name for the zone. message.update.os.preference=Please choose a OS preference for this host. All virtual instances with similar preferences will be first allocated to this host before choosing another. message.update.resource.count=Please confirm that you want to update resource counts for this account. -message.update.ssl=Please submit a new X.509 compliant SSL certificate to be updated to each console proxy virtual instance: +message.update.ssl=Please submit a new X.509 compliant SSL certificate to be updated to each console proxy virtual instance\: message.validate.instance.name=Instance name can not be longer than 63 characters. Only ASCII letters a~z, A~Z, digits 0~9, hyphen are allowed. Must start with a letter and end with a letter or a digit. message.virtual.network.desc=A dedicated virtualized network for your account. The broadcast domain is contained within a VLAN and all public network access is routed out by a virtual router. message.vm.create.template.confirm=Create Template will reboot the VM automatically. @@ -1478,9 +1490,9 @@ message.zone.creation.complete.would.you.like.to.enable.this.zone=Zone creation message.Zone.creation.complete=Zone creation complete message.zone.no.network.selection=The zone you selected does not have any choices for network selection. message.zone.step.1.desc=Please select a network model for your zone. -message.zone.step.2.desc=Please enter the following info to add a new zone -message.zone.step.3.desc=Please enter the following info to add a new pod -message.zoneWizard.enable.local.storage=WARNING: If you enable local storage for this zone, you must do the following, depending on where you would like your system VMs to launch:

1. If system VMs need to be launched in primary storage, primary storage needs to be added to the zone after creation. You must also start the zone in a disabled state.

2. If system VMs need to be launched in local storage, system.vm.use.local.storage needs to be set to true before you enable the zone.


Would you like to continue? +message.zone.step.2.desc=Please enter the following info to add a new zone +message.zone.step.3.desc=Please enter the following info to add a new pod +message.zoneWizard.enable.local.storage=WARNING\: If you enable local storage for this zone, you must do the following, depending on where you would like your system VMs to launch\:

1. If system VMs need to be launched in primary storage, primary storage needs to be added to the zone after creation. You must also start the zone in a disabled state.

2. If system VMs need to be launched in local storage, system.vm.use.local.storage needs to be set to true before you enable the zone.


Would you like to continue? mode=Mode network.rate=Network Rate notification.reboot.instance=Reboot instance @@ -1498,14 +1510,14 @@ state.Creating=Creating state.Declined=Declined state.Destroyed=Destroyed state.Disabled=Disabled -state.enabled=Enabled state.Enabled=Enabled +state.enabled=Enabled state.Error=Error state.Expunging=Expunging state.Migrating=Migrating state.Pending=Pending -state.ready=Ready state.Ready=Ready +state.ready=Ready state.Running=Running state.Starting=Starting state.Stopped=Stopped diff --git a/client/WEB-INF/classes/resources/messages_ar.properties b/client/WEB-INF/classes/resources/messages_ar.properties new file mode 100644 index 00000000000..4d3011b5a6c --- /dev/null +++ b/client/WEB-INF/classes/resources/messages_ar.properties @@ -0,0 +1,285 @@ +# 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. + + +changed.item.properties=\u062a\u063a\u064a\u0631 \u062e\u0635\u0627\u0626\u0635 \u0627\u0644\u0639\u0646\u0635\u0631 +confirm.enable.s3=\u0641\u0636\u0644\u0627 \u0642\u0645 \u0628\u062a\u0639\u0628\u0626\u0629 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a \u0627\u0644\u0642\u0627\u062f\u0645\u0629 \u0644\u062a\u0645\u0643\u064a\u0646 \u0627\u0644\u062a\u062e\u0632\u064a\u0646 S3 \u0644\u0644\u0630\u0627\u0643\u0631\u0629 \u0627\u0644\u062b\u0627\u0646\u0648\u064a\u0629. +instances.actions.reboot.label=\u0625\u0639\u0627\u062f\u0629 \u062a\u0634\u063a\u064a\u0644 \u0627\u0644\u0646\u0645\u0648\u0630\u062c +label.accept.project.invitation=\u0642\u0628\u0648\u0644 \u062f\u0639\u0648\u0629 \u0627\u0644\u0645\u0634\u0631\u0648\u0639 +label.action.delete.system.service.offering=\u062d\u0630\u0641 \u0646\u0638\u0627\u0645 \u062a\u0642\u062f\u064a\u0645 \u0627\u0644\u062e\u062f\u0645\u0629 +label.action.disable.physical.network=\u062a\u0639\u0637\u064a\u0644 \u0634\u0628\u0643\u0629 \u0641\u064a\u0632\u064a\u0627\u0626\u064a\u0629 +label.action.enable.physical.network=\u062a\u0645\u0643\u064a\u0646 \u0634\u0628\u0643\u0629 \u0641\u064a\u0632\u064a\u0627\u0626\u064a\u0629 +label.activate.project=\u062a\u0641\u0639\u064a\u0644 \u0627\u0644\u0645\u0634\u0631\u0648\u0639 +label.add.accounts.to=\u0625\u0636\u0627\u0641\u0629 \u062d\u0633\u0627\u0628\u0627\u062a \u0625\u0644\u0649 +label.add.accounts=\u0625\u0636\u0627\u0641\u0629 \u062d\u0633\u0627\u0628\u0627\u062a +label.add.account.to.project=\u0625\u0636\u0627\u0641\u0629 \u062d\u0633\u0627\u0628 \u0644\u0644\u0645\u0634\u0631\u0648\u0639 +label.add.ACL=\u0625\u0636\u0627\u0641\u0629 ACL +label.add.network.ACL=\u0625\u0636\u0627\u0641\u0629 \u0634\u0628\u0643\u0629 ACL +label.add.new.gateway=\u0623\u0636\u0641 \u0628\u0648\u0627\u0628\u0629 \u062c\u062f\u064a\u062f\u0629 +label.add.new.tier=\u0625\u0636\u0627\u0641\u0629 \u0637\u0628\u0642\u0629 \u062c\u062f\u064a\u062f\u0629 +label.add.port.forwarding.rule=\u0625\u0636\u0627\u0641\u0629 \u0642\u0627\u0639\u062f\u0629 \u0645\u0646\u0641\u0630 \u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u062a\u0648\u062c\u064a\u0647 +label.add.route=\u0625\u0636\u0627\u0641\u0629 \u0645\u0633\u0627\u0631 +label.add.rule=\u0625\u0636\u0627\u0641\u0629 \u0642\u0627\u0639\u062f\u0629 +label.add.static.route=\u0625\u0636\u0627\u0641\u0629 \u062a\u0648\u062c\u064a\u0647 \u062b\u0627\u0628\u062a +label.add.to.group=\u0625\u0636\u0627\u0641\u0629 \u0625\u0644\u0649 \u0627\u0644\u0645\u062c\u0645\u0648\u0639\u0629 +label.add.VM.to.tier=\u0625\u0636\u0627\u0641\u0629 \u062c\u0647\u0627\u0632 \u0625\u0641\u062a\u0631\u0627\u0636\u064a \u0641\u064a \u0637\u0628\u0642\u0629 +label.add.vpc=\u0625\u0636\u0627\u0641\u0629 \u0633\u062d\u0627\u0628\u0629 \u0625\u0641\u062a\u0631\u0627\u0636\u064a\u0629 \u062e\u0627\u0635\u0629 +label.add.VPN.gateway=\u0623\u0636\u0641 \u0628\u0648\u0627\u0628\u0629 \u0627\u0644\u0634\u0628\u0643\u0629 \u0627\u0644\u0627\u0641\u062a\u0631\u0627\u0636\u064a\u0629 \u0627\u0644\u0634\u062e\u0635\u064a\u0629 +label.allocated=\u062a\u062e\u0635\u064a\u0635 +label.apply=\u062a\u0637\u0628\u064a\u0642 +label.associated.network=\u0634\u0628\u0643\u0629 \u0645\u0631\u062a\u0628\u0637\u0629 +label.broadcast.uri=\u0628\u062b \u0627\u0644\u0631\u0627\u0628\u0637 +label.change.value=\u062a\u063a\u064a\u0631 \u0627\u0644\u0642\u064a\u0645\u0629 +label.CIDR.list=\u0642\u0627\u0626\u0645\u0629 CIDR +label.CIDR.of.destination.network=CIDR \u0627\u0644\u062e\u0627\u0635 \u0628\u0627\u0644\u0634\u0628\u0643\u0629 \u0627\u0644\u0645\u0648\u062c\u0647\u0629. +label.clean.up=\u062a\u0646\u0638\u064a\u0641 +label.clear.list=\u0645\u0633\u062d \u0627\u0644\u0642\u0627\u0626\u0645\u0629 +label.configuration=\u0627\u0644\u062a\u0643\u0648\u064a\u0646 +label.configure.network.ACLs=\u0636\u0628\u0637 \u0634\u0628\u0643\u0629 ACLs +label.configure=\u0642\u0645 \u0628\u062a\u0643\u0648\u064a\u0646 +label.configure.vpc=\u062a\u0643\u0648\u064a\u0646 VPC +label.corrections.saved=\u062a\u0645 \u062d\u0641\u0638 \u0627\u0644\u062a\u0635\u062d\u064a\u062d\u0627\u062a +label.cpu.mhz=\u0648\u062d\u062f\u0629 \u0627\u0644\u0645\u0639\u0627\u0644\u062c\u0629 \u0627\u0644\u0645\u0631\u0643\u0632\u064a\u0629 (\u0628\u0627\u0644\u0645\u064a\u063a\u0627\u0647\u064a\u0631\u062a\u0632) +label.cpu=\u00d9\u0088\u00d8\u00ad\u00d8\u00af\u00d8\u00a9 \u00d8\u00a7\u00d9\u0084\u00d9 +label.create.project=\u0623\u0646\u0634\u0626 \u0645\u0634\u0631\u0648\u0639 +label.create.VPN.connection=\u0625\u0646\u0634\u0627\u0621 \u0627\u062a\u0635\u0627\u0644 \u0628\u0648\u0627\u0628\u0629 \u0627\u0644\u0634\u0628\u0643\u0629 \u0627\u0644\u0627\u0641\u062a\u0631\u0627\u0636\u064a\u0629 \u0627\u0644\u0634\u062e\u0635\u064a\u0629 +label.dead.peer.detection=\u0643\u0634\u0641 \u0627\u0644\u0642\u0631\u064a\u0646 \u0627\u0644\u0645\u0641\u0642\u0648\u062f +label.decline.invitation=\u0631\u0641\u0636 \u0627\u0644\u062f\u0639\u0648\u0629 +label.default=\u0627\u0644\u0625\u0641\u062a\u0631\u0627\u0636\u064a +label.default.view=\u0637\u0631\u064a\u0642\u0629 \u0627\u0644\u0639\u0631\u0636 \u0627\u0644\u0627\u0641\u062a\u0631\u0627\u0636\u064a\u0629 +label.delete.gateway=\u0627\u062d\u0630\u0641 \u0627\u0644\u0628\u0648\u0627\u0628\u0629 +label.delete.project=\u062d\u0630\u0641 \u0627\u0644\u0645\u0634\u0631\u0648\u0639 +label.delete.VPN.connection=\u0627\u062d\u0630\u0641 \u0628\u0648\u0627\u0628\u0629 \u0627\u0644\u0634\u0628\u0643\u0629 \u0627\u0644\u0627\u0641\u062a\u0631\u0627\u0636\u064a\u0629 \u0627\u0644\u0634\u062e\u0635\u064a\u0629 +label.delete.VPN.customer.gateway=\u062d\u0630\u0641 \u0628\u0648\u0627\u0628\u0629 VPN \u0627\u0644\u0645\u062e\u0635\u0635\u0629 +label.delete.VPN.gateway=\u0627\u062d\u0630\u0641 \u0628\u0648\u0627\u0628\u0629 \u0627\u0644\u0634\u0628\u0643\u0629 \u0627\u0644\u0627\u0641\u062a\u0631\u0627\u0636\u064a\u0629 \u0627\u0644\u0634\u062e\u0635\u064a\u0629 +label.destroy=\u0647\u062f\u0645 +label.devices=\u0627\u0644\u0623\u062c\u0647\u0632\u0629 +label.direct.ips=\u0627\u0644\u0634\u0628\u0643\u0629 \u0627\u0644\u0645\u0634\u062a\u0631\u0643\u0629 IPs +label.display.name=\u0639\u0631\u0636 \u0627\u0644\u0627\u0633\u0645 +label.DNS.domain.for.guest.networks=\u0645\u062c\u0627\u0644 DNS \u0644\u0634\u0628\u0643\u0627\u062a \u0627\u0644\u0632\u0627\u0626\u0631 +label.dns=\u0646\u0638\u0627\u0645 \u062a\u0633\u0645\u064a\u0629 \u0627\u0644\u0645\u062c\u0627\u0644 DNS +label.drag.new.position=\u0627\u0633\u062d\u0628 \u0644\u0645\u0648\u0642\u0641 \u062c\u062f\u064a\u062f +label.edit.network.details=\u062a\u062d\u0631\u064a\u0631 \u062a\u0641\u0627\u0635\u064a\u0644 \u0627\u0644\u0634\u0628\u0643\u0629 +label.edit.project.details=\u0627\u0636\u0627\u0641\u0629 \u062a\u0641\u0627\u0635\u064a\u0644 \u0627\u0644\u0645\u0634\u0631\u0648\u0639 +label.edit.tags=\u062a\u0639\u062f\u064a\u0644 \u0627\u0644\u0639\u0644\u0627\u0645\u0627\u062a +label.edit.vpc=\u062a\u0639\u062f\u064a\u0644 VPC +label.egress.rules=\u0642\u0648\u0627\u0639\u062f \u0627\u0644\u062e\u0631\u0648\u062c +label.elastic=\u0645\u0631\u0646 +label.enable.s3=\u062a\u0645\u0643\u064a\u0646 \u0627\u0644\u062a\u062e\u0632\u064a\u0646 \u0627\u0644\u062b\u0627\u0646\u0648\u064a S3 +label.endpoint=\u0646\u0642\u0637\u0629 \u0627\u0644\u0646\u0647\u0627\u064a\u0629 +label.error=\u062e\u0637\u0623 +label.ESP.lifetime=\u0639\u0645\u0631 ESP (\u062b\u0627\u0646\u064a\u0629) +label.ESP.policy=\u0633\u064a\u0627\u0633\u0629 ESP +label.filterBy=\u062a\u0635\u0641\u064a\u0629 \u062d\u0633\u0628 +label.full.path=\u0645\u0633\u0627\u0631 \u0643\u0627\u0645\u0644 +label.guest.type=\u0646\u0648\u0639 \u0627\u0644\u0636\u064a\u0641 +label.IKE.lifetime=\u0639\u0645\u0631 IKE (\u062b\u0627\u0646\u064a\u0629) +label.IKE.policy=\u0633\u064a\u0627\u0633\u0629 IKE +label.instances=\u0627\u0644\u062d\u0627\u0644\u0627\u062a +label.invitations=\u062f\u0639\u0648\u0627\u062a +label.invited.accounts=\u062f\u0639\u0648\u0629 \u062d\u0633\u0627\u0628\u0627\u062a +label.invite.to=\u062f\u0639\u0648\u0629 \u0644\u0640 +label.IPsec.preshared.key=\u0645\u0641\u062a\u0627\u062d \u0623\u0645\u0646 \u0628\u0631\u0648\u062a\u0648\u0643\u0648\u0644 \u0627\u0644\u0625\u0646\u062a\u0631\u0646\u062a \u062a\u0645\u062a \u0645\u0634\u0627\u0631\u0643\u062a\u0647 \u0645\u0633\u0628\u0642\u0627 +label.isolation.uri=\u0639\u0632\u0644 \u0627\u0644\u0631\u0627\u0628\u0637 +label.keyboard.type=\u0646\u0648\u0639 \u0644\u0648\u062d\u0629 \u0627\u0644\u0645\u0641\u0627\u062a\u064a\u062d +label.least.connections=\u0623\u0642\u0644 \u0627\u0644\u0625\u062a\u0635\u0627\u0644\u0627\u062a +label.local.storage.enabled=\u062a\u0645\u0643\u064a\u0646 \u0627\u0644\u062a\u062e\u0632\u064a\u0646 \u0627\u0644\u0645\u062d\u0644\u064a +label.make.project.owner=\u062c\u0639\u0644 \u0627\u0644\u062d\u0633\u0627\u0628 \u0645\u0627\u0644\u0643 \u0644\u0644\u0645\u0634\u0631\u0648\u0639 +label.max.guest.limit=\u0627\u0644\u062d\u062f \u0627\u0644\u0623\u0642\u0635\u0627\u0621 \u0644\u0636\u064a\u0641 +label.memory.mb=\u0627\u0644\u0630\u0627\u0643\u0631\u0629 ( \u0628\u0627\u0644\u0645\u064a\u062c\u0627\u0628\u0627\u064a\u0628\u062a) +label.memory=\u0627\u0644\u0630\u0627\u0643\u0631\u0629 +label.menu.alerts=\u0627\u0644\u062a\u0646\u0628\u064a\u0647\u0627\u062a +label.menu.all.accounts=\u062c\u0645\u064a\u0639 \u0627\u0644\u062d\u0633\u0627\u0628\u0627\u062a +label.menu.all.instances=\u062c\u0645\u064a\u0639 \u0627\u0644\u062d\u0627\u0644\u0627\u062a +label.menu.community.isos=\u0627\u0644\u062a\u0636\u0627\u0645\u0646 \u0627\u0644\u062f\u0648\u0644\u064a \u0627\u0644\u0645\u062c\u062a\u0645\u0639\u064a +label.menu.community.templates=\u0642\u0648\u0627\u0644\u0628 \u0627\u0644\u0645\u062c\u062a\u0645\u0639 +label.menu.configuration=\u062a\u0631\u062a\u064a\u0628 +label.menu.dashboard=\u0644\u0648\u062d\u0629 \u0627\u0644\u0642\u064a\u0627\u062f\u0629 +label.menu.destroyed.instances=\u062d\u0627\u0644\u0627\u062a \u0627\u0644\u062a\u062f\u0645\u064a\u0631 +label.menu.disk.offerings=\u0639\u0631\u0648\u0636 \u0627\u0644\u0642\u0631\u0635 +label.menu.domains=\u0627\u0644\u0645\u062c\u0627\u0644\u0627\u062a +label.menu.events=\u0623\u062d\u062f\u0627\u062b +label.menu.featured.isos=\u0645\u0645\u064a\u0632\u0627\u062a \u0627\u0644\u062a\u0636\u0627\u0645\u0646 \u0627\u0644\u062f\u0648\u0644\u064a +label.menu.featured.templates=\u0642\u0648\u0627\u0644\u0628 \u0645\u0645\u064a\u0632\u0629 +label.menu.global.settings=\u0627\u0644\u0625\u0639\u062f\u0627\u062f\u0627\u062a \u0627\u0644\u0639\u0645\u0648\u0645\u064a\u0629 +label.menu.instances=\u0627\u0644\u062d\u0627\u0644\u0627\u062a +label.migrate.instance.to.host=\u0646\u0642\u0644 \u0627\u0644\u0642\u0627\u0644\u0628 \u0625\u0644\u0649 \u0645\u0636\u064a\u0641 \u0622\u062e\u0631 +label.migrate.instance.to.ps=\u0646\u0642\u0644 \u0627\u0644\u0642\u0627\u0644\u0628 \u0625\u0644\u0649 \u0627\u0644\u0630\u0627\u0643\u0631\u0629 \u0627\u0644\u0623\u0633\u0627\u0633\u064a\u0629 +label.migrate.to.host=\u0627\u0644\u062a\u062d\u0648\u0644 \u0625\u0644\u0649 \u0627\u0644\u0645\u0636\u064a\u0641 +label.migrate.to.storage=\u0627\u0644\u062a\u062d\u0648\u0644 \u0625\u0644\u0649 \u0627\u0644\u062a\u062e\u0632\u064a\u0646 +label.move.down.row=\u0627\u0644\u0627\u0646\u062a\u0642\u0627\u0644 \u0625\u0644\u0649 \u0627\u0644\u0623\u0633\u0641\u0644 \u0628\u0635\u0641 \u0648\u0627\u062d\u062f +label.move.to.bottom=\u0627\u0644\u0627\u0646\u062a\u0642\u0627\u0644 \u0625\u0644\u0649 \u0627\u0644\u0623\u0633\u0641\u0644 +label.move.to.top=\u0627\u0646\u062a\u0642\u0627\u0644 \u0625\u0644\u0649 \u0623\u0639\u0644\u0649 +label.move.up.row=\u0627\u0644\u0627\u0646\u062a\u0642\u0627\u0644 \u0625\u0644\u0649 \u0627\u0644\u0623\u0639\u0644\u0649 \u0628\u0635\u0641 \u0648\u0627\u062d\u062f +label.my.network=\u0634\u0628\u0643\u062a\u064a +label.my.templates=\u0642\u0648\u0627\u0644\u0628\u064a +label.network.ACLs=\u0634\u0628\u0643\u0629 ACLs +label.network.ACL.total=\u0625\u062c\u0645\u0627\u0644 \u0634\u0628\u0643\u0629 ACL +label.network.ACL=\u0634\u0628\u0643\u0629 ACL +label.networks=\u0627\u0644\u0634\u0628\u0643\u0627\u062a +label.new.project=\u0645\u0634\u0631\u0648\u0639 \u062c\u062f\u064a\u062f +label.new=\u062c\u062f\u064a\u062f +label.no.data=\u0644\u0627 \u064a\u0648\u062c\u062f \u0628\u064a\u0627\u0646\u0627\u062a \u0644\u0644\u0639\u0631\u0636 +label.no.thanks=\u0644\u0627\u061b \u0634\u0643\u0631\u0627\u064b +label.notifications=\u0627\u0644\u062a\u0646\u0628\u064a\u0647\u0627\u062a +label.ok=\u0645\u0648\u0627\u0641\u0642 +label.order=\u062a\u0631\u062a\u064a\u0628 +label.previous=\u0627\u0644\u0633\u0627\u0628\u0642 +label.private.Gateway=\u0645\u0646\u0641\u0630\\Gateway \u062e\u0627\u0635 +label.project.invite=\u062f\u0639\u0648\u0629 \u0625\u0644\u0649 \u0627\u0644\u0645\u0634\u0631\u0648\u0639 +label.project.name=\u0627\u0633\u0645 \u0627\u0644\u0645\u0634\u0631\u0648\u0639 +label.projects=\u0627\u0644\u0645\u0634\u0627\u0631\u064a\u0639 +label.project=\u0645\u0634\u0631\u0648\u0639 +label.project.view=\u0639\u0631\u0636 \u0627\u0644\u0645\u0634\u0631\u0648\u0639 +label.quickview=\u0646\u0638\u0631\u0629 \u0633\u0631\u064a\u0639\u0629 +label.reboot=\u0625\u0639\u0627\u062f\u0629 \u062a\u0634\u063a\u064a\u0644 +label.remind.later=\u0630\u0643\u0631\u0646\u064a \u0644\u0627\u062d\u0642\u0627\u064b +label.remove.ACL=\u0625\u0632\u0627\u0644\u0629 ACL +label.remove.static.route=\u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u062a\u0648\u062c\u064a\u0647 \u062b\u0627\u0628\u062a +label.remove.tier=\u0625\u0636\u0627\u0641\u0629 \u0637\u0628\u0642\u0629 +label.remove.vpc=\u0625\u0632\u0627\u0644\u0629 VPC +label.reset.VPN.connection=\u0625\u0639\u0627\u062f\u0629 \u062a\u0639\u064a\u064a\u0646 \u0627\u062a\u0635\u0627\u0644 \u0627\u0644\u0634\u0628\u0643\u0629 \u0627\u0644\u0627\u0641\u062a\u0631\u0627\u0636\u064a\u0629 \u0627\u0644\u0634\u062e\u0635\u064a\u0629 +label.restart.network=\u0625\u0639\u0627\u062f\u0629 \u062a\u0634\u063a\u064a\u0644 \u0627\u0644\u0634\u0628\u0643\u0629 +label.restart.required=\u0645\u0637\u0644\u0648\u0628 \u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u062a\u0634\u063a\u064a\u0644 +label.restart.vpc=\u0625\u0639\u062f\u0627\u0629 \u062a\u0634\u063a\u064a\u0644 VPC +label.restore=\u0625\u0633\u062a\u0639\u0627\u062f\u0629 +label.review=\u0645\u0631\u0627\u062c\u0639\u0629 +label.revoke.project.invite=\u0625\u0644\u063a\u0627\u0621 \u0627\u0644\u062f\u0639\u0648\u0629 +label.s3.access_key=\u0645\u0641\u062a\u0627\u062d \u0627\u0644\u0648\u0635\u0648\u0644 +label.s3.bucket=\u062f\u0644\u0648 +label.s3.connection_timeout=\u0645\u0647\u0644\u0629 \u0627\u0644\u0627\u062a\u0635\u0627\u0644 +label.s3.endpoint=\u0646\u0642\u0637\u0629 \u0627\u0644\u0646\u0647\u0627\u064a\u0629 +label.s3.max_error_retry=\u0623\u0642\u0635\u0649 \u062e\u0637\u0623 \u0641\u064a \u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u0645\u062d\u0627\u0648\u0644\u0629 +label.s3.secret_key=\u0627\u0644\u0645\u0641\u062a\u0627\u062d \u0627\u0644\u0633\u0631\u064a +label.s3.socket_timeout=\u0645\u0647\u0644\u0629 \u0627\u0644\u0645\u0642\u0628\u0633 +label.s3.use_https=\u0627\u0633\u062a\u062e\u062f\u0645 HTTPS +label.scope=\u0627\u0644\u0645\u062c\u0627\u0644 +label.search=\u0628\u062d\u062b +label.secret.key=\u0627\u0644\u0645\u0641\u062a\u0627\u062d \u0627\u0644\u0633\u0631\u064a +label.select.a.template=\u0627\u062e\u062a\u0631 \u0642\u0627\u0644\u0628 +label.select.project=\u062d\u062f\u062f \u0627\u0644\u0645\u0634\u0631\u0648\u0639 +label.select.tier=\u062d\u062f\u062f \u0637\u0628\u0642\u0629 +label.select-view=\u062d\u062f\u062f \u0637\u0631\u064a\u0642\u0629 \u0627\u0644\u0639\u0631\u0636 +label.service.capabilities=\u0642\u062f\u0631\u0627\u062a \u0627\u0644\u062e\u062f\u0645\u0629 +label.setup=\u0627\u0644\u062a\u062b\u0628\u064a\u062a +label.site.to.site.VPN=\u0645\u0648\u0642\u0639 \u0625\u0644\u0649 \u0645\u0648\u0642\u0639-\u0627\u0644\u0634\u0628\u0643\u0629 \u0627\u0644\u0634\u062e\u0635\u064a\u0629 \u0627\u0644\u0638\u0627\u0647\u0631\u064a\u0629 VPN +label.source=\u0645\u0635\u062f\u0631 +label.specify.IP.ranges=\u062a\u062d\u062f\u064a\u062f \u0646\u0637\u0627\u0642\u0627\u062a IP +label.sticky.tablesize=\u062d\u062c\u0645 \u0627\u0644\u062c\u062f\u0648\u0644 +label.stop=\u062a\u0648\u0642\u0641 +label.super.cidr.for.guest.networks=CIDR \u0645\u0645\u062a\u0627\u0632 \u0644\u0634\u0628\u0643\u0627\u062a \u0627\u0644\u0636\u064a\u0641. +label.supported.services=\t\u0627\u0644\u062e\u062f\u0645\u0627\u062a \u0627\u0644\u0645\u062f\u0639\u0648\u0645\u0629 +label.suspend.project=\u0625\u064a\u0642\u0627\u0641 \u0627\u0644\u0645\u0634\u0631\u0648\u0639 +label.tier.details=\u062a\u0641\u0627\u0635\u064a\u0644 \u0627\u0644\u0637\u0628\u0642\u0629 +label.tier=\u0637\u0628\u0642\u0629 +label.upload=\u0631\u0641\u0639 +label.view.all=\u0639\u0631\u0636 \u0627\u0644\u0643\u0644 +label.viewing=\u0639\u0631\u0636 +label.view=\u0639\u0631\u0636 +label.vm.destroy=\u0647\u062f\u0645 +label.vm.reboot=\u0625\u0639\u0627\u062f\u0629 \u062a\u0634\u063a\u064a\u0644 +label.VMs.in.tier=\u0627\u0644\u0623\u062c\u0647\u0632\u0629 \u0627\u0644\u0625\u0641\u062a\u0631\u0627\u0636\u064a\u0629 \u0641\u064a \u0637\u0628\u0642\u0629 +label.vm.stop=\u062a\u0648\u0642\u0641 +label.volume.limits=\u062d\u062f\u0648\u062f \u0627\u0644\u0645\u0646\u0637\u0642\u0629 +label.vpc.id=\u0647\u0648\u064a\u0629 \u062e\u0627\u0635\u0629 \u0628\u0633\u062d\u0627\u0628\u0629 \u0625\u0641\u062a\u0631\u0627\u0636\u064a\u0629 \u062e\u0627\u0635\u0629 +label.VPC.router.details=\u062a\u0641\u0627\u0635\u064a\u0644 \u062c\u0647\u0627\u0632 \u0627\u0644\u062a\u0648\u062c\u064a\u0647 VPC +label.vpc=\u0633\u062d\u0627\u0628\u0629 \u0625\u0641\u062a\u0631\u0627\u0636\u064a\u0629 \u062e\u0627\u0635\u0629 VPC +label.VPN.connection=\u0625\u062a\u0635\u0627\u0644 \u0627\u0644\u0634\u0628\u0643\u0629 \u0627\u0644\u0627\u0641\u062a\u0631\u0627\u0636\u064a\u0629 \u0627\u0644\u0634\u062e\u0635\u064a\u0629 +label.vpn.customer.gateway=\u0628\u0648\u0627\u0628\u0629 \u0627\u0644\u0634\u0628\u0643\u0629 \u0627\u0644\u0627\u0641\u062a\u0631\u0627\u0636\u064a\u0629 \u0627\u0644\u0634\u062e\u0635\u064a\u0629 \u0644\u0644\u0639\u0645\u064a\u0644 +label.VPN.customer.gateway=\u0628\u0648\u0627\u0628\u0629 \u0627\u0644\u0634\u0628\u0643\u0629 \u0627\u0644\u0627\u0641\u062a\u0631\u0627\u0636\u064a\u0629 \u0627\u0644\u0634\u062e\u0635\u064a\u0629 \u0644\u0644\u0639\u0645\u064a\u0644 +label.VPN.gateway=\u0628\u0648\u0627\u0628\u0629 \u0627\u0644\u0634\u0628\u0643\u0629 \u0627\u0644\u0627\u0641\u062a\u0631\u0627\u0636\u064a\u0629 \u0627\u0644\u0634\u062e\u0635\u064a\u0629 +label.waiting=\u0642\u064a\u062f \u0627\u0644\u0625\u0646\u062a\u0638\u0627\u0631 +label.warn=\u062a\u062d\u0630\u064a\u0631 +label.wednesday=\u0627\u0644\u0623\u0631\u0628\u0639\u0627\u0621 +label.weekly=\u0625\u0633\u0628\u0648\u0639\u064a +label.welcome.cloud.console=\u0645\u0631\u062d\u0628\u0627 \u0628\u0643\u0645 \u0641\u064a \u0648\u062d\u062f\u0629 \u0627\u0644\u062a\u062d\u0643\u0645 \u0627\u0644\u0625\u0631\u0627\u062f\u064a\u0629 +label.welcome=\u0645\u0631\u062d\u0628\u0627 +label.yes=\u0646\u0639\u0645 +label.zone.details=\u062a\u0641\u0627\u0635\u064a\u0644 \u0627\u0644\u0645\u0646\u0637\u0642\u0629 +label.zone.name=\u0627\u0633\u0645 \u0627\u0644\u0645\u0646\u0637\u0642\u0629 +label.zone.step.1.title=\u0627\u0644\u062e\u0637\u0648\u0629 1 \\\: \u0639\u0644\u0649 .<\u0642\u0648\u064a> \u0627\u062e\u062a\u0631 \u0634\u0628\u0643\u0629 +label.zone.step.2.title=\u0627\u0644\u062e\u0637\u0648\u0629 2 \\\: <\u0642\u0648\u064a> \u0625\u0636\u0627\u0641\u0629 \u0645\u0646\u0637\u0642\u0629 +label.zone.step.3.title=\u0627\u0644\u062e\u0637\u0648\u0629 3 \\\: \u0639\u0644\u0649 <\u0642\u0648\u064a> \u0625\u0636\u0627\u0641\u0629 \u0628\u0648\u062f +label.zone.step.4.title=\u0627\u0644\u062e\u0637\u0648\u0629 4 \\\: <\u0642\u0648\u064a> \u0625\u0636\u0627\u0641\u0629 \u0645\u062c\u0645\u0648\u0639\u0629 IP <\\\u0642\u0648\u064a> +label.zone.wide=\u0645\u0646\u0637\u0642\u0629 \u0648\u0627\u0633\u0639\u0629 +label.zoneWizard.trafficType.guest=\u0627\u0644\u0636\u064a\u0641 \\\: \u0627\u0644\u062d\u0631\u0643\u0629 \u0628\u064a\u0646 \u0627\u0644\u0623\u062c\u0647\u0632\u0629 \u0627\u0644\u0625\u0641\u062a\u0631\u0627\u0636\u064a\u0629 \u0644\u0644\u0645\u0633\u062a\u062e\u062f\u0645 \u0627\u0644\u0646\u0647\u0627\u0626\u064a. +label.zoneWizard.trafficType.public=\u0627\u0644\u0639\u0627\u0645\u0629 \\\: \u0627\u0644\u0645\u0631\u0648\u0631 \u0628\u064a\u0646 \u0627\u0644\u0625\u0646\u062a\u0631\u0646\u062a \u0648\u0627\u0644\u0623\u062c\u0647\u0632\u0629 \u0627\u0644\u0638\u0627\u0647\u0631\u064a\u0629 \u0641\u064a \u0627\u0644\u0633\u062d\u0627\u0628\u0629. +label.zoneWizard.trafficType.storage=\u0627\u0644\u062a\u062e\u0632\u064a\u0646 \\\: \u0627\u0644\u0645\u0631\u0648\u0631 \u0628\u064a\u0646 \u0645\u0644\u0642\u0645\u0627\u062a \u0627\u0644\u062a\u062e\u0632\u064a\u0646 \u0627\u0644\u0627\u0628\u062a\u062f\u0627\u0626\u064a\u0629 \u0648\u0627\u0644\u062b\u0627\u0646\u0648\u064a\u0629\u060c \u0645\u062b\u0644 \u0642\u0648\u0627\u0644\u0628 VM \u0648\u0627\u0644\u0644\u0642\u0637\u0627\u062a +message.acquire.new.ip.vpc=\u064a\u0631\u062c\u0649 \u0627\u0644\u062a\u0623\u0643\u064a\u062f \u0628\u0623\u0646\u0643 \u062a\u0631\u063a\u0628 \u0641\u064a \u0627\u0644\u062d\u0635\u0648\u0644 \u0639\u0644\u0649 \u0628\u0648\u0631\u062a\u0648\u0643\u0648\u0644 \u0625\u0646\u062a\u0631\u0646\u062a \u062c\u062f\u064a\u062f \u0644\u0647\u0630\u0627 \u0627\u0644\u062d\u0627\u0633\u0648\u0628 \u0627\u0644\u0625\u0641\u062a\u0631\u0627\u0636\u064a. +message.action.delete.system.service.offering=\u0627\u0644\u0631\u062c\u0627\u0621 \u062a\u0623\u0643\u064a\u062f \u0631\u063a\u0628\u062a\u0643 \u0641\u064a \u062d\u0630\u0641 \u062e\u062f\u0645\u0629 \u0627\u0644\u0646\u0638\u0627\u0645 \u0627\u0644\u0645\u0642\u062f\u0645\u0629. +message.action.disable.physical.network=\u0641\u0636\u0644\u0627 \u060c \u0623\u0643\u0651\u062f \u0623\u0646\u0643 \u062a\u0631\u064a\u062f \u062a\u0639\u0637\u064a\u0644 \u0647\u0630\u0647 \u0627\u0644\u0634\u0628\u0643\u0629 \u0627\u0644\u0641\u064a\u0632\u064a\u0627\u0626\u064a\u0629 +message.action.enable.physical.network=\u0641\u0636\u0644\u0627 \u060c \u0623\u0643\u0651\u062f \u0623\u0646\u0643 \u062a\u0631\u064a\u062f \u062a\u0645\u0643\u064a\u0646 \u0647\u0630\u0647 \u0627\u0644\u0634\u0628\u0643\u0629 \u0627\u0644\u0641\u064a\u0632\u064a\u0627\u0626\u064a\u0629 +message.activate.project=\u0647\u0644 \u0623\u0646\u062a \u0645\u062a\u0623\u0643\u062f \u0645\u0646 \u0623\u0646\u0643 \u062a\u0631\u064a\u062f \u062a\u0641\u0639\u064a\u0644 \u0647\u0630\u0627 \u0627\u0644\u0645\u0634\u0631\u0648\u0639 \u061f +message.add.domain=\u064a\u0631\u062c\u0649 \u062a\u062d\u062f\u064a\u062f \u0627\u0644\u0645\u062c\u0627\u0644 \u0627\u0644\u0641\u0631\u0639\u064a \u0627\u0644\u0630\u064a \u062a\u0631\u064a\u062f \u0625\u0646\u0634\u0627\u0621 \u062a\u062d\u062a \u0647\u0630\u0627 \u0627\u0644\u0646\u0637\u0627\u0642 +message.add.new.gateway.to.vpc=\u0641\u0636\u0644\u0627 \u062d\u062f\u062f \u0627\u0644\u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0644\u0625\u0636\u0627\u0641\u0629 \u0628\u0648\u0627\u0628\u0629 gateway \u0644\u0647\u0630\u0647 \u0627\u0644\u0633\u062d\u0627\u0628\u0629 \u0627\u0644\u0625\u0641\u062a\u0631\u0627\u0636\u064a\u0629 \u0627\u0644\u062e\u0627\u0635\u0629 VPC +message.add.system.service.offering=\u0627\u0644\u0631\u062c\u0627\u0621 \u062a\u0639\u0628\u0626\u0629 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a \u0627\u0644\u062a\u0627\u0644\u064a\u0629 \u0644\u0625\u0636\u0627\u0641\u0629 \u0646\u0638\u0627\u0645 \u062c\u062f\u064a\u062f \u0644\u0637\u0631\u062d +message.add.VPN.gateway=\u064a\u0631\u062c\u0649 \u062a\u0623\u0643\u064a\u062f \u0631\u063a\u0628\u062a\u0643 \u0641\u064a \u0625\u0636\u0627\u0641\u0629 \u0628\u0648\u0627\u0628\u0629 \u0627\u0644\u0634\u0628\u0643\u0629 \u0627\u0644\u0627\u0641\u062a\u0631\u0627\u0636\u064a\u0629 \u0627\u0644\u0634\u062e\u0635\u064a\u0629 VPN +message.after.enable.s3=\u062a\u0645 \u0625\u0639\u062f\u0627\u062f \u0627\u0644\u062a\u062e\u0632\u064a\u0646 S3 \u0644\u0644\u0630\u0627\u0643\u0631\u0629 \u0627\u0644\u062b\u0627\u0646\u0648\u064a\u0629. \u062a\u0646\u0648\u064a\u0647 \: \u0639\u0646\u062f \u0645\u063a\u0627\u062f\u0631\u062a\u0643 \u0644\u0647\u0630\u0647 \u0627\u0644\u0635\u0641\u062d\u0629 \u0644\u0646 \u064a\u0643\u0648\u0646 \u0628\u0625\u0645\u0643\u0627\u0646\u0643 \u0625\u0639\u0627\u062f\u0629 \u0636\u0628\u0637 S3 \u0645\u0631\u0629 \u0623\u062e\u0631\u0649. +message.confirm.join.project=\u0646\u0631\u062c\u0648 \u062a\u0623\u0643\u064a\u062f \u0631\u063a\u0628\u062a\u0643 \u0641\u064a \u0627\u0644\u0645\u0634\u0627\u0631\u0643\u0629 \u0641\u064a \u0627\u0644\u0645\u0634\u0631\u0648\u0639 +message.decline.invitation=\u0647\u0644 \u0623\u0646\u062a \u0645\u062a\u0623\u0643\u062f \u0645\u0646 \u0623\u0646\u0643 \u062a\u0631\u064a\u062f \u0631\u0641\u0636 \u0647\u0630\u0647 \u0627\u0644\u062f\u0639\u0648\u0629 \u0627\u0644\u0645\u0634\u0631\u0648\u0639\u061f +message.delete.gateway=\u064a\u0631\u062c\u0649 \u062a\u0623\u0643\u064a\u062f \u0631\u063a\u0628\u062a\u0643 \u0641\u064a \u062d\u0630\u0641 \u0627\u0644\u0628\u0648\u0627\u0628\u0629 +message.delete.project=\u0647\u0644 \u0623\u0646\u062a \u0645\u062a\u0623\u0643\u062f \u0645\u0646 \u0623\u0646\u0643 \u062a\u0631\u064a\u062f \u062d\u0630\u0641 \u0627\u0644\u0645\u0634\u0631\u0648\u0639 \u061f +message.delete.user=\u0627\u0644\u0631\u062c\u0627\u0621 \u0627\u0644\u062a\u0623\u0643\u064a\u062f \u0628\u0623\u0646\u0643 \u062a\u0631\u063a\u0628 \u0628\u062d\u0630\u0641 \u0647\u0630\u0627 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645 +message.delete.VPN.connection=\u064a\u0631\u062c\u0649 \u062a\u0623\u0643\u064a\u062f \u0631\u063a\u0628\u062a\u0643 \u0641\u064a \u062d\u0630\u0641 \u0628\u0648\u0627\u0628\u0629 \u0627\u0644\u0634\u0628\u0643\u0629 \u0627\u0644\u0627\u0641\u062a\u0631\u0627\u0636\u064a\u0629 \u0627\u0644\u0634\u062e\u0635\u064a\u0629 VPN +message.delete.VPN.gateway=\u064a\u0631\u062c\u0649 \u062a\u0623\u0643\u064a\u062f \u0631\u063a\u0628\u062a\u0643 \u0641\u064a \u062d\u0630\u0641 \u0628\u0648\u0627\u0628\u0629 \u0627\u0644\u0634\u0628\u0643\u0629 \u0627\u0644\u0627\u0641\u062a\u0631\u0627\u0636\u064a\u0629 \u0627\u0644\u0634\u062e\u0635\u064a\u0629 +message.detach.disk=\u0647\u0644 \u0623\u0646\u062a \u0645\u062a\u0623\u0643\u062f \u0645\u0646 \u0623\u0646\u0643 \u062a\u0631\u064a\u062f \u0641\u0635\u0644 \u0647\u0630\u0627 \u0627\u0644\u0642\u0631\u0635\u061f +message.disable.user=\u0627\u0644\u0631\u062c\u0627\u0621 \u0627\u0644\u062a\u0623\u0643\u064a\u062f \u0628\u0623\u0646\u0643 \u062a\u0631\u063a\u0628 \u0628\u062a\u0639\u0637\u064a\u0644 \u0647\u0630\u0627 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645 +message.enable.account=\u0627\u0644\u0631\u062c\u0627\u0621 \u062a\u0623\u0643\u064a\u062f \u0623\u0646\u0643 \u062a\u0631\u064a\u062f \u062a\u0645\u0643\u064a\u0646 \u0647\u0630\u0627 \u0627\u0644\u062d\u0633\u0627\u0628. +message.enable.user=\u0627\u0644\u0631\u062c\u0627\u0621 \u0627\u0644\u062a\u0623\u0643\u064a\u062f \u0628\u0623\u0646\u0643 \u062a\u0631\u063a\u0628 \u0628\u062a\u0641\u0639\u064a\u0644 \u0647\u0630\u0627 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645 +message.generate.keys=\u0627\u0644\u0631\u062c\u0627\u0621 \u0627\u0644\u062a\u0623\u0643\u064a\u062f \u0628\u0623\u0646\u0643 \u062a\u0631\u063a\u0628 \u0628\u0625\u0646\u0634\u0627\u0621 \u0645\u0641\u0627\u062a\u064a\u062d \u062c\u062f\u064a\u062f\u0629 \u0644\u0647\u0630\u0627 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645 +message.instanceWizard.noTemplates=\u0644\u064a\u0633 \u0644\u062f\u064a\u0643 \u0623\u064a \u0642\u0648\u0627\u0644\u0628 \u0645\u062a\u0627\u062d\u0629\u061b \u064a\u0631\u062c\u0649 \u0625\u0636\u0627\u0641\u0629 \u0642\u0627\u0644\u0628 \u0645\u062a\u0648\u0627\u0641\u0642\u060c \u0648\u0625\u0639\u0627\u062f\u0629 \u0625\u0637\u0644\u0627\u0642 \u0627\u0644\u0645\u0639\u0627\u0644\u062c . +message.join.project=\u0644\u0642\u062f \u0627\u0646\u0636\u0645\u0645\u062a \u0625\u0644\u0649 \u0627\u0644\u0645\u0634\u0631\u0648\u0639. \u064a\u0631\u062c\u0649 \u0627\u0644\u062a\u0628\u062f\u064a\u0644 \u0625\u0644\u0649 \u0637\u0631\u064a\u0642\u0629 \u0639\u0631\u0636 \u0627\u0644\u0645\u0634\u0631\u0648\u0639 \u0644\u0631\u0624\u064a\u0629 \u0627\u0644\u0645\u0634\u0631\u0648\u0639 +message.migrate.instance.to.host=\u064a\u0631\u062c\u0649 \u062a\u0623\u0643\u064a\u062f \u0623\u0646\u0643 \u062a\u0631\u064a\u062f \u0646\u0642\u0644 \u0627\u0644\u0642\u0627\u0644\u0628 \u0625\u0644\u0649 \u0645\u0636\u064a\u0641 \u0622\u062e\u0631. +message.migrate.instance.to.ps=\u064a\u0631\u062c\u0649 \u062a\u0623\u0643\u064a\u062f \u0623\u0646\u0643 \u062a\u0631\u064a\u062f \u0646\u0642\u0644 \u0627\u0644\u0642\u0627\u0644\u0628 \u0625\u0644\u0649 \u0627\u0644\u0630\u0627\u0643\u0631\u0629 \u0627\u0644\u0623\u0633\u0627\u0633\u064a\u0629. +message.no.projects.adminOnly=\u0644\u064a\u0633 \u0644\u062f\u064a\u0643 \u0623\u064a \u0645\u0634\u0627\u0631\u064a\u0639.
\u0627\u0644\u0631\u062c\u0627\u0621 \u0637\u0644\u0628 \u0645\u0646 \u0627\u0644\u0645\u0633\u0624\u0648\u0644 \u0625\u0646\u0634\u0627\u0621 \u0645\u0634\u0631\u0648\u0639 \u062c\u062f\u064a\u062f. +message.no.projects=\u0644\u064a\u0633 \u0644\u062f\u064a\u0643 \u0623\u064a \u0645\u0634\u0627\u0631\u064a\u0639.
\u064a\u0631\u062c\u0649 \u0625\u0646\u0634\u0627\u0621 \u0645\u0634\u0631\u0648\u0639 \u062c\u062f\u064a\u062f \u0645\u0646 \u0642\u0633\u0645 \u0627\u0644\u0645\u0634\u0627\u0631\u064a\u0639. +message.pending.projects.1=\u0644\u062f\u064a\u0643 \u062f\u0639\u0648\u0627\u062a \u0645\u0634\u0631\u0648\u0639 \u0645\u0639\u0644\u0642\u0629/\: +message.pending.projects.2=\u0644\u0639\u0631\u0636\u060c \u0627\u0644\u0631\u062c\u0627\u0621 \u0627\u0644\u0630\u0647\u0627\u0628 \u0625\u0644\u0649 \u0642\u0633\u0645 \u0627\u0644\u0645\u0634\u0627\u0631\u064a\u0639\u060c \u062b\u0645 \u062d\u062f\u062f \u062f\u0639\u0648\u0627\u062a \u0645\u0646 \u0627\u0644\u0642\u0627\u0626\u0645\u0629 \u0627\u0644\u0645\u0646\u0633\u062f\u0644\u0629. +message.please.select.networks=\u0627\u0644\u0631\u062c\u0627\u0621 \u0627\u062e\u062a\u064a\u0627\u0631 \u0627\u0644\u0634\u0628\u0643\u0627\u062a \u0644\u062c\u0647\u0627\u0632\u0643 \u0627\u0644\u0625\u0641\u062a\u0631\u0627\u0636\u064a +message.project.invite.sent=\u062a\u0645 \u0625\u0631\u0633\u0627\u0644 \u0627\u0644\u062f\u0639\u0648\u0629 ; \u0633\u064a\u062a\u0645 \u0625\u0636\u0627\u0641\u062a\u0647\u0645 \u0625\u0644\u0649 \u0627\u0644\u0645\u0634\u0631\u0648\u0639 \u0628\u0645\u062c\u0631\u062f \u0642\u0628\u0648\u0644 \u0627\u0644\u062f\u0639\u0648\u0629 +message.remove.vpc=\u064a\u0631\u062c\u0649 \u062a\u0623\u0643\u064a\u062f \u0631\u063a\u0628\u062a\u0643 \u0641\u064a \u062d\u0630\u0641 \u0627\u0644\u0640VPC +message.reset.password.warning.notPasswordEnabled=\u0627\u0644\u0642\u0627\u0644\u0628 \u0644\u0647\u0630\u0627 \u0627\u0644\u0646\u0645\u0648\u0630\u062c \u062a\u0645 \u0627\u0646\u0634\u0627\u0626\u0647 \u0645\u0646 \u062f\u0648\u0646 \u0643\u0644\u0645\u0629 \u0645\u0631\u0648\u0631 \u0645\u0645\u0643\u0646\u0629 +message.reset.password.warning.notStopped=\u064a\u062c\u0628 \u0625\u064a\u0642\u0627\u0641 \u0627\u0644\u0646\u0645\u0648\u0630\u062c \u0627\u0644\u062e\u0627\u0635 \u0628\u0643 \u0642\u0628\u0644 \u0645\u062d\u0627\u0648\u0644\u0629 \u062a\u063a\u064a\u064a\u0631 \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 \u0627\u0644\u062d\u0627\u0644\u064a\u0629 +message.reset.VPN.connection=\u064a\u0631\u062c\u0649 \u062a\u0623\u0643\u064a\u062f \u0623\u0646\u0643 \u062a\u0631\u064a\u062f \u0625\u0639\u0627\u062f\u0629-\u0636\u0628\u0637 \u0625\u062a\u0635\u0627\u0644 \u0627\u0644\u0634\u0628\u0643\u0629 \u0627\u0644\u0627\u0641\u062a\u0631\u0627\u0636\u064a\u0629 \u0627\u0644\u0634\u062e\u0635\u064a\u0629 VPN +message.restart.vpc=\u064a\u0631\u062c\u0649 \u062a\u0623\u0643\u064a\u062f \u0631\u063a\u0628\u062a\u0643 \u0641\u064a \u0625\u0639\u0627\u062f\u0629 \u062a\u0634\u063a\u064a\u0644 \u0627\u0644\u0640VPN +message.select.template=\u0627\u0644\u0631\u062c\u0627\u0621 \u0627\u062e\u062a\u064a\u0627\u0631 \u0642\u0627\u0644\u0628 \u0644\u0645\u062b\u0627\u0644\u0643 \u0627\u0644\u0625\u0641\u062a\u0631\u0627\u0636\u064a \u0627\u0644\u062c\u062f\u064a\u062f +message.step.2.desc= +message.step.3.desc= +message.suspend.project=\u0647\u0644 \u0623\u0646\u062a \u0645\u062a\u0623\u0643\u062f \u0645\u0646 \u0623\u0646\u0643 \u062a\u0631\u064a\u062f \u0625\u064a\u0642\u0627\u0641 \u0647\u0630\u0627 \u0627\u0644\u0645\u0634\u0631\u0648\u0639 \u061f +message.update.resource.count=\u0627\u0644\u0631\u062c\u0627\u0621 \u0627\u0644\u062a\u0623\u0643\u064a\u062f \u0628\u0623\u0646\u0643 \u062a\u0631\u063a\u0628 \u0628\u062a\u062d\u062f\u064a\u062b \u0645\u0635\u0627\u062f\u0631 \u0627\u0644\u062d\u0633\u0627\u0628\u0627\u062a \u0644\u0647\u0630\u0627 \u0627\u0644\u062d\u0633\u0627\u0628 +message.vm.review.launch=\u064a\u0631\u062c\u0649 \u0645\u0631\u0627\u062c\u0639\u0629 \u0627\u0644\u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0627\u0644\u062a\u0627\u0644\u064a\u0629 \u0648\u062a\u0623\u0643\u062f \u0623\u0646 \u0645\u062b\u0627\u0644\u0643 \u0627\u0644\u0625\u0641\u062a\u0631\u0627\u0636\u064a \u0635\u062d\u064a\u062d \u0642\u0628\u0644 \u0627\u0644\u0625\u0646\u0637\u0644\u0627\u0642 +message.zoneWizard.enable.local.storage=\u062a\u062d\u0630\u064a\u0631\\\: \u0625\u0630\u0627 \u0642\u0645\u062a \u0628\u062a\u0645\u0643\u064a\u0646 \u0627\u0644\u0630\u0627\u0643\u0631\u0629 \u0627\u0644\u0645\u062d\u0644\u064a\u0629 \u0644\u0647\u0630\u0627 \u0627\u0644\u0646\u0637\u0627\u0642 \u064a\u062c\u0628 \u0639\u0644\u064a\u0643 \u0639\u0645\u0644 \u0627\u0644\u0622\u062a\u064a \u060c \u0625\u0639\u062a\u0645\u0627\u062f\u0627 \u0639\u0644\u0649 \u0627\u0644\u0645\u0643\u0627\u0646 \u0627\u0644\u0630\u064a \u062a\u0631\u063a\u0628 \u0623\u0646 \u064a\u0646\u0637\u0644\u0642 \u0645\u0646\u0647 \u0646\u0638\u0627\u0645\u0643 \u0627\u0644\u0625\u0641\u062a\u0631\u0627\u0636\u064a \\\:

1.\u0625\u0630\u0627 \u0643\u0627\u0646 \u0646\u0638\u0627\u0645\u0643 \u0627\u0644\u0625\u0641\u062a\u0631\u0627\u0636\u064a \u064a\u062d\u062a\u0627\u062c \u0625\u0644\u0649 \u062a\u0634\u063a\u064a\u0644 \u0627\u0644\u0630\u0627\u0643\u0631\u0629 \u0627\u0644\u0625\u0628\u062a\u062f\u0627\u0626\u064a\u0629 +notification.reboot.instance=\u0625\u0639\u0627\u062f\u0629 \u062a\u0634\u063a\u064a\u0644 \u0627\u0644\u0646\u0645\u0648\u0630\u062c +notification.start.instance=\u0628\u062f\u0621 \u0627\u0644\u0646\u0645\u0648\u0630\u062c +notification.stop.instance=\u0625\u064a\u0642\u0627\u0641 \u0627\u0644\u0646\u0645\u0648\u0630\u062c +state.Accepted=\u062a\u0645 \u0627\u0644\u0642\u0628\u0648\u0644 +state.Active=\u0646\u0634\u0637 +state.Allocated=\u062a\u062e\u0635\u064a\u0635 +state.Completed=\u062a\u0645 \u0627\u0644\u0627\u0643\u0645\u0627\u0644 +state.Creating=\u0625\u0646\u0634\u0627\u0621 +state.Declined=\u062a\u0645 \u0627\u0644\u0631\u0641\u0636 +state.Destroyed=\u062f\u0645\u0631 +state.enabled=\u062a\u0645\u0643\u064a\u0646 +state.Enabled=\u062a\u0645\u0643\u064a\u0646 +state.Error=\u062e\u0637\u0623 +state.Expunging=\u0645\u062d\u0648 +state.Pending=\u0641\u064a \u0627\u0644\u0627\u0646\u062a\u0638\u0627\u0631 +state.ready=\u062c\u0627\u0647\u0632 +state.Ready=\u062c\u0627\u0647\u0632 +state.Stopped=\u062a\u0648\u0642\u0641 +state.Suspended=\u062a\u0645 \u0627\u0644\u0625\u064a\u0642\u0627\u0641 +ui.listView.filters.all=\u0627\u0644\u0643\u0644 diff --git a/client/WEB-INF/classes/resources/messages_ca.properties b/client/WEB-INF/classes/resources/messages_ca.properties index 2d8e953419f..4e66083dbd5 100644 --- a/client/WEB-INF/classes/resources/messages_ca.properties +++ b/client/WEB-INF/classes/resources/messages_ca.properties @@ -15,6 +15,7 @@ # specific language governing permissions and limitations # under the License. + confirm.enable.swift=Si us plau ompliu la seg\u00fcent informaci\u00f3 per habilitar el suport per a Swift error.installWizard.message=Quelcom ha fallat, vost\u00e8 pot tornar enrere i corregir els errors detalls suggerime error.password.not.match=Els camps de contrasenya no coincideixen diff --git a/client/WEB-INF/classes/resources/messages_de_DE.properties b/client/WEB-INF/classes/resources/messages_de_DE.properties index 45812687d2f..ca87323cc77 100644 --- a/client/WEB-INF/classes/resources/messages_de_DE.properties +++ b/client/WEB-INF/classes/resources/messages_de_DE.properties @@ -15,13 +15,14 @@ # specific language governing permissions and limitations # under the License. + error.installWizard.message=Ein Fehler ist aufgetreten; Sie k\u00f6nnen zur\u00fcckgehen und den Fehler korregieren error.login=Ihr Benutzername / Passwort stimmt nicht mit uneren unseren Aufzeichnungen \u00fcberein. error.session.expired=Ihre Sitzung ist abgelaufen. force.delete.domain.warning=Achtung\: Diese Auswahl f\u00fchrt zu einer L\u00f6schung aller untergeordneten Domains und aller angeschlossenen Konten sowie ihrer Quellen. force.delete=Erzwinge L\u00f6schung force.remove=Erzwinge Entfernung -force.remove.host.warning=Achtung\: Diese Auswahl wird CloudStack zum sofortigen Anhalten der virtuellen Maschine f\u00fchren, bevor der Host vom Cluster entfernt wurde. +force.remove.host.warning=Achtung\: Diese Auswahl wird CloudStack zum sofortigen Anhalten der virtuellen Maschine f\u00fchren, bevor der Host vom Cluster entfernt wurde. force.stop=Erzwinge Abbruch ICMP.code=ICMP Code ICMP.type=ICMP-Typ @@ -159,7 +160,7 @@ label.action.migrate.instance.processing=Umziehen einer Instanz label.action.reboot.instance=Instanz neustarten label.action.reboot.instance.processing=Neustarten der Instanz... label.action.reboot.router.processing=Neustart vom Router .... -label.action.reboot.router=Router neu starten +label.action.reboot.router=Router neu starten label.action.reboot.systemvm.processing=Neustart-System VM .... label.action.reboot.systemvm=System VM neu starten label.action.release.ip=IP ver\u00f6ffentlichen @@ -271,7 +272,7 @@ label.cidr=CIDR label.cidr.list=Quelle CIDR label.close=Schliessen label.cloud.console=Cloud Management Konsole -label.cloud.managed=Geleitet von cloud.com +label.cloud.managed=Geleitet von cloud.com label.cluster=Cluster label.cluster.type=Cluster-Typ label.code=Code @@ -279,7 +280,7 @@ label.configuration=Konfiguration label.confirmation=Best\u00e4tigung label.congratulations=Herzlichen Gl\u00fcckwunsch label.corrections.saved=Korrekturen gespeichert -label.cpu.allocated=Zugeteilte CPU +label.cpu.allocated=Zugeteilte CPU label.CPU.cap=CPU Obergrenze label.cpu=CPU label.cpu.mhz=CPU (in MHz) @@ -708,7 +709,7 @@ message.enable.account=Bitte best\u00e4tigen Sie, dass Sie dieses Konto aktivier message.enabled.vpn=Ihr VPN Zugriff ist zurzeit aktiv und via IP k\u00f6nnen Sie darauf zugreifen message.enable.vpn.access=VPN ist zurzeit nicht f\u00fcr diese IP Addresse aktiviert. M\u00f6chten Sie den VPN Zugriff aktivieren? message.installWizard.click.retry=Bitte den Start Button f\u00fcr einen neuen Versuch dr\u00fccken -message.installWizard.tooltip.addCluster.name=Der Name des Clusters. Der Name kann frei gew\u00e4hlt werden und wird von Cloudstack nicht genutzt. +message.installWizard.tooltip.addCluster.name=Der Name des Clusters. Der Name kann frei gew\u00e4hlt werden und wird von Cloudstack nicht genutzt. message.installWizard.tooltip.addHost.hostname=Der DNS-Name oder die IP-Adresse des hosts message.installWizard.tooltip.addHost.password=Dies ist das Passwort des o.a. Users (von der XenServer Installation) message.installWizard.tooltip.addHost.username=\u00fcberlicherweise root @@ -717,16 +718,16 @@ message.installWizard.tooltip.addPod.reservedSystemGateway=Das Gateways f\u00fcr message.installWizard.tooltip.addPod.reservedSystemNetmask=Die Subnetzmaske des Gast-Netzwerks message.installWizard.tooltip.addPrimaryStorage.name=Der Name der Storage Devices message.installWizard.tooltip.addPrimaryStorage.path=(f\u00fcr NFS) Bei NFS wird hier der exportierte Pfad (Shared Mount Point) angegeben. F\u00fcr KVM wird hier der Pfad angegeben, wo auf jedem Host das primary storage gemountet wurde. Z.B. "/mnt/primary" -message.installWizard.tooltip.addPrimaryStorage.server=(f\u00fcr NFS, iSCSI oder PreSetup) Die IP-Adresse oder der DNS-Name des storage devices. -message.installWizard.tooltip.addSecondaryStorage.nfsServer=Die IP-Adresse des NFS-Servers, der den Secondary Storage bereitstellt. -message.installWizard.tooltip.addSecondaryStorage.path=Der exportierte Pfad, der auf dem o.a. Server liegt. +message.installWizard.tooltip.addPrimaryStorage.server=(f\u00fcr NFS, iSCSI oder PreSetup) Die IP-Adresse oder der DNS-Name des storage devices. +message.installWizard.tooltip.addSecondaryStorage.nfsServer=Die IP-Adresse des NFS-Servers, der den Secondary Storage bereitstellt. +message.installWizard.tooltip.addSecondaryStorage.path=Der exportierte Pfad, der auf dem o.a. Server liegt. message.installWizard.tooltip.addZone.name=Der Name f\u00fcr die zone -message.installWizard.tooltip.configureGuestTraffic.description=Eine Beschreibung des Netzwerkes. -message.installWizard.tooltip.configureGuestTraffic.guestGateway=Das gateway, welches der Gast benutzen soll. +message.installWizard.tooltip.configureGuestTraffic.description=Eine Beschreibung des Netzwerkes. +message.installWizard.tooltip.configureGuestTraffic.guestGateway=Das gateway, welches der Gast benutzen soll. message.installWizard.tooltip.configureGuestTraffic.guestNetmask=Die Subnetzmaske des Gast-Netzwerks message.installWizard.tooltip.configureGuestTraffic.name=Der Name f\u00fcr das Netzwerk message.migrate.instance.to.host=Bitte best\u00e4tigen sie, dass die Instanz auf einen anderen Host migriert werden soll -message.migrate.instance.to.ps=Bitte best\u00e4tigen sie, dass sie die Instanz auf einen anderen prim\u00e4ren Speicher migrieren wollen. +message.migrate.instance.to.ps=Bitte best\u00e4tigen sie, dass sie die Instanz auf einen anderen prim\u00e4ren Speicher migrieren wollen. message.new.user=Spezifieren Sie das folgende um einen neuen Nutzer dem Benutzerkonto hinzuzuf\u00fcgen message.remove.vpn.access=Bitte best\u00e4tigen Sie, dass Sie den VPN-Zugriff vom folgenden Benutzer entfernen m\u00f6chten. message.setup.successful=Cloud setup erfolgreich diff --git a/client/WEB-INF/classes/resources/messages_es.properties b/client/WEB-INF/classes/resources/messages_es.properties index 28f9363724a..16cfc1cda49 100644 --- a/client/WEB-INF/classes/resources/messages_es.properties +++ b/client/WEB-INF/classes/resources/messages_es.properties @@ -15,7 +15,8 @@ # specific language governing permissions and limitations # under the License. -error.installWizard.message=Algo salio mal, debes ir para atr\u00e1s y corregir los error. + +error.installWizard.message=Algo salio mal, debes ir para atr\u00e1s y corregir los error. error.login=Su nombre de usuario / contrase\u00c3\u00b1a no coincide con nuestros registros. error.mgmt.server.inaccessible=El Servidor de Gesti\u00c3\u00b3n es inaccesible. Por favor, int\u00c3\u00a9ntelo de nuevo m\u00c3\u00a1s tarde. error.session.expired=Su sesi\u00c3\u00b3n ha caducado. @@ -31,133 +32,133 @@ ICMP.code=ICMP C\u00c3\u00b3digo ICMP.type=Tipo ICMP image.directory=Directorio de la imagen inline=en l\u00c3\u00adnea -label.account=Cuenta -label.account.id=ID de la cuenta -label.account.name=Nombre de la cuenta +label.account=Cuenta +label.account.id=ID de la cuenta +label.account.name=Nombre de la cuenta label.accounts=Cuentas -label.account.specific=espec\u00c3\u00adficas de la cuenta +label.account.specific=espec\u00c3\u00adficas de la cuenta label.acquire.new.ip=adquirir nuevas IP -label.action.attach.disk=Conecte el disco -label.action.attach.disk.processing=disco Fijaci\u00c3\u00b3n .... -label.action.attach.iso=Adjuntar ISO -label.action.attach.iso.processing=Colocaci\u00c3\u00b3n de la norma ISO .... -label.action.cancel.maintenance.mode=Cancelar modo de mantenimiento -label.action.cancel.maintenance.mode.processing=Cancelaci\u00c3\u00b3n del modo de mantenimiento .... -label.action.change.password=Cambiar contrase\u00c3\u00b1a -label.action.change.service=Cambio de Servicio -label.action.change.service.processing=Cambio de servicio .... -label.action.copy.ISO=Copia de la ISO -label.action.copy.ISO.processing=hacer frente ISO .... -label.action.copy.template=Copia de plantilla -label.action.copy.template.processing=hacer frente plantilla .... -label.action.create.template=Crear plantilla +label.action.attach.disk=Conecte el disco +label.action.attach.disk.processing=disco Fijaci\u00c3\u00b3n .... +label.action.attach.iso=Adjuntar ISO +label.action.attach.iso.processing=Colocaci\u00c3\u00b3n de la norma ISO .... +label.action.cancel.maintenance.mode=Cancelar modo de mantenimiento +label.action.cancel.maintenance.mode.processing=Cancelaci\u00c3\u00b3n del modo de mantenimiento .... +label.action.change.password=Cambiar contrase\u00c3\u00b1a +label.action.change.service=Cambio de Servicio +label.action.change.service.processing=Cambio de servicio .... +label.action.copy.ISO=Copia de la ISO +label.action.copy.ISO.processing=hacer frente ISO .... +label.action.copy.template=Copia de plantilla +label.action.copy.template.processing=hacer frente plantilla .... +label.action.create.template=Crear plantilla label.action.create.template.from.vm=Crear plantilla de VM label.action.create.template.from.volume=Crear plantilla de volumen -label.action.create.template.processing=Creaci\u00c3\u00b3n de plantillas .... -label.action.create.vm=Crear VM -label.action.create.vm.processing=Creaci\u00c3\u00b3n de m\u00c3\u00a1quina virtual .... -label.action.create.volume=Crear volumen -label.action.create.volume.processing=Crear volumen .... -label.action.delete.account=Eliminar cuenta -label.action.delete.account.processing=Eliminar cuentas .... -label.action.delete.cluster=Borrar Grupo -label.action.delete.cluster.processing=Borrar Grupo .... -label.action.delete.disk.offering=Borrar disco Ofrenda -label.action.delete.disk.offering.processing=Borrar disco ofrece .... -label.action.delete.domain=Eliminar de dominio -label.action.delete.domain.processing=Eliminaci\u00c3\u00b3n de dominio .... -label.action.delete.firewall=Eliminar servidor de seguridad -label.action.delete.firewall.processing=Eliminaci\u00c3\u00b3n de firewall .... -label.action.delete.ingress.rule=Borrar ingreso Regla -label.action.delete.ingress.rule.processing=Eliminaci\u00c3\u00b3n de ingreso regla .... -label.action.delete.IP.range=Eliminar Rango de IP -label.action.delete.IP.range.processing=Eliminar Rango de IP .... -label.action.delete.ISO=Eliminar ISO -label.action.delete.ISO.processing=Eliminaci\u00c3\u00b3n de la norma ISO .... -label.action.delete.load.balancer=Eliminar equilibrador de carga +label.action.create.template.processing=Creaci\u00c3\u00b3n de plantillas .... +label.action.create.vm=Crear VM +label.action.create.vm.processing=Creaci\u00c3\u00b3n de m\u00c3\u00a1quina virtual .... +label.action.create.volume=Crear volumen +label.action.create.volume.processing=Crear volumen .... +label.action.delete.account=Eliminar cuenta +label.action.delete.account.processing=Eliminar cuentas .... +label.action.delete.cluster=Borrar Grupo +label.action.delete.cluster.processing=Borrar Grupo .... +label.action.delete.disk.offering=Borrar disco Ofrenda +label.action.delete.disk.offering.processing=Borrar disco ofrece .... +label.action.delete.domain=Eliminar de dominio +label.action.delete.domain.processing=Eliminaci\u00c3\u00b3n de dominio .... +label.action.delete.firewall=Eliminar servidor de seguridad +label.action.delete.firewall.processing=Eliminaci\u00c3\u00b3n de firewall .... +label.action.delete.ingress.rule=Borrar ingreso Regla +label.action.delete.ingress.rule.processing=Eliminaci\u00c3\u00b3n de ingreso regla .... +label.action.delete.IP.range=Eliminar Rango de IP +label.action.delete.IP.range.processing=Eliminar Rango de IP .... +label.action.delete.ISO=Eliminar ISO +label.action.delete.ISO.processing=Eliminaci\u00c3\u00b3n de la norma ISO .... +label.action.delete.load.balancer=Eliminar equilibrador de carga label.action.delete.load.balancer.processing=Eliminaci\u00c3\u00b3n del equilibrador de carga .... -label.action.delete.network=Eliminar Red -label.action.delete.network.processing=Eliminaci\u00c3\u00b3n de red .... -label.action.delete.pod=Eliminar Pod -label.action.delete.pod.processing=Eliminar Pod .... -label.action.delete.primary.storage=Almacenamiento primario Eliminar -label.action.delete.primary.storage.processing=Eliminaci\u00c3\u00b3n de almacenamiento primaria .... -label.action.delete.secondary.storage.processing=Eliminaci\u00c3\u00b3n de almacenamiento secundario .... -label.action.delete.secondary.storage=secundaria almacenamiento Eliminar -label.action.delete.security.group=Borrar Grupo de Seguridad -label.action.delete.security.group.processing=Eliminar grupo de seguridad .... -label.action.delete.service.offering=Eliminar Oferta de Servicio -label.action.delete.service.offering.processing=Eliminaci\u00c3\u00b3n de Oferta de Servicio .... -label.action.delete.snapshot=Eliminar instant\u00c3\u00a1nea -label.action.delete.snapshot.processing=Eliminar instant\u00c3\u00a1nea .... -label.action.delete.template=Eliminar plantilla -label.action.delete.template.processing=Eliminar plantilla .... -label.action.delete.user=Eliminar usuario -label.action.delete.user.processing=Eliminar usuario .... -label.action.delete.volume=Eliminar volumen -label.action.delete.volume.processing=Eliminar volumen .... -label.action.delete.zone=Eliminar Zona -label.action.delete.zone.processing=Eliminaci\u00c3\u00b3n de la Zona .... -label.action.destroy.instance=Destruye Instancia -label.action.destroy.instance.processing=Destrucci\u00c3\u00b3n Instancia .... +label.action.delete.network=Eliminar Red +label.action.delete.network.processing=Eliminaci\u00c3\u00b3n de red .... +label.action.delete.pod=Eliminar Pod +label.action.delete.pod.processing=Eliminar Pod .... +label.action.delete.primary.storage=Almacenamiento primario Eliminar +label.action.delete.primary.storage.processing=Eliminaci\u00c3\u00b3n de almacenamiento primaria .... +label.action.delete.secondary.storage.processing=Eliminaci\u00c3\u00b3n de almacenamiento secundario .... +label.action.delete.secondary.storage=secundaria almacenamiento Eliminar +label.action.delete.security.group=Borrar Grupo de Seguridad +label.action.delete.security.group.processing=Eliminar grupo de seguridad .... +label.action.delete.service.offering=Eliminar Oferta de Servicio +label.action.delete.service.offering.processing=Eliminaci\u00c3\u00b3n de Oferta de Servicio .... +label.action.delete.snapshot=Eliminar instant\u00c3\u00a1nea +label.action.delete.snapshot.processing=Eliminar instant\u00c3\u00a1nea .... +label.action.delete.template=Eliminar plantilla +label.action.delete.template.processing=Eliminar plantilla .... +label.action.delete.user=Eliminar usuario +label.action.delete.user.processing=Eliminar usuario .... +label.action.delete.volume=Eliminar volumen +label.action.delete.volume.processing=Eliminar volumen .... +label.action.delete.zone=Eliminar Zona +label.action.delete.zone.processing=Eliminaci\u00c3\u00b3n de la Zona .... +label.action.destroy.instance=Destruye Instancia +label.action.destroy.instance.processing=Destrucci\u00c3\u00b3n Instancia .... label.action.destroy.systemvm=destruir el sistema VM label.action.destroy.systemvm.processing=Destrucci\u00c3\u00b3n del sistema VM .... -label.action.detach.disk.processing=Extracci\u00c3\u00b3n disco .... -label.action.detach.disk=Separar disco -label.action.detach.iso.processing=Extracci\u00c3\u00b3n ISO .... -label.action.detach.iso=Separar ISO -label.action.disable.account=Desactivar cuenta -label.action.disable.account.processing=Deshabilitar cuenta .... -label.action.disable.cluster=Deshabilitar cl\u00c3\u00baster -label.action.disable.cluster.processing=Desactivaci\u00c3\u00b3n de Cluster Server .... -label.action.disable.pod=Deshabilitar Pod -label.action.disable.pod.processing=Deshabilitar Pod .... -label.action.disable.static.NAT=Deshabilitar NAT est\u00c3\u00a1tica -label.action.disable.static.NAT.processing=Deshabilitar NAT est\u00c3\u00a1tica .... -label.action.disable.user=Deshabilitar usuario -label.action.disable.user.processing=Desactivaci\u00c3\u00b3n de usuario .... -label.action.disable.zone=Deshabilitar la zona -label.action.disable.zone.processing=Desactivaci\u00c3\u00b3n de la zona .... -label.action.download.ISO=ISO Descargar -label.action.download.template=Descargar plantilla -label.action.download.volume=Descargar Volumen -label.action.download.volume.processing=Volumen Descargar .... -label.action.edit.account=Editar cuenta -label.action.edit.disk.offering=Editar disco Ofrenda -label.action.edit.domain=Editar Dominio -label.action.edit.global.setting=Editar Mundial Marco +label.action.detach.disk.processing=Extracci\u00c3\u00b3n disco .... +label.action.detach.disk=Separar disco +label.action.detach.iso.processing=Extracci\u00c3\u00b3n ISO .... +label.action.detach.iso=Separar ISO +label.action.disable.account=Desactivar cuenta +label.action.disable.account.processing=Deshabilitar cuenta .... +label.action.disable.cluster=Deshabilitar cl\u00c3\u00baster +label.action.disable.cluster.processing=Desactivaci\u00c3\u00b3n de Cluster Server .... +label.action.disable.pod=Deshabilitar Pod +label.action.disable.pod.processing=Deshabilitar Pod .... +label.action.disable.static.NAT=Deshabilitar NAT est\u00c3\u00a1tica +label.action.disable.static.NAT.processing=Deshabilitar NAT est\u00c3\u00a1tica .... +label.action.disable.user=Deshabilitar usuario +label.action.disable.user.processing=Desactivaci\u00c3\u00b3n de usuario .... +label.action.disable.zone=Deshabilitar la zona +label.action.disable.zone.processing=Desactivaci\u00c3\u00b3n de la zona .... +label.action.download.ISO=ISO Descargar +label.action.download.template=Descargar plantilla +label.action.download.volume=Descargar Volumen +label.action.download.volume.processing=Volumen Descargar .... +label.action.edit.account=Editar cuenta +label.action.edit.disk.offering=Editar disco Ofrenda +label.action.edit.domain=Editar Dominio +label.action.edit.global.setting=Editar Mundial Marco label.action.edit.host=edici\u00c3\u00b3n Anfitri\u00c3\u00b3n -label.action.edit.instance=Editar Instancia -label.action.edit.ISO=Editar ISO +label.action.edit.instance=Editar Instancia +label.action.edit.ISO=Editar ISO label.action.edit.network=Edici\u00c3\u00b3n de redes -label.action.edit.network.offering=Editar Red ofrece -label.action.edit.pod=Editar Pod -label.action.edit.primary.storage=Editar Almacenamiento primario -label.action.edit.resource.limits=Editar l\u00c3\u00admites de recursos -label.action.edit.service.offering=Editar Oferta de Servicio -label.action.edit.template=Editar plantilla -label.action.edit.user=Editar usuario -label.action.edit.zone=Edici\u00c3\u00b3n Zona -label.action.enable.account=Habilitar cuenta -label.action.enable.account.processing=cuenta de Habilitaci\u00c3\u00b3n .... -label.action.enable.cluster=Habilitar cl\u00c3\u00baster -label.action.enable.cluster.processing=Habilitar cl\u00c3\u00baster .... -label.action.enable.maintenance.mode=Activar el modo de mantenimiento -label.action.enable.maintenance.mode.processing=Habilitaci\u00c3\u00b3n del modo de mantenimiento .... -label.action.enable.pod=Habilitar Pod -label.action.enable.pod.processing=Habilitaci\u00c3\u00b3n Pod .... -label.action.enable.static.NAT=Habilitar NAT est\u00c3\u00a1tica -label.action.enable.static.NAT.processing=Habilitar NAT est\u00c3\u00a1tica .... -label.action.enable.user.processing=Habilitaci\u00c3\u00b3n del usuario .... -label.action.enable.user=usuario Activar +label.action.edit.network.offering=Editar Red ofrece +label.action.edit.pod=Editar Pod +label.action.edit.primary.storage=Editar Almacenamiento primario +label.action.edit.resource.limits=Editar l\u00c3\u00admites de recursos +label.action.edit.service.offering=Editar Oferta de Servicio +label.action.edit.template=Editar plantilla +label.action.edit.user=Editar usuario +label.action.edit.zone=Edici\u00c3\u00b3n Zona +label.action.enable.account=Habilitar cuenta +label.action.enable.account.processing=cuenta de Habilitaci\u00c3\u00b3n .... +label.action.enable.cluster=Habilitar cl\u00c3\u00baster +label.action.enable.cluster.processing=Habilitar cl\u00c3\u00baster .... +label.action.enable.maintenance.mode=Activar el modo de mantenimiento +label.action.enable.maintenance.mode.processing=Habilitaci\u00c3\u00b3n del modo de mantenimiento .... +label.action.enable.pod=Habilitar Pod +label.action.enable.pod.processing=Habilitaci\u00c3\u00b3n Pod .... +label.action.enable.static.NAT=Habilitar NAT est\u00c3\u00a1tica +label.action.enable.static.NAT.processing=Habilitar NAT est\u00c3\u00a1tica .... +label.action.enable.user.processing=Habilitaci\u00c3\u00b3n del usuario .... +label.action.enable.user=usuario Activar label.action.enable.zone=Habilitar la zona -label.action.enable.zone.processing=Habilitaci\u00c3\u00b3n de zona .... -label.action.force.reconnect=Fuerza Vuelva a conectar -label.action.force.reconnect.processing=Reconectando .... -label.action.generate.keys=Generar Claves -label.action.generate.keys.processing=Generar claves .... -label.action.lock.account=Bloqueo de cuenta -label.action.lock.account.processing=Bloqueo de cuenta .... +label.action.enable.zone.processing=Habilitaci\u00c3\u00b3n de zona .... +label.action.force.reconnect=Fuerza Vuelva a conectar +label.action.force.reconnect.processing=Reconectando .... +label.action.generate.keys=Generar Claves +label.action.generate.keys.processing=Generar claves .... +label.action.lock.account=Bloqueo de cuenta +label.action.lock.account.processing=Bloqueo de cuenta .... label.action.manage.cluster=gestionar racimo label.action.manage.cluster.processing=La gesti\u00c3\u00b3n de cl\u00c3\u00basteres .... label.action.migrate.instance=Migrar Instancia @@ -166,650 +167,650 @@ label.action.migrate.router=migrar Router label.action.migrate.router.processing=Migraci\u00c3\u00b3n router .... label.action.migrate.systemvm=Migrar del sistema VM label.action.migrate.systemvm.processing=La migraci\u00c3\u00b3n de VM del sistema .... -label.action.reboot.instance.processing=Reiniciar Instancia .... -label.action.reboot.instance=Reiniciar Instancia -label.action.reboot.router.processing=Reiniciar router .... -label.action.reboot.router=Reiniciar router -label.action.reboot.systemvm.processing=reinicio del sistema VM .... -label.action.reboot.systemvm=Reiniciar sistema VM -label.action.recurring.snapshot=recurrente instant\u00c3\u00a1neas -label.action.release.ip=estreno IP -label.action.release.ip.processing=Liberar IP .... -label.action.remove.host.processing=Extracci\u00c3\u00b3n de host .... -label.action.remove.host=Quitar host -label.action.reset.password.processing=Restablecimiento de la contrase\u00c3\u00b1a .... -label.action.reset.password=Restablecer contrase\u00c3\u00b1a -label.action.resource.limits=Recursos l\u00c3\u00admites -label.action.restore.instance.processing=Restaurar Instancia .... -label.action.restore.instance=Restaurar Instancia -label.actions=Acciones -label.action.start.instance=Iniciar Instancia -label.action.start.instance.processing=A partir Instancia .... -label.action.start.router=inicio del router -label.action.start.router.processing=A partir del router .... -label.action.start.systemvm=Inicio del sistema VM -label.action.start.systemvm.processing=A partir del sistema VM .... -label.action.stop.instance=Detener Instancia -label.action.stop.instance.processing=Detener Instancia .... -label.action.stop.router=Detener router -label.action.stop.router.processing=Detener router .... -label.action.stop.systemvm=parada del sistema VM -label.action.stop.systemvm.processing=Detener sistema VM .... -label.action.take.snapshot.processing=Tomar instant\u00c3\u00a1neas .... -label.action.take.snapshot=Tomar instant\u00c3\u00a1nea +label.action.reboot.instance.processing=Reiniciar Instancia .... +label.action.reboot.instance=Reiniciar Instancia +label.action.reboot.router.processing=Reiniciar router .... +label.action.reboot.router=Reiniciar router +label.action.reboot.systemvm.processing=reinicio del sistema VM .... +label.action.reboot.systemvm=Reiniciar sistema VM +label.action.recurring.snapshot=recurrente instant\u00c3\u00a1neas +label.action.release.ip=estreno IP +label.action.release.ip.processing=Liberar IP .... +label.action.remove.host.processing=Extracci\u00c3\u00b3n de host .... +label.action.remove.host=Quitar host +label.action.reset.password.processing=Restablecimiento de la contrase\u00c3\u00b1a .... +label.action.reset.password=Restablecer contrase\u00c3\u00b1a +label.action.resource.limits=Recursos l\u00c3\u00admites +label.action.restore.instance.processing=Restaurar Instancia .... +label.action.restore.instance=Restaurar Instancia +label.actions=Acciones +label.action.start.instance=Iniciar Instancia +label.action.start.instance.processing=A partir Instancia .... +label.action.start.router=inicio del router +label.action.start.router.processing=A partir del router .... +label.action.start.systemvm=Inicio del sistema VM +label.action.start.systemvm.processing=A partir del sistema VM .... +label.action.stop.instance=Detener Instancia +label.action.stop.instance.processing=Detener Instancia .... +label.action.stop.router=Detener router +label.action.stop.router.processing=Detener router .... +label.action.stop.systemvm=parada del sistema VM +label.action.stop.systemvm.processing=Detener sistema VM .... +label.action.take.snapshot.processing=Tomar instant\u00c3\u00a1neas .... +label.action.take.snapshot=Tomar instant\u00c3\u00a1nea label.action.unmanage.cluster.processing=Unmanaging Grupo .... label.action.unmanage.cluster=Unmanage racimo -label.action.update.OS.preference=Actualizar OS Preferencia -label.action.update.OS.preference.processing=Actualizaci\u00c3\u00b3n de sistema operativo preferencia .... +label.action.update.OS.preference=Actualizar OS Preferencia +label.action.update.OS.preference.processing=Actualizaci\u00c3\u00b3n de sistema operativo preferencia .... label.action.update.resource.count=Actualizaci\u00c3\u00b3n de recursos Conde label.action.update.resource.count.processing=Actualizaci\u00c3\u00b3n de Conde de recursos .... -label.active.sessions=Sesiones activas -label.add.account=A\u00c3\u00b1adir cuenta -label.add=Agregar -label.add.by.cidr=A\u00c3\u00b1adir Por CIDR -label.add.by.group=A\u00c3\u00b1adir Por el Grupo de -label.add.cluster=A\u00c3\u00b1adir Grupo -label.add.direct.iprange=A\u00c3\u00b1adir Direct IP Gama -label.add.disk.offering=A\u00c3\u00b1adir disco Ofrenda -label.add.domain=Agregar dominio -label.add.firewall=Agregar Servidor de seguridad -label.add.host=Agregar host -label.adding=Agregar -label.adding.cluster=Adici\u00c3\u00b3n de cl\u00c3\u00baster -label.adding.failed=No se pudo agregar -label.adding.pod=Agregar Pod -label.adding.processing=A\u00c3\u00b1adir .... -label.add.ingress.rule=A\u00c3\u00b1adir regla del ingreso -label.adding.succeeded=Agregar Sucesor -label.adding.user=Agregar usuario -label.adding.zone=Agregar la zona -label.add.ip.range=A\u00c3\u00b1adir Rango de IP -label.additional.networks=Redes adicional -label.add.load.balancer=A\u00c3\u00b1adir equilibrador de carga -label.add.more=A\u00c3\u00b1adir m\u00c3\u00a1s -label.add.network=Agregar sitios de red +label.active.sessions=Sesiones activas +label.add.account=A\u00c3\u00b1adir cuenta +label.add=Agregar +label.add.by.cidr=A\u00c3\u00b1adir Por CIDR +label.add.by.group=A\u00c3\u00b1adir Por el Grupo de +label.add.cluster=A\u00c3\u00b1adir Grupo +label.add.direct.iprange=A\u00c3\u00b1adir Direct IP Gama +label.add.disk.offering=A\u00c3\u00b1adir disco Ofrenda +label.add.domain=Agregar dominio +label.add.firewall=Agregar Servidor de seguridad +label.add.host=Agregar host +label.adding=Agregar +label.adding.cluster=Adici\u00c3\u00b3n de cl\u00c3\u00baster +label.adding.failed=No se pudo agregar +label.adding.pod=Agregar Pod +label.adding.processing=A\u00c3\u00b1adir .... +label.add.ingress.rule=A\u00c3\u00b1adir regla del ingreso +label.adding.succeeded=Agregar Sucesor +label.adding.user=Agregar usuario +label.adding.zone=Agregar la zona +label.add.ip.range=A\u00c3\u00b1adir Rango de IP +label.additional.networks=Redes adicional +label.add.load.balancer=A\u00c3\u00b1adir equilibrador de carga +label.add.more=A\u00c3\u00b1adir m\u00c3\u00a1s +label.add.network=Agregar sitios de red label.add.network.device=A\u00c3\u00b1adir dispositivo de red -label.add.pod=A\u00c3\u00b1adir Pod -label.add.primary.storage=A\u00c3\u00b1adir Almacenamiento primario -label.add.secondary.storage=A\u00c3\u00b1adir secundaria almacenamiento -label.add.security.group=Agregar grupo de seguridad -label.add.service.offering=A\u00c3\u00b1adir Servicio de Oferta -label.add.template=A\u00c3\u00b1adir plantilla +label.add.pod=A\u00c3\u00b1adir Pod +label.add.primary.storage=A\u00c3\u00b1adir Almacenamiento primario +label.add.secondary.storage=A\u00c3\u00b1adir secundaria almacenamiento +label.add.security.group=Agregar grupo de seguridad +label.add.service.offering=A\u00c3\u00b1adir Servicio de Oferta +label.add.template=A\u00c3\u00b1adir plantilla label.add.to.group=Agregar al grupo -label.add.user=Agregar usuario -label.add.vlan=A\u00c3\u00b1adir VLAN -label.add.volume=A\u00c3\u00b1adir volumen -label.add.zone=A\u00c3\u00b1adir Zona -label.admin.accounts=Administrador de Cuentas -label.admin=Admin -label.advanced=Avanzado -label.advanced.mode=Modo avanzado -label.advanced.search=B\u00c3\u00basqueda Avanzada +label.add.user=Agregar usuario +label.add.vlan=A\u00c3\u00b1adir VLAN +label.add.volume=A\u00c3\u00b1adir volumen +label.add.zone=A\u00c3\u00b1adir Zona +label.admin.accounts=Administrador de Cuentas +label.admin=Admin +label.advanced=Avanzado +label.advanced.mode=Modo avanzado +label.advanced.search=B\u00c3\u00basqueda Avanzada label.alert=Alerta -label.algorithm=Algoritmo -label.allocated=Asignados -label.api.key=clave de API -label.assign=Asignar -label.assign.to.load.balancer=instancia de Asignaci\u00c3\u00b3n de equilibrador de carga -label.associated.network.id=ID de red asociados -label.attached.iso=adjunta ISO -label.availability=Disponibilidad -label.availability.zone=Disponibilidad de la zona +label.algorithm=Algoritmo +label.allocated=Asignados +label.api.key=clave de API +label.assign=Asignar +label.assign.to.load.balancer=instancia de Asignaci\u00c3\u00b3n de equilibrador de carga +label.associated.network.id=ID de red asociados +label.attached.iso=adjunta ISO +label.availability=Disponibilidad +label.availability.zone=Disponibilidad de la zona label.available=Disponible -label.available.public.ips=Disponible direcciones IP p\u00c3\u00bablicas -label.back=Volver -label.basic.mode=Modo b\u00c3\u00a1sico -label.bootable=arranque -label.broadcast.domain.type=Tipo de dominio de difusi\u00c3\u00b3n +label.available.public.ips=Disponible direcciones IP p\u00c3\u00bablicas +label.back=Volver +label.basic.mode=Modo b\u00c3\u00a1sico +label.bootable=arranque +label.broadcast.domain.type=Tipo de dominio de difusi\u00c3\u00b3n label.by.account=Por Cuenta -label.by.availability=Por Disponibilidad +label.by.availability=Por Disponibilidad label.by.domain=Por dominio label.by.end.date=Por Fecha de finalizaci\u00c3\u00b3n -label.by.level=por Nivel +label.by.level=por Nivel label.by.pod=Por Pod -label.by.role=por funci\u00c3\u00b3n +label.by.role=por funci\u00c3\u00b3n label.by.start.date=Por Fecha de inicio -label.by.state=Por Estado -label.bytes.received=Bytes recibidos -label.bytes.sent=Bytes enviados -label.by.traffic.type=Por tipo de tr\u00c3\u00a1fico +label.by.state=Por Estado +label.bytes.received=Bytes recibidos +label.bytes.sent=Bytes enviados +label.by.traffic.type=Por tipo de tr\u00c3\u00a1fico label.by.type.id=Por tipo de identificaci\u00c3\u00b3n -label.by.type=Por tipo +label.by.type=Por tipo label.by.zone=Por Zona -label.cancel=Cancelar -label.certificate=Certificado -label.character=Personaje -label.cidr.account=CIDR o de cuenta / Grupo de Seguridad +label.cancel=Cancelar +label.certificate=Certificado +label.character=Personaje +label.cidr.account=CIDR o de cuenta / Grupo de Seguridad label.cidr=CIDR label.cidr.list=fuente CIDR -label.close=Cerrar -label.cloud.console=Cloud Management Console -label.cloud.managed=Cloud.com Gestionado -label.cluster=Grupo -label.cluster.type=Tipo de Cluster Server +label.close=Cerrar +label.cloud.console=Cloud Management Console +label.cloud.managed=Cloud.com Gestionado +label.cluster=Grupo +label.cluster.type=Tipo de Cluster Server label.clvm=CLVM -label.code=C\u00c3\u00b3digo -label.configuration=Configuraci\u00c3\u00b3n +label.code=C\u00c3\u00b3digo +label.configuration=Configuraci\u00c3\u00b3n label.confirmation=Confirmation -label.congratulations=Felicitaciones \! +label.congratulations=Felicitaciones \! label.cpu.allocated=CPU asignado label.cpu.allocated.for.VMs=CPU asignado para m\u00c3\u00a1quinas virtuales label.CPU.cap=CPU Cap -label.cpu=CPU +label.cpu=CPU label.cpu.utilized=CPU Utilizado -label.created=creaci\u00c3\u00b3n -label.cross.zones=Cruz Zonas -label.custom.disk.size=Personal Disk Size -label.daily=diario +label.created=creaci\u00c3\u00b3n +label.cross.zones=Cruz Zonas +label.custom.disk.size=Personal Disk Size +label.daily=diario label.data.disk.offering=Datos Disco Offering -label.date=Fecha -label.day.of.month=D\u00c3\u00ada del mes -label.day.of.week=d\u00c3\u00ada de la semana +label.date=Fecha +label.day.of.month=D\u00c3\u00ada del mes +label.day.of.week=d\u00c3\u00ada de la semana label.default.use=Usar por defecto -label.delete=Eliminar -label.deleting.failed=No se pudo eliminar -label.deleting.processing=Eliminar .... -label.description=Descripci\u00c3\u00b3n -label.destroy=Destroy -label.detaching.disk=Extracci\u00c3\u00b3n del disco -label.details=Detalles -label.device.id=ID de dispositivo +label.delete=Eliminar +label.deleting.failed=No se pudo eliminar +label.deleting.processing=Eliminar .... +label.description=Descripci\u00c3\u00b3n +label.destroy=Destroy +label.detaching.disk=Extracci\u00c3\u00b3n del disco +label.details=Detalles +label.device.id=ID de dispositivo label.DHCP.server.type=Tipo de servidor DHCP -label.disabled=personas de movilidad reducida -label.disabling.vpn.access=Desactivaci\u00c3\u00b3n de VPN de acceso -label.disk.allocated=disco asignado -label.disk.offering=disco Ofrenda -label.disk.size.gb=tama\u00c3\u00b1o de disco (en GB) -label.disk.size=tama\u00c3\u00b1o de disco -label.disk.total=disco Total -label.disk.volume=volumen de disco -label.display.text=visualizaci\u00c3\u00b3n de texto -label.dns.1=DNS 1 -label.dns.2=DNS 2 -label.domain.admin=Administrador de dominio -label.domain=dominio -label.domain.id=ID de dominio -label.domain.name=Nombre de dominio +label.disabled=personas de movilidad reducida +label.disabling.vpn.access=Desactivaci\u00c3\u00b3n de VPN de acceso +label.disk.allocated=disco asignado +label.disk.offering=disco Ofrenda +label.disk.size.gb=tama\u00c3\u00b1o de disco (en GB) +label.disk.size=tama\u00c3\u00b1o de disco +label.disk.total=disco Total +label.disk.volume=volumen de disco +label.display.text=visualizaci\u00c3\u00b3n de texto +label.dns.1=DNS 1 +label.dns.2=DNS 2 +label.domain.admin=Administrador de dominio +label.domain=dominio +label.domain.id=ID de dominio +label.domain.name=Nombre de dominio label.domain.suffix=DNS sufijo de dominio (es decir, xyz.com) -label.double.quotes.are.not.allowed=comillas dobles no se permite +label.double.quotes.are.not.allowed=comillas dobles no se permite label.download.progress=Progreso de la descarga -label.edit=Editar -label.email=correo electr\u00c3\u00b3nico -label.enabling.vpn.access=Habilitaci\u00c3\u00b3n de Acceso VPN -label.enabling.vpn=Habilitaci\u00c3\u00b3n VPN -label.endpoint.or.operation=punto final o de Operaci\u00c3\u00b3n -label.end.port=Puerto final -label.error.code=C\u00c3\u00b3digo de error -label.error=Error -label.esx.host=ESX / ESXi anfitri\u00c3\u00b3n -label.example=Ejemplo -label.failed=Error -label.featured=destacados -label.firewall=Servidor de seguridad -label.first.name=Nombre -label.format=Formato -label.friday=Viernes +label.edit=Editar +label.email=correo electr\u00c3\u00b3nico +label.enabling.vpn.access=Habilitaci\u00c3\u00b3n de Acceso VPN +label.enabling.vpn=Habilitaci\u00c3\u00b3n VPN +label.endpoint.or.operation=punto final o de Operaci\u00c3\u00b3n +label.end.port=Puerto final +label.error.code=C\u00c3\u00b3digo de error +label.error=Error +label.esx.host=ESX / ESXi anfitri\u00c3\u00b3n +label.example=Ejemplo +label.failed=Error +label.featured=destacados +label.firewall=Servidor de seguridad +label.first.name=Nombre +label.format=Formato +label.friday=Viernes label.full=completo -label.gateway=puerta de enlace -label.general.alerts=General de Alertas -label.generating.url=Generar URL -label.go.step.2=Ir al paso 2 -label.go.step.3=Ir al paso 3 -label.go.step.4=Ir al paso 4 -label.go.step.5=Ir al paso 5 -label.group=Grupo -label.group.optional=Grupo (Opcional) -label.guest.cidr=Habitaci\u00c3\u00b3n CIDR -label.guest.gateway=Habitaci\u00c3\u00b3n Gateway -label.guest.ip=Habitaci\u00c3\u00b3n direcci\u00c3\u00b3n IP -label.guest.ip.range=Habitaci\u00c3\u00b3n Rango de IP -label.guest.netmask=Habitaci\u00c3\u00b3n m\u00c3\u00a1scara de red -label.ha.enabled=HA Activado -label.help=Ayuda +label.gateway=puerta de enlace +label.general.alerts=General de Alertas +label.generating.url=Generar URL +label.go.step.2=Ir al paso 2 +label.go.step.3=Ir al paso 3 +label.go.step.4=Ir al paso 4 +label.go.step.5=Ir al paso 5 +label.group=Grupo +label.group.optional=Grupo (Opcional) +label.guest.cidr=Habitaci\u00c3\u00b3n CIDR +label.guest.gateway=Habitaci\u00c3\u00b3n Gateway +label.guest.ip=Habitaci\u00c3\u00b3n direcci\u00c3\u00b3n IP +label.guest.ip.range=Habitaci\u00c3\u00b3n Rango de IP +label.guest.netmask=Habitaci\u00c3\u00b3n m\u00c3\u00a1scara de red +label.ha.enabled=HA Activado +label.help=Ayuda label.hide.ingress.rule=Ocultar el art\u00c3\u00adculo ingreso -label.host.alerts=Host Alertas -label.host=Ej\u00c3\u00a9rcitos -label.host.name=nombre de host -label.hosts=Ej\u00c3\u00a9rcitos -label.hourly=por hora -label.hypervisor=Hypervisor -label.hypervisor.type=Tipo Hypervisor -label.id=ID -label.info=Informaci\u00c3\u00b3n -label.ingress.rule=ingreso Regla -label.initiated.by=Iniciado por -label.installWizard.click.launch=Click en el bot\u00f3n de lanzar. -label.instance=Instancia -label.instance.limits=Instancia L\u00c3\u00admites -label.instance.name=Nombre de instancia -label.instances=Instancias -label.internal.dns.1=DNS interno una -label.internal.dns.2=DNS interno 2 -label.interval.type=Tipo de intervalo -label.invalid.integer=entero no v\u00c3\u00a1lido -label.invalid.number=N\u00c3\u00bamero no v\u00c3\u00a1lido +label.host.alerts=Host Alertas +label.host=Ej\u00c3\u00a9rcitos +label.host.name=nombre de host +label.hosts=Ej\u00c3\u00a9rcitos +label.hourly=por hora +label.hypervisor=Hypervisor +label.hypervisor.type=Tipo Hypervisor +label.id=ID +label.info=Informaci\u00c3\u00b3n +label.ingress.rule=ingreso Regla +label.initiated.by=Iniciado por +label.installWizard.click.launch=Click en el bot\u00f3n de lanzar. +label.instance=Instancia +label.instance.limits=Instancia L\u00c3\u00admites +label.instance.name=Nombre de instancia +label.instances=Instancias +label.internal.dns.1=DNS interno una +label.internal.dns.2=DNS interno 2 +label.interval.type=Tipo de intervalo +label.invalid.integer=entero no v\u00c3\u00a1lido +label.invalid.number=N\u00c3\u00bamero no v\u00c3\u00a1lido label.invite=Invitar label.invite.to=Invitar a . -label.ip.address=Direcci\u00c3\u00b3n IP -label.ipaddress=Direcci\u00c3\u00b3n IP -label.ip.allocations=IP asignaciones -label.ip=IP -label.ip.limits=IP p\u00c3\u00bablica L\u00c3\u00admites -label.ip.or.fqdn=IP o FQDN -label.ip.range=Rango de IP -label.ips=IP -label.iscsi=iSCSI -label.is.default=Es por defecto -label.iso.boot=ISO de arranque -label.iso=ISO +label.ip.address=Direcci\u00c3\u00b3n IP +label.ipaddress=Direcci\u00c3\u00b3n IP +label.ip.allocations=IP asignaciones +label.ip=IP +label.ip.limits=IP p\u00c3\u00bablica L\u00c3\u00admites +label.ip.or.fqdn=IP o FQDN +label.ip.range=Rango de IP +label.ips=IP +label.iscsi=iSCSI +label.is.default=Es por defecto +label.iso.boot=ISO de arranque +label.iso=ISO label.isolation.mode=modo de aislamiento label.is.redundant.router=redundante -label.is.shared=es compartido -label.is.system=es el Sistema -label.keep=Mantener -label.lang.chinese=Chino (simplificado) -label.lang.english=Ingl\u00c3\u00a9s -label.lang.japanese=japon\u00c3\u00a9s -label.lang.spanish=Espa\u00c3\u00b1ol -label.last.disconnected=\u00c3\u009altima Desconectado -label.last.name=Apellido +label.is.shared=es compartido +label.is.system=es el Sistema +label.keep=Mantener +label.lang.chinese=Chino (simplificado) +label.lang.english=Ingl\u00c3\u00a9s +label.lang.japanese=japon\u00c3\u00a9s +label.lang.spanish=Espa\u00c3\u00b1ol +label.last.disconnected=\u00c3\u009altima Desconectado +label.last.name=Apellido label.launch=Lanzar label.launch.vm=Lanzar maquina virtual -label.level=Nivel -label.load.balancer=equilibrador de carga -label.loading=Carga -label.local=local -label.login=Login -label.logout=Cerrar sesi\u00c3\u00b3n -label.lun=LUN -label.manage=Administrar -label.maximum=m\u00c3\u00a1ximo +label.level=Nivel +label.load.balancer=equilibrador de carga +label.loading=Carga +label.local=local +label.login=Login +label.logout=Cerrar sesi\u00c3\u00b3n +label.lun=LUN +label.manage=Administrar +label.maximum=m\u00c3\u00a1ximo label.max.volumes=Maxima cantidad de Volumes -label.memory.allocated=memoria asignada -label.memory=memoria (en MB) -label.memory.total=Total de memoria -label.memory.used=memoria usada +label.memory.allocated=memoria asignada +label.memory=memoria (en MB) +label.memory.total=Total de memoria +label.memory.used=memoria usada label.menu.accounts=Cuentas -label.menu.alerts=Alertas -label.menu.all.accounts=Todas las cuentas -label.menu.all.instances=todas las instancias -label.menu.community.isos=Comunidad ISOs -label.menu.community.templates=plantillas de la comunidad -label.menu.configuration=Configuraci\u00c3\u00b3n -label.menu.dashboard=Interfaz -label.menu.destroyed.instances=Destruir instancias -label.menu.disk.offerings=disco ofertas -label.menu.domains=dominio -label.menu.events=Eventos -label.menu.featured.isos=destacados ISO -label.menu.featured.templates=destacados plantillas -label.menu.global.settings=Configuraci\u00c3\u00b3n global -label.menu.instances=Instancias -label.menu.ipaddresses=Direcciones IP -label.menu.isos=ISO -label.menu.my.accounts=Mis cuentas -label.menu.my.instances=Mi instancias -label.menu.my.isos=Mi ISOs -label.menu.my.templates=Mis plantillas -label.menu.network.offerings=Red de ofertas -label.menu.network=Red -label.menu.physical.resources=Recursos F\u00c3\u00adsicos -label.menu.running.instances=Ejecuci\u00c3\u00b3n de instancias -label.menu.security.groups=Grupos de seguridad -label.menu.service.offerings=Ofertas de Servicios -label.menu.snapshots=instant\u00c3\u00a1neas -label.menu.stopped.instances=Detenido instancias -label.menu.storage=Almacenamiento -label.menu.system=Sistema -label.menu.system.vms=Sistema de m\u00c3\u00a1quinas virtuales -label.menu.templates=plantillas -label.menu.virtual.appliances=Virtual Appliances -label.menu.virtual.resources=Virtual de Recursos -label.menu.volumes=Vol\u00c3\u00bamenes +label.menu.alerts=Alertas +label.menu.all.accounts=Todas las cuentas +label.menu.all.instances=todas las instancias +label.menu.community.isos=Comunidad ISOs +label.menu.community.templates=plantillas de la comunidad +label.menu.configuration=Configuraci\u00c3\u00b3n +label.menu.dashboard=Interfaz +label.menu.destroyed.instances=Destruir instancias +label.menu.disk.offerings=disco ofertas +label.menu.domains=dominio +label.menu.events=Eventos +label.menu.featured.isos=destacados ISO +label.menu.featured.templates=destacados plantillas +label.menu.global.settings=Configuraci\u00c3\u00b3n global +label.menu.instances=Instancias +label.menu.ipaddresses=Direcciones IP +label.menu.isos=ISO +label.menu.my.accounts=Mis cuentas +label.menu.my.instances=Mi instancias +label.menu.my.isos=Mi ISOs +label.menu.my.templates=Mis plantillas +label.menu.network.offerings=Red de ofertas +label.menu.network=Red +label.menu.physical.resources=Recursos F\u00c3\u00adsicos +label.menu.running.instances=Ejecuci\u00c3\u00b3n de instancias +label.menu.security.groups=Grupos de seguridad +label.menu.service.offerings=Ofertas de Servicios +label.menu.snapshots=instant\u00c3\u00a1neas +label.menu.stopped.instances=Detenido instancias +label.menu.storage=Almacenamiento +label.menu.system=Sistema +label.menu.system.vms=Sistema de m\u00c3\u00a1quinas virtuales +label.menu.templates=plantillas +label.menu.virtual.appliances=Virtual Appliances +label.menu.virtual.resources=Virtual de Recursos +label.menu.volumes=Vol\u00c3\u00bamenes label.migrate.instance.to.host=Migrar instancia a otro host. label.migrate.instance.to=Migraci\u00c3\u00b3n de ejemplo para label.migrate.instance.to.ps=Migrar instancia a otro primary storage. label.migrate.router.to=Router para migrar label.migrate.systemvm.to=Migrar m\u00c3\u00a1quina virtual del sistema para -label.minimum=M\u00c3\u00adnimo -label.minute.past.hour=Minuto (s) despu\u00c3\u00a9s de la hora -label.monday=lunes -label.monthly=mensual -label.more.templates=plantillas \= M\u00c3\u00a1s -label.my.account=Mi Cuenta +label.minimum=M\u00c3\u00adnimo +label.minute.past.hour=Minuto (s) despu\u00c3\u00a9s de la hora +label.monday=lunes +label.monthly=mensual +label.more.templates=plantillas \= M\u00c3\u00a1s +label.my.account=Mi Cuenta label.my.templates=Mis plantillas -label.name=Nombre -label.name.optional=Nombre (Opcional) -label.netmask=m\u00c3\u00a1scara de red -label.network.desc=Red de Desc +label.name=Nombre +label.name.optional=Nombre (Opcional) +label.netmask=m\u00c3\u00a1scara de red +label.network.desc=Red de Desc label.network.device=De dispositivos de red label.network.device.type=Tipo de red de dispositivos label.network.domain=red de dominio -label.network.id=ID de red -label.network.name=Nombre de red -label.network.offering.display.text=Red ofrece visualizaci\u00c3\u00b3n de texto -label.network.offering.id=Red ofrece ID -label.network.offering.name=Red ofrece Nombre -label.network.offering=Red ofrece -label.network.rate=Tasa de Red -label.network.read=Leer de la red -label.network=Red +label.network.id=ID de red +label.network.name=Nombre de red +label.network.offering.display.text=Red ofrece visualizaci\u00c3\u00b3n de texto +label.network.offering.id=Red ofrece ID +label.network.offering.name=Red ofrece Nombre +label.network.offering=Red ofrece +label.network.rate=Tasa de Red +label.network.read=Leer de la red +label.network=Red label.networks=Redes -label.network.type=Tipo de red -label.network.write=Escribir en la red +label.network.type=Tipo de red +label.network.write=Escribir en la red label.new=Nuevo -label.new.password=Nueva contrase\u00c3\u00b1a +label.new.password=Nueva contrase\u00c3\u00b1a label.new.vm=Nueva maquina virtual -label.next=Siguiente -label.nfs=NFS -label.nfs.server=servidor NFS -label.nfs.storage=NFS Almacenamiento -label.nics=NIC -label.no.actions=No Acciones disponibles -label.no.alerts=No alertas recientes -label.no.errors=No recientes errores -label.no.isos=No ISOs disponibles -label.no.items=No art\u00c3\u00adculos disponibles +label.next=Siguiente +label.nfs=NFS +label.nfs.server=servidor NFS +label.nfs.storage=NFS Almacenamiento +label.nics=NIC +label.no.actions=No Acciones disponibles +label.no.alerts=No alertas recientes +label.no.errors=No recientes errores +label.no.isos=No ISOs disponibles +label.no.items=No art\u00c3\u00adculos disponibles label.none=Ninguno -label.no=No -label.no.security.groups=No hay grupos disponibles de Seguridad +label.no=No +label.no.security.groups=No hay grupos disponibles de Seguridad label.not.found=No se ha encontrado -label.no.thanks=No, gracias -label.num.cpu.cores=n\u00c3\u00bamero de n\u00c3\u00bacleos de CPU +label.no.thanks=No, gracias +label.num.cpu.cores=n\u00c3\u00bamero de n\u00c3\u00bacleos de CPU label.numretries=N\u00c3\u00bamero de reintentos label.ocfs2=OCFS2 -label.offer.ha=Oferta HA -label.optional=Opcional -label.os.preference=OS Preferencia -label.os.type=tipo de Sistema Operativo -label.owned.public.ips=propiedad p\u00c3\u00bablica Direcciones IP -label.owner.account=titular de la cuenta -label.parent.domain=Padres de dominio -label.password=Contrase\u00c3\u00b1a -label.password.enabled=Contrase\u00c3\u00b1a Activado -label.path=Ruta +label.offer.ha=Oferta HA +label.optional=Opcional +label.os.preference=OS Preferencia +label.os.type=tipo de Sistema Operativo +label.owned.public.ips=propiedad p\u00c3\u00bablica Direcciones IP +label.owner.account=titular de la cuenta +label.parent.domain=Padres de dominio +label.password=Contrase\u00c3\u00b1a +label.password.enabled=Contrase\u00c3\u00b1a Activado +label.path=Ruta label.PING.CIFS.password=PING CIFS contrase\u00c3\u00b1a label.PING.CIFS.username=PING CIFS nombre de usuario label.PING.dir=PING Directorio label.PING.storage.IP=PING almacenamiento IP -label.please.wait=Por favor espere -label.pod=Pod -label.port.forwarding=Port Forwarding -label.port.range=rango de puertos +label.please.wait=Por favor espere +label.pod=Pod +label.port.forwarding=Port Forwarding +label.port.range=rango de puertos label.PreSetup=PreSetup -label.prev=Anterior +label.prev=Anterior label.previous=Previo -label.primary.allocated=primaria asignado de almacenamiento -label.primary.network=Red Primaria -label.primary.storage=Almacenamiento Primario -label.primary.used=Primaria Almacenado -label.private.interface=Interfaz privada -label.private.ip=direcci\u00c3\u00b3n IP privada -label.private.ip.range=IP privada Gama -label.private.ips=direcciones IP privadas +label.primary.allocated=primaria asignado de almacenamiento +label.primary.network=Red Primaria +label.primary.storage=Almacenamiento Primario +label.primary.used=Primaria Almacenado +label.private.interface=Interfaz privada +label.private.ip=direcci\u00c3\u00b3n IP privada +label.private.ip.range=IP privada Gama +label.private.ips=direcciones IP privadas label.privatekey=PKCS\#8 la clave privada -label.private.port=Puerto privado -label.private.zone=Zona Privada +label.private.port=Puerto privado +label.private.zone=Zona Privada label.project.name=Nombre del Proyecto -label.protocol=Protocolo -label.public.interface=interfaz p\u00c3\u00bablica -label.public.ip=direcci\u00c3\u00b3n IP p\u00c3\u00bablica -label.public.ips=direcciones IP p\u00c3\u00bablicas -label.public.port=Puerto P\u00c3\u00bablico -label.public=P\u00c3\u00bablica -label.public.zone=Zona P\u00c3\u00bablica +label.protocol=Protocolo +label.public.interface=interfaz p\u00c3\u00bablica +label.public.ip=direcci\u00c3\u00b3n IP p\u00c3\u00bablica +label.public.ips=direcciones IP p\u00c3\u00bablicas +label.public.port=Puerto P\u00c3\u00bablico +label.public=P\u00c3\u00bablica +label.public.zone=Zona P\u00c3\u00bablica label.Pxe.server.type=Tipo de servidor Pxe -label.reboot=Reiniciar -label.recent.errors=recientes errores +label.reboot=Reiniciar +label.recent.errors=recientes errores label.redundant.router=enrutador redundante -label.refresh=Actualizar -label.related=relacionados -label.remind.later=Recordar mas tarde -label.remove.from.load.balancer=ejemplo Eliminaci\u00c3\u00b3n de equilibrador de carga +label.refresh=Actualizar +label.related=relacionados +label.remind.later=Recordar mas tarde +label.remove.from.load.balancer=ejemplo Eliminaci\u00c3\u00b3n de equilibrador de carga label.removing=Borrando. -label.removing.user=Eliminar usuario -label.required=Requerido -label.reserved.system.ip=Reservados sistema de PI -label.resource.limits=L\u00c3\u00admites de Recursos -label.resource=Recursos -label.resources=Recursos -label.role=Papel +label.removing.user=Eliminar usuario +label.required=Requerido +label.reserved.system.ip=Reservados sistema de PI +label.resource.limits=L\u00c3\u00admites de Recursos +label.resource=Recursos +label.resources=Recursos +label.role=Papel label.root.disk.offering=Root Disco Offering -label.running.vms=Ejecuci\u00c3\u00b3n de m\u00c3\u00a1quinas virtuales -label.s3.secret_key=clave secreta -label.saturday=s\u00c3\u00a1bado -label.save=Guardar -label.saving.processing=ahorro .... -label.scope=Alcance -label.search=Buscar -label.secondary.storage=Almacenamiento secundario -label.secondary.used=Secundaria Almacenado -label.secret.key=clave secreta -label.security.group=Grupo de Seguridad -label.security.group.name=Nombre de grupo de seguridad +label.running.vms=Ejecuci\u00c3\u00b3n de m\u00c3\u00a1quinas virtuales +label.s3.secret_key=clave secreta +label.saturday=s\u00c3\u00a1bado +label.save=Guardar +label.saving.processing=ahorro .... +label.scope=Alcance +label.search=Buscar +label.secondary.storage=Almacenamiento secundario +label.secondary.used=Secundaria Almacenado +label.secret.key=clave secreta +label.security.group=Grupo de Seguridad +label.security.group.name=Nombre de grupo de seguridad label.security.groups.enabled=Los grupos de seguridad habilitado -label.security.groups=Grupos de seguridad +label.security.groups=Grupos de seguridad label.select.a.zone=Seleccione una zona. -label.sent=Enviados -label.server=Servidor -label.service.offering=Oferta de Servicio +label.sent=Enviados +label.server=Servidor +label.service.offering=Oferta de Servicio label.session.expired=Session Caducado -label.shared=compartidas -label.SharedMountPoint=SharedMountPoint +label.shared=compartidas +label.SharedMountPoint=SharedMountPoint label.show.ingress.rule=Mostrar la regla del ingreso -label.size=Tama\u00c3\u00b1o -label.snapshot=Instant\u00c3\u00a1nea -label.snapshot.limits=instant\u00c3\u00a1neas L\u00c3\u00admites -label.snapshot.name=Nombre de instant\u00c3\u00a1neas -label.snapshot.schedule=Lista de instant\u00c3\u00a1neas -label.snapshot.s=Instant\u00c3\u00a1nea (s) -label.snapshots=instant\u00c3\u00a1neas -label.source.nat=NAT Fuente -label.specify.vlan=Especifique VLAN +label.size=Tama\u00c3\u00b1o +label.snapshot=Instant\u00c3\u00a1nea +label.snapshot.limits=instant\u00c3\u00a1neas L\u00c3\u00admites +label.snapshot.name=Nombre de instant\u00c3\u00a1neas +label.snapshot.schedule=Lista de instant\u00c3\u00a1neas +label.snapshot.s=Instant\u00c3\u00a1nea (s) +label.snapshots=instant\u00c3\u00a1neas +label.source.nat=NAT Fuente +label.specify.vlan=Especifique VLAN label.SR.name = SR Nombre de etiqueta -label.start.port=Iniciar Puerto -label.state=Estado -label.static.nat=NAT est\u00c3\u00a1tica -label.static.nat.to=est\u00c3\u00a1tico NAT para -label.statistics=Estad\u00c3\u00adsticas -label.status=Estado -label.step.1=Paso 1 -label.step.1.title=Paso 1\: Seleccione una plantilla -label.step.2=Paso 2 -label.step.2.title=Paso 2\: Oferta de Servicio -label.step.3=Paso 3 -label.step.3.title=Paso 3\: Seleccione un disco Ofrenda -label.step.4=Paso 4 -label.step.4.title=Paso 4\: Red -label.step.5=Paso 5 -label.step.5.title=Paso 5\: Revisi\u00c3\u00b3n -label.sticky.domain=dominio +label.start.port=Iniciar Puerto +label.state=Estado +label.static.nat=NAT est\u00c3\u00a1tica +label.static.nat.to=est\u00c3\u00a1tico NAT para +label.statistics=Estad\u00c3\u00adsticas +label.status=Estado +label.step.1=Paso 1 +label.step.1.title=Paso 1\: Seleccione una plantilla +label.step.2=Paso 2 +label.step.2.title=Paso 2\: Oferta de Servicio +label.step.3=Paso 3 +label.step.3.title=Paso 3\: Seleccione un disco Ofrenda +label.step.4=Paso 4 +label.step.4.title=Paso 4\: Red +label.step.5=Paso 5 +label.step.5.title=Paso 5\: Revisi\u00c3\u00b3n +label.sticky.domain=dominio label.sticky.mode=modo -label.stop=Detener -label.stopped.vms=Detenido m\u00c3\u00a1quinas virtuales -label.storage=Almacenamiento +label.stop=Detener +label.stopped.vms=Detenido m\u00c3\u00a1quinas virtuales +label.storage=Almacenamiento label.storage.tags=Etiquetas de almacenamiento -label.storage.type=Tipo de almacenamiento -label.submit=Enviar -label.submitted.by=[Enviado por\: ] -label.succeeded=Sucesor -label.sunday=domingo -label.system.capacity=Capacidad de todo el sistema -label.system.vm=Sistema de VM -label.system.vms=Sistema de m\u00c3\u00a1quinas virtuales -label.system.vm.type=Tipo de sistema VM -label.tagged=etiqueta -label.tags=Etiquetas -label.target.iqn=Objetivo IQN -label.task.completed=Tarea finalizada. -label.template.limits=Plantilla L\u00c3\u00admites -label.template=plantilla +label.storage.type=Tipo de almacenamiento +label.submit=Enviar +label.submitted.by=[Enviado por\: ] +label.succeeded=Sucesor +label.sunday=domingo +label.system.capacity=Capacidad de todo el sistema +label.system.vm=Sistema de VM +label.system.vms=Sistema de m\u00c3\u00a1quinas virtuales +label.system.vm.type=Tipo de sistema VM +label.tagged=etiqueta +label.tags=Etiquetas +label.target.iqn=Objetivo IQN +label.task.completed=Tarea finalizada. +label.template.limits=Plantilla L\u00c3\u00admites +label.template=plantilla label.TFTP.dir=Directorio de TFTP -label.theme.default=Tema Por Defecto +label.theme.default=Tema Por Defecto label.theme.grey=Personal - Gris label.theme.lightblue=Personal - Azul -label.thursday=Jueves +label.thursday=Jueves label.timeout.in.second = Tiempo de espera (segundos) -label.time=Tiempo -label.time.zone=Zona horaria -label.timezone=Zona horaria +label.time=Tiempo +label.time.zone=Zona horaria +label.timezone=Zona horaria label.total.cpu=Total CPU label.total.CPU=Total CPU -label.total.vms=Total de m\u00c3\u00a1quinas virtuales -label.traffic.type=Tipo de Tr\u00c3\u00a1fico -label.tuesday=martes -label.type.id=Tipo de identificaci\u00c3\u00b3n -label.type=Tipo -label.unavailable=no disponible +label.total.vms=Total de m\u00c3\u00a1quinas virtuales +label.traffic.type=Tipo de Tr\u00c3\u00a1fico +label.tuesday=martes +label.type.id=Tipo de identificaci\u00c3\u00b3n +label.type=Tipo +label.unavailable=no disponible label.unlimited=Unlimited -label.untagged=sin etiquetar -label.updating=Actualizar +label.untagged=sin etiquetar +label.updating=Actualizar label.url=URL -label.usage.interface=Interfaz de uso -label.used=Usado -label.username=Nombre de usuario -label.users=usuario -label.user=Usuario -label.value=Valor -label.vcenter.cluster=vCenter cl\u00c3\u00baster -label.vcenter.datacenter=vCenter de centros de datos -label.vcenter.datastore=vCenter almac\u00c3\u00a9n de datos -label.vcenter.host=vCenter anfitri\u00c3\u00b3n -label.vcenter.password=vCenter Contrase\u00c3\u00b1a -label.vcenter.username=vCenter Nombre de usuario -label.version=Versi\u00c3\u00b3n -label.virtual.appliances=Virtual Appliances -label.virtual.appliance=Virtual Appliance +label.usage.interface=Interfaz de uso +label.used=Usado +label.username=Nombre de usuario +label.users=usuario +label.user=Usuario +label.value=Valor +label.vcenter.cluster=vCenter cl\u00c3\u00baster +label.vcenter.datacenter=vCenter de centros de datos +label.vcenter.datastore=vCenter almac\u00c3\u00a9n de datos +label.vcenter.host=vCenter anfitri\u00c3\u00b3n +label.vcenter.password=vCenter Contrase\u00c3\u00b1a +label.vcenter.username=vCenter Nombre de usuario +label.version=Versi\u00c3\u00b3n +label.virtual.appliances=Virtual Appliances +label.virtual.appliance=Virtual Appliance label.virtual.machines=Maquinas virtuales -label.virtual.network=Red Virtual -label.vlan.id=ID de VLAN -label.vlan.range=VLAN Gama -label.vlan=VLAN -label.vm.add=A\u00c3\u00b1adir Instancia -label.vm.destroy=Destroy +label.virtual.network=Red Virtual +label.vlan.id=ID de VLAN +label.vlan.range=VLAN Gama +label.vlan=VLAN +label.vm.add=A\u00c3\u00b1adir Instancia +label.vm.destroy=Destroy label.VMFS.datastore=VMFS de datos tienda -label.vmfs=VMFS -label.vm.reboot=Reiniciar -label.vmsnapshot.type=Tipo -label.vm.start=Inicio -label.vm.stop=Detener -label.vms=VM +label.vmfs=VMFS +label.vm.reboot=Reiniciar +label.vmsnapshot.type=Tipo +label.vm.start=Inicio +label.vm.stop=Detener +label.vms=VM label.volgroup=Volume Group -label.volume.limits=l\u00c3\u00admites de volumen -label.volume.name=Nombre de Volumen -label.volumes=Vol\u00c3\u00bamenes -label.volume=Volumen -label.vpn=VPN -label.vsphere.managed=Gestionado \= vSphere -label.waiting=Esperando -label.warn=Advertir -label.wednesday=mi\u00c3\u00a9rcoles -label.weekly=Semanal -label.welcome=Bienvenido -label.welcome.cloud.console=Bienvenido a la consola de administraci\u00c3\u00b3n -label.yes=S\u00c3\u00ad -label.zone.id=Zona de identificaci\u00c3\u00b3n -label.zone.step.1.title=Paso 1\: Seleccione una red -label.zone.step.2.title=Paso 2\: A\u00c3\u00b1adir una zona -label.zone.step.3.title=Paso 3\: A\u00c3\u00b1adir una vaina -label.zone.step.4.title=Paso 4\: A\u00c3\u00b1adir un rango de IP -label.zone.wide=Zona para todo el +label.volume.limits=l\u00c3\u00admites de volumen +label.volume.name=Nombre de Volumen +label.volumes=Vol\u00c3\u00bamenes +label.volume=Volumen +label.vpn=VPN +label.vsphere.managed=Gestionado \= vSphere +label.waiting=Esperando +label.warn=Advertir +label.wednesday=mi\u00c3\u00a9rcoles +label.weekly=Semanal +label.welcome=Bienvenido +label.welcome.cloud.console=Bienvenido a la consola de administraci\u00c3\u00b3n +label.yes=S\u00c3\u00ad +label.zone.id=Zona de identificaci\u00c3\u00b3n +label.zone.step.1.title=Paso 1\: Seleccione una red +label.zone.step.2.title=Paso 2\: A\u00c3\u00b1adir una zona +label.zone.step.3.title=Paso 3\: A\u00c3\u00b1adir una vaina +label.zone.step.4.title=Paso 4\: A\u00c3\u00b1adir un rango de IP +label.zone.wide=Zona para todo el label.zone=Zona managed.state=Estado logr\u00c3\u00b3 -message.acquire.public.ip=Por favor seleccione una zona de la que desea adquirir su nueva IP. -message.action.cancel.maintenance.mode=Por favor, confirme que desea cancelar el mantenimiento +message.acquire.public.ip=Por favor seleccione una zona de la que desea adquirir su nueva IP. +message.action.cancel.maintenance.mode=Por favor, confirme que desea cancelar el mantenimiento message.action.cancel.maintenance=Su acogida ha sido cancelado con \u00c3\u00a9xito para el mantenimiento. Este proceso puede tardar hasta varios minutos. -message.action.delete.cluster=Por favor, confirme que desea eliminar del cl\u00c3\u00baster -message.action.delete.disk.offering=Por favor, confirme que desea eliminar ofreciendo disco -message.action.delete.domain=Por favor, confirme que desea eliminar de dominio +message.action.delete.cluster=Por favor, confirme que desea eliminar del cl\u00c3\u00baster +message.action.delete.disk.offering=Por favor, confirme que desea eliminar ofreciendo disco +message.action.delete.domain=Por favor, confirme que desea eliminar de dominio message.action.delete.external.firewall=Por favor, confirme que desea quitar este servidor de seguridad externo. Advertencia\: Si usted est\u00c3\u00a1 planeando volver a agregar el servidor de seguridad externo mismo, debe restablecer los datos de uso en el dispositivo. message.action.delete.external.load.balancer=Por favor, confirme que desea eliminar este equilibrador de carga externa. Advertencia\: Si usted est\u00c3\u00a1 planeando volver a agregar la misma equilibrador de carga externo, debe restablecer los datos de uso en el dispositivo. -message.action.delete.ingress.rule=Por favor, confirme que desea eliminar la regla de ingreso -message.action.delete.ISO.for.all.zones=La ISO es utilizado por todas las zonas. Por favor, confirme que desea eliminar de todas las zonas. -message.action.delete.ISO=Por favor, confirme que desea eliminar la norma ISO -message.action.delete.network=Por favor, confirme que desea eliminar de la red -message.action.delete.pod=Por favor, confirme que desea eliminar de la vaina -message.action.delete.primary.storage=Por favor, confirme que desea eliminar el almacenamiento primario -message.action.delete.secondary.storage=Por favor, confirme que desea eliminar de almacenamiento secundario -message.action.delete.security.group=Por favor, confirme que desea eliminar el grupo de seguridad -message.action.delete.service.offering=Por favor, confirme que desea eliminar oferta de servicios +message.action.delete.ingress.rule=Por favor, confirme que desea eliminar la regla de ingreso +message.action.delete.ISO.for.all.zones=La ISO es utilizado por todas las zonas. Por favor, confirme que desea eliminar de todas las zonas. +message.action.delete.ISO=Por favor, confirme que desea eliminar la norma ISO +message.action.delete.network=Por favor, confirme que desea eliminar de la red +message.action.delete.pod=Por favor, confirme que desea eliminar de la vaina +message.action.delete.primary.storage=Por favor, confirme que desea eliminar el almacenamiento primario +message.action.delete.secondary.storage=Por favor, confirme que desea eliminar de almacenamiento secundario +message.action.delete.security.group=Por favor, confirme que desea eliminar el grupo de seguridad +message.action.delete.service.offering=Por favor, confirme que desea eliminar oferta de servicios message.action.delete.snapshot=Por favor, confirme que desea eliminar instant\u00c3\u00a1neas -message.action.delete.template.for.all.zones=La plantilla es utilizada por todas las zonas. Por favor, confirme que desea eliminar de todas las zonas. -message.action.delete.template=Por favor, confirme que desea eliminar la plantilla -message.action.delete.volume=Por favor, confirme que desea eliminar el volumen -message.action.delete.zone=Por favor, confirme que desea eliminar la zona -message.action.destroy.instance=Por favor, confirme que desea destruir ejemplo +message.action.delete.template.for.all.zones=La plantilla es utilizada por todas las zonas. Por favor, confirme que desea eliminar de todas las zonas. +message.action.delete.template=Por favor, confirme que desea eliminar la plantilla +message.action.delete.volume=Por favor, confirme que desea eliminar el volumen +message.action.delete.zone=Por favor, confirme que desea eliminar la zona +message.action.destroy.instance=Por favor, confirme que desea destruir ejemplo message.action.destroy.systemvm=Por favor, confirme que desea destruir la m\u00c3\u00a1quina virtual del sistema. message.action.disable.cluster=Por favor, confirme que desea desactivar este grupo. message.action.disable.pod=Por favor, confirme que desea desactivar esta vaina. -message.action.disable.static.NAT=Por favor, confirme que desea desactivar NAT est\u00c3\u00a1tica +message.action.disable.static.NAT=Por favor, confirme que desea desactivar NAT est\u00c3\u00a1tica message.action.disable.zone=Por favor, confirme que desea desactivar esta zona. message.action.enable.cluster=Por favor, confirme que desea habilitar este grupo. message.action.enable.maintenance=Su acogida ha sido preparado con \u00c3\u00a9xito para el mantenimiento. Este proceso puede tardar hasta varios minutos o m\u00c3\u00a1s dependiendo de c\u00c3\u00b3mo las m\u00c3\u00a1quinas virtuales se encuentran actualmente en este servidor. -message.action.enable.pod=Por favor, confirme que desea habilitar esta vaina. -message.action.enable.zone=Por favor, confirme que desea habilitar esta zona. -message.action.force.reconnect=Por favor, confirme que desea forzar una reconexi\u00c3\u00b3n para el anfitri\u00c3\u00b3n -message.action.host.enable.maintenance.mode=mode \= mantenimiento de Habilitaci\u00c3\u00b3n provocar\u00c3\u00a1 una migraci\u00c3\u00b3n en vivo de todas las instancias que se ejecutan en el sistema para cualquier m\u00c3\u00a1quina disponible. +message.action.enable.pod=Por favor, confirme que desea habilitar esta vaina. +message.action.enable.zone=Por favor, confirme que desea habilitar esta zona. +message.action.force.reconnect=Por favor, confirme que desea forzar una reconexi\u00c3\u00b3n para el anfitri\u00c3\u00b3n +message.action.host.enable.maintenance.mode=mode \= mantenimiento de Habilitaci\u00c3\u00b3n provocar\u00c3\u00a1 una migraci\u00c3\u00b3n en vivo de todas las instancias que se ejecutan en el sistema para cualquier m\u00c3\u00a1quina disponible. message.action.manage.cluster=Por favor, confirme que desea para administrar el cl\u00c3\u00baster. -message.action.primarystorage.enable.maintenance.mode=Advertencia\: colocar el almacenamiento principal en modo de mantenimiento har\u00c3\u00a1 que todas las m\u00c3\u00a1quinas virtuales utilizando vol\u00c3\u00bamenes de que sea detenido. \u00c2\u00bfDesea continuar? -message.action.reboot.instance=Por favor, confirme que desea reiniciar el ejemplo -message.action.reboot.systemvm=Por favor, confirme que desea reiniciar el sistema VM -message.action.release.ip=Por favor, confirme que desea liberar IP +message.action.primarystorage.enable.maintenance.mode=Advertencia\: colocar el almacenamiento principal en modo de mantenimiento har\u00c3\u00a1 que todas las m\u00c3\u00a1quinas virtuales utilizando vol\u00c3\u00bamenes de que sea detenido. \u00c2\u00bfDesea continuar? +message.action.reboot.instance=Por favor, confirme que desea reiniciar el ejemplo +message.action.reboot.systemvm=Por favor, confirme que desea reiniciar el sistema VM +message.action.release.ip=Por favor, confirme que desea liberar IP message.action.reset.password.off=Su ejemplo en la actualidad no es compatible con esta funci\u00c3\u00b3n. message.action.reset.password.warning=Su ejemplo debe ser detenido antes de intentar cambiar su contrase\u00c3\u00b1a actual. -message.action.restore.instance=Por favor, confirme que desea restaurar ejemplo -message.action.start.instance=Por favor, confirme que desea iniciar la instancia -message.action.start.router=Por favor, confirme que desea iniciar router -message.action.start.systemvm=Por favor, confirme que desea iniciar el sistema VM -message.action.stop.instance=Por favor, confirme que desea detener la instancia -message.action.stop.systemvm=Por favor, confirme que desea detener sistema VM -message.action.take.snapshot=Por favor, confirme que desea tomar instant\u00c3\u00a1neas +message.action.restore.instance=Por favor, confirme que desea restaurar ejemplo +message.action.start.instance=Por favor, confirme que desea iniciar la instancia +message.action.start.router=Por favor, confirme que desea iniciar router +message.action.start.systemvm=Por favor, confirme que desea iniciar el sistema VM +message.action.stop.instance=Por favor, confirme que desea detener la instancia +message.action.stop.systemvm=Por favor, confirme que desea detener sistema VM +message.action.take.snapshot=Por favor, confirme que desea tomar instant\u00c3\u00a1neas message.action.unmanage.cluster=Por favor, confirme que desea unmanage del cl\u00c3\u00baster. -message.add.cluster=A\u00c3\u00b1adir un hipervisor administradas por cl\u00c3\u00baster de zona , la consola de -message.add.cluster.zone=A\u00c3\u00b1adir un hipervisor administradas por cl\u00c3\u00baster de zona -message.add.disk.offering=Por favor, especifique los par\u00c3\u00a1metros siguientes para agregar un nuevo disco que ofrece -message.add.firewall=A\u00c3\u00b1adir un servidor de seguridad a la zona -message.add.host=Por favor, especifique los par\u00c3\u00a1metros siguientes para agregar un nuevo host -message.add.ip.range=A\u00c3\u00b1adir un rango de IP a la red p\u00c3\u00bablica en la zona -message.add.ip.range.direct.network=A\u00c3\u00b1adir un rango de IP para dirigir red en la zona -message.add.ip.range.to.pod=

A\u00c3\u00b1adir un rango de IP de la vaina\:

-message.additional.networks.desc=Por favor seleccione de red adicionales (s) que la instancia virtual estar\u00c3\u00a1 conectado. -message.add.load.balancer=A\u00c3\u00b1adir un equilibrador de carga a la zona -message.add.network=Agregar una nueva red para la zona\: -message.add.pod=Agregar una vaina nueva zona -message.add.primary=Por favor, especifique los par\u00c3\u00a1metros siguientes para agregar un nuevo almacenamiento primario -message.add.primary.storage=Agregar una nueva almacenamiento primario para zona , la consola de -message.add.secondary.storage=A\u00c3\u00b1adir un nuevo almacenamiento de zona -message.add.service.offering=Por favor, rellene los siguientes datos para agregar una nueva oferta de servicio. -message.add.template=Por favor ingrese los siguientes datos para crear la nueva plantilla -message.add.volume=Por favor, rellene los siguientes datos para agregar un nuevo volumen. -message.advanced.mode.desc=Seleccione este modelo de red si desea habilitar soporte VLAN. Este modelo de red proporciona la m\u00c3\u00a1xima flexibilidad al permitir a los administradores proporcionar ofertas personalizadas de la red como el suministro de firewall, VPN, o el apoyo equilibrador de carga, as\u00c3\u00ad como permitir vs directa de redes virtuales. +message.add.cluster=A\u00c3\u00b1adir un hipervisor administradas por cl\u00c3\u00baster de zona , la consola de +message.add.cluster.zone=A\u00c3\u00b1adir un hipervisor administradas por cl\u00c3\u00baster de zona +message.add.disk.offering=Por favor, especifique los par\u00c3\u00a1metros siguientes para agregar un nuevo disco que ofrece +message.add.firewall=A\u00c3\u00b1adir un servidor de seguridad a la zona +message.add.host=Por favor, especifique los par\u00c3\u00a1metros siguientes para agregar un nuevo host +message.add.ip.range=A\u00c3\u00b1adir un rango de IP a la red p\u00c3\u00bablica en la zona +message.add.ip.range.direct.network=A\u00c3\u00b1adir un rango de IP para dirigir red en la zona +message.add.ip.range.to.pod=

A\u00c3\u00b1adir un rango de IP de la vaina\:

+message.additional.networks.desc=Por favor seleccione de red adicionales (s) que la instancia virtual estar\u00c3\u00a1 conectado. +message.add.load.balancer=A\u00c3\u00b1adir un equilibrador de carga a la zona +message.add.network=Agregar una nueva red para la zona\: +message.add.pod=Agregar una vaina nueva zona +message.add.primary=Por favor, especifique los par\u00c3\u00a1metros siguientes para agregar un nuevo almacenamiento primario +message.add.primary.storage=Agregar una nueva almacenamiento primario para zona , la consola de +message.add.secondary.storage=A\u00c3\u00b1adir un nuevo almacenamiento de zona +message.add.service.offering=Por favor, rellene los siguientes datos para agregar una nueva oferta de servicio. +message.add.template=Por favor ingrese los siguientes datos para crear la nueva plantilla +message.add.volume=Por favor, rellene los siguientes datos para agregar un nuevo volumen. +message.advanced.mode.desc=Seleccione este modelo de red si desea habilitar soporte VLAN. Este modelo de red proporciona la m\u00c3\u00a1xima flexibilidad al permitir a los administradores proporcionar ofertas personalizadas de la red como el suministro de firewall, VPN, o el apoyo equilibrador de carga, as\u00c3\u00ad como permitir vs directa de redes virtuales. message.advanced.security.group=Elija esta opci\u00c3\u00b3n si desea utilizar grupos de seguridad para proporcionar resultados de aislamiento VM. message.advanced.virtual=Elija esta opci\u00c3\u00b3n si desea utilizar VLAN toda la zona para proporcionar el aislamiento VM invitado. -message.allow.vpn.access=Por favor, introduzca un nombre de usuario y la contrase\u00c3\u00b1a del usuario que desea permitir el acceso de VPN. +message.allow.vpn.access=Por favor, introduzca un nombre de usuario y la contrase\u00c3\u00b1a del usuario que desea permitir el acceso de VPN. message.apply.snapshot.policy=Ha actualizado su pol\u00c3\u00adtica instant\u00c3\u00a1nea actual. -message.attach.iso.confirm=Por favor, confirme que desea conectar el ISO a la instancia virtual -message.attach.volume=Por favor, rellene los siguientes datos para fijar un nuevo volumen. Si est\u00c3\u00a1 colocando un volumen de disco a una m\u00c3\u00a1quina virtual de Windows basado, usted tendr\u00c3\u00a1 que reiniciar la instancia para ver el disco adjunto. -message.basic.mode.desc=Seleccione este modelo de red si lo haces * no * desea habilitar cualquier soporte VLAN. Todas las instancias virtuales creados en virtud de este modelo de red se le asignar\u00c3\u00a1 una direcci\u00c3\u00b3n IP directamente desde la red y grupos de seguridad se utilizan para proporcionar la seguridad y la segregaci\u00c3\u00b3n. -message.change.offering.confirm=Por favor, confirme que desea cambiar la oferta de servicio de la instancia virtual. -message.copy.iso.confirm=Por favor, confirme que desea copiar el ISO a -message.copy.template=Copia plantilla XXX de la zona -message.create.template.vm=Crear VM de la plantilla -message.create.template.volume=Por favor, especifique la siguiente informaci\u00c3\u00b3n antes de crear una plantilla de su volumen de disco\: . Creaci\u00c3\u00b3n de la plantilla puede oscilar entre varios minutos m\u00c3\u00a1s, dependiendo del tama\u00c3\u00b1o del volumen. -message.delete.account=Por favor, confirme que desea eliminar esta cuenta. -message.detach.iso.confirm=Por favor, confirme que desea quitar el ISO de la instancia virtual +message.attach.iso.confirm=Por favor, confirme que desea conectar el ISO a la instancia virtual +message.attach.volume=Por favor, rellene los siguientes datos para fijar un nuevo volumen. Si est\u00c3\u00a1 colocando un volumen de disco a una m\u00c3\u00a1quina virtual de Windows basado, usted tendr\u00c3\u00a1 que reiniciar la instancia para ver el disco adjunto. +message.basic.mode.desc=Seleccione este modelo de red si lo haces * no * desea habilitar cualquier soporte VLAN. Todas las instancias virtuales creados en virtud de este modelo de red se le asignar\u00c3\u00a1 una direcci\u00c3\u00b3n IP directamente desde la red y grupos de seguridad se utilizan para proporcionar la seguridad y la segregaci\u00c3\u00b3n. +message.change.offering.confirm=Por favor, confirme que desea cambiar la oferta de servicio de la instancia virtual. +message.copy.iso.confirm=Por favor, confirme que desea copiar el ISO a +message.copy.template=Copia plantilla XXX de la zona +message.create.template.vm=Crear VM de la plantilla +message.create.template.volume=Por favor, especifique la siguiente informaci\u00c3\u00b3n antes de crear una plantilla de su volumen de disco\: . Creaci\u00c3\u00b3n de la plantilla puede oscilar entre varios minutos m\u00c3\u00a1s, dependiendo del tama\u00c3\u00b1o del volumen. +message.delete.account=Por favor, confirme que desea eliminar esta cuenta. +message.detach.iso.confirm=Por favor, confirme que desea quitar el ISO de la instancia virtual message.disable.snapshot.policy=Ha desactivado su pol\u00c3\u00adtica instant\u00c3\u00a1nea actual. message.disable.vpn.access=Por favor, confirme que desea desactivar VPN de acceso. message.download.volume=Por favor, haga clic 00000 para bajar el volumen -message.edit.confirm=Por favor confirmar los cambios antes de hacer clic en "Guardar" -message.edit.limits=Por favor, especifique los l\u00c3\u00admites de los recursos siguientes. A "-1" indica que no hay l\u00c3\u00admite a la cantidad de los recursos de crear. -message.enable.account=Por favor, confirme que desea habilitar esta cuenta. -message.enabled.vpn.ip.sec=La clave pre-compartida IPSec es -message.enabled.vpn=Su acceso a la VPN est\u00c3\u00a1 habilitado y se puede acceder a trav\u00c3\u00a9s de la IP -message.enable.vpn.access=VPN \= est\u00c3\u00a1 desactivado para esta direcci\u00c3\u00b3n IP. \u00c2\u00bfTe gustar\u00c3\u00ada que permitan el acceso VPN? -message.enable.vpn=VPN de acceso actualmente no est\u00c3\u00a1 habilitado. Por favor, haga clic aqu\u00c3\u00ad para habilitar VPN. +message.edit.confirm=Por favor confirmar los cambios antes de hacer clic en "Guardar" +message.edit.limits=Por favor, especifique los l\u00c3\u00admites de los recursos siguientes. A "-1" indica que no hay l\u00c3\u00admite a la cantidad de los recursos de crear. +message.enable.account=Por favor, confirme que desea habilitar esta cuenta. +message.enabled.vpn.ip.sec=La clave pre-compartida IPSec es +message.enabled.vpn=Su acceso a la VPN est\u00c3\u00a1 habilitado y se puede acceder a trav\u00c3\u00a9s de la IP +message.enable.vpn.access=VPN \= est\u00c3\u00a1 desactivado para esta direcci\u00c3\u00b3n IP. \u00c2\u00bfTe gustar\u00c3\u00ada que permitan el acceso VPN? +message.enable.vpn=VPN de acceso actualmente no est\u00c3\u00a1 habilitado. Por favor, haga clic aqu\u00c3\u00ad para habilitar VPN. message.installWizard.click.retry=Haz click en el bot\u00f3n para re-intentar el lanzamiento de la instancia. -message.installWizard.tooltip.addCluster.name=Nombre del Cluster. Puede ser alfanum\u00e9rico .Este no es usado por CloudStack +message.installWizard.tooltip.addCluster.name=Nombre del Cluster. Puede ser alfanum\u00e9rico .Este no es usado por CloudStack message.installWizard.tooltip.addHost.hostname=El nombre DNS o direcci\u00f3n IP del host message.installWizard.tooltip.addHost.username=Generalmente root message.installWizard.tooltip.addPod.name=Nombre del POD @@ -818,44 +819,44 @@ message.installWizard.tooltip.addPrimaryStorage.name=\ Nombre para el storage message.installWizard.tooltip.addSecondaryStorage.nfsServer=Direcci\u00f3n IP del servidor NFS que contiene el secondary storage message.installWizard.tooltip.addZone.name=Nombre de la zona. message.installWizard.tooltip.configureGuestTraffic.description=Una breve descripci\u00f3n para su red. -message.installWizard.tooltip.configureGuestTraffic.guestGateway=El gatway, puerta de enlace, que las maquinas guest deben usar. -message.installWizard.tooltip.configureGuestTraffic.name=Nombre de su RED -message.lock.account=Por favor, confirme que desea bloquear esta cuenta. Al bloquear la cuenta, todos los usuarios de esta cuenta ya no ser\u00c3\u00a1 capaz de gestionar sus recursos de la nube. Los recursos existentes todav\u00c3\u00ada se puede acceder. +message.installWizard.tooltip.configureGuestTraffic.guestGateway=El gatway, puerta de enlace, que las maquinas guest deben usar. +message.installWizard.tooltip.configureGuestTraffic.name=Nombre de su RED +message.lock.account=Por favor, confirme que desea bloquear esta cuenta. Al bloquear la cuenta, todos los usuarios de esta cuenta ya no ser\u00c3\u00a1 capaz de gestionar sus recursos de la nube. Los recursos existentes todav\u00c3\u00ada se puede acceder. message.migrate.instance.confirm=Por favor, confirme el anfitri\u00c3\u00b3n desea migrar la instancia virtual. message.migrate.instance.to.host=Por favor, confirmar que desea mover la instancia a otro host. message.migrate.instance.to.ps=Por favor, confirmar que desea mover la instancia a otro primary storage. message.migrate.router.confirm=Por favor, confirme el hu\u00c3\u00a9sped que desea migrar el router\: message.migrate.systemvm.confirm=Por favor, confirme el hu\u00c3\u00a9sped que desea migrar la m\u00c3\u00a1quina virtual de sistema\: message.no.network.support.configuration.not.true=Usted no tiene ninguna zona que ha permitido a grupo de seguridad. Por lo tanto, no hay funciones de red adicionales. Por favor, contin\u00c3\u00bae con el paso 5. -message.no.network.support=El hipervisor seleccionado, vSphere, no tiene funciones de red adicionales. Por favor, contin\u00c3\u00bae con el paso 5. -message.number.clusters=

\# de Grupos

-message.number.hosts=

\# de Anfitri\u00c3\u00b3n

-message.number.pods=

\# de Las vainas

-message.number.storage=

\# de Almacenamiento primario

-message.number.zones=

\# de Zonas

-message.remove.vpn.access=Por favor, confirme que desea eliminar el acceso VPN desde el siguiente usuario -message.restart.mgmt.server=Por favor, reinicie el servidor de administraci\u00c3\u00b3n (s) para la nueva configuraci\u00c3\u00b3n surta efecto. -message.security.group.usage=(Uso pulse Ctrl para seleccionar todos los grupos de seguridad se aplica) -message.select.item=Por favor, seleccionar un item . +message.no.network.support=El hipervisor seleccionado, vSphere, no tiene funciones de red adicionales. Por favor, contin\u00c3\u00bae con el paso 5. +message.number.clusters=

\# de Grupos

+message.number.hosts=

\# de Anfitri\u00c3\u00b3n

+message.number.pods=

\# de Las vainas

+message.number.storage=

\# de Almacenamiento primario

+message.number.zones=

\# de Zonas

+message.remove.vpn.access=Por favor, confirme que desea eliminar el acceso VPN desde el siguiente usuario +message.restart.mgmt.server=Por favor, reinicie el servidor de administraci\u00c3\u00b3n (s) para la nueva configuraci\u00c3\u00b3n surta efecto. +message.security.group.usage=(Uso pulse Ctrl para seleccionar todos los grupos de seguridad se aplica) +message.select.item=Por favor, seleccionar un item . message.setup.successful=La configuraci\u00f3n de la cloud finalizo satisfactoriamente. -message.snapshot.schedule=Puede horarios de configuraci\u00c3\u00b3n recurrente instant\u00c3\u00a1neas mediante la selecci\u00c3\u00b3n de las opciones disponibles a continuaci\u00c3\u00b3n y la aplicaci\u00c3\u00b3n de su preferencia pol\u00c3\u00adtica -message.step.1.continue=Por favor seleccione una plantilla o ISO para continuar -message.step.1.desc=Por favor seleccione una plantilla para la instancia virtual. Tambi\u00c3\u00a9n puede optar por seleccionar una plantilla en blanco desde el que puede ser una imagen ISO instalado en. -message.step.2.continue=Por favor seleccione una oferta de servicio para continuar +message.snapshot.schedule=Puede horarios de configuraci\u00c3\u00b3n recurrente instant\u00c3\u00a1neas mediante la selecci\u00c3\u00b3n de las opciones disponibles a continuaci\u00c3\u00b3n y la aplicaci\u00c3\u00b3n de su preferencia pol\u00c3\u00adtica +message.step.1.continue=Por favor seleccione una plantilla o ISO para continuar +message.step.1.desc=Por favor seleccione una plantilla para la instancia virtual. Tambi\u00c3\u00a9n puede optar por seleccionar una plantilla en blanco desde el que puede ser una imagen ISO instalado en. +message.step.2.continue=Por favor seleccione una oferta de servicio para continuar message.step.2.desc= -message.step.3.continue=Por favor seleccione una oferta en disco para continuar +message.step.3.continue=Por favor seleccione una oferta en disco para continuar message.step.3.desc= message.step.4.continue=Por favor seleccione al menos una red social para continuar -message.step.4.desc=Por favor, seleccione la red primaria que la instancia virtual estar\u00c3\u00a1 conectado. -message.update.os.preference=Por favor seleccione un sistema operativo de preferencia para este equipo. Todas las instancias virtuales con preferencias similares ser\u00c3\u00a1n los primeros asignados a este equipo antes de elegir otro. -message.update.ssl=Por favor, env\u00c3\u00ade una nueva X.509 compatible con certificado SSL que se actualizar\u00c3\u00a1 a cada instancia virtual de la consola del servidor proxy\: -message.virtual.network.desc=Una red dedicada virtualizados para su cuenta. El dominio de difusi\u00c3\u00b3n est\u00c3\u00a1 contenida dentro de una VLAN y todos los acceso a la red p\u00c3\u00bablica se encamina a cabo por un router virtual. +message.step.4.desc=Por favor, seleccione la red primaria que la instancia virtual estar\u00c3\u00a1 conectado. +message.update.os.preference=Por favor seleccione un sistema operativo de preferencia para este equipo. Todas las instancias virtuales con preferencias similares ser\u00c3\u00a1n los primeros asignados a este equipo antes de elegir otro. +message.update.ssl=Por favor, env\u00c3\u00ade una nueva X.509 compatible con certificado SSL que se actualizar\u00c3\u00a1 a cada instancia virtual de la consola del servidor proxy\: +message.virtual.network.desc=Una red dedicada virtualizados para su cuenta. El dominio de difusi\u00c3\u00b3n est\u00c3\u00a1 contenida dentro de una VLAN y todos los acceso a la red p\u00c3\u00bablica se encamina a cabo por un router virtual. message.vm.create.template.confirm=Crear plantilla de la m\u00c3\u00a1quina virtual se reiniciar\u00c3\u00a1 autom\u00c3\u00a1ticamente. -message.volume.create.template.confirm=Por favor, confirme que desea crear una plantilla para este volumen de disco. Creaci\u00c3\u00b3n de la plantilla puede oscilar entre varios minutos m\u00c3\u00a1s, dependiendo del tama\u00c3\u00b1o del volumen. -message.zone.step.1.desc=Por favor seleccione un modelo de red para su zona. +message.volume.create.template.confirm=Por favor, confirme que desea crear una plantilla para este volumen de disco. Creaci\u00c3\u00b3n de la plantilla puede oscilar entre varios minutos m\u00c3\u00a1s, dependiendo del tama\u00c3\u00b1o del volumen. +message.zone.step.1.desc=Por favor seleccione un modelo de red para su zona. mode=modo -network.rate=Tasa de Red +network.rate=Tasa de Red side.by.side=Juntos -state.Allocated=Asignados -state.Disabled=personas de movilidad reducida -state.Error=Error +state.Allocated=Asignados +state.Disabled=personas de movilidad reducida +state.Error=Error diff --git a/client/WEB-INF/classes/resources/messages_fr_FR.properties b/client/WEB-INF/classes/resources/messages_fr_FR.properties index 6a7cc9a9d55..8be438a11c1 100644 --- a/client/WEB-INF/classes/resources/messages_fr_FR.properties +++ b/client/WEB-INF/classes/resources/messages_fr_FR.properties @@ -15,78 +15,46 @@ # specific language governing permissions and limitations # under the License. -#Stored by I18NEdit, may be edited! -ICMP.code=Code ICMP -ICMP.type=Type ICMP -changed.item.properties=Propri\u00E9t\u00E9s de l\\'\u00E9l\u00E9ment modifi\u00E9es + +changed.item.properties=Propri\u00e9t\u00e9s de l\\'\u00e9l\u00e9ment modifi\u00e9es confirm.enable.s3=Remplir les informations suivantes pour activer le support de stockage secondaire S3 confirm.enable.swift=Remplir les informations suivantes pour activer Swift error.could.not.enable.zone=Impossible d\\'activer la zone -error.installWizard.message=Une erreur s\\'est produite ; vous pouvez retourner en arri\u00E8re et corriger les erreurs +error.installWizard.message=Une erreur s\\'est produite ; vous pouvez retourner en arri\u00e8re et corriger les erreurs error.invalid.username.password=Utilisateur ou mot de passe invalide -error.login=Votre nom d\\'utilisateur / mot de passe ne correspond pas \u00E0 nos donn\u00E9es. -error.menu.select=\u00C9chec de l\\'action car il n\\'y a aucun \u00E9l\u00E9ment s\u00E9lectionn\u00E9. +error.login=Votre nom d\\'utilisateur / mot de passe ne correspond pas \u00e0 nos donn\u00e9es. +error.menu.select=\u00c9chec de l\\'action car il n\\'y a aucun \u00e9l\u00e9ment s\u00e9lectionn\u00e9. error.mgmt.server.inaccessible=Le serveur de gestion est indisponible. Essayez plus tard. error.password.not.match=Les mots de passe ne correspondent pas -error.please.specify.physical.network.tags=L\\'offre r\u00E9seau ne sera pas disponible tant que des libell\u00E9s n\\'auront pas \u00E9t\u00E9 renseign\u00E9s pour ce r\u00E9seau physique. -error.session.expired=Votre session a expir\u00E9e. +error.please.specify.physical.network.tags=L\\'offre r\u00e9seau ne sera pas disponible tant que des libell\u00e9s n\\'auront pas \u00e9t\u00e9 renseign\u00e9s pour ce r\u00e9seau physique. +error.session.expired=Votre session a expir\u00e9e. error.something.went.wrong.please.correct.the.following=Erreur; corriger le point suivant error.unable.to.reach.management.server=Impossible de joindre le serveur d\\'administration -error.unresolved.internet.name=Votre nom Internet ne peut pas \u00EAtre r\u00E9solu. -extractable=D\u00E9compressable +error.unresolved.internet.name=Votre nom Internet ne peut pas \u00eatre r\u00e9solu. +extractable=D\u00e9compressable +force.delete.domain.warning=Attention \: Choisir cette option entra\u00eenera la suppression de tous les domaines issus et l\\'ensemble des comptes associ\u00e9s, ainsi que de leur ressources force.delete=Forcer la suppression -force.delete.domain.warning=Attention \: Choisir cette option entra\u00EEnera la suppression de tous les domaines issus et l\\'ensemble des comptes associ\u00E9s, ainsi que de leur ressources force.remove=Forcer la suppression -force.remove.host.warning=Attention \: Choisir cette option entra\u00EEnera CloudStack \u00E0\u00A0arr\u00EAter l\\'ensemble des machines virtuelles avant d\\'enlever l\\'h\u00F4te du cluster -force.stop=Forcer l\\'arr\u00EAt -force.stop.instance.warning=Attention \: un arr\u00EAt forc\u00E9 sur cette instance est la dernier option. Cela peut engendrer des pertes de donn\u00E9es et/ou un comportement inconsistant de votre instance. -image.directory=R\u00E9pertoire d\\'images -inline=Align\u00E9 -instances.actions.reboot.label=Red\u00E9marrer l\\'instance -label.CIDR.list=Liste CIDR -label.CIDR.of.destination.network=CIDR du r\u00E9seau de destination -label.CPU.cap=Limitation CPU -label.DHCP.server.type=Serveur DHCP -label.DNS.domain.for.guest.networks=Domaine DNS pour les r\u00E9seaux invit\u00E9s -label.ESP.encryption=Chiffrement ESP -label.ESP.hash=Empreinte ESP -label.ESP.lifetime=Dur\u00E9e de vie ESP (secondes) -label.ESP.policy=Mode ESP -label.IKE.DH=DH IKE -label.IKE.encryption=Chiffrement IKE -label.IKE.hash=Empreinte IKE -label.IKE.lifetime=Dur\u00E9e de vie IKE (secondes) -label.IKE.policy=Mode IKE -label.IPsec.preshared.key=Cl\u00E9 partag\u00E9e IPsec -label.LB.isolation=R\u00E9partition de charge isol\u00E9e -label.LUN.number=N\u00B0 LUN -label.PING.CIFS.password=Mot de passe CIFS PING -label.PING.CIFS.username=Identifiant CIFS PING -label.PING.dir=R\u00E9pertoire PING -label.PING.storage.IP=IP stockage PING -label.PreSetup=PreSetup -label.Pxe.server.type=Serveur PXE -label.SR.name=Nom du point de montage -label.SharedMountPoint=Point de montage partag\u00E9 -label.TFTP.dir=R\u00E9pertoire TFTP -label.VMFS.datastore=Magasin de donn\u00E9es VMFS -label.VMs.in.tier=Machines virtuelles dans le tiers -label.VPC.router.details=D\u00E9tails routeur VPC -label.VPN.connection=Connexion VPN -label.VPN.customer.gateway=Passerelle VPN client -label.VPN.gateway=Passerelle VPN +force.remove.host.warning=Attention \: Choisir cette option entra\u00eenera CloudStack \u00e0\u00a0arr\u00eater l\\'ensemble des machines virtuelles avant d\\'enlever l\\'h\u00f4te du cluster +force.stop=Forcer l\\'arr\u00eat +force.stop.instance.warning=Attention \: un arr\u00eat forc\u00e9 sur cette instance est la dernier option. Cela peut engendrer des pertes de donn\u00e9es et/ou un comportement inconsistant de votre instance. +ICMP.code=Code ICMP +ICMP.type=Type ICMP +image.directory=R\u00e9pertoire d\\'images +inline=Align\u00e9 +instances.actions.reboot.label=Red\u00e9marrer l\\'instance label.accept.project.invitation=Accepter l\\'invitation au projet +label.account.and.security.group=Compte, groupe de s\u00e9curit\u00e9 label.account=Compte -label.account.and.security.group=Compte, groupe de s\u00E9curit\u00E9 label.account.id=ID du Compte label.account.name=Nom du compte -label.account.specific=Sp\u00E9cifique au compte label.accounts=Comptes -label.acquire.new.ip=Acqu\u00E9rir une nouvelle adresse IP -label.action.attach.disk=Rattacher un disque +label.account.specific=Sp\u00e9cifique au compte +label.acquire.new.ip=Acqu\u00e9rir une nouvelle adresse IP label.action.attach.disk.processing=Rattachement du Disque... -label.action.attach.iso=Rattacher une image ISO +label.action.attach.disk=Rattacher un disque label.action.attach.iso.processing=Rattachement de l\\'image ISO +label.action.attach.iso=Rattacher une image ISO label.action.cancel.maintenance.mode=Annuler le mode maintenance label.action.cancel.maintenance.mode.processing=Annulation du mode maintenance... label.action.change.password=Changer le mot de passe @@ -94,100 +62,100 @@ label.action.change.service=Changer d\\'offre de service label.action.change.service.processing=Changement de d\\'offre de service... label.action.copy.ISO=Copier une image ISO label.action.copy.ISO.processing=Copie de l\\'image ISO... -label.action.copy.template=Copier un mod\u00E8le -label.action.copy.template.processing=Copie du Mod\u00E8le... -label.action.create.template=Cr\u00E9er un mod\u00E8le -label.action.create.template.from.vm=Cr\u00E9er un mod\u00E8le depuis la VM -label.action.create.template.from.volume=Cr\u00E9er un mod\u00E8le depuis le volume -label.action.create.template.processing=Cr\u00E9ation du Mod\u00E8le... -label.action.create.vm=Cr\u00E9er une VM -label.action.create.vm.processing=Cr\u00E9ation de la VM... -label.action.create.volume=Cr\u00E9er un Volume -label.action.create.volume.processing=Cr\u00E9ation du Volume... -label.action.delete.IP.range=Supprimer la plage IP -label.action.delete.IP.range.processing=Suppression de la plage IP... -label.action.delete.ISO=Supprimer l\\'image ISO -label.action.delete.ISO.processing=Suppression de l\\'image ISO... -label.action.delete.account=Supprimer un compte +label.action.copy.template=Copier un mod\u00e8le +label.action.copy.template.processing=Copie du Mod\u00e8le... +label.action.create.template=Cr\u00e9er un mod\u00e8le +label.action.create.template.from.vm=Cr\u00e9er un mod\u00e8le depuis la VM +label.action.create.template.from.volume=Cr\u00e9er un mod\u00e8le depuis le volume +label.action.create.template.processing=Cr\u00e9ation du Mod\u00e8le... +label.action.create.vm=Cr\u00e9er une VM +label.action.create.vm.processing=Cr\u00e9ation de la VM... +label.action.create.volume=Cr\u00e9er un Volume +label.action.create.volume.processing=Cr\u00e9ation du Volume... label.action.delete.account.processing=Suppression du compte... -label.action.delete.cluster=Supprimer le Cluster +label.action.delete.account=Supprimer un compte label.action.delete.cluster.processing=Suppression du Cluster... -label.action.delete.disk.offering=Supprimer l\\'offre Disque +label.action.delete.cluster=Supprimer le Cluster label.action.delete.disk.offering.processing=Suppression de l\\'offre Disque... -label.action.delete.domain=Supprimer le domaine +label.action.delete.disk.offering=Supprimer l\\'offre Disque label.action.delete.domain.processing=Suppression du domaine... -label.action.delete.firewall=Supprimer la r\u00E8gle de pare-feu +label.action.delete.domain=Supprimer le domaine label.action.delete.firewall.processing=Suppression du Pare-feu... -label.action.delete.ingress.rule=Supprimer la r\u00E8gle d\\'entr\u00E9e -label.action.delete.ingress.rule.processing=Suppression de la r\u00E8gle d\\'entr\u00E9e.. -label.action.delete.load.balancer=Supprimer la r\u00E8gle de r\u00E9partition de charge -label.action.delete.load.balancer.processing=Suppression du r\u00E9partiteur de charge... -label.action.delete.network=Supprimer le r\u00E9seau -label.action.delete.network.processing=Suppression du r\u00E9seau... +label.action.delete.firewall=Supprimer la r\u00e8gle de pare-feu +label.action.delete.ingress.rule.processing=Suppression de la r\u00e8gle d\\'entr\u00e9e.. +label.action.delete.ingress.rule=Supprimer la r\u00e8gle d\\'entr\u00e9e +label.action.delete.IP.range.processing=Suppression de la plage IP... +label.action.delete.IP.range=Supprimer la plage IP +label.action.delete.ISO.processing=Suppression de l\\'image ISO... +label.action.delete.ISO=Supprimer l\\'image ISO +label.action.delete.load.balancer.processing=Suppression du r\u00e9partiteur de charge... +label.action.delete.load.balancer=Supprimer la r\u00e8gle de r\u00e9partition de charge +label.action.delete.network.processing=Suppression du r\u00e9seau... +label.action.delete.network=Supprimer le r\u00e9seau label.action.delete.nexusVswitch=Supprimer le Nexus 1000v -label.action.delete.physical.network=Supprimer le r\u00E9seau physique -label.action.delete.pod=Supprimer le Pod +label.action.delete.physical.network=Supprimer le r\u00e9seau physique label.action.delete.pod.processing=Suppression du pod... -label.action.delete.primary.storage=Supprimer le stockage principal +label.action.delete.pod=Supprimer le Pod label.action.delete.primary.storage.processing=Suppression du stockage principal... -label.action.delete.secondary.storage=Supprimer le stockage secondaire +label.action.delete.primary.storage=Supprimer le stockage principal label.action.delete.secondary.storage.processing=Suppression du stockage secondaire... -label.action.delete.security.group=Supprimer le groupe de s\u00E9curit\u00E9 -label.action.delete.security.group.processing=Suppression du groupe de s\u00E9curit\u00E9 -label.action.delete.service.offering=Supprimer l\\'offre de service +label.action.delete.secondary.storage=Supprimer le stockage secondaire +label.action.delete.security.group.processing=Suppression du groupe de s\u00e9curit\u00e9 +label.action.delete.security.group=Supprimer le groupe de s\u00e9curit\u00e9 label.action.delete.service.offering.processing=Suppression de l\\'offre de service... -label.action.delete.snapshot=Supprimer l\\'instantan\u00E9 -label.action.delete.snapshot.processing=Suppression de l\\'instantan\u00E9... -label.action.delete.system.service.offering=Supprimer l\\'offre syst\u00E8me -label.action.delete.template=Supprimer le mod\u00E8le -label.action.delete.template.processing=Suppression du mod\u00E8le... -label.action.delete.user=Supprimer l\\'utilisateur +label.action.delete.service.offering=Supprimer l\\'offre de service +label.action.delete.snapshot.processing=Suppression de l\\'instantan\u00e9... +label.action.delete.snapshot=Supprimer l\\'instantan\u00e9 +label.action.delete.system.service.offering=Supprimer l\\'offre syst\u00e8me +label.action.delete.template.processing=Suppression du mod\u00e8le... +label.action.delete.template=Supprimer le mod\u00e8le label.action.delete.user.processing=Suppression de l\\'utilisateur... -label.action.delete.volume=Supprimer le volume +label.action.delete.user=Supprimer l\\'utilisateur label.action.delete.volume.processing=Suppression du volume... -label.action.delete.zone=Supprimer la zone +label.action.delete.volume=Supprimer le volume label.action.delete.zone.processing=Suppression de la zone... -label.action.destroy.instance=Supprimer l\\'instance +label.action.delete.zone=Supprimer la zone label.action.destroy.instance.processing=Suppression de l\\'instance... -label.action.destroy.systemvm=Supprimer la VM Syst\u00E8me -label.action.destroy.systemvm.processing=Suppression de la VM Syst\u00E8me... -label.action.detach.disk=D\u00E9tacher le disque -label.action.detach.disk.processing=D\u00E9tachement du disque... -label.action.detach.iso=D\u00E9tacher l\\'image ISO -label.action.detach.iso.processing=D\u00E9tachement de l\\'image ISO... -label.action.disable.account=D\u00E9sactiver le compte -label.action.disable.account.processing=D\u00E9sactivation du compte... -label.action.disable.cluster=D\u00E9sactiver le cluster -label.action.disable.cluster.processing=D\u00E9sactivation du cluster... -label.action.disable.nexusVswitch=D\u00E9sactiver le Nexus 1000v -label.action.disable.physical.network=D\u00E9sactiver le r\u00E9seau physique -label.action.disable.pod=D\u00E9sactiver le Pod -label.action.disable.pod.processing=D\u00E9sactivation du Pod... -label.action.disable.static.NAT=D\u00E9sactiver le NAT Statique -label.action.disable.static.NAT.processing=D\u00E9sactivation du NAT Statique... -label.action.disable.user=D\u00E9sactiver l\\'utilisateur -label.action.disable.user.processing=D\u00E9sactivation de l\\'utilisateur... -label.action.disable.zone=D\u00E9sactivation de la zone -label.action.disable.zone.processing=D\u00E9sactivation de la zone... -label.action.download.ISO=T\u00E9l\u00E9charger une image ISO -label.action.download.template=T\u00E9l\u00E9charger un mod\u00E8le -label.action.download.volume=T\u00E9l\u00E9charger un volume -label.action.download.volume.processing=T\u00E9l\u00E9chargement du volume... -label.action.edit.ISO=Modifier l\\'image ISO +label.action.destroy.instance=Supprimer l\\'instance +label.action.destroy.systemvm.processing=Suppression de la VM Syst\u00e8me... +label.action.destroy.systemvm=Supprimer la VM Syst\u00e8me +label.action.detach.disk=D\u00e9tacher le disque +label.action.detach.disk.processing=D\u00e9tachement du disque... +label.action.detach.iso=D\u00e9tacher l\\'image ISO +label.action.detach.iso.processing=D\u00e9tachement de l\\'image ISO... +label.action.disable.account=D\u00e9sactiver le compte +label.action.disable.account.processing=D\u00e9sactivation du compte... +label.action.disable.cluster=D\u00e9sactiver le cluster +label.action.disable.cluster.processing=D\u00e9sactivation du cluster... +label.action.disable.nexusVswitch=D\u00e9sactiver le Nexus 1000v +label.action.disable.physical.network=D\u00e9sactiver le r\u00e9seau physique +label.action.disable.pod=D\u00e9sactiver le Pod +label.action.disable.pod.processing=D\u00e9sactivation du Pod... +label.action.disable.static.NAT=D\u00e9sactiver le NAT Statique +label.action.disable.static.NAT.processing=D\u00e9sactivation du NAT Statique... +label.action.disable.user=D\u00e9sactiver l\\'utilisateur +label.action.disable.user.processing=D\u00e9sactivation de l\\'utilisateur... +label.action.disable.zone=D\u00e9sactivation de la zone +label.action.disable.zone.processing=D\u00e9sactivation de la zone... +label.action.download.ISO=T\u00e9l\u00e9charger une image ISO +label.action.download.template=T\u00e9l\u00e9charger un mod\u00e8le +label.action.download.volume.processing=T\u00e9l\u00e9chargement du volume... +label.action.download.volume=T\u00e9l\u00e9charger un volume label.action.edit.account=Modifier le Compte label.action.edit.disk.offering=Modifier l\\'offre de disque label.action.edit.domain=Modifier le domaine label.action.edit.global.setting=Modifier la configuration globale -label.action.edit.host=Modifier l\\'h\u00F4te +label.action.edit.host=Modifier l\\'h\u00f4te label.action.edit.instance=Modifier l\\'instance -label.action.edit.network=Modifier le r\u00E9seau -label.action.edit.network.offering=Modifier l\\'offre de service r\u00E9seau -label.action.edit.network.processing=Modification du R\u00E9seau... +label.action.edit.ISO=Modifier l\\'image ISO +label.action.edit.network=Modifier le r\u00e9seau +label.action.edit.network.offering=Modifier l\\'offre de service r\u00e9seau +label.action.edit.network.processing=Modification du R\u00e9seau... label.action.edit.pod=Modifier le pod label.action.edit.primary.storage=Modifier le stockage principal label.action.edit.resource.limits=Modifier les limites de ressources label.action.edit.service.offering=Modifier l\\'offre de service -label.action.edit.template=Modifier le mod\u00E8le +label.action.edit.template=Modifier le mod\u00e8le label.action.edit.user=Modifier l\\'utilisateur label.action.edit.zone=Modifier la zone label.action.enable.account=Activer le compte @@ -197,7 +165,7 @@ label.action.enable.cluster.processing=Activation du cluster... label.action.enable.maintenance.mode=Activer le mode maintenance label.action.enable.maintenance.mode.processing=Activation du mode maintenance... label.action.enable.nexusVswitch=Activer le Nexus 1000v -label.action.enable.physical.network=Activer le r\u00E9seau physique +label.action.enable.physical.network=Activer le r\u00e9seau physique label.action.enable.pod=Activer le Pod label.action.enable.pod.processing=Activation du Pod... label.action.enable.static.NAT=Activer le NAT Statique @@ -208,74 +176,74 @@ label.action.enable.zone=Activer la zone label.action.enable.zone.processing=Activation de la zone... label.action.force.reconnect=Forcer la reconnexion label.action.force.reconnect.processing=Reconnexion en cours... -label.action.generate.keys=G\u00E9n\u00E9rer les cl\u00E9s -label.action.generate.keys.processing=G\u00E9n\u00E9ration des cl\u00E9s... +label.action.generate.keys=G\u00e9n\u00e9rer les cl\u00e9s +label.action.generate.keys.processing=G\u00e9n\u00e9ration des cl\u00e9s... label.action.list.nexusVswitch=Liste des Nexus 1000v -label.action.lock.account=Verrouiller le compte label.action.lock.account.processing=Verrouillage du compte... -label.action.manage.cluster=G\u00E9rer le Cluster +label.action.lock.account=Verrouiller le compte +label.action.manage.cluster=G\u00e9rer le Cluster label.action.manage.cluster.processing=Gestion du cluster... label.action.migrate.instance=Migrer l\\'instance label.action.migrate.instance.processing=Migration de l\\'instance... label.action.migrate.router=Migration routeur label.action.migrate.router.processing=Migration routeur en cours... -label.action.migrate.systemvm=Migration VM syst\u00E8me -label.action.migrate.systemvm.processing=Migration VM syst\u00E8me en cours ... -label.action.reboot.instance=Red\u00E9marrer l\\'instance -label.action.reboot.instance.processing=Red\u00E9marrage de l\\'instance... -label.action.reboot.router=Red\u00E9marrer le routeur -label.action.reboot.router.processing=Red\u00E9marrage du routeur... -label.action.reboot.systemvm=Red\u00E9marrer la VM Syst\u00E8me -label.action.reboot.systemvm.processing=Red\u00E9marrage de la VM Syst\u00E8me... -label.action.recurring.snapshot=Instantan\u00E9s r\u00E9currents +label.action.migrate.systemvm=Migration VM syst\u00e8me +label.action.migrate.systemvm.processing=Migration VM syst\u00e8me en cours ... +label.action.reboot.instance.processing=Red\u00e9marrage de l\\'instance... +label.action.reboot.instance=Red\u00e9marrer l\\'instance +label.action.reboot.router.processing=Red\u00e9marrage du routeur... +label.action.reboot.router=Red\u00e9marrer le routeur +label.action.reboot.systemvm.processing=Red\u00e9marrage de la VM Syst\u00e8me... +label.action.reboot.systemvm=Red\u00e9marrer la VM Syst\u00e8me +label.action.recurring.snapshot=Instantan\u00e9s r\u00e9currents label.action.register.iso=Enregistrer ISO -label.action.register.template=Enregistrer mod\u00E8le -label.action.release.ip=Lib\u00E9rer l\\'adresse IP -label.action.release.ip.processing=Lib\u00E9ration de l\\'adresse IP... -label.action.remove.host=Supprimer l\\'h\u00F4te -label.action.remove.host.processing=Suppression de l\\'h\u00F4te... -label.action.reset.password=R\u00E9-initialiser le mot de passe -label.action.reset.password.processing=R\u00E9-initialisation du mot de passe... -label.action.resize.volume=Redimensionner Volume +label.action.register.template=Enregistrer mod\u00e8le +label.action.release.ip=Lib\u00e9rer l\\'adresse IP +label.action.release.ip.processing=Lib\u00e9ration de l\\'adresse IP... +label.action.remove.host.processing=Suppression de l\\'h\u00f4te... +label.action.remove.host=Supprimer l\\'h\u00f4te +label.action.reset.password.processing=R\u00e9-initialisation du mot de passe... +label.action.reset.password=R\u00e9-initialiser le mot de passe label.action.resize.volume.processing=Redimensionnement en cours... +label.action.resize.volume=Redimensionner Volume label.action.resource.limits=Limites de ressources -label.action.restore.instance=Restaurer l\\'instance label.action.restore.instance.processing=Restauration de l\\'instance... -label.action.start.instance=D\u00E9marrer l\\'instance -label.action.start.instance.processing=D\u00E9marrage de l\\'instance... -label.action.start.router=D\u00E9marrer le routeur -label.action.start.router.processing=D\u00E9marrage du routeur... -label.action.start.systemvm=D\u00E9marrer la VM syst\u00E8me -label.action.start.systemvm.processing=D\u00E9marrage de la VM syst\u00E8me... -label.action.stop.instance=Arr\u00EAter l\\'Instance -label.action.stop.instance.processing=Arr\u00EAt de l\\'Instance... -label.action.stop.router=Arr\u00EAter le routeur -label.action.stop.router.processing=Arr\u00EAt du routeur... -label.action.stop.systemvm=Arr\u00EAter la VM syst\u00E8me -label.action.stop.systemvm.processing=Arr\u00EAt de la VM syst\u00E8me... -label.action.take.snapshot=Prendre un instantan\u00E9 -label.action.take.snapshot.processing=Prise de l\\'instantan\u00E9... -label.action.unmanage.cluster=Ne plus g\u00E9rer le Cluster -label.action.unmanage.cluster.processing=Arr\u00EAt de la gestion du Cluster -label.action.update.OS.preference=Mettre \u00E0 jour les pr\u00E9f\u00E9rences d\\'OS -label.action.update.OS.preference.processing=Mise \u00E0 jour des pr\u00E9f\u00E9rences d\\'OS... -label.action.update.resource.count=Mettre \u00E0 jour le compteur des ressources -label.action.update.resource.count.processing=Mise \u00E0 jour du compteur... +label.action.restore.instance=Restaurer l\\'instance label.actions=Actions +label.action.start.instance=D\u00e9marrer l\\'instance +label.action.start.instance.processing=D\u00e9marrage de l\\'instance... +label.action.start.router=D\u00e9marrer le routeur +label.action.start.router.processing=D\u00e9marrage du routeur... +label.action.start.systemvm=D\u00e9marrer la VM syst\u00e8me +label.action.start.systemvm.processing=D\u00e9marrage de la VM syst\u00e8me... +label.action.stop.instance=Arr\u00eater l\\'Instance +label.action.stop.instance.processing=Arr\u00eat de l\\'Instance... +label.action.stop.router=Arr\u00eater le routeur +label.action.stop.router.processing=Arr\u00eat du routeur... +label.action.stop.systemvm=Arr\u00eater la VM syst\u00e8me +label.action.stop.systemvm.processing=Arr\u00eat de la VM syst\u00e8me... +label.action.take.snapshot=Prendre un instantan\u00e9 +label.action.take.snapshot.processing=Prise de l\\'instantan\u00e9... +label.action.unmanage.cluster=Ne plus g\u00e9rer le Cluster +label.action.unmanage.cluster.processing=Arr\u00eat de la gestion du Cluster +label.action.update.OS.preference=Mettre \u00e0 jour les pr\u00e9f\u00e9rences d\\'OS +label.action.update.OS.preference.processing=Mise \u00e0 jour des pr\u00e9f\u00e9rences d\\'OS... +label.action.update.resource.count=Mettre \u00e0 jour le compteur des ressources +label.action.update.resource.count.processing=Mise \u00e0 jour du compteur... +label.action.vmsnapshot.create=Prendre un instantan\u00e9 VM +label.action.vmsnapshot.delete=Supprimer l\\'instantan\u00e9 VM +label.action.vmsnapshot.revert=Revenir \u00e0 un instantan\u00e9 VM label.activate.project=Activer projet label.active.sessions=Sessions actives -label.add=Ajouter -label.add.ACL=Ajouter r\u00E8gle ACL -label.add.F5.device=Ajouter un F5 -label.add.NiciraNvp.device=Ajouter un contr\u00F4leur Nvp -label.add.SRX.device=Ajouter un SRX -label.add.VM.to.tier=Ajouter une machine virtuelle au tiers -label.add.VPN.gateway=Ajouter une passerelle VPN label.add.account=Ajouter un compte -label.add.account.to.project=Ajouter un compte au projet label.add.accounts=Ajouter des comptes label.add.accounts.to=Ajouter des comptes sur -label.add.by=Ajout\u00E9 par +label.add.account.to.project=Ajouter un compte au projet +label.add.ACL=Ajouter r\u00e8gle ACL +label.add.affinity.group=Ajouter nouvea groupe d\\'affinit\u00e9 +label.add=Ajouter +label.add.BigSwitchVns.device=Ajouter contr\u00f4leur BigSwitch Vns +label.add.by=Ajout\u00e9 par label.add.by.cidr=Ajouter par CIDR label.add.by.group=Ajouter par groupe label.add.cluster=Ajouter un cluster @@ -283,308 +251,343 @@ label.add.compute.offering=Ajouter une offre de calcul label.add.direct.iprange=Ajouter une plage d\\'adresse IP directe label.add.disk.offering=Ajouter une offre disque label.add.domain=Ajouter un domaine -label.add.egress.rule=Ajouter la r\u00E8gle sortante -label.add.firewall=Ajouter une r\u00E8gle de pare-feu -label.add.guest.network=Ajouter un r\u00E9seau d\\'invit\u00E9 -label.add.host=Ajouter un h\u00F4te -label.add.ingress.rule=Ajouter une r\u00E8gle d\\'entr\u00E9e +label.add.egress.rule=Ajouter la r\u00e8gle sortante +label.add.F5.device=Ajouter un F5 +label.add.firewall=Ajouter une r\u00e8gle de pare-feu +label.add.guest.network=Ajouter un r\u00e9seau d\\'invit\u00e9 +label.add.host=Ajouter un h\u00f4te +label.adding=Ajout +label.adding.cluster=Ajout du Cluster +label.adding.failed=\u00c9chec de l\\'ajout +label.adding.pod=Ajout du Pod +label.adding.processing=Ajout... +label.add.ingress.rule=Ajouter une r\u00e8gle d\\'entr\u00e9e +label.adding.succeeded=Ajout r\u00e9ussi +label.adding.user=Ajout de l\\'utilisateur +label.adding.zone=Ajout de la zone label.add.ip.range=Ajouter une plage IP -label.add.load.balancer=Ajouter un r\u00E9partiteur de charge +label.additional.networks=R\u00e9seaux additionnels +label.add.load.balancer=Ajouter un r\u00e9partiteur de charge label.add.more=Ajouter plus label.add.netScaler.device=Ajouter un Netscaler -label.add.network=Ajouter un r\u00E9seau -label.add.network.ACL=Ajouter une r\u00E8gle d\\'acc\u00E8s r\u00E9seau ACL -label.add.network.device=Ajouter un \u00E9quipement r\u00E9seau -label.add.network.offering=Ajouter une offre r\u00E9seau +label.add.network.ACL=Ajouter une r\u00e8gle d\\'acc\u00e8s r\u00e9seau ACL +label.add.network=Ajouter un r\u00e9seau +label.add.network.device=Ajouter un \u00e9quipement r\u00e9seau +label.add.network.offering=Ajouter une offre r\u00e9seau label.add.new.F5=Ajouter un F5 +label.add.new.gateway=Ajouter une nouvelle passerelle label.add.new.NetScaler=Ajouter un Netscaler label.add.new.SRX=Ajouter un SRX -label.add.new.gateway=Ajouter une nouvelle passerelle label.add.new.tier=Ajouter un nouveau tiers -label.add.physical.network=Ajouter un r\u00E9seau physique +label.add.NiciraNvp.device=Ajouter un contr\u00f4leur Nvp +label.add.physical.network=Ajouter un r\u00e9seau physique label.add.pod=Ajouter un pod -label.add.port.forwarding.rule=Ajouter une r\u00E8gle de transfert de port +label.add.port.forwarding.rule=Ajouter une r\u00e8gle de transfert de port label.add.primary.storage=Ajouter un stockage principal +label.add.region=Ajouter R\u00e9gion label.add.resources=Ajouter ressources label.add.route=Ajouter route -label.add.rule=Ajouter r\u00E8gle +label.add.rule=Ajouter r\u00e8gle label.add.secondary.storage=Ajouter un stockage secondaire -label.add.security.group=Ajouter un groupe de s\u00E9curit\u00E9 +label.add.security.group=Ajouter un groupe de s\u00e9curit\u00e9 label.add.service.offering=Ajouter une offre de service -label.add.static.nat.rule=Ajouter une r\u00E8gle de NAT statique +label.add.SRX.device=Ajouter un SRX +label.add.static.nat.rule=Ajouter une r\u00e8gle de NAT statique label.add.static.route=Ajouter une route statique -label.add.system.service.offering=Ajouter une offre de service syst\u00E8me -label.add.template=Ajouter un mod\u00E8le +label.add.system.service.offering=Ajouter une offre de service syst\u00e8me +label.add.template=Ajouter un mod\u00e8le label.add.to.group=Ajouter au groupe label.add.user=Ajouter un utilisateur label.add.vlan=Ajouter un VLAN label.add.vm=Ajouter VM label.add.vms=Ajouter VMs -label.add.vms.to.lb=Ajouter une/des VM(s) \u00E0 la r\u00E8gle de r\u00E9partition de charge +label.add.vms.to.lb=Ajouter une/des VM(s) \u00e0 la r\u00e8gle de r\u00e9partition de charge +label.add.VM.to.tier=Ajouter une machine virtuelle au tiers label.add.volume=Ajouter un volume label.add.vpc=Ajouter un VPC label.add.vpn.customer.gateway=Ajouter une passerelle VPN cliente +label.add.VPN.gateway=Ajouter une passerelle VPN label.add.vpn.user=Ajouter un utilisateur VPN label.add.zone=Ajouter une zone -label.adding=Ajout -label.adding.cluster=Ajout du Cluster -label.adding.failed=\u00C9chec de l\\'ajout -label.adding.pod=Ajout du Pod -label.adding.processing=Ajout... -label.adding.succeeded=Ajout r\u00E9ussi -label.adding.user=Ajout de l\\'utilisateur -label.adding.zone=Ajout de la zone -label.additional.networks=R\u00E9seaux additionnels -label.admin=Administrateur label.admin.accounts=Comptes Administrateur -label.advanced=Avanc\u00E9 -label.advanced.mode=Mode avanc\u00E9 -label.advanced.search=Recherche avanc\u00E9e +label.admin=Administrateur +label.advanced=Avanc\u00e9 +label.advanced.mode=Mode avanc\u00e9 +label.advanced.search=Recherche avanc\u00e9e +label.affinity=Affinit\u00e9 +label.affinity.group=Groupe d\\'Affinit\u00e9 +label.affinity.groups=Groups d\\'Affinit\u00e9 label.agent.password=Mot de passe Agent label.agent.username=Identifiant Agent label.agree=Accepter label.alert=Alerte label.algorithm=Algorithme -label.allocated=Allou\u00E9 -label.allocation.state=\u00C9tat -label.api.key=Cl\u00E9 d\\'API +label.allocated=Allou\u00e9 +label.allocation.state=\u00c9tat +label.anti.affinity=Anti-affinit\u00e9 +label.anti.affinity.group=Groupe d\\'Anti-affinit\u00e9 +label.anti.affinity.groups=Groupes d\\'Anti-affinit\u00e9 +label.api.key=Cl\u00e9 d\\'API label.apply=Appliquer label.assign=Assigner -label.assign.to.load.balancer=Assigner l\\'instance au r\u00E9partiteur de charge -label.associated.network=R\u00E9seau associ\u00E9 -label.associated.network.id=ID du r\u00E9seau associ\u00E9 -label.attached.iso=Image ISO attach\u00E9e -label.availability=Disponibilit\u00E9 -label.availability.zone=Zone de disponibilit\u00E9 +label.assign.to.load.balancer=Assigner l\\'instance au r\u00e9partiteur de charge +label.associated.network.id=ID du r\u00e9seau associ\u00e9 +label.associated.network=R\u00e9seau associ\u00e9 +label.attached.iso=Image ISO attach\u00e9e +label.author.email=Email auteur +label.author.name=Nom auteur +label.availability=Disponibilit\u00e9 +label.availability.zone=Zone de disponibilit\u00e9 label.available=Disponible label.available.public.ips=Adresses IP publiques disponibles label.back=Retour label.bandwidth=Bande passante label.basic=Basique label.basic.mode=Mode basique -label.bootable=Amor\u00E7able +label.bigswitch.controller.address=Adresse du contr\u00f4leur BigSwitch Vns +label.bootable=Amor\u00e7able label.broadcast.domain.range=Plage du domaine multi-diffusion label.broadcast.domain.type=Type de domaine de multi-diffusion label.broadcast.uri=URI multi-diffusion label.by.account=Par compte -label.by.availability=Par disponibilit\u00E9 +label.by.availability=Par disponibilit\u00e9 label.by.domain=Par domaine label.by.end.date=Par date de fin label.by.level=Par niveau label.by.pod=Par Pod -label.by.role=Par r\u00F4le -label.by.start.date=Par date de d\u00E9but -label.by.state=Par \u00E9tat +label.by.role=Par r\u00f4le +label.by.start.date=Par date de d\u00e9but +label.by.state=Par \u00e9tat +label.bytes.received=Octets re\u00e7us +label.bytes.sent=Octets envoy\u00e9s label.by.traffic.type=Par type de trafic -label.by.type=Par type label.by.type.id=Par type d\\'ID +label.by.type=Par type label.by.zone=Par zone -label.bytes.received=Octets re\u00E7us -label.bytes.sent=Octets envoy\u00E9s label.cancel=Annuler -label.capacity=Capacit\u00E9 +label.capacity=Capacit\u00e9 label.certificate=Certificat label.change.service.offering=Modifier l\\'offre de service label.change.value=Modifier la valeur -label.character=Caract\u00E8re -label.checksum=Somme de contr\u00F4le MD5 +label.character=Caract\u00e8re +label.checksum=Somme de contr\u00f4le MD5 +label.cidr.account=CIDR ou Compte/Groupe de s\u00e9curit\u00e9 label.cidr=CIDR -label.cidr.account=CIDR ou Compte/Groupe de s\u00E9curit\u00E9 label.cidr.list=CIDR Source +label.CIDR.list=Liste CIDR +label.CIDR.of.destination.network=CIDR du r\u00e9seau de destination label.clean.up=Nettoyage label.clear.list=Purger la liste label.close=Fermer label.cloud.console=Console d\\'Administration du Cloud -label.cloud.managed=G\u00E9r\u00E9 par Cloud.com +label.cloud.managed=G\u00e9r\u00e9 par Cloud.com label.cluster=Cluster label.cluster.name=Nom du cluster -label.cluster.type=Type de Cluster label.clusters=Clusters +label.cluster.type=Type de Cluster label.clvm=CLVM label.code=Code -label.community=Communaut\u00E9 -label.compute=Processeur +label.community=Communaut\u00e9 label.compute.and.storage=Calcul et Stockage label.compute.offering=Offre de calcul label.compute.offerings=Offres de calcul +label.compute=Processeur label.configuration=Configuration label.configure=Configurer -label.configure.network.ACLs=Configurer les r\u00E8gles d\\'acc\u00E8s r\u00E9seau ACL +label.configure.network.ACLs=Configurer les r\u00e8gles d\\'acc\u00e8s r\u00e9seau ACL label.configure.vpc=Configurer le VPC -label.confirm.password=Confirmer le mot de passe label.confirmation=Confirmation -label.congratulations=F\u00E9licitations \! +label.confirm.password=Confirmer le mot de passe +label.congratulations=F\u00e9licitations \! label.conserve.mode=Conserver le mode label.console.proxy=Console proxy -label.continue=Continuer label.continue.basic.install=Continuer avec l\\'installation basique -label.corrections.saved=Modifications enregistr\u00E9es +label.continue=Continuer +label.corrections.saved=Modifications enregistr\u00e9es +label.cpu.allocated=CPU allou\u00e9e +label.cpu.allocated.for.VMs=CPU allou\u00e9e aux VMs +label.CPU.cap=Limitation CPU label.cpu=CPU -label.cpu.allocated=CPU allou\u00E9e -label.cpu.allocated.for.VMs=CPU allou\u00E9e aux VMs +label.cpu.limits=Limites CPU label.cpu.mhz=CPU (en MHz) -label.cpu.utilized=CPU utilis\u00E9e -label.create.VPN.connection=Cr\u00E9er une connexion VPN -label.create.project=Cr\u00E9er un projet -label.create.template=Cr\u00E9er un mod\u00E8le -label.created=Cr\u00E9\u00E9 -label.created.by.system=Cr\u00E9\u00E9 par le syst\u00E8me +label.cpu.utilized=CPU utilis\u00e9e +label.created.by.system=Cr\u00e9\u00e9 par le syst\u00e8me +label.created=Cr\u00e9\u00e9 +label.create.project=Cr\u00e9er un projet +label.create.template=Cr\u00e9er un mod\u00e8le +label.create.VPN.connection=Cr\u00e9er une connexion VPN label.cross.zones=Multi Zones -label.custom.disk.size=Taille de disque personnalis\u00E9e +label.custom.disk.size=Taille de disque personnalis\u00e9e label.daily=Quotidien -label.data.disk.offering=Offre de disque de donn\u00E9es +label.data.disk.offering=Offre de disque de donn\u00e9es label.date=Date label.day.of.month=Jour du mois label.day.of.week=Jour de la semaine -label.dead.peer.detection=D\u00E9tection de pair mort +label.dead.peer.detection=D\u00e9tection de pair mort label.decline.invitation=Refuser l\\'invitation -label.dedicated=D\u00E9di\u00E9 -label.default=Par d\u00E9faut -label.default.use=Utilisation par d\u00E9faut -label.default.view=Vue par d\u00E9faut -label.delete=Supprimer +label.dedicated=D\u00e9di\u00e9 +label.default=Par d\u00e9faut +label.default.use=Utilisation par d\u00e9faut +label.default.view=Vue par d\u00e9faut +label.delete.affinity.group=Supprimer le groupe d\\'affinit\u00e9 +label.delete.BigSwitchVns=Supprimer contr\u00f4leur BigSwitch Vns label.delete.F5=Supprimer F5 +label.delete.gateway=Supprimer la passerelle label.delete.NetScaler=Supprimer Netscaler -label.delete.NiciraNvp=Supprimer un contr\u00F4leur Nvp +label.delete.NiciraNvp=Supprimer un contr\u00f4leur Nvp +label.delete.project=Supprimer projet label.delete.SRX=Supprimer SRX +label.delete=Supprimer label.delete.VPN.connection=Supprimer la connexion VPN label.delete.VPN.customer.gateway=Supprimer la passerelle VPN client label.delete.VPN.gateway=Supprimer la passerelle VPN -label.delete.gateway=Supprimer la passerelle -label.delete.project=Supprimer projet label.delete.vpn.user=Supprimer l\\'utilisateur VPN -label.deleting.failed=Suppression \u00E9chou\u00E9e +label.deleting.failed=Suppression \u00e9chou\u00e9e label.deleting.processing=Suppression... label.description=Description -label.destination.physical.network.id=Identifiant du r\u00E9seau physique de destination +label.destination.physical.network.id=Identifiant du r\u00e9seau physique de destination label.destination.zone=Zone de destination -label.destroy=D\u00E9truire +label.destroy=D\u00e9truire label.destroy.router=Supprimer le routeur -label.detaching.disk=D\u00E9tacher le disque -label.details=D\u00E9tails -label.device.id=ID du p\u00E9riph\u00E9rique +label.detaching.disk=D\u00e9tacher le disque +label.details=D\u00e9tails +label.device.id=ID du p\u00e9riph\u00e9rique label.devices=Machines label.dhcp=DHCP -label.direct.ips=Adresses IP du r\u00E9seau partag\u00E9 -label.disable.provider=D\u00E9sactiver ce fournisseur -label.disable.vpn=D\u00E9sactiver le VPN -label.disabled=D\u00E9sactiv\u00E9 -label.disabling.vpn.access=D\u00E9sactiver l\\'acc\u00E8s VPN -label.disk.allocated=Disque Allou\u00E9 +label.DHCP.server.type=Serveur DHCP +label.direct.ips=Adresses IP du r\u00e9seau partag\u00e9 +label.disabled=D\u00e9sactiv\u00e9 +label.disable.provider=D\u00e9sactiver ce fournisseur +label.disable.vpn=D\u00e9sactiver le VPN +label.disabling.vpn.access=D\u00e9sactiver l\\'acc\u00e8s VPN +label.disk.allocated=Disque Allou\u00e9 label.disk.offering=Offre de Disque -label.disk.size=Taille du disque label.disk.size.gb=Taille du disque (en Go) +label.disk.size=Taille du disque label.disk.total=Espace disque total label.disk.volume=Volume disque label.display.name=Nom commun -label.display.text=Texte affich\u00E9 -label.dns=DNS +label.display.text=Texte affich\u00e9 label.dns.1=DNS 1 label.dns.2=DNS 2 -label.domain=Domaine +label.dns=DNS +label.DNS.domain.for.guest.networks=Domaine DNS pour les r\u00e9seaux invit\u00e9s label.domain.admin=Administrateur du domaine +label.domain=Domaine label.domain.id=ID du domaine label.domain.name=Nom de domaine label.domain.router=Routeur du domaine label.domain.suffix=Suffixe de domaine DNS (i.e., xyz.com) -label.done=Termin\u00E9 -label.double.quotes.are.not.allowed=Les guillemets ne sont pas autoris\u00E9es -label.download.progress=Progression du t\u00E9l\u00E9chargement -label.drag.new.position=D\u00E9placer sur une autre position +label.done=Termin\u00e9 +label.double.quotes.are.not.allowed=Les guillemets ne sont pas autoris\u00e9es +label.download.progress=Progression du t\u00e9l\u00e9chargement +label.drag.new.position=D\u00e9placer sur une autre position +label.edit.affinity.group=Modifier le groupe d\\'affinit\u00e9 +label.edit.lb.rule=Modifier la r\u00e8gle LB label.edit=Modifier -label.edit.lb.rule=Modifier la r\u00E8gle LB -label.edit.network.details=Modifier les param\u00E8tres r\u00E9seau -label.edit.project.details=Modifier les d\u00E9tails du projet +label.edit.network.details=Modifier les param\u00e8tres r\u00e9seau +label.edit.project.details=Modifier les d\u00e9tails du projet label.edit.tags=Modifier les balises label.edit.traffic.type=Modifier le type de trafic label.edit.vpc=Modifier le VPC -label.egress.rule=R\u00E8gle sortante -label.egress.rules=R\u00E8gles de sortie -label.elastic=\u00C9lastique +label.egress.rule=R\u00e8gle sortante +label.egress.rules=R\u00e8gles de sortie label.elastic.IP=IP extensible -label.elastic.LB=R\u00E9partition de charge extensible +label.elastic.LB=R\u00e9partition de charge extensible +label.elastic=\u00c9lastique label.email=Email label.enable.provider=Activer le fournisseur label.enable.s3=Activer le stockage secondaire de type S3 label.enable.swift=Activer Swift label.enable.vpn=Activer VPN +label.enabling.vpn.access=Activation de l\\'acc\u00e8s VPN label.enabling.vpn=Activation du VPN -label.enabling.vpn.access=Activation de l\\'acc\u00E8s VPN label.end.IP=Fin de plage IP +label.endpoint.or.operation=Terminaison ou Op\u00e9ration +label.endpoint=Terminaison label.end.port=Port de fin -label.end.reserved.system.IP=Adresse IP de fin r\u00E9serv\u00E9e Syst\u00E8me +label.end.reserved.system.IP=Adresse IP de fin r\u00e9serv\u00e9e Syst\u00e8me label.end.vlan=VLAN de fin -label.endpoint.or.operation=Terminaison ou Op\u00E9ration label.enter.token=Entrez le jeton unique -label.error=Erreur label.error.code=Code d\\'erreur -label.esx.host=H\u00F4te ESX/ESXi +label.error=Erreur +label.ESP.encryption=Chiffrement ESP +label.ESP.hash=Empreinte ESP +label.ESP.lifetime=Dur\u00e9e de vie ESP (secondes) +label.ESP.policy=Mode ESP +label.esx.host=H\u00f4te ESX/ESXi label.example=Exemple +label.external.link=Lien externe label.f5=F5 -label.failed=\u00C9chou\u00E9 -label.featured=Sponsoris\u00E9 -label.fetch.latest=Rafra\u00EEchir +label.failed=\u00c9chou\u00e9 +label.featured=Sponsoris\u00e9 +label.fetch.latest=Rafra\u00eechir label.filterBy=Filtre label.firewall=Pare-feu -label.first.name=Pr\u00E9nom +label.first.name=Pr\u00e9nom label.format=Format label.friday=Vendredi label.full=Complet label.full.path=Chemin complet label.gateway=Passerelle -label.general.alerts=Alertes g\u00E9n\u00E9rales -label.generating.url=G\u00E9n\u00E9ration de l\\'URL -label.go.step.2=Aller \u00E0 l\\'\u00E9tape 2 -label.go.step.3=Aller \u00E0 l\\'\u00E9tape 3 -label.go.step.4=Aller \u00E0 l\\'\u00E9tape 4 -label.go.step.5=Aller \u00E0 l\\'\u00E9tape 5 +label.general.alerts=Alertes g\u00e9n\u00e9rales +label.generating.url=G\u00e9n\u00e9ration de l\\'URL +label.go.step.2=Aller \u00e0 l\\'\u00e9tape 2 +label.go.step.3=Aller \u00e0 l\\'\u00e9tape 3 +label.go.step.4=Aller \u00e0 l\\'\u00e9tape 4 +label.go.step.5=Aller \u00e0 l\\'\u00e9tape 5 label.group=Groupe label.group.optional=Groupe (optionnel) -label.guest=Invit\u00E9 -label.guest.cidr=CIDR invit\u00E9 -label.guest.end.ip=Adresse IP de fin pour les invit\u00E9s -label.guest.gateway=Passerelle pour les invit\u00E9s -label.guest.ip=Adresse IP des invit\u00E9s -label.guest.ip.range=Plage d\\'adresses IP des invit\u00E9s -label.guest.netmask=Masque de r\u00E9seau des invit\u00E9s -label.guest.networks=R\u00E9seaux d\\'invit\u00E9 -label.guest.start.ip=Adresse IP de d\u00E9but pour les invit\u00E9s -label.guest.traffic=Trafic invit\u00E9 -label.guest.type=Type d\\'invit\u00E9 -label.ha.enabled=Haute disponibilit\u00E9 activ\u00E9e +label.guest.cidr=CIDR invit\u00e9 +label.guest.end.ip=Adresse IP de fin pour les invit\u00e9s +label.guest.gateway=Passerelle pour les invit\u00e9s +label.guest=Invit\u00e9 +label.guest.ip=Adresse IP des invit\u00e9s +label.guest.ip.range=Plage d\\'adresses IP des invit\u00e9s +label.guest.netmask=Masque de r\u00e9seau des invit\u00e9s +label.guest.networks=R\u00e9seaux d\\'invit\u00e9 +label.guest.start.ip=Adresse IP de d\u00e9but pour les invit\u00e9s +label.guest.traffic=Trafic invit\u00e9 +label.guest.type=Type d\\'invit\u00e9 +label.ha.enabled=Haute disponibilit\u00e9 activ\u00e9e label.help=Aide -label.hide.ingress.rule=Cacher la r\u00E8gle d\\'entr\u00E9e +label.hide.ingress.rule=Cacher la r\u00e8gle d\\'entr\u00e9e label.hints=Astuces -label.host=H\u00F4te -label.host.MAC=Adresse MAC h\u00F4te -label.host.alerts=Alertes des h\u00F4tes -label.host.name=Nom d\\'h\u00F4te -label.host.tags=\u00C9tiquettes d\\'h\u00F4te -label.hosts=H\u00F4tes +label.host.alerts=Alertes des h\u00f4tes +label.host=H\u00f4te +label.host.MAC=Adresse MAC h\u00f4te +label.host.name=Nom d\\'h\u00f4te +label.hosts=H\u00f4tes +label.host.tags=\u00c9tiquettes d\\'h\u00f4te label.hourly=Chaque heure -label.hypervisor=Hyperviseur label.hypervisor.capabilities=Fonctions hyperviseur +label.hypervisor=Hyperviseur label.hypervisor.type=Type d\\'hyperviseur label.hypervisor.version=Version hyperviseur label.id=ID +label.IKE.DH=DH IKE +label.IKE.encryption=Chiffrement IKE +label.IKE.hash=Empreinte IKE +label.IKE.lifetime=Dur\u00e9e de vie IKE (secondes) +label.IKE.policy=Mode IKE label.info=Information -label.ingress.rule=R\u00E8gle d\\'entr\u00E9e -label.initiated.by=Initi\u00E9 par +label.ingress.rule=R\u00e8gle d\\'entr\u00e9e +label.initiated.by=Initi\u00e9 par label.installWizard.addClusterIntro.subtitle=Qu\\'est ce qu\\'un cluster ? label.installWizard.addClusterIntro.title=Ajoutons un cluster -label.installWizard.addHostIntro.subtitle=Qu\\'est ce qu\\'un h\u00F4te ? -label.installWizard.addHostIntro.title=Ajoutons un h\u00F4te +label.installWizard.addHostIntro.subtitle=Qu\\'est ce qu\\'un h\u00f4te ? +label.installWizard.addHostIntro.title=Ajoutons un h\u00f4te label.installWizard.addPodIntro.subtitle=Qu\\'est ce qu\\'un pod ? label.installWizard.addPodIntro.title=Ajoutons un pod label.installWizard.addPrimaryStorageIntro.subtitle=Qu\\'est ce que le stockage principal ? label.installWizard.addPrimaryStorageIntro.title=Ajoutons du stockage principal label.installWizard.addSecondaryStorageIntro.subtitle=Qu\\'est ce que le stockage secondaire ? label.installWizard.addSecondaryStorageIntro.title=Ajoutons du stockage secondaire -label.installWizard.addZone.title=Ajouter une zone label.installWizard.addZoneIntro.subtitle=Qu\\'est ce qu\\'une zone ? label.installWizard.addZoneIntro.title=Ajoutons une zone -label.installWizard.click.launch=Appuyer sur le bouton d\u00E9marrer. -label.installWizard.subtitle=Ce tutoriel vous aidera \u00E0 configurer votre installation CloudStack&\#8482; +label.installWizard.addZone.title=Ajouter une zone +label.installWizard.click.launch=Appuyer sur le bouton d\u00e9marrer. +label.installWizard.subtitle=Ce tutoriel vous aidera \u00e0 configurer votre installation CloudStack&\#8482; label.installWizard.title=Bonjour et bienvenue dans CloudStack&\#8482; label.instance=Instance label.instance.limits=Limites des instances @@ -594,105 +597,114 @@ label.internal.dns.1=DNS interne 1 label.internal.dns.2=DNS interne 2 label.internal.name=Nom interne label.interval.type=Type d\\'intervalle -label.introduction.to.cloudstack=Introduction \u00E0 CloudStack&\#8482; +label.introduction.to.cloudstack=Introduction \u00e0 CloudStack&\#8482; label.invalid.integer=Nombre entier invalide label.invalid.number=Nombre invalide label.invitations=Invitations +label.invited.accounts=Comptes invit\u00e9s label.invite=Inviter label.invite.to=Inviter sur -label.invited.accounts=Comptes invit\u00E9s -label.ip=IP label.ip.address=Adresse IP +label.ipaddress=Adresse IP label.ip.allocations=Allocations de IPs +label.ip=IP label.ip.limits=Limite de IPs publiques label.ip.or.fqdn=IP ou FQDN label.ip.range=Plage IP label.ip.ranges=Plages IP -label.ipaddress=Adresse IP +label.IPsec.preshared.key=Cl\u00e9 partag\u00e9e IPsec label.ips=IPs -label.is.default=Est par d\u00E9faut -label.is.redundant.router=Redondant -label.is.shared=Est partag\u00E9 -label.is.system=Est Syst\u00E8me label.iscsi=iSCSI +label.is.default=Est par d\u00e9faut +label.iso.boot=D\u00e9marrage par ISO label.iso=ISO -label.iso.boot=D\u00E9marrage par ISO -label.isolated.networks=R\u00E9seaux isol\u00E9s -label.isolation.method=M\u00E9thode de s\u00E9paration +label.isolated.networks=R\u00e9seaux isol\u00e9s +label.isolation.method=M\u00e9thode de s\u00e9paration label.isolation.mode=Mode d\\'isolation label.isolation.uri=URI d\\'isolation -label.item.listing=Liste des \u00E9l\u00E9ments +label.is.redundant.router=Redondant +label.is.shared=Est partag\u00e9 +label.is.system=Est Syst\u00e8me +label.item.listing=Liste des \u00e9l\u00e9ments label.keep=Conserver -label.key=Clef label.keyboard.type=Type de clavier -label.kvm.traffic.label=Libell\u00E9 pour le trafic KVM -label.label=Libell\u00E9 -label.lang.brportugese=Portuguais Br\u00E9sil +label.key=Clef +label.kvm.traffic.label=Libell\u00e9 pour le trafic KVM +label.label=Libell\u00e9 +label.lang.arabic=Arabe +label.lang.brportugese=Portuguais Br\u00e9sil label.lang.catalan=Catalan -label.lang.chinese=Chinois (simplifi\u00E9) +label.lang.chinese=Chinois (simplifi\u00e9) label.lang.english=Anglais -label.lang.french=Fran\u00E7ais +label.lang.french=Fran\u00e7ais label.lang.german=Allemand label.lang.italian=Italien label.lang.japanese=Japonais -label.lang.korean=Cor\u00E9en -label.lang.norwegian=Norv\u00E9gien +label.lang.korean=Cor\u00e9en +label.lang.norwegian=Norv\u00e9gien label.lang.russian=Russe label.lang.spanish=Espagnol -label.last.disconnected=Derni\u00E8re D\u00E9connexion +label.last.disconnected=Derni\u00e8re D\u00e9connexion label.last.name=Nom -label.latest.events=Derniers \u00E9v\u00E9nements -label.launch=D\u00E9marrer -label.launch.vm=D\u00E9marrer VM -label.launch.zone=D\u00E9marrer la zone +label.latest.events=Derniers \u00e9v\u00e9nements +label.launch=D\u00e9marrer +label.launch.vm=D\u00e9marrer VM +label.launch.zone=D\u00e9marrer la zone +label.LB.isolation=R\u00e9partition de charge isol\u00e9e label.least.connections=Le moins de connexions label.level=Niveau label.linklocal.ip=Adresse IP de lien local -label.load.balancer=R\u00E9partiteur de charge -label.load.balancing=R\u00E9partition de charge -label.load.balancing.policies=R\u00E8gles de r\u00E9partition de charge +label.load.balancer=R\u00e9partiteur de charge +label.load.balancing.policies=R\u00e8gles de r\u00e9partition de charge +label.load.balancing=R\u00e9partition de charge label.loading=Chargement en cours label.local=Local +label.local.storage.enabled=Stockage local activ\u00e9 label.local.storage=Stockage local -label.local.storage.enabled=Stockage local activ\u00E9 label.login=Connexion -label.logout=D\u00E9connexion +label.logout=D\u00e9connexion label.lun=LUN -label.make.project.owner=Devenir propri\u00E9taire du projet -label.manage=G\u00E9r\u00E9 -label.manage.resources=G\u00E9rer les ressources +label.LUN.number=N\u00b0 LUN +label.make.project.owner=Devenir propri\u00e9taire du projet +label.manage=G\u00e9r\u00e9 label.management=Administration label.management.ips=Adresses IP de gestion -label.max.guest.limit=Nombre maximum d\\'invit\u00E9s -label.max.networks=R\u00E9seaux Max. +label.manage.resources=G\u00e9rer les ressources +label.max.cpus=Nombre coeurs CPU max. +label.max.guest.limit=Nombre maximum d\\'invit\u00e9s +label.maximum=Maximum +label.max.memory=M\u00e9moire max. (Mo) +label.max.networks=R\u00e9seaux Max. +label.max.primary.storage=Principal max. (Go) label.max.public.ips=Max. IP publiques -label.max.snapshots=Max instantan\u00E9es -label.max.templates=Max. mod\u00E8les +label.max.secondary.storage=Secondaire max. (Go) +label.max.snapshots=Max instantan\u00e9es +label.max.templates=Max. mod\u00e8les label.max.vms=Max. VMs utilisateur label.max.volumes=Max. volumes label.max.vpcs=Max. VPCs -label.maximum=Maximum label.may.continue=Vous pouvez continuer. -label.memory=M\u00E9moire (en Mo) -label.memory.allocated=M\u00E9moire allou\u00E9e -label.memory.mb=M\u00E9moire (en MB) -label.memory.total=M\u00E9moire totale -label.memory.used=M\u00E9moire utilis\u00E9e +label.memory.allocated=M\u00e9moire allou\u00e9e +label.memory.limits=Limites m\u00e9moire (Mo) +label.memory.mb=M\u00e9moire (en MB) +label.memory=M\u00e9moire (en Mo) +label.memory.total=M\u00e9moire totale +label.memory.used=M\u00e9moire utilis\u00e9e label.menu.accounts=Comptes label.menu.alerts=Alertes label.menu.all.accounts=Tous les comptes label.menu.all.instances=Toutes les instances -label.menu.community.isos=ISO de la communaut\u00E9 -label.menu.community.templates=Mod\u00E8les de la communaut\u00E9 +label.menu.community.isos=ISO de la communaut\u00e9 +label.menu.community.templates=Mod\u00e8les de la communaut\u00e9 label.menu.configuration=Configuration label.menu.dashboard=Tableau de bord -label.menu.destroyed.instances=Instances d\u00E9truites +label.menu.destroyed.instances=Instances d\u00e9truites label.menu.disk.offerings=Offres de disque label.menu.domains=Domaines -label.menu.events=\u00C9v\u00E9nements -label.menu.featured.isos=ISOs Sponsoris\u00E9es -label.menu.featured.templates=Mod\u00E8les sponsoris\u00E9s -label.menu.global.settings=Param\u00E8tres globaux +label.menu.events=\u00c9v\u00e9nements +label.menu.featured.isos=ISOs Sponsoris\u00e9es +label.menu.featured.templates=Mod\u00e8les sponsoris\u00e9s +label.menu.global.settings=Param\u00e8tres globaux label.menu.infrastructure=Infrastructure label.menu.instances=Instances label.menu.ipaddresses=Adresses IP @@ -700,72 +712,73 @@ label.menu.isos=ISOs label.menu.my.accounts=Mes comptes label.menu.my.instances=Mes instances label.menu.my.isos=Mes ISOs -label.menu.my.templates=Mes mod\u00E8les -label.menu.network=R\u00E9seau -label.menu.network.offerings=Offres de Service R\u00E9seau +label.menu.my.templates=Mes mod\u00e8les +label.menu.network.offerings=Offres de Service R\u00e9seau +label.menu.network=R\u00e9seau label.menu.physical.resources=Ressources physiques +label.menu.regions=R\u00e9gions label.menu.running.instances=Instances actives -label.menu.security.groups=Groupes de s\u00E9curit\u00E9 +label.menu.security.groups=Groupes de s\u00e9curit\u00e9 label.menu.service.offerings=Offres de Service -label.menu.snapshots=Instantan\u00E9s -label.menu.stopped.instances=Instances Arr\u00EAt\u00E9es +label.menu.snapshots=Instantan\u00e9s +label.menu.stopped.instances=Instances Arr\u00eat\u00e9es label.menu.storage=Stockage -label.menu.system=Syst\u00E8me -label.menu.system.service.offerings=Offres syst\u00E8me -label.menu.system.vms=\ VMs Syst\u00E8mes -label.menu.templates=Mod\u00E8les +label.menu.system.service.offerings=Offres syst\u00e8me +label.menu.system=Syst\u00e8me +label.menu.system.vms=\ VMs Syst\u00e8mes +label.menu.templates=Mod\u00e8les label.menu.virtual.appliances=Appliances Virtuelles label.menu.virtual.resources=Ressources Virtuelles label.menu.volumes=Volumes +label.migrate.instance.to.host=Migration de l\\'instance sur un autre h\u00f4te label.migrate.instance.to=Migrer l\\'instance vers -label.migrate.instance.to.host=Migration de l\\'instance sur un autre h\u00F4te label.migrate.instance.to.ps=Migration de l\\'instance sur un autre stockage principal -label.migrate.router.to=Migrer le routeur vers -label.migrate.systemvm.to=Migrer la VM syst\u00E8me vers -label.migrate.to.host=Migrer vers un h\u00F4te +label.migrate.router.to=Migrer le routeur vers +label.migrate.systemvm.to=Migrer la VM syst\u00e8me vers +label.migrate.to.host=Migrer vers un h\u00f4te label.migrate.to.storage=Migrer vers un stockage label.migrate.volume=Migration du volume vers un autre stockage principal label.minimum=Minimum label.minute.past.hour=minute(s) label.monday=Lundi label.monthly=Mensuel -label.more.templates=Plus de mod\u00E8les +label.more.templates=Plus de mod\u00e8les label.move.down.row=Descendre d\\'un cran -label.move.to.bottom=D\u00E9placer en bas +label.move.to.bottom=D\u00e9placer en bas label.move.to.top=Placer au dessus label.move.up.row=Monter d\\'un cran label.my.account=Mon compte -label.my.network=Mon r\u00E9seau -label.my.templates=Mes mod\u00E8les +label.my.network=Mon r\u00e9seau +label.my.templates=Mes mod\u00e8les label.name=Nom label.name.optional=Nom (optionnel) label.nat.port.range=Plage de port NAT +label.netmask=Masque de r\u00e9seau label.netScaler=NetScaler -label.netmask=Masque de r\u00E9seau -label.network=R\u00E9seau -label.network.ACL=R\u00E8gles d\\'acc\u00E8s r\u00E9seau ACL -label.network.ACL.total=Total R\u00E8gles d\\'acc\u00E8s r\u00E9seau -label.network.ACLs=R\u00E8gles d\\'acc\u00E8s r\u00E9seau -label.network.desc=Description r\u00E9seau -label.network.device=\u00C9quipement R\u00E9seau -label.network.device.type=Type d\\'\u00E9quipement r\u00E9seau +label.network.ACL=R\u00e8gles d\\'acc\u00e8s r\u00e9seau ACL +label.network.ACLs=R\u00e8gles d\\'acc\u00e8s r\u00e9seau +label.network.ACL.total=Total R\u00e8gles d\\'acc\u00e8s r\u00e9seau +label.network.desc=Description r\u00e9seau +label.network.device.type=Type d\\'\u00e9quipement r\u00e9seau +label.network.device=\u00c9quipement R\u00e9seau label.network.domain=Nom de domaine -label.network.domain.text=Domaine r\u00E9seau -label.network.id=ID r\u00E9seau -label.network.label.display.for.blank.value=Utiliser la passerelle par d\u00E9faut -label.network.name=Nom du r\u00E9seau -label.network.offering=Offre de Service R\u00E9seau -label.network.offering.display.text=Texte affich\u00E9 d\\'Offre de R\u00E9seau -label.network.offering.id=ID de l\\'Offre de Service R\u00E9seau -label.network.offering.name=Nom de l\\'Offre de Service R\u00E9seau -label.network.rate=D\u00E9bit R\u00E9seau -label.network.rate.megabytes=D\u00E9bit r\u00E9seau (Mo/s) -label.network.read=Lecture r\u00E9seau -label.network.service.providers=Fournisseurs de service r\u00E9seau -label.network.type=Type de r\u00E9seau -label.network.write=\u00C9criture r\u00E9seau -label.networking.and.security=R\u00E9seau et s\u00E9curit\u00E9 -label.networks=R\u00E9seaux +label.network.domain.text=Domaine r\u00e9seau +label.network.id=ID r\u00e9seau +label.networking.and.security=R\u00e9seau et s\u00e9curit\u00e9 +label.network.label.display.for.blank.value=Utiliser la passerelle par d\u00e9faut +label.network.name=Nom du r\u00e9seau +label.network.offering.display.text=Texte affich\u00e9 d\\'Offre de R\u00e9seau +label.network.offering.id=ID de l\\'Offre de Service R\u00e9seau +label.network.offering.name=Nom de l\\'Offre de Service R\u00e9seau +label.network.offering=Offre de Service R\u00e9seau +label.network.rate=D\u00e9bit R\u00e9seau +label.network.rate.megabytes=D\u00e9bit r\u00e9seau (Mo/s) +label.network.read=Lecture r\u00e9seau +label.network=R\u00e9seau +label.network.service.providers=Fournisseurs de service r\u00e9seau +label.networks=R\u00e9seaux +label.network.type=Type de r\u00e9seau +label.network.write=\u00c9criture r\u00e9seau label.new=Nouveau label.new.password=Nouveau mot de passe label.new.project=Nouveau projet @@ -775,220 +788,234 @@ label.nexusVswitch=Nexus 1000v label.nfs=NFS label.nfs.server=Serveur NFS label.nfs.storage=Stockage NFS -label.nic.adapter.type=Type de carte r\u00E9seau -label.nicira.controller.address=Adresse du contr\u00F4leur +label.nic.adapter.type=Type de carte r\u00e9seau +label.nicira.controller.address=Adresse du contr\u00f4leur label.nicira.l3gatewayserviceuuid=Uuid du service passerelle L3 label.nicira.transportzoneuuid=Uuid de la Zone Transport label.nics=Cartes NIC -label.no=Non label.no.actions=Aucune action disponible -label.no.alerts=Aucune alerte r\u00E9cente -label.no.data=Aucune donn\u00E9e -label.no.errors=Aucune erreur r\u00E9cente +label.no.alerts=Aucune alerte r\u00e9cente +label.no.data=Aucune donn\u00e9e +label.no.errors=Aucune erreur r\u00e9cente label.no.isos=Aucun ISOs disponible -label.no.items=Aucun \u00E9l\u00E9ment disponible -label.no.security.groups=Aucun groupe de s\u00E9curit\u00E9 disponible -label.no.thanks=Non merci +label.no.items=Aucun \u00e9l\u00e9ment disponible label.none=Aucun +label.no=Non +label.no.security.groups=Aucun groupe de s\u00e9curit\u00e9 disponible label.not.found=Introuvable +label.no.thanks=Non merci label.notifications=Messages -label.num.cpu.cores=Nombre de c\u0153urs label.number.of.clusters=Nombre de clusters -label.number.of.hosts=Nombre d\\'H\u00F4tes +label.number.of.hosts=Nombre d\\'H\u00f4tes label.number.of.pods=Nombre de Pods -label.number.of.system.vms=Nombre de VM Syst\u00E8me +label.number.of.system.vms=Nombre de VM Syst\u00e8me label.number.of.virtual.routers=Nombre de routeurs virtuels label.number.of.zones=Nombre de zones +label.num.cpu.cores=Nombre de c\u0153urs label.numretries=Nombre de tentatives label.ocfs2=OCFS2 -label.offer.ha=Offrir la haute disponibilit\u00E9 +label.offer.ha=Offrir la haute disponibilit\u00e9 label.ok=OK label.optional=Facultatif label.order=Ordre -label.os.preference=Pr\u00E9f\u00E9rence OS +label.os.preference=Pr\u00e9f\u00e9rence OS label.os.type=Type du OS -label.owned.public.ips=Adresses IP Publiques d\u00E9tenues -label.owner.account=Propri\u00E9taire -label.owner.domain=Propri\u00E9taire +label.owned.public.ips=Adresses IP Publiques d\u00e9tenues +label.owner.account=Propri\u00e9taire +label.owner.domain=Propri\u00e9taire label.parent.domain=Parent du Domaine +label.password.enabled=Mot de passe activ\u00e9 label.password=Mot de passe -label.password.enabled=Mot de passe activ\u00E9 label.path=Chemin -label.perfect.forward.secrecy=Confidentialit\u00E9 persistante -label.physical.network=R\u00E9seau physique -label.physical.network.ID=Identifiant du r\u00E9seau physique +label.perfect.forward.secrecy=Confidentialit\u00e9 persistante +label.physical.network.ID=Identifiant du r\u00e9seau physique +label.physical.network=R\u00e9seau physique +label.PING.CIFS.password=Mot de passe CIFS PING +label.PING.CIFS.username=Identifiant CIFS PING +label.PING.dir=R\u00e9pertoire PING +label.PING.storage.IP=IP stockage PING label.please.specify.netscaler.info=Renseigner les informations sur le Netscaler label.please.wait=Patientez s\\'il vous plait -label.pod=Pod +label.plugin.details=D\u00e9tails extension +label.plugins=Extensions label.pod.name=Nom du pod +label.pod=Pod label.pods=Pods +label.port.forwarding.policies=R\u00e8gles de transfert de port label.port.forwarding=Redirection de port -label.port.forwarding.policies=R\u00E8gles de transfert de port label.port.range=Plage de ports -label.prev=Pr\u00E9c\u00E9dent +label.PreSetup=PreSetup label.previous=Retour -label.primary.allocated=Stockage principal allou\u00E9 -label.primary.network=R\u00E9seau principal -label.primary.storage=Premier stockage +label.prev=Pr\u00e9c\u00e9dent +label.primary.allocated=Stockage principal allou\u00e9 +label.primary.network=R\u00e9seau principal label.primary.storage.count=Groupes de stockage principal -label.primary.used=Stockage principal utilis\u00E9 -label.private.Gateway=Passerelle priv\u00E9e -label.private.interface=Interface priv\u00E9e -label.private.ip=Adresse IP Priv\u00E9e -label.private.ip.range=Plage d\\'adresses IP Priv\u00E9es -label.private.ips=Adresses IP Priv\u00E9es -label.private.network=R\u00E9seau priv\u00E9 -label.private.port=Port priv\u00E9 -label.private.zone=Zone Priv\u00E9e -label.privatekey=Cl\u00E9 priv\u00E9e PKCS\#8 -label.project=Projet +label.primary.storage.limits=Limites stockage principal (Go) +label.primary.storage=Premier stockage +label.primary.used=Stockage principal utilis\u00e9 +label.private.Gateway=Passerelle priv\u00e9e +label.private.interface=Interface priv\u00e9e +label.private.ip=Adresse IP Priv\u00e9e +label.private.ip.range=Plage d\\'adresses IP Priv\u00e9es +label.private.ips=Adresses IP Priv\u00e9es +label.privatekey=Cl\u00e9 priv\u00e9e PKCS\#8 +label.private.network=R\u00e9seau priv\u00e9 +label.private.port=Port priv\u00e9 +label.private.zone=Zone Priv\u00e9e label.project.dashboard=Tableau de bord projet label.project.id=ID projet label.project.invite=Inviter sur le projet label.project.name=Nom du projet -label.project.view=Vue projet +label.project=Projet label.projects=Projets +label.project.view=Vue projet label.protocol=Protocole label.providers=Fournisseurs -label.public=Publique label.public.interface=Interface publique label.public.ip=Adresse IP publique label.public.ips=Adresses IP publiques -label.public.network=R\u00E9seau public +label.public.network=R\u00e9seau public label.public.port=Port public +label.public=Publique label.public.traffic=Trafic public label.public.zone=Zone publique -label.purpose=R\u00F4le -label.quickview=Aper\u00E7u -label.reboot=Red\u00E9marrer -label.recent.errors=Erreurs r\u00E9centes -label.redundant.router=Routeur redondant +label.purpose=R\u00f4le +label.Pxe.server.type=Serveur PXE +label.quickview=Aper\u00e7u +label.reboot=Red\u00e9marrer +label.recent.errors=Erreurs r\u00e9centes label.redundant.router.capability=Router redondant -label.redundant.state=\u00C9tat de la redondance +label.redundant.router=Routeur redondant +label.redundant.state=\u00c9tat de la redondance label.refresh=Actualiser +label.region=R\u00e9gion label.related=Connexes label.remind.later=Rappeler moi plus tard -label.remove.ACL=Supprimer une r\u00E8gle ACL -label.remove.egress.rule=Supprimer la r\u00E8gle sortante -label.remove.from.load.balancer=Supprimer l\\'instance du r\u00E9partiteur de charge -label.remove.ingress.rule=Supprimer la r\u00E8gle entrante +label.remove.ACL=Supprimer une r\u00e8gle ACL +label.remove.egress.rule=Supprimer la r\u00e8gle sortante +label.remove.from.load.balancer=Supprimer l\\'instance du r\u00e9partiteur de charge +label.remove.ingress.rule=Supprimer la r\u00e8gle entrante label.remove.ip.range=Supprimer la plage IP -label.remove.pf=Supprimer la r\u00E8gle de transfert de port +label.remove.pf=Supprimer la r\u00e8gle de transfert de port label.remove.project.account=Supprimer le compte projet -label.remove.rule=Supprimer la r\u00E8gle +label.remove.region=Supprimer r\u00e9gion +label.remove.rule=Supprimer la r\u00e8gle label.remove.static.nat.rule=Supprimer le NAT statique label.remove.static.route=Supprimer une route statique label.remove.tier=Supprimer le tiers -label.remove.vm.from.lb=Supprimer la VM de la r\u00E8gle de r\u00E9partition de charge +label.remove.vm.from.lb=Supprimer la VM de la r\u00e8gle de r\u00e9partition de charge label.remove.vpc=Supprimer le VPC label.removing=Suppression label.removing.user=Retrait de l\\'utilisateur label.required=Requis -label.reserved.system.gateway=Passerelle r\u00E9serv\u00E9e Syst\u00E8me -label.reserved.system.ip=Adresse IP Syst\u00E8me r\u00E9serv\u00E9e -label.reserved.system.netmask=Masque de sous-r\u00E9seau r\u00E9serv\u00E9 Syst\u00E8me -label.reset.VPN.connection=R\u00E9-initialiser la connexion VPN +label.reserved.system.gateway=Passerelle r\u00e9serv\u00e9e Syst\u00e8me +label.reserved.system.ip=Adresse IP Syst\u00e8me r\u00e9serv\u00e9e +label.reserved.system.netmask=Masque de sous-r\u00e9seau r\u00e9serv\u00e9 Syst\u00e8me +label.reset.VPN.connection=R\u00e9-initialiser la connexion VPN label.resize.new.offering.id=Nouvelle Offre label.resize.new.size=Nouvelle Taille (Go) -label.resize.shrink.ok=R\u00E9duction OK -label.resource=Ressource +label.resize.shrink.ok=R\u00e9duction OK label.resource.limits=Limite des ressources -label.resource.state=\u00C9tat des ressources +label.resource=Ressource label.resources=Ressources -label.restart.network=Red\u00E9marrage du r\u00E9seau -label.restart.required=Red\u00E9marrage n\u00E9cessaire -label.restart.vpc=Red\u00E9marrer le VPC +label.resource.state=\u00c9tat des ressources +label.restart.network=Red\u00e9marrage du r\u00e9seau +label.restart.required=Red\u00e9marrage n\u00e9cessaire +label.restart.vpc=Red\u00e9marrer le VPC label.restore=Restaurer label.review=Revoir -label.revoke.project.invite=R\u00E9voquer l\\'invitation -label.role=R\u00F4le -label.root.disk.controller=Contr\u00F4leur de disque principal +label.revoke.project.invite=R\u00e9voquer l\\'invitation +label.role=R\u00f4le +label.root.disk.controller=Contr\u00f4leur de disque principal label.root.disk.offering=Offre de disque racine -label.round.robin=Al\u00E9atoire -label.rules=R\u00E8gles +label.round.robin=Al\u00e9atoire +label.rules=R\u00e8gles label.running.vms=VMs actives -label.s3.access_key=Cl\u00E9 d\\'Acc\u00E8s +label.s3.access_key=Cl\u00e9 d\\'Acc\u00e8s label.s3.bucket=Seau -label.s3.connection_timeout=D\u00E9lai d\\'expiration de connexion +label.s3.connection_timeout=D\u00e9lai d\\'expiration de connexion label.s3.endpoint=Terminaison -label.s3.max_error_retry=Nombre d\\'essai en erreur max. -label.s3.secret_key=Cl\u00E9 Priv\u00E9e -label.s3.socket_timeout=D\u00E9lai d\\'expiration de la socket +label.s3.max_error_retry=Nombre d\\'essai en erreur max. +label.s3.secret_key=Cl\u00e9 Priv\u00e9e +label.s3.socket_timeout=D\u00e9lai d\\'expiration de la socket label.s3.use_https=Utiliser HTTPS label.saturday=Samedi -label.save=Sauvegarder label.save.and.continue=Enregistrer et continuer +label.save=Sauvegarder label.saving.processing=Sauvegarde en cours... -label.scope=Port\u00E9e +label.scope=Port\u00e9e label.search=Rechercher -label.secondary.storage=Stockage secondaire label.secondary.storage.count=Groupes de stockage secondaire +label.secondary.storage.limits=Limites stockage secondaire (Go) +label.secondary.storage=Stockage secondaire label.secondary.storage.vm=VM stockage secondaire -label.secondary.used=Stockage secondaire utilis\u00E9 -label.secret.key=Cl\u00E9 priv\u00E9e -label.security.group=Groupe de s\u00E9curit\u00E9 -label.security.group.name=Nom du groupe de s\u00E9curit\u00E9 -label.security.groups=Groupes de s\u00E9curit\u00E9 -label.security.groups.enabled=Groupes de s\u00E9curit\u00E9 Activ\u00E9s -label.select=S\u00E9lectionner -label.select-view=S\u00E9lectionner la vue -label.select.a.template=S\u00E9lectionner un mod\u00E8le -label.select.a.zone=S\u00E9lectionner une zone -label.select.instance=S\u00E9lectionner une instance -label.select.instance.to.attach.volume.to=S\u00E9lectionner l\\'instance \u00E0 laquelle rattacher ce volume -label.select.iso.or.template=S\u00E9lectionner un ISO ou un mod\u00E8le -label.select.offering=S\u00E9lectionner une offre -label.select.project=S\u00E9lectionner un projet -label.select.tier=S\u00E9lectionner le tiers -label.select.vm.for.static.nat=S\u00E9lectionner une VM pour le NAT statique -label.sent=Envoy\u00E9 +label.secondary.used=Stockage secondaire utilis\u00e9 +label.secret.key=Cl\u00e9 priv\u00e9e +label.security.group=Groupe de s\u00e9curit\u00e9 +label.security.group.name=Nom du groupe de s\u00e9curit\u00e9 +label.security.groups.enabled=Groupes de s\u00e9curit\u00e9 Activ\u00e9s +label.security.groups=Groupes de s\u00e9curit\u00e9 +label.select.a.template=S\u00e9lectionner un mod\u00e8le +label.select.a.zone=S\u00e9lectionner une zone +label.select.instance=S\u00e9lectionner une instance +label.select.instance.to.attach.volume.to=S\u00e9lectionner l\\'instance \u00e0 laquelle rattacher ce volume +label.select.iso.or.template=S\u00e9lectionner un ISO ou un mod\u00e8le +label.select.offering=S\u00e9lectionner une offre +label.select.project=S\u00e9lectionner un projet +label.select=S\u00e9lectionner +label.select.tier=S\u00e9lectionner le tiers +label.select-view=S\u00e9lectionner la vue +label.select.vm.for.static.nat=S\u00e9lectionner une VM pour le NAT statique +label.sent=Envoy\u00e9 label.server=Serveur label.service.capabilities=Fonctions disponibles label.service.offering=Offre de Service -label.session.expired=Session expir\u00E9e -label.set.up.zone.type=Configurer le type de zone +label.session.expired=Session expir\u00e9e label.setup=Configuration -label.setup.network=Configurer le r\u00E9seau +label.setup.network=Configurer le r\u00e9seau label.setup.zone=Configurer la zone +label.set.up.zone.type=Configurer le type de zone label.shared=En partage -label.show.ingress.rule=Montrer la r\u00E8gle d\\'entr\u00E9e -label.shutdown.provider=\u00C9teindre ce fournisseur -label.site.to.site.VPN=VPN Site-\u00E0-Site +label.SharedMountPoint=Point de montage partag\u00e9 +label.show.ingress.rule=Montrer la r\u00e8gle d\\'entr\u00e9e +label.shutdown.provider=\u00c9teindre ce fournisseur +label.site.to.site.VPN=VPN Site-\u00e0-Site label.size=Taille -label.skip.guide=J\\'ai d\u00E9j\u00E0 utilis\u00E9 CloudStack avant, passer ce tutoriel -label.snapshot=Instantan\u00E9 -label.snapshot.limits=Limites d\\'instantan\u00E9s -label.snapshot.name=Nom Instantan\u00E9 -label.snapshot.s=Instantan\u00E9(s) -label.snapshot.schedule=Configurer un instantan\u00E9 r\u00E9current -label.snapshots=Instantan\u00E9s -label.source=Origine +label.skip.guide=J\\'ai d\u00e9j\u00e0 utilis\u00e9 CloudStack avant, passer ce tutoriel +label.snapshot=Instantan\u00e9 +label.snapshot.limits=Limites d\\'instantan\u00e9s +label.snapshot.name=Nom Instantan\u00e9 +label.snapshot.schedule=Configurer un instantan\u00e9 r\u00e9current +label.snapshot.s=Instantan\u00e9(s) +label.snapshots=Instantan\u00e9s label.source.nat=NAT Source -label.specify.IP.ranges=Sp\u00E9cifier des plages IP -label.specify.vlan=Pr\u00E9ciser le VLAN +label.source=Origine +label.specify.IP.ranges=Sp\u00e9cifier des plages IP +label.specify.vlan=Pr\u00e9ciser le VLAN +label.SR.name = Nom du point de montage label.srx=SRX -label.start.IP=Plage de d\u00E9but IP -label.start.port=Port de d\u00E9but -label.start.reserved.system.IP=Adresse IP de d\u00E9but r\u00E9serv\u00E9e Syst\u00E8me -label.start.vlan=VLAN de d\u00E9part -label.state=\u00C9tat +label.start.IP=Plage de d\u00e9but IP +label.start.port=Port de d\u00e9but +label.start.reserved.system.IP=Adresse IP de d\u00e9but r\u00e9serv\u00e9e Syst\u00e8me +label.start.vlan=VLAN de d\u00e9part +label.state=\u00c9tat +label.static.nat.enabled=NAT statique activ\u00e9 label.static.nat=NAT Statique -label.static.nat.enabled=NAT statique activ\u00E9 label.static.nat.to=NAT Statique vers -label.static.nat.vm.details=D\u00E9tails des NAT statique VM +label.static.nat.vm.details=D\u00e9tails des NAT statique VM label.statistics=Statistiques label.status=Statut -label.step.1=\u00C9tape 1 -label.step.1.title=\u00C9tape 1 \: S\u00E9lectionnez un mod\u00E8le -label.step.2=\u00C9tape 2 -label.step.2.title=\u00C9tape 2 \: Offre de Service -label.step.3=\u00C9tape 3 -label.step.3.title=\u00C9tape 3 \: S\u00E9lectionnez une offre de service -label.step.4=\u00C9tape 4 -label.step.4.title=\u00C9tape 4 \: R\u00E9seau -label.step.5=\u00C9tape 5 -label.step.5.title=\u00C9tape 5 \: V\u00E9rification -label.stickiness=Fid\u00E9lit\u00E9 +label.step.1.title=\u00c9tape 1 \: S\u00e9lectionnez un mod\u00e8le +label.step.1=\u00c9tape 1 +label.step.2.title=\u00c9tape 2 \: Offre de Service +label.step.2=\u00c9tape 2 +label.step.3.title=\u00c9tape 3 \: S\u00e9lectionnez une offre de service +label.step.3=\u00c9tape 3 +label.step.4.title=\u00c9tape 4 \: R\u00e9seau +label.step.4=\u00c9tape 4 +label.step.5.title=\u00c9tape 5 \: V\u00e9rification +label.step.5=\u00c9tape 5 +label.stickiness=Fid\u00e9lit\u00e9 label.sticky.cookie-name=Nom du cookie label.sticky.domain=Domaine label.sticky.expire=Expiration @@ -997,127 +1024,140 @@ label.sticky.indirect=Indirect label.sticky.length=Longueur label.sticky.mode=Mode label.sticky.nocache=Pas de cache -label.sticky.postonly=Apr\u00E8s seulement -label.sticky.prefix=Pr\u00E9fixe -label.sticky.request-learn=Apprendre la requ\u00EAte +label.sticky.postonly=Apr\u00e8s seulement +label.sticky.prefix=Pr\u00e9fixe +label.sticky.request-learn=Apprendre la requ\u00eate label.sticky.tablesize=Taille du tableau -label.stop=Arr\u00EAter -label.stopped.vms=VMs arr\u00EAt\u00E9es +label.stop=Arr\u00eater +label.stopped.vms=VMs arr\u00eat\u00e9es label.storage=Stockage -label.storage.tags=\u00C9tiquettes de stockage +label.storage.tags=\u00c9tiquettes de stockage label.storage.traffic=Trafic stockage label.storage.type=Type de stockage -label.subdomain.access=Acc\u00E8s sous-domaine +label.subdomain.access=Acc\u00e8s sous-domaine label.submit=Envoyer label.submitted.by=[Soumis par \: ] -label.succeeded=R\u00E9ussi +label.succeeded=R\u00e9ussi label.sunday=Dimanche -label.super.cidr.for.guest.networks=Super CIDR pour les r\u00E9seaux invit\u00E9s -label.supported.services=Services support\u00E9s -label.supported.source.NAT.type=Type de NAT support\u00E9 +label.super.cidr.for.guest.networks=Super CIDR pour les r\u00e9seaux invit\u00e9s +label.supported.services=Services support\u00e9s +label.supported.source.NAT.type=Type de NAT support\u00e9 label.suspend.project=Suspendre projet -label.system.capacity=Capacit\u00E9 syst\u00E8me -label.system.offering=Offre de syst\u00E8me -label.system.service.offering=Offre de Service Syst\u00E8me -label.system.vm=VM Syst\u00E8me -label.system.vm.type=Type de VM syst\u00E8me -label.system.vms=\ VMs Syst\u00E8mes -label.system.wide.capacity=Capacit\u00E9 globale -label.tagged=\u00C9tiquet\u00E9 -label.tags=\u00C9tiquette +label.system.capacity=Capacit\u00e9 syst\u00e8me +label.system.offering=Offre de syst\u00e8me +label.system.service.offering=Offre de Service Syst\u00e8me +label.system.vms=\ VMs Syst\u00e8mes +label.system.vm.type=Type de VM syst\u00e8me +label.system.vm=VM Syst\u00e8me +label.system.wide.capacity=Capacit\u00e9 globale +label.tagged=\u00c9tiquet\u00e9 +label.tags=\u00c9tiquette label.target.iqn=Cible IQN -label.task.completed=T\u00E2che termin\u00E9e -label.template=Mod\u00E8le -label.template.limits=Limites de mod\u00E8le -label.theme.default=Th\u00E8me par d\u00E9faut -label.theme.grey=Personnalis\u00E9 - Gris -label.theme.lightblue=Personnalis\u00E9 - Bleu clair +label.task.completed=T\u00e2che termin\u00e9e +label.template.limits=Limites de mod\u00e8le +label.template=Mod\u00e8le +label.TFTP.dir=R\u00e9pertoire TFTP +label.theme.default=Th\u00e8me par d\u00e9faut +label.theme.grey=Personnalis\u00e9 - Gris +label.theme.lightblue=Personnalis\u00e9 - Bleu clair label.thursday=Jeudi +label.tier.details=D\u00e9tails du tiers label.tier=Tiers -label.tier.details=D\u00E9tails du tiers +label.timeout=D\u00e9lai d\\'expiration +label.timeout.in.second = D\u00e9lai d\\'expiration (secondes) label.time=Temps label.time.zone=Fuseau horaire -label.timeout=D\u00E9lai d\\'expiration -label.timeout.in.second=D\u00E9lai d\\'expiration (secondes) label.timezone=Fuseau horaire label.token=Jeton unique -label.total.CPU=Capacit\u00E9 totale en CPU -label.total.cpu=Capacit\u00E9 Totale en CPU -label.total.hosts=Total H\u00F4tes -label.total.memory=Total m\u00E9moire +label.total.cpu=Capacit\u00e9 Totale en CPU +label.total.CPU=Capacit\u00e9 totale en CPU +label.total.hosts=Total H\u00f4tes +label.total.memory=Total m\u00e9moire label.total.of.ip=Total adresses IP label.total.of.vm=Total VM label.total.storage=Total stockage label.total.vms=Nombre total de VMs -label.traffic.label=Libell\u00E9 de trafic -label.traffic.type=Type de Trafic +label.traffic.label=Libell\u00e9 de trafic label.traffic.types=Types de trafic +label.traffic.type=Type de Trafic label.tuesday=Mardi -label.type=Type label.type.id=ID du Type +label.type=Type label.unavailable=Indisponible -label.unlimited=Illimit\u00E9 -label.untagged=Non Tagg\u00E9 -label.update.project.resources=Mettre \u00E0 jour les ressources du projet -label.update.ssl=Certificat SSL -label.update.ssl.cert=Certificat SSL -label.updating=Mise \u00E0 jour +label.unlimited=Illimit\u00e9 +label.untagged=Non Tagg\u00e9 +label.update.project.resources=Mettre \u00e0 jour les ressources du projet +label.update.ssl.cert= Certificat SSL +label.update.ssl= Certificat SSL +label.updating=Mise \u00e0 jour label.upload=Charger label.upload.volume=Charger un volume label.url=URL label.usage.interface=Interface Utilisation -label.used=Utilis\u00E9 -label.user=Utilisateur +label.used=Utilis\u00e9 label.username=Nom d\\'Utilisateur label.users=Utilisateurs +label.user=Utilisateur +label.use.vm.ip=Utiliser IP VM \: label.value=Valeur label.vcdcname=Nom du DC vCenter label.vcenter.cluster=Cluster vCenter label.vcenter.datacenter=Datacenter vCenter label.vcenter.datastore=Datastore vCenter -label.vcenter.host=H\u00F4te vCenter +label.vcenter.host=H\u00f4te vCenter label.vcenter.password=Mot de passe vCenter label.vcenter.username=Nom d\\'utilisateur vCenter label.vcipaddress=Adresse IP vCenter label.version=Version -label.view=Voir label.view.all=Voir tout label.view.console=Voir la console -label.view.more=Voir plus label.viewing=Consultation en cours +label.view.more=Voir plus +label.view=Voir label.virtual.appliance=Appliance Virtuelle label.virtual.appliances=Appliances Virtuelles label.virtual.machines=Machines virtuelles -label.virtual.network=R\u00E9seau virtuel +label.virtual.network=R\u00e9seau virtuel label.virtual.router=Routeur Virtuel label.virtual.routers=Routeurs virtuels -label.vlan=VLAN label.vlan.id=ID du VLAN label.vlan.range=Plage du VLAN +label.vlan=VLAN label.vm.add=Ajouter une instance -label.vm.destroy=D\u00E9truire +label.vm.destroy=D\u00e9truire label.vm.display.name=Nom commun VM -label.vm.name=Nom de la VM -label.vm.reboot=Red\u00E9marrer -label.vm.start=D\u00E9marrer -label.vm.state=\u00C9tat VM -label.vm.stop=Arr\u00EAter +label.VMFS.datastore=Magasin de donn\u00e9es VMFS label.vmfs=VMFS +label.vm.name=Nom de la VM +label.vm.reboot=Red\u00e9marrer +label.VMs.in.tier=Machines virtuelles dans le tiers +label.vmsnapshot.current=estCourant +label.vmsnapshot=Instantan\u00e9s VM +label.vmsnapshot.memory=M\u00e9more instantan\u00e9 +label.vmsnapshot.parentname=Parent +label.vmsnapshot.type=Type +label.vm.start=D\u00e9marrer +label.vm.state=\u00c9tat VM +label.vm.stop=Arr\u00eater label.vms=VMs -label.vmware.traffic.label=Libell\u00E9 pour le trafic VMware +label.vmware.traffic.label=Libell\u00e9 pour le trafic VMware label.volgroup=Groupe de Volume -label.volume=Volume label.volume.limits=Limites des volumes label.volume.name=Nom du volume label.volumes=Volumes -label.vpc=VPC +label.volume=Volume label.vpc.id=ID VPC -label.vpn=VPN +label.VPC.router.details=D\u00e9tails routeur VPC +label.vpc=VPC +label.VPN.connection=Connexion VPN label.vpn.customer.gateway=Passerelle VPN client -label.vsmctrlvlanid=\ ID VLAN Contr\u00F4le +label.VPN.customer.gateway=Passerelle VPN client +label.VPN.gateway=Passerelle VPN +label.vpn=VPN +label.vsmctrlvlanid=\ ID VLAN Contr\u00f4le label.vsmpktvlanid=ID VLAN Paquet label.vsmstoragevlanid=VLAN ID Stockage -label.vsphere.managed=G\u00E9r\u00E9e par vSphere +label.vsphere.managed=G\u00e9r\u00e9e par vSphere label.waiting=En attente label.warn=Avertissement label.wednesday=Mercredi @@ -1125,353 +1165,361 @@ label.weekly=Hebdomadaire label.welcome=Bienvenue label.welcome.cloud.console=Bienvenue dans la Console d\\'Administration label.what.is.cloudstack=Qu\\'est-ce-que CloudStack&\#8482; ? -label.xen.traffic.label=Libell\u00E9 pour le trafic XenServer +label.xen.traffic.label=Libell\u00e9 pour le trafic XenServer label.yes=Oui -label.zone=Zone -label.zone.details=D\u00E9tails de la zone +label.zone.details=D\u00e9tails de la zone label.zone.id=ID de la zone label.zone.name=Nom de zone -label.zone.step.1.title=\u00C9tape 1 \: S\u00E9lectionnez un r\u00E9seau -label.zone.step.2.title=\u00C9tape 2 \: Ajoutez une zone -label.zone.step.3.title=\u00C9tape 3 \: Ajoutez un Pod -label.zone.step.4.title=\u00C9tape 4 \: Ajoutez une plage d\\'adresses IP -label.zone.type=Type de zone -label.zone.wide=Transverse \u00E0 la zone -label.zoneWizard.trafficType.guest=Invit\u00E9 \: Trafic entre les machines virtuelles utilisateurs -label.zoneWizard.trafficType.management=Administration \: Trafic entre les ressources internes de CloudStack, incluant tous les composants qui communiquent avec le serveur d\\'administration, tels que les h\u00F4tes and les machines virtuelles Syst\u00E8mes CloudStack -label.zoneWizard.trafficType.public=Public \: Trafic entre Internet et les machines virtuelles dans le nuage -label.zoneWizard.trafficType.storage=Stockage \: Trafic entre les serveurs de stockages principaux et secondaires, tel que le transfert de machines virtuelles mod\u00E8les et des instantan\u00E9s de disques +label.zone.step.1.title=\u00c9tape 1 \: S\u00e9lectionnez un r\u00e9seau +label.zone.step.2.title=\u00c9tape 2 \: Ajoutez une zone +label.zone.step.3.title=\u00c9tape 3 \: Ajoutez un Pod +label.zone.step.4.title=\u00c9tape 4 \: Ajoutez une plage d\\'adresses IP label.zones=Zones -managed.state=\u00C9tat de la gestion -message.Zone.creation.complete=Cr\u00E9ation de la zone termin\u00E9e -message.acquire.new.ip=Confirmer l\\'acquisition d\\'une nouvelle adresse IP pour ce r\u00E9seau. +label.zone.type=Type de zone +label.zone.wide=Transverse \u00e0 la zone +label.zoneWizard.trafficType.guest=Invit\u00e9 \: Trafic entre les machines virtuelles utilisateurs +label.zoneWizard.trafficType.management=Administration \: Trafic entre les ressources internes de CloudStack, incluant tous les composants qui communiquent avec le serveur d\\'administration, tels que les h\u00f4tes and les machines virtuelles Syst\u00e8mes CloudStack +label.zoneWizard.trafficType.public=Public \: Trafic entre Internet et les machines virtuelles dans le nuage +label.zoneWizard.trafficType.storage=Stockage \: Trafic entre les serveurs de stockages principaux et secondaires, tel que le transfert de machines virtuelles mod\u00e8les et des instantan\u00e9s de disques +label.zone=Zone +managed.state=\u00c9tat de la gestion +message.acquire.new.ip=Confirmer l\\'acquisition d\\'une nouvelle adresse IP pour ce r\u00e9seau. message.acquire.new.ip.vpc=Veuillez confirmer que vous voulez une nouvelle adresse IP pour ce VPC -message.acquire.public.ip=S\u00E9lectionnez la zone dans laquelle vous voulez acqu\u00E9rir votre nouvelle adresse IP. -message.action.cancel.maintenance=Votre h\u00F4te a quitt\u00E9 la maintenance. Ce processus peut prendre jusqu\\'\u00E0 plusieurs minutes. +message.acquire.public.ip=S\u00e9lectionnez la zone dans laquelle vous voulez acqu\u00e9rir votre nouvelle adresse IP. message.action.cancel.maintenance.mode=Confirmer l\\'annulation de cette maintenance. -message.action.change.service.warning.for.instance=Votre instance doit \u00EAtre arr\u00EAt\u00E9e avant d\\'essayer de changer son offre de service. -message.action.change.service.warning.for.router=Votre routeur doit \u00EAtre arr\u00EAt\u00E9 avant d\\'essayer de changer son offre de service. -message.action.delete.ISO=\u00CAtes-vous s\u00FBr que vous souhaitez supprimer cette ISO. -message.action.delete.ISO.for.all.zones=L\\'ISO est utilis\u00E9 par toutes les zones. S\\'il vous pla\u00EEt confirmer que vous voulez le supprimer de toutes les zones. -message.action.delete.cluster=\u00CAtes-vous s\u00FBr que vous voulez supprimer ce cluster. -message.action.delete.disk.offering=\u00CAtes-vous s\u00FBr que vous souhaitez supprimer cette offre de disque. -message.action.delete.domain=\u00CAtes-vous s\u00FBr que vous voulez supprimer ce domaine. -message.action.delete.external.firewall=\u00CAtes-vous s\u00FBr que vous souhaitez supprimer ce pare-feu externe. Attention \: Si vous pr\u00E9voyez de rajouter le m\u00EAme pare-feu externe de nouveau, vous devez r\u00E9-initialiser les donn\u00E9es d\\'utilisation sur l\\'appareil. -message.action.delete.external.load.balancer=\u00CAtes-vous s\u00FBr que vous souhaitez supprimer ce r\u00E9partiteur de charge externe. Attention \: Si vous pensez ajouter le m\u00EAme r\u00E9partiteur de charge plus tard, vous devez remettre \u00E0 z\u00E9ro les statistiques d\\'utilisation de cet \u00E9quipement. -message.action.delete.ingress.rule=\u00CAtes-vous s\u00FBr que vous souhaitez supprimer cette r\u00E8gle d\\'entr\u00E9e. -message.action.delete.network=\u00CAtes-vous s\u00FBr que vous voulez supprimer ce r\u00E9seau. +message.action.cancel.maintenance=Votre h\u00f4te a quitt\u00e9 la maintenance. Ce processus peut prendre jusqu\\'\u00e0 plusieurs minutes. +message.action.change.service.warning.for.instance=Votre instance doit \u00eatre arr\u00eat\u00e9e avant d\\'essayer de changer son offre de service. +message.action.change.service.warning.for.router=Votre routeur doit \u00eatre arr\u00eat\u00e9 avant d\\'essayer de changer son offre de service. +message.action.delete.cluster=\u00cates-vous s\u00fbr que vous voulez supprimer ce cluster. +message.action.delete.disk.offering=\u00cates-vous s\u00fbr que vous souhaitez supprimer cette offre de disque. +message.action.delete.domain=\u00cates-vous s\u00fbr que vous voulez supprimer ce domaine. +message.action.delete.external.firewall=\u00cates-vous s\u00fbr que vous souhaitez supprimer ce pare-feu externe. Attention \: Si vous pr\u00e9voyez de rajouter le m\u00eame pare-feu externe de nouveau, vous devez r\u00e9-initialiser les donn\u00e9es d\\'utilisation sur l\\'appareil. +message.action.delete.external.load.balancer=\u00cates-vous s\u00fbr que vous souhaitez supprimer ce r\u00e9partiteur de charge externe. Attention \: Si vous pensez ajouter le m\u00eame r\u00e9partiteur de charge plus tard, vous devez remettre \u00e0 z\u00e9ro les statistiques d\\'utilisation de cet \u00e9quipement. +message.action.delete.ingress.rule=\u00cates-vous s\u00fbr que vous souhaitez supprimer cette r\u00e8gle d\\'entr\u00e9e. +message.action.delete.ISO.for.all.zones=L\\'ISO est utilis\u00e9 par toutes les zones. S\\'il vous pla\u00eet confirmer que vous voulez le supprimer de toutes les zones. +message.action.delete.ISO=\u00cates-vous s\u00fbr que vous souhaitez supprimer cette ISO. +message.action.delete.network=\u00cates-vous s\u00fbr que vous voulez supprimer ce r\u00e9seau. message.action.delete.nexusVswitch=Confirmer la suppession de ce Nexus 1000v -message.action.delete.physical.network=Confirmer la suppression du r\u00E9seau physique -message.action.delete.pod=\u00CAtes-vous s\u00FBr que vous souhaitez supprimer ce pod. -message.action.delete.primary.storage=\u00CAtes-vous s\u00FBr que vous voulez supprimer ce stockage principal. -message.action.delete.secondary.storage=\u00CAtes-vous s\u00FBr que vous souhaitez supprimer ce stockage secondaire. -message.action.delete.security.group=\u00CAtes-vous s\u00FBr que vous souhaitez supprimer ce groupe de s\u00E9curit\u00E9. -message.action.delete.service.offering=\u00CAtes-vous s\u00FBr que vous souhaitez supprimer cette offre de service. -message.action.delete.snapshot=\u00CAtes-vous s\u00FBr que vous souhaitez supprimer cet instantan\u00E9 -message.action.delete.system.service.offering=\u00CAtes-vous s\u00FBr que vous voulez supprimer l\\'offre syst\u00E8me. -message.action.delete.template=\u00CAtes-vous s\u00FBr que vous souhaitez supprimer ce mod\u00E8le. -message.action.delete.template.for.all.zones=Ce mod\u00E8le est utilis\u00E9 par toutes les zones. \u00CAtes-vous s\u00FBr que vous souhaitez le supprimer de toutes les zones. -message.action.delete.volume=\u00CAtes-vous s\u00FBr que vous souhaitez supprimer ce volume. -message.action.delete.zone=\u00CAtes-vous s\u00FBr que vous souhaitez supprimer cette zone. -message.action.destroy.instance=\u00CAtes-vous s\u00FBr que vous souhaitez supprimer cette instance. -message.action.destroy.systemvm=\u00CAtes-vous s\u00FBr que vous souhaitez supprimer cette VM Syst\u00E8me. -message.action.disable.cluster=\u00CAtes-vous s\u00FBr que vous souhaitez d\u00E9sactiver ce cluster -message.action.disable.nexusVswitch=Confirmer la d\u00E9sactivation de ce Nexus 1000v -message.action.disable.physical.network=Confirmer l\\'activation de ce r\u00E9seau physique. -message.action.disable.pod=\u00CAtes-vous s\u00FBr que vous souhaitez d\u00E9sactiver ce Pod -message.action.disable.static.NAT=\u00CAtes-vous s\u00FBr que vous souhaitez d\u00E9sactiver le NAT statique. -message.action.disable.zone=\u00CAtes-vous s\u00FBr que vous souhaitez d\u00E9sactiver cette zone -message.action.download.iso=Confirmer le t\u00E9l\u00E9chargement de cet ISO -message.action.download.template=Confirmer le t\u00E9l\u00E9chargement de ce mod\u00E8le -message.action.enable.cluster=\u00CAtes-vous s\u00FBr que vous souhaitez activer ce cluster -message.action.enable.maintenance=Votre h\u00F4te a \u00E9t\u00E9 mis en mode maintenance avec succ\u00E8s. Ce processus peut durer plusieurs minutes ou plus, suivant le nombre de VMs actives sur cet h\u00F4te. +message.action.delete.physical.network=Confirmer la suppression du r\u00e9seau physique +message.action.delete.pod=\u00cates-vous s\u00fbr que vous souhaitez supprimer ce pod. +message.action.delete.primary.storage=\u00cates-vous s\u00fbr que vous voulez supprimer ce stockage principal. +message.action.delete.secondary.storage=\u00cates-vous s\u00fbr que vous souhaitez supprimer ce stockage secondaire. +message.action.delete.security.group=\u00cates-vous s\u00fbr que vous souhaitez supprimer ce groupe de s\u00e9curit\u00e9. +message.action.delete.service.offering=\u00cates-vous s\u00fbr que vous souhaitez supprimer cette offre de service. +message.action.delete.snapshot=\u00cates-vous s\u00fbr que vous souhaitez supprimer cet instantan\u00e9 +message.action.delete.system.service.offering=\u00cates-vous s\u00fbr que vous voulez supprimer l\\'offre syst\u00e8me. +message.action.delete.template.for.all.zones=Ce mod\u00e8le est utilis\u00e9 par toutes les zones. \u00cates-vous s\u00fbr que vous souhaitez le supprimer de toutes les zones. +message.action.delete.template=\u00cates-vous s\u00fbr que vous souhaitez supprimer ce mod\u00e8le. +message.action.delete.volume=\u00cates-vous s\u00fbr que vous souhaitez supprimer ce volume. +message.action.delete.zone=\u00cates-vous s\u00fbr que vous souhaitez supprimer cette zone. +message.action.destroy.instance=\u00cates-vous s\u00fbr que vous souhaitez supprimer cette instance. +message.action.destroy.systemvm=\u00cates-vous s\u00fbr que vous souhaitez supprimer cette VM Syst\u00e8me. +message.action.disable.cluster=\u00cates-vous s\u00fbr que vous souhaitez d\u00e9sactiver ce cluster +message.action.disable.nexusVswitch=Confirmer la d\u00e9sactivation de ce Nexus 1000v +message.action.disable.physical.network=Confirmer l\\'activation de ce r\u00e9seau physique. +message.action.disable.pod=\u00cates-vous s\u00fbr que vous souhaitez d\u00e9sactiver ce Pod +message.action.disable.static.NAT=\u00cates-vous s\u00fbr que vous souhaitez d\u00e9sactiver le NAT statique. +message.action.disable.zone=\u00cates-vous s\u00fbr que vous souhaitez d\u00e9sactiver cette zone +message.action.download.iso=Confirmer le t\u00e9l\u00e9chargement de cet ISO +message.action.download.template=Confirmer le t\u00e9l\u00e9chargement de ce mod\u00e8le +message.action.enable.cluster=\u00cates-vous s\u00fbr que vous souhaitez activer ce cluster +message.action.enable.maintenance=Votre h\u00f4te a \u00e9t\u00e9 mis en mode maintenance avec succ\u00e8s. Ce processus peut durer plusieurs minutes ou plus, suivant le nombre de VMs actives sur cet h\u00f4te. message.action.enable.nexusVswitch=Confirmer l\\'activation de ce Nexus 1000v -message.action.enable.physical.network=Confirmer l\\'activation de ce r\u00E9seau physique. -message.action.enable.pod=\u00CAtes-vous s\u00FBr que vous souhaitez activer ce Pod -message.action.enable.zone=\u00CAtes-vous s\u00FBr que vous souhaitez activer cette zone -message.action.force.reconnect=Votre h\u00F4te a \u00E9t\u00E9 forc\u00E9e \u00E0 se reconnecter avec succ\u00E8s. Ce processus peut prendre jusqu\\'\u00E0 plusieurs minutes. -message.action.host.enable.maintenance.mode=Activer le mode maintenance va causer la migration \u00E0 chaud de l\\'ensemble des instances de cet h\u00F4te sur les autres h\u00F4tes disponibles. +message.action.enable.physical.network=Confirmer l\\'activation de ce r\u00e9seau physique. +message.action.enable.pod=\u00cates-vous s\u00fbr que vous souhaitez activer ce Pod +message.action.enable.zone=\u00cates-vous s\u00fbr que vous souhaitez activer cette zone +message.action.force.reconnect=Votre h\u00f4te a \u00e9t\u00e9 forc\u00e9e \u00e0 se reconnecter avec succ\u00e8s. Ce processus peut prendre jusqu\\'\u00e0 plusieurs minutes. +message.action.host.enable.maintenance.mode=Activer le mode maintenance va causer la migration \u00e0 chaud de l\\'ensemble des instances de cet h\u00f4te sur les autres h\u00f4tes disponibles. message.action.instance.reset.password=Confirmer le changement du mot de passe ROOT pour cette machine virtuelle. -message.action.manage.cluster=\u00CAtes-vous s\u00FBr que vous souhaitez g\u00E9rer le cluster -message.action.primarystorage.enable.maintenance.mode=Attention \: placer ce stockage principal en mode maintenance va provoquer l\\'arr\u00EAt de l\\'ensemble des VMs utilisant des volumes sur ce stockage. Souhaitez-vous continuer ? -message.action.reboot.instance=\u00CAtes-vous s\u00FBr que vous souhaitez red\u00E9marrer cette instance. -message.action.reboot.router=Tous les services fournit par ce routeur virtuel vont \u00EAtre interrompus. Confirmer le r\u00E9-amor\u00E7age de ce routeur. -message.action.reboot.systemvm=\u00CAtes-vous s\u00FBr que vous souhaitez red\u00E9marrer cette VM Syst\u00E8me -message.action.release.ip=\u00CAtes-vous s\u00FBr que vous souhaitez lib\u00E9rer cette IP. -message.action.remove.host=\u00CAtes-vous s\u00FBr que vous voulez supprimer cet h\u00F4te. -message.action.reset.password.off=Votre instance ne supporte pas pour le moment cette fonctionnalit\u00E9. -message.action.reset.password.warning=Votre instance doit \u00EAtre arr\u00EAt\u00E9e avant d\\'essayer de changer son mot de passe. -message.action.restore.instance=\u00CAtes-vous s\u00FBr que vous souhaitez restaurer cette instance. -message.action.start.instance=\u00CAtes-vous s\u00FBr que vous souhaitez d\u00E9marrer cette instance. -message.action.start.router=\u00CAtes-vous s\u00FBr que vous souhaitez d\u00E9marrer ce routeur. -message.action.start.systemvm=\u00CAtes-vous s\u00FBr que vous souhaitez red\u00E9marrer cette VM syst\u00E8me. -message.action.stop.instance=\u00CAtes-vous s\u00FBr que vous souhaitez arr\u00EAter cette instance. -message.action.stop.router=Tous les services fournit par ce routeur virtuel vont \u00EAtre interrompus. Confirmer l\\'arr\u00EAt de ce routeur. -message.action.stop.systemvm=\u00CAtes-vous s\u00FBr que vous souhaitez arr\u00EAter cette VM. -message.action.take.snapshot=Confirmer la prise d\\'un instantan\u00E9 pour ce volume. -message.action.unmanage.cluster=Confirmez que vous ne voulez plus g\u00E9rer le cluster -message.activate.project=\u00CAtes-vous s\u00FBr de vouloir activer ce projet ? -message.add.VPN.gateway=Confirmer l\\'ajout d\\'une passerelle VPN -message.add.cluster=Ajouter un cluster d\\'hyperviseurs g\u00E9r\u00E9 pour cette zone , pod -message.add.cluster.zone=Ajouter un cluster d\\'hyperviseurs g\u00E9r\u00E9 pour cette zone -message.add.disk.offering=Renseignez les param\u00E8tres suivants pour ajouter un offre de service de disques -message.add.domain=Sp\u00E9cifier le sous domaine que vous souhaitez cr\u00E9er sous ce domaine -message.add.firewall=Ajouter un pare-feu \u00E0 cette zone -message.add.guest.network=Confirmer l\\'ajout du r\u00E9seau invit\u00E9 -message.add.host=Renseignez les param\u00E8tres suivants pour ajouter une h\u00F4te -message.add.ip.range=Ajouter une plage IP pour le r\u00E9seau publique dans la zone -message.add.ip.range.direct.network=Ajouter une plage IP au r\u00E9seau direct dans la zone -message.add.ip.range.to.pod=

Ajouter une plage IP pour le pod\:

-message.add.load.balancer=Ajouter un r\u00E9partiteur de charge \u00E0 la zone -message.add.load.balancer.under.ip=La r\u00E8gle de r\u00E9partition de charge \u00E9t\u00E9 ajout\u00E9e sous l\\'adresse IP \: -message.add.network=Ajouter un nouveau r\u00E9seau \u00E0 la zone\: -message.add.new.gateway.to.vpc=Renseigner les informations suivantes pour ajouter une nouvelle passerelle pour ce VPC -message.add.pod=Ajouter un nouveau pod \u00E0 la zone -message.add.pod.during.zone.creation=Chaque zone doit contenir un ou plusieurs pods, et le premier pod sera ajout\u00E9 maintenant. Une pod contient les h\u00F4tes et les serveurs de stockage principal, qui seront ajout\u00E9s dans une \u00E9tape ult\u00E9rieure. Configurer une plage d\\'adresses IP r\u00E9serv\u00E9es pour le trafic de gestion interne de CloudStack. La plage d\\'IP r\u00E9serv\u00E9e doit \u00EAtre unique pour chaque zone dans le nuage. -message.add.primary=Renseignez les param\u00E8tres suivants pour ajouter un stockage principal -message.add.primary.storage=Ajouter un nouveau stockage principal \u00E0 la zone , pod -message.add.secondary.storage=Ajouter un nouveau stockage pour la zone -message.add.service.offering=Renseigner les informations suivantes pour ajouter une nouvelle offre de service de calcul. -message.add.system.service.offering=Ajouter les informations suivantes pour cr\u00E9er une nouvelle offre syst\u00E8me. -message.add.template=Renseignez les informations suivantes pour cr\u00E9er votre nouveau mod\u00E8le -message.add.volume=Renseignez les informations suivantes pour ajouter un nouveau volume +message.action.manage.cluster=\u00cates-vous s\u00fbr que vous souhaitez g\u00e9rer le cluster +message.action.primarystorage.enable.maintenance.mode=Attention \: placer ce stockage principal en mode maintenance va provoquer l\\'arr\u00eat de l\\'ensemble des VMs utilisant des volumes sur ce stockage. Souhaitez-vous continuer ? +message.action.reboot.instance=\u00cates-vous s\u00fbr que vous souhaitez red\u00e9marrer cette instance. +message.action.reboot.router=Tous les services fournit par ce routeur virtuel vont \u00eatre interrompus. Confirmer le r\u00e9-amor\u00e7age de ce routeur. +message.action.reboot.systemvm=\u00cates-vous s\u00fbr que vous souhaitez red\u00e9marrer cette VM Syst\u00e8me +message.action.release.ip=\u00cates-vous s\u00fbr que vous souhaitez lib\u00e9rer cette IP. +message.action.remove.host=\u00cates-vous s\u00fbr que vous voulez supprimer cet h\u00f4te. +message.action.reset.password.off=Votre instance ne supporte pas pour le moment cette fonctionnalit\u00e9. +message.action.reset.password.warning=Votre instance doit \u00eatre arr\u00eat\u00e9e avant d\\'essayer de changer son mot de passe. +message.action.restore.instance=\u00cates-vous s\u00fbr que vous souhaitez restaurer cette instance. +message.action.start.instance=\u00cates-vous s\u00fbr que vous souhaitez d\u00e9marrer cette instance. +message.action.start.router=\u00cates-vous s\u00fbr que vous souhaitez d\u00e9marrer ce routeur. +message.action.start.systemvm=\u00cates-vous s\u00fbr que vous souhaitez red\u00e9marrer cette VM syst\u00e8me. +message.action.stop.instance=\u00cates-vous s\u00fbr que vous souhaitez arr\u00eater cette instance. +message.action.stop.router=Tous les services fournit par ce routeur virtuel vont \u00eatre interrompus. Confirmer l\\'arr\u00eat de ce routeur. +message.action.stop.systemvm=\u00cates-vous s\u00fbr que vous souhaitez arr\u00eater cette VM. +message.action.take.snapshot=Confirmer la prise d\\'un instantan\u00e9 pour ce volume. +message.action.unmanage.cluster=Confirmez que vous ne voulez plus g\u00e9rer le cluster +message.action.vmsnapshot.delete=Confirmez que vous souhaitez supprimer cet instantan\u00e9 VM. +message.action.vmsnapshot.revert=Revenir \u00e0 un instantan\u00e9 VM +message.activate.project=\u00cates-vous s\u00fbr de vouloir activer ce projet ? +message.add.cluster=Ajouter un cluster d\\'hyperviseurs g\u00e9r\u00e9 pour cette zone , pod +message.add.cluster.zone=Ajouter un cluster d\\'hyperviseurs g\u00e9r\u00e9 pour cette zone +message.add.disk.offering=Renseignez les param\u00e8tres suivants pour ajouter un offre de service de disques +message.add.domain=Sp\u00e9cifier le sous domaine que vous souhaitez cr\u00e9er sous ce domaine +message.add.firewall=Ajouter un pare-feu \u00e0 cette zone +message.add.guest.network=Confirmer l\\'ajout du r\u00e9seau invit\u00e9 +message.add.host=Renseignez les param\u00e8tres suivants pour ajouter une h\u00f4te +message.adding.host=Ajout un h\u00f4te message.adding.Netscaler.device=Ajouter un Netscaler message.adding.Netscaler.provider=Ajouter un fournisseur Netscaler -message.adding.host=Ajout un h\u00F4te -message.additional.networks.desc=S\u00E9lectionnez le(s) r\u00E9seau(x) additionnel(s) au(x)quel(s) sera connect\u00E9e votre instance. -message.advanced.mode.desc=Choisissez ce mod\u00E8le de r\u00E9seau si vous souhaitez b\u00E9n\u00E9ficier du support des VLANs. Ce mode de r\u00E9seau donne le plus de flexibilit\u00E9 aux administrateurs pour fournir des offres de service r\u00E9seau personnalis\u00E9es comme fournir des pare-feux, VPN, r\u00E9partiteurs de charge ou \u00E9galement activer des r\u00E9seaux virtuels ou directs. -message.advanced.security.group=Choisissez ceci si vous souhaitez utiliser les groupes de s\u00E9curit\u00E9 pour fournir l\\'isolation des VMs invit\u00E9es. -message.advanced.virtual=Choisissez ceci si vous souhaitez utiliser des VLANs pour fournir l\\'isolation des VMs invit\u00E9es. -message.after.enable.s3=Le stockage secondaire S3 est configur\u00E9. Note \: Quand vous quitterez cette page, vous ne pourrez plus re-configurer le support S3. -message.after.enable.swift=Swift configur\u00E9. Remarque \: une fois que vous quitterez cette page, il ne sera plus possible de re-configurer Swift \u00E0 nouveau. -message.alert.state.detected=\u00C9tat d\\'alerte d\u00E9tect\u00E9 -message.allow.vpn.access=Entrez un nom d\\'utilisateur et un mot de passe pour l\\'utilisateur que vous souhaitez autoriser \u00E0 utiliser l\\'acc\u00E8s VPN. -message.apply.snapshot.policy=Vous avez mis \u00E0 jour votre politique d\\'instantan\u00E9s avec succ\u00E8s. -message.attach.iso.confirm=\u00CAtes-vous s\u00FBr que vous souhaitez attacher l\\'image ISO \u00E0 cette instance. -message.attach.volume=Renseignez les donn\u00E9es suivantes pour attacher un nouveau volume. Si vous attachez un volume disque \u00E0 une machine virtuelle sous Windows, vous aurez besoin de red\u00E9marrer l\\'instance pour voir le nouveau disque. -message.basic.mode.desc=Choisissez ce mod\u00E8le de r\u00E9seau si vous *ne voulez pas* activer le support des VLANs. Toutes les instances cr\u00E9\u00E9es avec ce mod\u00E8le de r\u00E9seau se verront assigner une adresse IP et les groupes de s\u00E9curit\u00E9 seront utilis\u00E9s pour fournir l\\'isolation entre les VMs. -message.change.offering.confirm=\u00CAtes-vous s\u00FBr que vous souhaitez changer l\\'offre de service de cette instance. +message.add.ip.range=Ajouter une plage IP pour le r\u00e9seau publique dans la zone +message.add.ip.range.direct.network=Ajouter une plage IP au r\u00e9seau direct dans la zone +message.add.ip.range.to.pod=

Ajouter une plage IP pour le pod\:

+message.additional.networks.desc=S\u00e9lectionnez le(s) r\u00e9seau(x) additionnel(s) au(x)quel(s) sera connect\u00e9e votre instance. +message.add.load.balancer=Ajouter un r\u00e9partiteur de charge \u00e0 la zone +message.add.load.balancer.under.ip=La r\u00e8gle de r\u00e9partition de charge \u00e9t\u00e9 ajout\u00e9e sous l\\'adresse IP \: +message.add.network=Ajouter un nouveau r\u00e9seau \u00e0 la zone\: +message.add.new.gateway.to.vpc=Renseigner les informations suivantes pour ajouter une nouvelle passerelle pour ce VPC +message.add.pod=Ajouter un nouveau pod \u00e0 la zone +message.add.pod.during.zone.creation=Chaque zone doit contenir un ou plusieurs pods, et le premier pod sera ajout\u00e9 maintenant. Une pod contient les h\u00f4tes et les serveurs de stockage primaire, qui seront ajout\u00e9s dans une \u00e9tape ult\u00e9rieure. Configurer une plage d\\'adresses IP r\u00e9serv\u00e9es pour le trafic de gestion interne de CloudStack. La plage d\\'IP r\u00e9serv\u00e9e doit \u00eatre unique pour chaque zone dans le nuage. +message.add.primary=Renseignez les param\u00e8tres suivants pour ajouter un stockage principal +message.add.primary.storage=Ajouter un nouveau stockage principal \u00e0 la zone , pod +message.add.region=Renseigner les informations suivantes pour ajouter une nouvelle r\u00e9gion. +message.add.secondary.storage=Ajouter un nouveau stockage pour la zone +message.add.service.offering=Renseigner les informations suivantes pour ajouter une nouvelle offre de service de calcul. +message.add.system.service.offering=Ajouter les informations suivantes pour cr\u00e9er une nouvelle offre syst\u00e8me. +message.add.template=Renseignez les informations suivantes pour cr\u00e9er votre nouveau mod\u00e8le +message.add.volume=Renseignez les informations suivantes pour ajouter un nouveau volume +message.add.VPN.gateway=Confirmer l\\'ajout d\\'une passerelle VPN +message.advanced.mode.desc=Choisissez ce mod\u00e8le de r\u00e9seau si vous souhaitez b\u00e9n\u00e9ficier du support des VLANs. Ce mode de r\u00e9seau donne le plus de flexibilit\u00e9 aux administrateurs pour fournir des offres de service r\u00e9seau personnalis\u00e9es comme fournir des pare-feux, VPN, r\u00e9partiteurs de charge ou \u00e9galement activer des r\u00e9seaux virtuels ou directs. +message.advanced.security.group=Choisissez ceci si vous souhaitez utiliser les groupes de s\u00e9curit\u00e9 pour fournir l\\'isolation des VMs invit\u00e9es. +message.advanced.virtual=Choisissez ceci si vous souhaitez utiliser des VLANs pour fournir l\\'isolation des VMs invit\u00e9es. +message.after.enable.s3=Le stockage secondaire S3 est configur\u00e9. Note \: Quand vous quitterez cette page, vous ne pourrez plus re-configurer le support S3. +message.after.enable.swift=Swift configur\u00e9. Remarque \: une fois que vous quitterez cette page, il ne sera plus possible de re-configurer Swift \u00e0 nouveau. +message.alert.state.detected=\u00c9tat d\\'alerte d\u00e9tect\u00e9 +message.allow.vpn.access=Entrez un nom d\\'utilisateur et un mot de passe pour l\\'utilisateur que vous souhaitez autoriser \u00e0 utiliser l\\'acc\u00e8s VPN. +message.apply.snapshot.policy=Vous avez mis \u00e0 jour votre politique d\\'instantan\u00e9s avec succ\u00e8s. +message.attach.iso.confirm=\u00cates-vous s\u00fbr que vous souhaitez attacher l\\'image ISO \u00e0 cette instance. +message.attach.volume=Renseignez les donn\u00e9es suivantes pour attacher un nouveau volume. Si vous attachez un volume disque \u00e0 une machine virtuelle sous Windows, vous aurez besoin de red\u00e9marrer l\\'instance pour voir le nouveau disque. +message.basic.mode.desc=Choisissez ce mod\u00e8le de r\u00e9seau si vous *ne voulez pas* activer le support des VLANs. Toutes les instances cr\u00e9\u00e9es avec ce mod\u00e8le de r\u00e9seau se verront assigner une adresse IP et les groupes de s\u00e9curit\u00e9 seront utilis\u00e9s pour fournir l\\'isolation entre les VMs. +message.change.offering.confirm=\u00cates-vous s\u00fbr que vous souhaitez changer l\\'offre de service de cette instance. message.change.password=Merci de modifier votre mot de passe. -message.configure.all.traffic.types=Vous avez de multiples r\u00E9seaux physiques ; veuillez configurer les libell\u00E9s pour chaque type de trafic en cliquant sur le bouton Modifier. -message.configuring.guest.traffic=Configuration du r\u00E9seau VM -message.configuring.physical.networks=Configuration des r\u00E9seaux physiques -message.configuring.public.traffic=Configuration du r\u00E9seau public -message.configuring.storage.traffic=Configuration du r\u00E9seau de stockage -message.confirm.action.force.reconnect=Confirmer la re-connexion forc\u00E9e de cet h\u00F4te. +message.configure.all.traffic.types=Vous avez de multiples r\u00e9seaux physiques ; veuillez configurer les libell\u00e9s pour chaque type de trafic en cliquant sur le bouton Modifier. +message.configuring.guest.traffic=Configuration du r\u00e9seau VM +message.configuring.physical.networks=Configuration des r\u00e9seaux physiques +message.configuring.public.traffic=Configuration du r\u00e9seau public +message.configuring.storage.traffic=Configuration du r\u00e9seau de stockage +message.confirm.action.force.reconnect=Confirmer la re-connexion forc\u00e9e de cet h\u00f4te. message.confirm.delete.F5=Confirmer la suppression du F5 message.confirm.delete.NetScaler=Confirmer la suppression du Netscaler message.confirm.delete.SRX=Confirmer la suppression du SRX -message.confirm.destroy.router=\u00CAtes-vous s\u00FBr que vous voulez supprimer ce routeur -message.confirm.disable.provider=Confirmer la d\u00E9sactivation de ce fournisseur +message.confirm.destroy.router=\u00cates-vous s\u00fbr que vous voulez supprimer ce routeur +message.confirm.disable.provider=Confirmer la d\u00e9sactivation de ce fournisseur message.confirm.enable.provider=Confirmer l\\'activation de ce fournisseur -message.confirm.join.project=\u00CAtes-vous s\u00FBr que vous souhaitez rejoindre ce projet. -message.confirm.remove.IP.range=\u00CAtes-vous s\u00FBr que vous voulez supprimer cette plage d\\'adresses IP -message.confirm.shutdown.provider=Confirmer l\\'arr\u00EAt de ce fournisseur -message.copy.iso.confirm=\u00CAtes-vous s\u00FBr que vous souhaitez copier votre image ISO vers -message.copy.template=Copier le mod\u00E8le XXX de la zone vers -message.create.template=Voulez vous cr\u00E9er un mod\u00E8le ? -message.create.template.vm=Cr\u00E9er la VM depuis le mod\u00E8le -message.create.template.volume=Renseignez les informations suivantes avec de cr\u00E9er un mod\u00E8le \u00E0 partir de votre volume de disque\:. La cr\u00E9ation du mod\u00E8le peut prendre plusieurs minutes suivant la taille du volume. -message.creating.cluster=Cr\u00E9ation du cluster -message.creating.guest.network=Cr\u00E9ation du r\u00E9seau pour les invit\u00E9s -message.creating.physical.networks=Cr\u00E9ation des r\u00E9seaux physiques -message.creating.pod=Cr\u00E9ation d\\'un pod -message.creating.primary.storage=Cr\u00E9ation du stockage principal -message.creating.secondary.storage=Cr\u00E9ation du stockage secondaire -message.creating.zone=Cr\u00E9ation de la zone +message.confirm.join.project=\u00cates-vous s\u00fbr que vous souhaitez rejoindre ce projet. +message.confirm.remove.IP.range=\u00cates-vous s\u00fbr que vous voulez supprimer cette plage d\\'adresses IP +message.confirm.shutdown.provider=Confirmer l\\'arr\u00eat de ce fournisseur +message.copy.iso.confirm=\u00cates-vous s\u00fbr que vous souhaitez copier votre image ISO vers +message.copy.template=Copier le mod\u00e8le XXX de la zone vers +message.create.template.vm=Cr\u00e9er la VM depuis le mod\u00e8le +message.create.template.volume=Renseignez les informations suivantes avec de cr\u00e9er un mod\u00e8le \u00e0 partir de votre volume de disque\:. La cr\u00e9ation du mod\u00e8le peut prendre plusieurs minutes suivant la taille du volume. +message.create.template=Voulez vous cr\u00e9er un mod\u00e8le ? +message.creating.cluster=Cr\u00e9ation du cluster +message.creating.guest.network=Cr\u00e9ation du r\u00e9seau pour les invit\u00e9s +message.creating.physical.networks=Cr\u00e9ation des r\u00e9seaux physiques +message.creating.pod=Cr\u00e9ation d\\'un pod +message.creating.primary.storage=Cr\u00e9ation du stockage principal +message.creating.secondary.storage=Cr\u00e9ation du stockage secondaire +message.creating.zone=Cr\u00e9ation de la zone message.decline.invitation=Voulez-vous refuser cette invitation au projet ? -message.delete.VPN.connection=\u00CAtes-vous s\u00FBr que vous voulez supprimer la connexion VPN -message.delete.VPN.customer.gateway=\u00CAtes-vous s\u00FBr que vous voulez supprimer cette passerelle VPN client -message.delete.VPN.gateway=\u00CAtes-vous s\u00FBr que vous voulez supprimer cette passerelle VPN -message.delete.account=\u00CAtes-vous s\u00FBr que vous souhaitez supprimer ce compte. -message.delete.gateway=\u00CAtes-vous s\u00FBr que vous voulez supprimer cette passerelle -message.delete.project=\u00CAtes-vous s\u00FBr de vouloir supprimer ce projet ? -message.delete.user=\u00CAtes-vous s\u00FBr que vous voulez supprimer cet utilisateur. -message.desc.advanced.zone=Pour des topologies de r\u00E9seau plus sophistiqu\u00E9es. Ce mod\u00E8le de r\u00E9seau permet plus de flexibilit\u00E9 dans la d\u00E9finition des r\u00E9seaux d\\'invit\u00E9s et propose des offres personnalis\u00E9es telles que le support de pare-feu, VPN ou d\\'\u00E9quilibrage de charge. -message.desc.basic.zone=Fournit un r\u00E9seau unique o\u00F9 chaque instance de machine virtuelle se voit attribuer une adresse IP directement depuis le r\u00E9seau. L\\'isolation des invit\u00E9s peut \u00EAtre assur\u00E9 au niveau de la couche r\u00E9seau-3 tels que les groupes de s\u00E9curit\u00E9 (filtrage d\\'adresse IP source). -message.desc.cluster=Chaque pod doit contenir un ou plusieurs clusters, et le premier cluster sera ajout\u00E9 tout de suite. Un cluster est un regroupement pour h\u00F4tes. Les h\u00F4tes d\\'un cluster ont tous un mat\u00E9riel identique, ex\u00E9cutent le m\u00EAme hyperviseur, sont dans le m\u00EAme sous-r\u00E9seau, et acc\u00E8dent au m\u00EAme stockage partag\u00E9. Chaque cluster comprend une ou plusieurs h\u00F4tes et un ou plusieurs serveurs de stockage principal. -message.desc.host=Chaque cluster doit contenir au moins un h\u00F4te (machine) pour ex\u00E9cuter des machines virtuelles invit\u00E9es, et le premier h\u00F4te sera ajout\u00E9 tout de suite. Pour un h\u00F4te fonctionnant dans CloudStack, vous devez installer un logiciel hyperviseur sur l\\'h\u00F4te, attribuer une adresse IP \u00E0 l\\'h\u00F4te, et s\\'assurer que l\\'h\u00F4te est connect\u00E9 au serveur d\\'administration CloudStack.

Indiquer le nom de l\\'h\u00F4te ou son adresse IP, l\\'identifiant de connexion (g\u00E9n\u00E9ralement root) et le mot de passe ainsi que toutes les \u00E9tiquettes permettant de classer les h\u00F4tes. -message.desc.primary.storage=Chaque cluster doit contenir un ou plusieurs serveurs de stockage principal, et le premier sera ajout\u00E9 tout de suite. Le stockage principal contient les volumes de disque pour les machines virtuelles s\\'ex\u00E9cutant sur les h\u00F4tes dans le cluster. Utiliser les protocoles standards pris en charge par l\\'hyperviseur sous-jacent. -message.desc.secondary.storage=Chaque zone doit avoir au moins un serveur NFS ou un serveur de stockage secondaire, et sera ajout\u00E9 en premier tout de suite. Le stockage secondaire entrepose les mod\u00E8les de machines virtuelles, les images ISO et les images disques des volumes des machines virtuelles. Ce serveur doit \u00EAtre accessible pour toutes les machines h\u00F4tes dans la zone.

Saisir l\\'adresse IP et le chemin d\\'export. -message.desc.zone=Une zone est la plus grande unit\u00E9 organisationnelle dans CloudStack, et correspond typiquement \u00E0 un centre de donn\u00E9es. Les zones fournissent un isolement physique et de la redondance. Une zone est constitu\u00E9e d\\'un ou plusieurs pods (dont chacun contient les h\u00F4tes et les serveurs de stockage principal) et un serveur de stockage secondaire qui est partag\u00E9e par tous les pods dans la zone. -message.detach.disk=Voulez-vous d\u00E9tacher ce disque ? -message.detach.iso.confirm=\u00CAtes-vous s\u00FBr que vous souhaitez d\u00E9tacher l\\'image ISO de cette instance. -message.disable.account=Veuillez confirmer que vous voulez d\u00E9sactiver ce compte. En d\u00E9sactivant le compte, tous les utilisateurs pour ce compte n\\'auront plus acc\u00E8s \u00E0 leurs ressources sur le cloud. Toutes les machines virtuelles vont \u00EAtre arr\u00EAt\u00E9es imm\u00E9diatement. -message.disable.snapshot.policy=Vous avez d\u00E9sactiv\u00E9 votre politique d\\'instantan\u00E9 avec succ\u00E8s. -message.disable.user=Confirmer la d\u00E9sactivation de cet utilisateur. -message.disable.vpn=\u00CAtes-vous s\u00FBr de vouloir d\u00E9sactiver le VPN ? -message.disable.vpn.access=\u00CAtes-vous s\u00FBr que vous souhaitez d\u00E9sactiver l\\'acc\u00E8s VPN. -message.download.ISO=Cliquer 00000 pour t\u00E9l\u00E9charger une image ISO -message.download.template=Cliquer sur 00000 pour t\u00E9l\u00E9charger le mod\u00E8le -message.download.volume=Cliquer sur 00000 pour t\u00E9l\u00E9charger le volume -message.download.volume.confirm=Confirmer le t\u00E9l\u00E9chargement du volume +message.delete.account=\u00cates-vous s\u00fbr que vous souhaitez supprimer ce compte. +message.delete.affinity.group=Confirmer la supression de ce groupe d\\'affinit\u00e9. +message.delete.gateway=\u00cates-vous s\u00fbr que vous voulez supprimer cette passerelle +message.delete.project=\u00cates-vous s\u00fbr de vouloir supprimer ce projet ? +message.delete.user=\u00cates-vous s\u00fbr que vous voulez supprimer cet utilisateur. +message.delete.VPN.connection=\u00cates-vous s\u00fbr que vous voulez supprimer la connexion VPN +message.delete.VPN.customer.gateway=\u00cates-vous s\u00fbr que vous voulez supprimer cette passerelle VPN client +message.delete.VPN.gateway=\u00cates-vous s\u00fbr que vous voulez supprimer cette passerelle VPN +message.desc.advanced.zone=Pour des topologies de r\u00e9seau plus sophistiqu\u00e9es. Ce mod\u00e8le de r\u00e9seau permet plus de flexibilit\u00e9 dans la d\u00e9finition des r\u00e9seaux d\\'invit\u00e9s et propose des offres personnalis\u00e9es telles que le support de pare-feu, VPN ou d\\'\u00e9quilibrage de charge. +message.desc.basic.zone=Fournit un r\u00e9seau unique o\u00f9 chaque instance de machine virtuelle se voit attribuer une adresse IP directement depuis le r\u00e9seau. L\\'isolation des invit\u00e9s peut \u00eatre assur\u00e9 au niveau de la couche r\u00e9seau-3 tels que les groupes de s\u00e9curit\u00e9 (filtrage d\\'adresse IP source). +message.desc.cluster=Chaque pod doit contenir un ou plusieurs clusters, et le premier cluster sera ajout\u00e9 tout de suite. Un cluster est un regroupement pour h\u00f4tes. Les h\u00f4tes d\\'un cluster ont tous un mat\u00e9riel identique, ex\u00e9cutent le m\u00eame hyperviseur, sont dans le m\u00eame sous-r\u00e9seau, et acc\u00e8dent au m\u00eame stockage partag\u00e9. Chaque cluster comprend une ou plusieurs h\u00f4tes et un ou plusieurs serveurs de stockage principal. +message.desc.host=Chaque cluster doit contenir au moins un h\u00f4te (machine) pour ex\u00e9ctuer des machines virtuelles invit\u00e9es, et le premier h\u00f4te sera ajout\u00e9e maintenant. Pour un h\u00f4te fonctionnant dans CloudStack, vous devez installer un logiciel hyperviseur sur l\\'h\u00f4te, attribuer une adresse IP \u00e0 l\\'h\u00f4te, et s\\'assurer que l\\'h\u00f4te est connect\u00e9 au serveur d\\'administration CloudStack.

Indiquer le nom de l\\'h\u00f4te ou son adresse IP, l\\'identifiant de connexion (g\u00e9n\u00e9ralement root) et le mot de passe ainsi que toutes les \u00e9tiquettes permettant de classer les h\u00f4tes. +message.desc.primary.storage=Chaque cluster doit contenir un ou plusieurs serveurs de stockage principal, et le premier sera ajout\u00e9 tout de suite. Le stockage principal contient les volumes de disque pour les machines virtuelles s\\'ex\u00e9cutant sur les h\u00f4tes dans le cluster. Utiliser les protocoles standards pris en charge par l\\'hyperviseur sous-jacent. +message.desc.secondary.storage=Chaque zone doit avoir au moins un serveur NFS ou un serveur de stockage secondaire, et sera ajout\u00e9 en premier tout de suite. Le stockage secondaire entrepose les mod\u00e8les de machines virtuelles, les images ISO et les images disques des volumes des machines virtuelles. Ce serveur doit \u00eatre accessible pour toutes les machines h\u00f4tes dans la zone.

Saisir l\\'adresse IP et le chemin d\\'export. +message.desc.zone=Une zone est la plus grande unit\u00e9 organisationnelle dans CloudStack, et correspond typiquement \u00e0 un centre de donn\u00e9es. Les zones fournissent un isolement physique et de la redondance. Une zone est constitu\u00e9e d\\'un ou plusieurs pods (dont chacun contient les h\u00f4tes et les serveurs de stockage principal) et un serveur de stockage secondaire qui est partag\u00e9e par tous les pods dans la zone. +message.detach.disk=Voulez-vous d\u00e9tacher ce disque ? +message.detach.iso.confirm=\u00cates-vous s\u00fbr que vous souhaitez d\u00e9tacher l\\'image ISO de cette instance. +message.disable.account=Veuillez confirmer que vous voulez d\u00e9sactiver ce compte. En d\u00e9sactivant le compte, tous les utilisateurs pour ce compte n\\'auront plus acc\u00e8s \u00e0 leurs ressources sur le cloud. Toutes les machines virtuelles vont \u00eatre arr\u00eat\u00e9es imm\u00e9diatement. +message.disable.snapshot.policy=Vous avez d\u00e9sactiv\u00e9 votre politique d\\'instantan\u00e9 avec succ\u00e8s. +message.disable.user=Confirmer la d\u00e9sactivation de cet utilisateur. +message.disable.vpn.access=\u00cates-vous s\u00fbr que vous souhaitez d\u00e9sactiver l\\'acc\u00e8s VPN. +message.disable.vpn=\u00cates-vous s\u00fbr de vouloir d\u00e9sactiver le VPN ? +message.download.ISO=Cliquer 00000 pour t\u00e9l\u00e9charger une image ISO +message.download.template=Cliquer sur 00000 pour t\u00e9l\u00e9charger le mod\u00e8le +message.download.volume=Cliquer sur 00000 pour t\u00e9l\u00e9charger le volume +message.download.volume.confirm=Confirmer le t\u00e9l\u00e9chargement du volume message.edit.account=Modifier ("-1" signifie pas de limite de ressources) message.edit.confirm=Confirmer les changements avant de cliquer sur "Enregistrer". -message.edit.limits=Renseignez les limites pour les ressources suivantes. "-1" indique qu\\'il n\\'y a pas de limites pour la cr\u00E9ation de ressources. -message.edit.traffic.type=Sp\u00E9cifier le libell\u00E9 de trafic associ\u00E9 avec ce type de trafic. -message.enable.account=\u00CAtes-vous s\u00FBr que vous souhaitez activer ce compte. +message.edit.limits=Renseignez les limites pour les ressources suivantes. "-1" indique qu\\'il n\\'y a pas de limites pour la cr\u00e9ation de ressources. +message.edit.traffic.type=Sp\u00e9cifier le libell\u00e9 de trafic associ\u00e9 avec ce type de trafic. +message.enable.account=\u00cates-vous s\u00fbr que vous souhaitez activer ce compte. +message.enabled.vpn.ip.sec=Votre cl\u00e9 partag\u00e9e IPSec est +message.enabled.vpn=Votre acc\u00e8s VPN est activ\u00e9 et peut \u00eatre acc\u00e9d\u00e9 par l\\'IP message.enable.user=Confirmer l\\'activation de cet utilisateur. -message.enable.vpn=Confirmer l\\'activation de l\\'acc\u00E8s VPN pour cette adresse IP. -message.enable.vpn.access=Le VPN est d\u00E9sactiv\u00E9 pour cette adresse IP. Voulez vous activer l\\'acc\u00E8s VPN ? -message.enabled.vpn=Votre acc\u00E8s VPN est activ\u00E9 et peut \u00EAtre acc\u00E9d\u00E9 par l\\'IP -message.enabled.vpn.ip.sec=Votre cl\u00E9 partag\u00E9e IPSec est -message.enabling.security.group.provider=Activation du fournisseur de groupe de s\u00E9curit\u00E9 +message.enable.vpn.access=Le VPN est d\u00e9sactiv\u00e9 pour cette adresse IP. Voulez vous activer l\\'acc\u00e8s VPN ? +message.enable.vpn=Confirmer l\\'activation de l\\'acc\u00e8s VPN pour cette adresse IP. +message.enabling.security.group.provider=Activation du fournisseur de groupe de s\u00e9curit\u00e9 message.enabling.zone=Activation de la zone -message.enter.token=Entrer le jeton unique re\u00E7u dans le message d\\'invitation. -message.generate.keys=Confirmer la g\u00E9n\u00E9ration de nouvelles clefs pour cet utilisateur. -message.guest.traffic.in.advanced.zone=Le trafic r\u00E9seau d\\'invit\u00E9 est la communication entre les machines virtuelles utilisateur. Sp\u00E9cifier une plage d\\'identifiant VLAN pour le trafic des invit\u00E9s pour chaque r\u00E9seau physique. -message.guest.traffic.in.basic.zone=Le trafic r\u00E9seau d\\'invit\u00E9 est la communication entre les machines virtuelles utilisateur. Sp\u00E9cifier une plage d\\'adresses IP que CloudStack peut assigner aux machines virtuelles Invit\u00E9. S\\'assurer que cette plage n\\'empi\u00E8te pas sur la plage r\u00E9serv\u00E9e aux adresses IP Syst\u00E8me. -message.installWizard.click.retry=Appuyer sur le bouton pour essayer \u00E0 nouveau le d\u00E9marrage. -message.installWizard.copy.whatIsACluster=Un cluster permet de grouper les h\u00F4tes. Les h\u00F4tes d\\'un cluster ont un mat\u00E9riel identique, ex\u00E9cutent le m\u00EAme hyperviseur, sont sur le m\u00EAme sous-r\u00E9seau, et acc\u00E8dent au m\u00EAme stockage partag\u00E9. Les instances de machines virtuelles (VM) peuvent \u00EAtre migr\u00E9es \u00E0 chaud d\\'un h\u00F4te \u00E0 un autre au sein du m\u00EAme groupe, sans interrompre les services utilisateur. Un cluster est la trois \u00E8me plus large unit\u00E9 organisationnelle dans un d\u00E9ploiement CloudStack&\#8482;. Les clusters sont contenus dans les pods et les pods sont contenus dans les zones.

CloudStack&\#8482; permet d\\'avoir plusieurs clusters dans un d\u00E9ploiement en nuage, mais pour une installation basique, il n\\'y a qu\\'un seul cluster. -message.installWizard.copy.whatIsAHost=Un h\u00F4te est une machine. Les h\u00F4tes fournissent les ressources informatiques qui ex\u00E9cutent les machines virtuelles invit\u00E9es. Chaque h\u00F4te a un logiciel hyperviseur install\u00E9 pour g\u00E9rer les machines virtuelles invit\u00E9es (sauf pour les h\u00F4tes de type \\'bare-metal\\', qui sont un cas particulier d\u00E9taill\u00E9 dans le Guide d\\'installation avanc\u00E9e). Par exemple, un serveur Linux avec KVM, un serveur Citrix XenServer, et un serveur ESXi sont des h\u00F4tes. Dans une installation basique, un seul h\u00F4te ex\u00E9cutant XenServer ou KVM est utilis\u00E9.

L\\'h\u00F4te est la plus petite unit\u00E9 organisation au sein d\\'un d\u00E9ploiement CloudStack&\#8482;. Les h\u00F4tes sont contenus dans les clusters, les clusters sont contenus dans les pods et les pods sont contenus dans les zones. -message.installWizard.copy.whatIsAPod=Un pod repr\u00E9sente souvent un seul rack. Les h\u00F4tes dans le m\u00EAme pod sont dans le m\u00EAme sous-r\u00E9seau.
Un pod est la deuxi\u00E8me plus grande unit\u00E9 organisationnelle au sein d\\'un d\u00E9ploiement CloudStack&\#8482;. Les pods sont contenus dans les zones. Chaque zone peut contenir un ou plusieurs pods ; dans l\\'Installation Basique, vous aurez juste un pod dans votre zone. -message.installWizard.copy.whatIsAZone=Une zone est la plus grande unit\u00E9 organisationnelle au sein d\\'un d\u00E9ploiement CloudStack&\#8482;. Une zone correspond typiquement \u00E0 un centre de donn\u00E9es, mais il est permis d\\'avoir plusieurs zones dans un centre de donn\u00E9es. L\\'avantage d\\'organiser une infrastructure en zones est de fournir une isolation physique et de la redondance. Par exemple, chaque zone peut avoir sa propre alimentation et de liaison avec le r\u00E9seau, et les zones peuvent \u00EAtre tr\u00E8s \u00E9loign\u00E9es g\u00E9ographiquement (m\u00EAme si ce n\\'est pas une obligation). -message.installWizard.copy.whatIsCloudStack=CloudStack&\#8482; est une plate-forme logicielle de pools de ressources informatiques pour construire des infrastructures publiques, priv\u00E9es et hybrides en tant que services (IaaS) dans les nuages. CloudStack&\#8482; g\u00E8re le r\u00E9seau, le stockage et les noeuds de calcul qui composent une infrastructure dans les nuages. Utilisez CloudStack&\#8482; pour d\u00E9ployer, g\u00E9rer et configurer les environnements d\\'informatiques dans les nuages.

S\\'\u00E9tendant au-del\u00E0 des machines virtuelles individuelles fonctionnant sur du mat\u00E9riel standard, CloudStack&\#8482; offre une solution d\\'informatique en nuage cl\u00E9 en main pour fournir des centres de donn\u00E9es virtuels comme service - fournissant tous les composants essentiels pour construire, d\u00E9ployer et g\u00E9rer des applications \\'cloud\\' multi-niveaux et multi-locataire. Les versions libre et Premium sont disponibles, la version Libre offrant des caract\u00E9ristiques presque identiques. -message.installWizard.copy.whatIsPrimaryStorage=Une infrastructure CloudStack&\#8482; utilise deux types de stockage \: stockage principal et stockage secondaire. Les deux peuvent \u00EAtre des serveurs iSCSI ou NFS, ou sur disque local.

Le stockage principal est associ\u00E9 \u00E0 un cluster, et stocke les volumes disques de chaque machine virtuelle pour toutes les VMs s\\'ex\u00E9cutant sur les h\u00F4tes dans le cluster. Le serveur de stockage principal est typiquement proche des h\u00F4tes. -message.installWizard.copy.whatIsSecondaryStorage=Le stockage secondaire est associ\u00E9 \u00E0 une zone, et il stocke les \u00E9l\u00E9ments suivants\:
  • Mod\u00E8les - images de syst\u00E8mes d\\'exploitation qui peuvent \u00EAtre utilis\u00E9es pour d\u00E9marrer les machines virtuelles et peuvent inclure des informations de configuration suppl\u00E9mentaires, telles que les applications pr\u00E9-install\u00E9es
  • Images ISO - images de syst\u00E8me d\\'exploitation ou d\\'installation d\\'OS qui peuvent \u00EAtre amor\u00E7able ou non-amor\u00E7able
  • Images de volume disque - capture des donn\u00E9es de machines virtuelles qui peuvent \u00EAtre utilis\u00E9es pour la r\u00E9cup\u00E9ration des donn\u00E9es ou cr\u00E9er des mod\u00E8les
+message.enter.token=Entrer le jeton unique re\u00e7u dans le message d\\'invitation. +message.generate.keys=Confirmer la g\u00e9n\u00e9ration de nouvelles clefs pour cet utilisateur. +message.guest.traffic.in.advanced.zone=Le trafic r\u00e9seau d\\'invit\u00e9 est la communication entre les machines virtuelles utilisateur. Sp\u00e9cifier une plage d\\'identifiant VLAN pour le trafic des invit\u00e9s pour chaque r\u00e9seau physique. +message.guest.traffic.in.basic.zone=Le trafic r\u00e9seau d\\'invit\u00e9 est la communication entre les machines virtuelles utilisateur. Sp\u00e9cifier une plage d\\'adresses IP que CloudStack peut assigner aux machines virtuelles Invit\u00e9. S\\'assurer que cette plage n\\'empi\u00e8te pas sur la plage r\u00e9serv\u00e9e aux adresses IP Syst\u00e8me. +message.installWizard.click.retry=Appuyer sur le bouton pour essayer \u00e0 nouveau le d\u00e9marrage. +message.installWizard.copy.whatIsACluster=Un cluster permet de grouper les h\u00f4tes. Les h\u00f4tes d\\'un cluster ont un mat\u00e9riel identique, ex\u00e9cutent le m\u00eame hyperviseur, sont sur le m\u00eame sous-r\u00e9seau, et acc\u00e8dent au m\u00eame stockage partag\u00e9. Les instances de machines virtuelles (VM) peuvent \u00eatre migr\u00e9es \u00e0 chaud d\\'un h\u00f4te \u00e0 un autre au sein du m\u00eame groupe, sans interrompre les services utilisateur. Un cluster est la trois \u00e8me plus large unit\u00e9 organisationnelle dans un d\u00e9ploiement CloudStack&\#8482;. Les clusters sont contenus dans les pods et les pods sont contenus dans les zones.

CloudStack&\#8482; permet d\\'avoir plusieurs clusters dans un d\u00e9ploiement en nuage, mais pour une installation basique, il n\\'y a qu\\'un seul cluster. +message.installWizard.copy.whatIsAHost=Un h\u00f4te est une machine. Les h\u00f4tes fournissent les ressources informatiques qui ex\u00e9cutent les machines virtuelles invit\u00e9es. Chaque h\u00f4te a un logiciel hyperviseur install\u00e9 pour g\u00e9rer les machines virtuelles invit\u00e9es (sauf pour les h\u00f4tes de type \\'bare-metal\\', qui sont un cas particulier d\u00e9taill\u00e9 dans le Guide d\\'installation avanc\u00e9e). Par exemple, un serveur Linux avec KVM, un serveur Citrix XenServer, et un serveur ESXi sont des h\u00f4tes. Dans une installation basique, un seul h\u00f4te ex\u00e9cutant XenServer ou KVM est utilis\u00e9.

L\\'h\u00f4te est la plus petite unit\u00e9 organisation au sein d\\'un d\u00e9ploiement CloudStack&\#8482;. Les h\u00f4tes sont contenus dans les clusters, les clusters sont contenus dans les pods et les pods sont contenus dans les zones. +message.installWizard.copy.whatIsAPod=Un pod repr\u00e9sente souvent un seul rack. Les h\u00f4tes dans le m\u00eame pod sont dans le m\u00eame sous-r\u00e9seau.
Un pod est la deuxi\u00e8me plus grande unit\u00e9 organisationnelle au sein d\\'un d\u00e9ploiement CloudStack&\#8482;. Les pods sont contenus dans les zones. Chaque zone peut contenir un ou plusieurs pods ; dans l\\'Installation Basique, vous aurez juste un pod dans votre zone. +message.installWizard.copy.whatIsAZone=Une zone est la plus grande unit\u00e9 organisationnelle au sein d\\'un d\u00e9ploiement CloudStack&\#8482;. Une zone correspond typiquement \u00e0 un centre de donn\u00e9es, mais il est permis d\\'avoir plusieurs zones dans un centre de donn\u00e9es. L\\'avantage d\\'organiser une infrastructure en zones est de fournir une isolation physique et de la redondance. Par exemple, chaque zone peut avoir sa propre alimentation et de liaison avec le r\u00e9seau, et les zones peuvent \u00eatre tr\u00e8s \u00e9loign\u00e9es g\u00e9ographiquement (m\u00eame si ce n\\'est pas une obligation). +message.installWizard.copy.whatIsCloudStack=CloudStack&\#8482; est une plate-forme logicielle de pools de ressources informatiques pour construire des infrastructures publiques, priv\u00e9es et hybrides en tant que services (IaaS) dans les nuages. CloudStack&\#8482; g\u00e8re le r\u00e9seau, le stockage et les noeuds de calcul qui composent une infrastructure dans les nuages. Utilisez CloudStack&\#8482; pour d\u00e9ployer, g\u00e9rer et configurer les environnements d\\'informatiques dans les nuages.

S\\'\u00e9tendant au-del\u00e0 des machines virtuelles individuelles fonctionnant sur du mat\u00e9riel standard, CloudStack&\#8482; offre une solution d\\'informatique en nuage cl\u00e9 en main pour fournir des centres de donn\u00e9es virtuels comme service - fournissant tous les composants essentiels pour construire, d\u00e9ployer et g\u00e9rer des applications \\'cloud\\' multi-niveaux et multi-locataire. Les versions libre et Premium sont disponibles, la version Libre offrant des caract\u00e9ristiques presque identiques. +message.installWizard.copy.whatIsPrimaryStorage=Une infrastructure CloudStack&\#8482; utilise deux types de stockage \: stockage principal et stockage secondaire. Les deux peuvent \u00eatre des serveurs iSCSI ou NFS, ou sur disque local.

Le stockage principal est associ\u00e9 \u00e0 un cluster, et stocke les volumes disques de chaque machine virtuelle pour toutes les VMs s\\'ex\u00e9cutant sur les h\u00f4tes dans le cluster. Le serveur de stockage principal est typiquement proche des h\u00f4tes. +message.installWizard.copy.whatIsSecondaryStorage=Le stockage secondaire est associ\u00e9 \u00e0 une zone, et il stocke les \u00e9l\u00e9ments suivants\:
  • Mod\u00e8les - images de syst\u00e8mes d\\'exploitation qui peuvent \u00eatre utilis\u00e9es pour d\u00e9marrer les machines virtuelles et peuvent inclure des informations de configuration suppl\u00e9mentaires, telles que les applications pr\u00e9-install\u00e9es
  • Images ISO - images de syst\u00e8me d\\'exploitation ou d\\'installation d\\'OS qui peuvent \u00eatre amor\u00e7able ou non-amor\u00e7able
  • Images de volume disque - capture des donn\u00e9es de machines virtuelles qui peuvent \u00eatre utilis\u00e9es pour la r\u00e9cup\u00e9ration des donn\u00e9es ou cr\u00e9er des mod\u00e8les
message.installWizard.now.building=Construction de votre Cloud en cours -message.installWizard.tooltip.addCluster.name=Un nom pour le cluster. Ce choix est libre et n\\'est pas utilis\u00E9 par CloudStack. +message.installWizard.tooltip.addCluster.name=Un nom pour le cluster. Ce choix est libre et n\\'est pas utilis\u00e9 par CloudStack. message.installWizard.tooltip.addHost.hostname=Le nom DNS ou adresse IP du serveur. -message.installWizard.tooltip.addHost.password=Le mot de passe pour l\\'utilisateur indiqu\u00E9 pr\u00E9c\u00E9demment (issu de l\\'installation XenServer). +message.installWizard.tooltip.addHost.password=Le mot de passe pour l\\'utilisateur indiqu\u00e9 pr\u00e9c\u00e9demment (issu de l\\'installation XenServer). message.installWizard.tooltip.addHost.username=Habituellement root. message.installWizard.tooltip.addPod.name=Nom pour le pod -message.installWizard.tooltip.addPod.reservedSystemEndIp=Ceci est la plage d\\'adresses IP dans le r\u00E9seau priv\u00E9 que CloudStack utilise la gestion des VMs du stockage secondaire et les VMs Console Proxy. Ces adresses IP sont prises dans le m\u00EAme sous-r\u00E9seau que les serveurs h\u00F4tes. +message.installWizard.tooltip.addPod.reservedSystemEndIp=Ceci est la plage d\\'adresses IP dans le r\u00e9seau priv\u00e9 que CloudStack utilise la gestion des VMs du stockage secondaire et les VMs Console Proxy. Ces adresses IP sont prises dans le m\u00eame sous-r\u00e9seau que les serveurs h\u00f4tes. message.installWizard.tooltip.addPod.reservedSystemGateway=Passerelle pour les serveurs dans ce pod -message.installWizard.tooltip.addPod.reservedSystemNetmask=Le masque r\u00E9seau que les instances utiliseront sur le r\u00E9seau -message.installWizard.tooltip.addPod.reservedSystemStartIp=Ceci est la plage d\\'adresses IP dans le r\u00E9seau priv\u00E9 que CloudStack utilise la gestion des VMs du stockage secondaire et les VMs Console Proxy. Ces adresses IP sont prises dans le m\u00EAme sous-r\u00E9seau que les serveurs h\u00F4tes. +message.installWizard.tooltip.addPod.reservedSystemNetmask=Le masque r\u00e9seau que les instances utiliseront sur le r\u00e9seau +message.installWizard.tooltip.addPod.reservedSystemStartIp=Ceci est la plage d\\'adresses IP dans le r\u00e9seau priv\u00e9 que CloudStack utilise la gestion des VMs du stockage secondaire et les VMs Console Proxy. Ces adresses IP sont prises dans le m\u00eame sous-r\u00e9seau que les serveurs h\u00f4tes. message.installWizard.tooltip.addPrimaryStorage.name=Nom pour ce stockage -message.installWizard.tooltip.addPrimaryStorage.path=(pour NFS) Dans NFS, ceci est le chemin d\\'export depuis le serveur. (pour SharedMountPoint) Le chemin. Avec KVM, c\\'est le chemin sur chaque h\u00F4te o\u00F9 ce stockage principal est mont\u00E9. Par exemple, "/mnt/primary". +message.installWizard.tooltip.addPrimaryStorage.path=(pour NFS) Dans NFS, ceci est le chemin d\\'export depuis le serveur. (pour SharedMountPoint) Le chemin. Avec KVM, c\\'est le chemin sur chaque h\u00f4te o\u00f9 ce stockage principal est mont\u00e9. Par exemple, "/mnt/primary". message.installWizard.tooltip.addPrimaryStorage.server=(pour NFS, iSCSI ou PreSetup) Adresse IP ou nom DNS du stockage message.installWizard.tooltip.addSecondaryStorage.nfsServer=Adresse IP du serveur NFS supportant le stockage secondaire -message.installWizard.tooltip.addSecondaryStorage.path=Le chemin export\u00E9, situ\u00E9 sur le serveur sp\u00E9cifi\u00E9 pr\u00E9c\u00E9demment -message.installWizard.tooltip.addZone.dns1=Ces serveurs DNS sont utilis\u00E9s par les machines virtuelles Invit\u00E9es dans la zone. Ces serveurs DNS seront accessibles par le r\u00E9seau public, ce dernier sera ajout\u00E9 plus tard. Les adresses IP publiques pour la zone doivent avoir une route vers les serveurs DNS indiqu\u00E9s ici. -message.installWizard.tooltip.addZone.dns2=Ces serveurs DNS sont utilis\u00E9s par les machines virtuelles Invit\u00E9es dans la zone. Ces serveurs DNS seront accessibles par le r\u00E9seau public, ce dernier sera ajout\u00E9 plus tard. Les adresses IP publiques pour la zone doivent avoir une route vers les serveurs DNS indiqu\u00E9s ici. -message.installWizard.tooltip.addZone.internaldns1=Ces serveurs DNS sont utilis\u00E9s par les machines virtuelles Invit\u00E9es dans la zone. Ces serveurs DNS seront accessibles par le r\u00E9seau public, ce dernier sera ajout\u00E9 plus tard. Les adresses IP publiques pour la zone doivent avoir une route vers les serveurs DNS indiqu\u00E9s ici. -message.installWizard.tooltip.addZone.internaldns2=Ces serveurs DNS sont utilis\u00E9s par les machines virtuelles Invit\u00E9es dans la zone. Ces serveurs DNS seront accessibles par le r\u00E9seau public, ce dernier sera ajout\u00E9 plus tard. Les adresses IP publiques pour la zone doivent avoir une route vers les serveurs DNS indiqu\u00E9s ici. +message.installWizard.tooltip.addSecondaryStorage.path=Le chemin export\u00e9, situ\u00e9 sur le serveur sp\u00e9cifi\u00e9 pr\u00e9c\u00e9demment +message.installWizard.tooltip.addZone.dns1=Ces serveurs DNS sont utilis\u00e9s par les machines virtuelles Invit\u00e9es dans la zone. Ces serveurs DNS seront accessibles par le r\u00e9seau public, ce dernier sera ajout\u00e9 plus tard. Les adresses IP publiques pour la zone doivent avoir une route vers les serveurs DNS indiqu\u00e9s ici. +message.installWizard.tooltip.addZone.dns2=Ces serveurs DNS sont utilis\u00e9s par les machines virtuelles Invit\u00e9es dans la zone. Ces serveurs DNS seront accessibles par le r\u00e9seau public, ce dernier sera ajout\u00e9 plus tard. Les adresses IP publiques pour la zone doivent avoir une route vers les serveurs DNS indiqu\u00e9s ici. +message.installWizard.tooltip.addZone.internaldns1=Ces serveurs DNS sont utilis\u00e9s par les machines virtuelles Invit\u00e9es dans la zone. Ces serveurs DNS seront accessibles par le r\u00e9seau public, ce dernier sera ajout\u00e9 plus tard. Les adresses IP publiques pour la zone doivent avoir une route vers les serveurs DNS indiqu\u00e9s ici. +message.installWizard.tooltip.addZone.internaldns2=Ces serveurs DNS sont utilis\u00e9s par les machines virtuelles Invit\u00e9es dans la zone. Ces serveurs DNS seront accessibles par le r\u00e9seau public, ce dernier sera ajout\u00e9 plus tard. Les adresses IP publiques pour la zone doivent avoir une route vers les serveurs DNS indiqu\u00e9s ici. message.installWizard.tooltip.addZone.name=Nom pour la zone -message.installWizard.tooltip.configureGuestTraffic.description=Description pour ce r\u00E9seau -message.installWizard.tooltip.configureGuestTraffic.guestEndIp=La plage d\\'adresses IP qui sera disponible en allocation pour les machines invit\u00E9es dans cette zone. Si une carte r\u00E9seau est utilis\u00E9e, ces adresses IP peuvent \u00EAtre dans le m\u00EAme CIDR que le CIDR du pod. -message.installWizard.tooltip.configureGuestTraffic.guestGateway=La passerelle que les instances invit\u00E9es doivent utiliser -message.installWizard.tooltip.configureGuestTraffic.guestNetmask=Le masque r\u00E9seau que les instances devrait utiliser sur le r\u00E9seau -message.installWizard.tooltip.configureGuestTraffic.guestStartIp=La plage d\\'adresses IP qui sera disponible en allocation pour les machines invit\u00E9es dans cette zone. Si une carte r\u00E9seau est utilis\u00E9e, ces adresses IP peuvent \u00EAtre dans le m\u00EAme CIDR que le CIDR du pod. -message.installWizard.tooltip.configureGuestTraffic.name=Nom pour ce r\u00E9seau -message.instanceWizard.noTemplates=Vous n\\'avez pas de image disponible ; Ajouter un mod\u00E8le compatible puis relancer l\\'assistant de cr\u00E9ation d\\'instance. -message.ip.address.changed=Vos adresses IP ont peut \u00EAtre chang\u00E9es ; Voulez vous rafra\u00EEchir la liste ? Dans ce cas, le panneau de d\u00E9tail se fermera. -message.iso.desc=Image disque contenant des donn\u00E9es ou un support amor\u00E7able pour OS -message.join.project=Vous avez rejoint un projet. S\u00E9lectionnez la vue Projet pour le voir. -message.launch.vm.on.private.network=Souhaitez vous d\u00E9marrer cette instance sur votre propre r\u00E9seau priv\u00E9 ? -message.launch.zone=La zone est pr\u00EAte \u00E0 d\u00E9marrer ; passer \u00E0 l\\'\u00E9tape suivante. -message.lock.account=\u00CAtes-vous s\u00FBr que vous souhaitez verrouiller ce compte. En le verrouillant, les utilisateurs de ce compte ne seront plus capables de g\u00E9rer leurs ressources. Les ressources existantes resteront toutefois accessibles. -message.migrate.instance.confirm=Confirmez l\\'h\u00F4te vers lequel vous souhaitez migrer cette instance -message.migrate.instance.to.host=Confirmer la migration de l\\'instance vers un autre h\u00F4te +message.installWizard.tooltip.configureGuestTraffic.description=Description pour ce r\u00e9seau +message.installWizard.tooltip.configureGuestTraffic.guestEndIp=La plage d\\'adresses IP qui sera disponible en allocation pour les machines invit\u00e9es dans cette zone. Si une carte r\u00e9seau est utilis\u00e9e, ces adresses IP peuvent \u00eatre dans le m\u00eame CIDR que le CIDR du pod. +message.installWizard.tooltip.configureGuestTraffic.guestGateway=La passerelle que les instances invit\u00e9es doivent utiliser +message.installWizard.tooltip.configureGuestTraffic.guestNetmask=Le masque r\u00e9seau que les instances devrait utiliser sur le r\u00e9seau +message.installWizard.tooltip.configureGuestTraffic.guestStartIp=La plage d\\'adresses IP qui sera disponible en allocation pour les machines invit\u00e9es dans cette zone. Si une carte r\u00e9seau est utilis\u00e9e, ces adresses IP peuvent \u00eatre dans le m\u00eame CIDR que le CIDR du pod. +message.installWizard.tooltip.configureGuestTraffic.name=Nom pour ce r\u00e9seau +message.instanceWizard.noTemplates=Vous n\\'avez pas de image disponible ; Ajouter un mod\u00e8le compatible puis relancer l\\'assistant de cr\u00e9ation d\\'instance. +message.ip.address.changed=Vos adresses IP ont peut \u00eatre chang\u00e9es ; Voulez vous rafra\u00eechir la liste ? Dans ce cas, le panneau de d\u00e9tail se fermera. +message.iso.desc=Image disque contenant des donn\u00e9es ou un support amor\u00e7able pour OS +message.join.project=Vous avez rejoint un projet. S\u00e9lectionnez la vue Projet pour le voir. +message.launch.vm.on.private.network=Souhaitez vous d\u00e9marrer cette instance sur votre propre r\u00e9seau priv\u00e9 ? +message.launch.zone=La zone est pr\u00eate \u00e0 d\u00e9marrer ; passer \u00e0 l\\'\u00e9tape suivante. +message.lock.account=\u00cates-vous s\u00fbr que vous souhaitez verrouiller ce compte. En le verrouillant, les utilisateurs de ce compte ne seront plus capables de g\u00e9rer leurs ressources. Les ressources existantes resteront toutefois accessibles. +message.migrate.instance.confirm=Confirmez l\\'h\u00f4te vers lequel vous souhaitez migrer cette instance +message.migrate.instance.to.host=Confirmer la migration de l\\'instance vers un autre h\u00f4te message.migrate.instance.to.ps=Confirmer la migration de l\\'instance vers un autre stockage principal message.migrate.router.confirm=Confirmer la migration du routeur vers \: -message.migrate.systemvm.confirm=Confirmer la migration de la VM syst\u00E8me vers \: +message.migrate.systemvm.confirm=Confirmer la migration de la VM syst\u00e8me vers \: message.migrate.volume=Confirmer la migration du volume vers un autre stockage principal. message.new.user=Renseigner les informations suivantes pour ajouter un nouveau compte utilisateur -message.no.network.support=S\u00E9lectionnez l\\'hyperviseur. vSphere, n\\'a pas de fonctionnalit\u00E9s suppl\u00E9mentaires pour le r\u00E9seau. Continuez \u00E0 l\\'\u00E9tape 5. -message.no.network.support.configuration.not.true=Il n\\'y a pas de zone avec la fonction groupe de s\u00E9curit\u00E9 active. D\u00E8s lors, pas de fonction r\u00E9seau suppl\u00E9mentaires disponibles. Continuer \u00E0 l\\'\u00E9tape 5. -message.no.projects=Vous n\\'avez pas de projet.
Vous pouvez en cr\u00E9er un depuis la section projets. +message.no.network.support.configuration.not.true=Il n\\'y a pas de zone avec la fonction groupe de s\u00e9curit\u00e9 active. D\u00e8s lors, pas de fonction r\u00e9seau suppl\u00e9mentaires disponibles. Continuer \u00e0 l\\'\u00e9tape 5. +message.no.network.support=S\u00e9lectionnez l\\'hyperviseur. vSphere, n\\'a pas de fonctionnalit\u00e9s suppl\u00e9mentaires pour le r\u00e9seau. Continuez \u00e0 l\\'\u00e9tape 5. message.no.projects.adminOnly=Vous n\\'avez pas de projet.
Contacter votre administrateur pour ajouter un projet. +message.no.projects=Vous n\\'avez pas de projet.
Vous pouvez en cr\u00e9er un depuis la section projets. message.number.clusters=

\# de Clusters

-message.number.hosts=

\# d\\' H\u00F4tes

+message.number.hosts=

\# d\\' H\u00f4tes

message.number.pods=

\# de Pods

message.number.storage=

\# de Volumes de Stockage Principal

message.number.zones=

\# de Zones

message.pending.projects.1=Vous avez des invitations projet en attente \: -message.pending.projects.2=Pour les visualiser, aller dans la section projets, puis s\u00E9lectionner invitation dans la liste d\u00E9roulante. -message.please.add.at.lease.one.traffic.range=Ajouter au moins une plage r\u00E9seau -message.please.proceed=Continuer vers la prochaine \u00E9tape. -message.please.select.a.configuration.for.your.zone=S\u00E9lectionner une configuration pour la zone. -message.please.select.a.different.public.and.management.network.before.removing=S\u00E9lectionner un r\u00E9seau public et d\\'administration diff\u00E9rent avant de supprimer -message.please.select.networks=S\u00E9lectionner les r\u00E9seaux pour votre machine virtuelle. -message.please.wait.while.zone.is.being.created=Patienter pendant la cr\u00E9ation de la zone, cela peut prendre du temps... -message.project.invite.sent=Invitation envoy\u00E9e ; les utilisateurs seront ajout\u00E9s apr\u00E8s acceptation de l\\'invitation -message.public.traffic.in.advanced.zone=Le trafic public est g\u00E9n\u00E9r\u00E9 lorsque les machines virtuelles dans le nuage acc\u00E8dent \u00E0 Internet. Des adresses IP publiquement accessibles doivent \u00EAtre pr\u00E9vues \u00E0 cet effet. Les utilisateurs peuvent utiliser l\\'interface d\\'administration de CloudStack pour acqu\u00E9rir ces adresses IP qui impl\u00E9menteront une translation d\\'adresse NAT entre le r\u00E9seau d\\'invit\u00E9 et le r\u00E9seau public.

Fournir au moins une plage d\\'adresses IP pour le trafic Internet. -message.public.traffic.in.basic.zone=Le trafic public est g\u00E9n\u00E9r\u00E9 lorsque les machines virtuelles dans le nuage acc\u00E8dent \u00E0 Internet ou fournissent des services \u00E0 des utilisateurs sur Internet. Des adresses IP publiquement accessibles doivent \u00EAtre pr\u00E9vus \u00E0 cet effet. Quand une instance est cr\u00E9\u00E9e, une adresse IP publique depuis un ensemble d\\'adresses IP publiques sera allou\u00E9e \u00E0 l\\'instance, en plus de l\\'adresse IP de l\\'invit\u00E9. La translation d\\'adresses statique NAT 1-1 sera mises en place automatiquement entre l\\'adresse IP publique et l\\'adresse IP de l\\'invit\u00E9. Les utilisateurs peuvent \u00E9galement utiliser l\\'interface d\\'administration CloudStack pour acqu\u00E9rir des adresses IP suppl\u00E9mentaires pour ajouter une translation d\\'adresse statique NAT entre leurs instances et le r\u00E9seau d\\'adresses IP publiques. +message.pending.projects.2=Pour les visualiser, aller dans la section projets, puis s\u00e9lectionner invitation dans la liste d\u00e9roulante. +message.please.add.at.lease.one.traffic.range=Ajouter au moins une plage r\u00e9seau +message.please.proceed=Continuer vers la prochaine \u00e9tape. +message.please.select.a.configuration.for.your.zone=S\u00e9lectionner une configuration pour la zone. +message.please.select.a.different.public.and.management.network.before.removing=S\u00e9lectionner un r\u00e9seau public et d\\'administration diff\u00e9rent avant de supprimer +message.please.select.networks=S\u00e9lectionner les r\u00e9seaux pour votre machine virtuelle. +message.please.wait.while.zone.is.being.created=Patienter pendant la cr\u00e9ation de la zone, cela peut prendre du temps... +message.project.invite.sent=Invitation envoy\u00e9e ; les utilisateurs seront ajout\u00e9s apr\u00e8s acceptation de l\\'invitation +message.public.traffic.in.advanced.zone=Le trafic public est g\u00e9n\u00e9r\u00e9 lorsque les machines virtuelles dans le nuage acc\u00e8dent \u00e0 Internet. Des adresses IP publiquement accessibles doivent \u00eatre pr\u00e9vues \u00e0 cet effet. Les utilisateurs peuvent utiliser l\\'interface d\\'administration de CloudStack pour acqu\u00e9rir ces adresses IP qui impl\u00e9menteront une translation d\\'adresse NAT entre le r\u00e9seau d\\'invit\u00e9 et le r\u00e9seau public.

Fournir au moins une plage d\\'adresses IP pour le trafic Internet. +message.public.traffic.in.basic.zone=Le trafic public est g\u00e9n\u00e9r\u00e9 lorsque les machines virtuelles dans le nuage acc\u00e8dent \u00e0 Internet ou fournissent des services \u00e0 des utilisateurs sur Internet. Des adresses IP publiquement accessibles doivent \u00eatre pr\u00e9vus \u00e0 cet effet. Quand une instance est cr\u00e9\u00e9e, une adresse IP publique depuis un ensemble d\\'adresses IP publiques sera allou\u00e9e \u00e0 l\\'instance, en plus de l\\'adresse IP de l\\'invit\u00e9. La translation d\\'adresses statique NAT 1-1 sera mises en place automatiquement entre l\\'adresse IP publique et l\\'adresse IP de l\\'invit\u00e9. Les utilisateurs peuvent \u00e9galement utiliser l\\'interface d\\'administration CloudStack pour acqu\u00e9rir des adresses IP suppl\u00e9mentaires pour ajouter une translation d\\'adresse statique NAT entre leurs instances et le r\u00e9seau d\\'adresses IP publiques. +message.redirecting.region=Redirection vers r\u00e9gion... +message.remove.region=Confirmer que vous souhaitez supprimer cette r\u00e9gion depuis ce serveur d\\'administration ? message.remove.vpc=Confirmer la suppression du VPC -message.remove.vpn.access=\u00CAtes-vous s\u00FBr que vous souhaitez supprimer l\\'acc\u00E8s VPN \u00E0 l\\'utilisateur suivant. -message.reset.VPN.connection=Confirmer le r\u00E9-initialisation de la connexion VPN -message.reset.password.warning.notPasswordEnabled=Le mod\u00E8le de cette instance a \u00E9t\u00E9 cr\u00E9\u00E9 sans la gestion de mot de passe -message.reset.password.warning.notStopped=Votre instance doit \u00EAtre arr\u00EAt\u00E9e avant de changer son mot de passe -message.restart.mgmt.server=Red\u00E9marrez votre(vos) serveur(s) de management pour appliquer les nouveaux param\u00E8tres. -message.restart.mgmt.usage.server=Red\u00E9marrer le ou les serveur(s) de gestion et le ou les serveur(s) de consommation pour que les nouveaux param\u00E8tres soient pris en compte. -message.restart.network=Tous les services fournit par ce routeur virtuel vont \u00EAtre interrompus. Confirmer le red\u00E9marrage de ce routeur. -message.restart.vpc=Confirmer le red\u00E9marrage du VPC -message.security.group.usage=(Utilisez Ctrl-clic pour s\u00E9lectionner les groupes de s\u00E9curit\u00E9 vis\u00E9s) -message.select.a.zone=Une zone correspond typiquement \u00E0 un seul centre de donn\u00E9es. Des zones multiples peuvent permettre de rendre votre cloud plus fiable en apportant une isolation physique et de la redondance. -message.select.instance=S\u00E9lectionner une instance. -message.select.iso=S\u00E9lectionner un ISO pour votre nouvelle instance virtuelle. -message.select.item=Merci de s\u00E9lectionner un \u00E9l\u00E9ment. -message.select.security.groups=Merci de s\u00E9lectionner un(des) groupe(s) de s\u00E9curit\u00E9 pour la nouvelle VM -message.select.template=S\u00E9lectionner un mod\u00E8le pour votre nouvelle instance virtuelle. -message.setup.physical.network.during.zone.creation=Lorsque vous ajoutez une zone avanc\u00E9e, vous avez besoin de d\u00E9finir un ou plusieurs r\u00E9seaux physiques. Chaque r\u00E9seau correspond \u00E0 une carte r\u00E9seau sur l\\'hyperviseur. Chaque r\u00E9seau physique peut supporter un ou plusieurs types de trafic, avec certaines restrictions sur la fa\u00E7on dont ils peuvent \u00EAtre combin\u00E9s.

Glisser et d\u00E9poser un ou plusieurs types de trafic sur chaque r\u00E9seau physique. -message.setup.physical.network.during.zone.creation.basic=Quand vous ajoutez une zone basique, vous pouvez param\u00E9trer un seul r\u00E9seau physique, correspondant \u00E0 une carte r\u00E9seau sur l\\'hyperviseur. Ce r\u00E9seau comportera plusieurs types de trafic.

Vous pouvez \u00E9galement glisser et d\u00E9poser d\\'autres types de trafic sur le r\u00E9seau physique. -message.setup.successful=Installation du Cloud r\u00E9ussie \! -message.snapshot.schedule=Vous pouvez mettre en place les politiques de g\u00E9n\u00E9ration d\\'instantan\u00E9s en s\u00E9lectionnant les options disponibles ci-dessous et en appliquant votre politique. +message.remove.vpn.access=\u00cates-vous s\u00fbr que vous souhaitez supprimer l\\'acc\u00e8s VPN \u00e0 l\\'utilisateur suivant. +message.reset.password.warning.notPasswordEnabled=Le mod\u00e8le de cette instance a \u00e9t\u00e9 cr\u00e9\u00e9 sans la gestion de mot de passe +message.reset.password.warning.notStopped=Votre instance doit \u00eatre arr\u00eat\u00e9e avant de changer son mot de passe +message.reset.VPN.connection=Confirmer le r\u00e9-initialisation de la connexion VPN +message.restart.mgmt.server=Red\u00e9marrez votre(vos) serveur(s) de management pour appliquer les nouveaux param\u00e8tres. +message.restart.mgmt.usage.server=Red\u00e9marrer le ou les serveur(s) de gestion et le ou les serveur(s) de consommation pour que les nouveaux param\u00e8tres soient pris en compte. +message.restart.network=Tous les services fournit par ce routeur virtuel vont \u00eatre interrompus. Confirmer le red\u00e9marrage de ce routeur. +message.restart.vpc=Confirmer le red\u00e9marrage du VPC +message.security.group.usage=(Utilisez Ctrl-clic pour s\u00e9lectionner les groupes de s\u00e9curit\u00e9 vis\u00e9s) +message.select.a.zone=Une zone correspond typiquement \u00e0 un seul centre de donn\u00e9es. Des zones multiples peuvent permettre de rendre votre cloud plus fiable en apportant une isolation physique et de la redondance. +message.select.instance=S\u00e9lectionner une instance. +message.select.iso=S\u00e9lectionner un ISO pour votre nouvelle instance virtuelle. +message.select.item=Merci de s\u00e9lectionner un \u00e9l\u00e9ment. +message.select.security.groups=Merci de s\u00e9lectionner un(des) groupe(s) de s\u00e9curit\u00e9 pour la nouvelle VM +message.select.template=S\u00e9lectionner un mod\u00e8le pour votre nouvelle instance virtuelle. +message.setup.physical.network.during.zone.creation.basic=Quand vous ajoutez une zone basique, vous pouvez param\u00e9trer un seul r\u00e9seau physique, correspondant \u00e0 une carte r\u00e9seau sur l\\'hyperviseur. Ce r\u00e9seau comportera plusieurs types de trafic.

Vous pouvez \u00e9galement glisser et d\u00e9poser d\\'autres types de trafic sur le r\u00e9seau physique. +message.setup.physical.network.during.zone.creation=Lorsque vous ajoutez une zone avanc\u00e9e, vous avez besoin de d\u00e9finir un ou plusieurs r\u00e9seaux physiques. Chaque r\u00e9seau correspond \u00e0 une carte r\u00e9seau sur l\\'hyperviseur. Chaque r\u00e9seau physique peut supporter un ou plusieurs types de trafic, avec certaines restrictions sur la fa\u00e7on dont ils peuvent \u00eatre combin\u00e9s.

Glisser et d\u00e9poser un ou plusieurs types de trafic sur chaque r\u00e9seau physique. +message.setup.successful=Installation du Cloud r\u00e9ussie \! +message.snapshot.schedule=Vous pouvez mettre en place les politiques de g\u00e9n\u00e9ration d\\'instantan\u00e9s en s\u00e9lectionnant les options disponibles ci-dessous et en appliquant votre politique. message.specify.url=Renseigner l\\'URL -message.step.1.continue=S\u00E9lectionnez un mod\u00E8le ou une image ISO pour continuer -message.step.1.desc=S\u00E9lectionnez un mod\u00E8le pour votre nouvelle instance virtuelle. Vous pouvez \u00E9galement choisir un mod\u00E8le vierge sur lequel une image ISO pourra \u00EAtre install\u00E9e. -message.step.2.continue=S\u00E9lectionnez une offre de service pour continuer -message.step.3.continue=S\u00E9lectionnez un offre de service de disque pour continuer -message.step.4.continue=S\u00E9lectionnez au moins un r\u00E9seau pour continuer -message.step.4.desc=S\u00E9lectionnez le r\u00E9seau principal auquel votre instance va \u00EAtre connect\u00E9. -message.storage.traffic=Trafic entre les ressources internes de CloudStack, incluant tous les composants qui communiquent avec le serveur d\\'administration, tels que les h\u00F4tes et les machines virtuelles Syst\u00E8mes CloudStack. Veuillez configurer le trafic de stockage ici. -message.suspend.project=\u00CAtes-vous s\u00FBr de vouloir suspendre ce projet ? -message.template.desc=Image OS pouvant \u00EAtre utilis\u00E9e pour d\u00E9marrer une VM -message.tooltip.dns.1=Nom d\\'un serveur DNS utilis\u00E9 par les VM de la zone. Les adresses IP publiques de cette zone doivent avoir une route vers ce serveur. -message.tooltip.dns.2=Nom d\\'un serveur DNS secondaire utilis\u00E9 par les VM de la zone. Les adresses IP publiques de cette zone doivent avoir une route vers ce serveur. -message.tooltip.internal.dns.1=Nom d\\'un serveur DNS que CloudStack peut utiliser pour les VM syst\u00E8me dans cette zone. Les adresses IP priv\u00E9es des pods doivent avoir une route vers ce serveur. -message.tooltip.internal.dns.2=Nom d\\'un serveur DNS que CloudStack peut utiliser pour les VM syst\u00E8me dans cette zone. Les adresses IP priv\u00E9es des pods doivent avoir une route vers ce serveur. -message.tooltip.network.domain=Suffixe DNS qui cr\u00E9era un nom de domaine personnalis\u00E9 pour les r\u00E9seau accessible par les VM invit\u00E9es. +message.step.1.continue=S\u00e9lectionnez un mod\u00e8le ou une image ISO pour continuer +message.step.1.desc=S\u00e9lectionnez un mod\u00e8le pour votre nouvelle instance virtuelle. Vous pouvez \u00e9galement choisir un mod\u00e8le vierge sur lequel une image ISO pourra \u00eatre install\u00e9e. +message.step.2.continue=S\u00e9lectionnez une offre de service pour continuer +message.step.2.desc= +message.step.3.continue=S\u00e9lectionnez un offre de service de disque pour continuer +message.step.3.desc= +message.step.4.continue=S\u00e9lectionnez au moins un r\u00e9seau pour continuer +message.step.4.desc=S\u00e9lectionnez le r\u00e9seau principal auquel votre instance va \u00eatre connect\u00e9. +message.storage.traffic=Trafic entre les ressources internes de CloudStack, incluant tous les composants qui communiquent avec le serveur d\\'administration, tels que les h\u00f4tes et les machines virtuelles Syst\u00e8mes CloudStack. Veuillez configurer le trafic de stockage ici. +message.suspend.project=\u00cates-vous s\u00fbr de vouloir suspendre ce projet ? +message.template.desc=Image OS pouvant \u00eatre utilis\u00e9e pour d\u00e9marrer une VM +message.tooltip.dns.1=Nom d\\'un serveur DNS utilis\u00e9 par les VM de la zone. Les adresses IP publiques de cette zone doivent avoir une route vers ce serveur. +message.tooltip.dns.2=Nom d\\'un serveur DNS secondaire utilis\u00e9 par les VM de la zone. Les adresses IP publiques de cette zone doivent avoir une route vers ce serveur. +message.tooltip.internal.dns.1=Nom d\\'un serveur DNS que CloudStack peut utiliser pour les VM syst\u00e8me dans cette zone. Les adresses IP priv\u00e9es des pods doivent avoir une route vers ce serveur. +message.tooltip.internal.dns.2=Nom d\\'un serveur DNS que CloudStack peut utiliser pour les VM syst\u00e8me dans cette zone. Les adresses IP priv\u00e9es des pods doivent avoir une route vers ce serveur. +message.tooltip.network.domain=Suffixe DNS qui cr\u00e9era un nom de domaine personnalis\u00e9 pour les r\u00e9seau accessible par les VM invit\u00e9es. message.tooltip.pod.name=Nom pour ce pod. -message.tooltip.reserved.system.gateway=La passerelle pour les h\u00F4tes du pod. -message.tooltip.reserved.system.netmask=Le pr\u00E9fixe r\u00E9seau utilis\u00E9 par le sous-r\u00E9seau du pod. Au format CIDR. +message.tooltip.reserved.system.gateway=La passerelle pour les h\u00f4tes du pod. +message.tooltip.reserved.system.netmask=Le pr\u00e9fixe r\u00e9seau utilis\u00e9 par le sous-r\u00e9seau du pod. Au format CIDR. message.tooltip.zone.name=Nom pour cette zone. -message.update.os.preference=Choisissez votre OS pr\u00E9f\u00E9r\u00E9 pour cet h\u00F4te. Toutes les instances avec des pr\u00E9f\u00E9rences similaires seront d\\'abord allou\u00E9es \u00E0 cet h\u00F4te avant d\\'en choisir un autre. -message.update.resource.count=Confirmer la mise \u00E0 jour des ressources pour ce compte. -message.update.ssl=Soumettez un nouveau certificat SSL compatible X.509 qui sera mis \u00E0 jour sur l\\'ensemble de instance de proxy console. -message.validate.instance.name=Le nom de l\\'instance ne peut d\u00E9passer 63 caract\u00E8res. Seuls les lettres de a \u00E0 z, les chiffres de 0 \u00E0 9 et les tirets sont accept\u00E9s. Le nom doit commencer par une lettre et se terminer par une lettre ou un chiffre. -message.virtual.network.desc=Un r\u00E9seau virtuel d\u00E9di\u00E9 pour votre compte. Ce domaine de multi-diffusion est contenu dans un VLAN et l\\'ensemble des r\u00E9seaux d\\'acc\u00E8s publique sont rout\u00E9s par un routeur virtuel. -message.vm.create.template.confirm=Cr\u00E9er un mod\u00E8le va red\u00E9marrer la VM automatiquement -message.vm.review.launch=Merci de v\u00E9rifier les informations suivantes et de confirmer que votre instance virtuelle est correcte avant de la d\u00E9marrer. -message.volume.create.template.confirm=\u00CAtes-vous s\u00FBr que vous souhaitez cr\u00E9er un mod\u00E8le pour ce disque. La cr\u00E9ation peut prendre plusieurs minutes, voire plus, selon la taille du volume. -message.you.must.have.at.least.one.physical.network=Vous devez avoir au moins un r\u00E9seau physique -message.zone.creation.complete.would.you.like.to.enable.this.zone=Cr\u00E9ation de la zone termin\u00E9e. Voulez-vous l\\'activer ? -message.zone.no.network.selection=La zone s\u00E9lectionn\u00E9e ne propose pas le r\u00E9seau choisi -message.zone.step.1.desc=S\u00E9lectionnez un mod\u00E8le de r\u00E9seau pour votre zone. +message.update.os.preference=Choisissez votre OS pr\u00e9f\u00e9r\u00e9 pour cet h\u00f4te. Toutes les instances avec des pr\u00e9f\u00e9rences similaires seront d\\'abord allou\u00e9es \u00e0 cet h\u00f4te avant d\\'en choisir un autre. +message.update.resource.count=Confirmer la mise \u00e0 jour des ressources pour ce compte. +message.update.ssl=Soumettez un nouveau certificat SSL compatible X.509 qui sera mis \u00e0 jour sur l\\'ensemble de instance de proxy console. +message.validate.instance.name=Le nom de l\\'instance ne peut d\u00e9passer 63 caract\u00e8res. Seuls les lettres de a \u00e0 z, les chiffres de 0 \u00e0 9 et les tirets sont accept\u00e9s. Le nom doit commencer par une lettre et se terminer par une lettre ou un chiffre. +message.virtual.network.desc=Un r\u00e9seau virtuel d\u00e9di\u00e9 pour votre compte. Ce domaine de multi-diffusion est contenu dans un VLAN et l\\'ensemble des r\u00e9seaux d\\'acc\u00e8s publique sont rout\u00e9s par un routeur virtuel. +message.vm.create.template.confirm=Cr\u00e9er un mod\u00e8le va red\u00e9marrer la VM automatiquement +message.vm.review.launch=Merci de v\u00e9rifier les informations suivantes et de confirmer que votre instance virtuelle est correcte avant de la d\u00e9marrer. +message.volume.create.template.confirm=\u00cates-vous s\u00fbr que vous souhaitez cr\u00e9er un mod\u00e8le pour ce disque. La cr\u00e9ation peut prendre plusieurs minutes, voire plus, selon la taille du volume. +message.you.must.have.at.least.one.physical.network=Vous devez avoir au moins un r\u00e9seau physique +message.Zone.creation.complete=Cr\u00e9ation de la zone termin\u00e9e +message.zone.creation.complete.would.you.like.to.enable.this.zone=Cr\u00e9ation de la zone termin\u00e9e. Voulez-vous l\\'activer ? +message.zone.no.network.selection=La zone s\u00e9lectionn\u00e9e ne propose pas le r\u00e9seau choisi +message.zone.step.1.desc=S\u00e9lectionnez un mod\u00e8le de r\u00e9seau pour votre zone. message.zone.step.2.desc=Renseigner les informations suivantes pour ajouter une nouvelle zone message.zone.step.3.desc=Renseigner les informations suivantes pour ajouter un nouveau pod -message.zoneWizard.enable.local.storage=ATTENTION \: si vous activez le stockage local pour cette zone, vous devez effectuer les op\u00E9rations suivantes, selon l\\'endroit o\u00F9 vous souhaitez lancer vos machines virtuelles Syst\u00E8mes \:

1. Si les machines virtuelles Syst\u00E8mes doivent \u00EAtre lanc\u00E9es depuis le stockage principal, ce dernier doit \u00EAtre ajout\u00E9 \u00E0 la zone apr\u00E8s la cr\u00E9ation. Vous devez \u00E9galement d\u00E9marrer la zone dans un \u00E9tat d\u00E9sactiv\u00E9.

2. Si les machines virtuelles Syst\u00E8mes doivent \u00EAtre lanc\u00E9es depuis le stockage local, le param\u00E8tre system.vm.use.local.storage doit \u00EAtre d\u00E9fini \u00E0 \\'true\\' avant d\\'activer la zone.


Voulez-vous continuer ? +message.zoneWizard.enable.local.storage=ATTENTION \: si vous activez le stockage local pour cette zone, vous devez effectuer les op\u00e9rations suivantes, selon l\\'endroit o\u00f9 vous souhaitez lancer vos machines virtuelles Syst\u00e8mes \:

1. Si les machines virtuelles Syst\u00e8mes doivent \u00eatre lanc\u00e9es depuis le stockage principal, ce dernier doit \u00eatre ajout\u00e9 \u00e0 la zone apr\u00e8s la cr\u00e9ation. Vous devez \u00e9galement d\u00e9marrer la zone dans un \u00e9tat d\u00e9sactiv\u00e9.

2. Si les machines virtuelles Syst\u00e8mes doivent \u00eatre lanc\u00e9es depuis le stockage local, le param\u00e8tre system.vm.use.local.storage doit \u00eatre d\u00e9fini \u00e0 \\'true\\' avant d\\'activer la zone.


Voulez-vous continuer ? mode=Mode -network.rate=D\u00E9bit R\u00E9seau -notification.reboot.instance=Red\u00E9marrer l\\'instance -notification.start.instance=D\u00E9marrer l\\'instance +network.rate=D\u00e9bit R\u00e9seau +notification.reboot.instance=Red\u00e9marrer l\\'instance +notification.start.instance=D\u00e9marrer l\\'instance notification.stop.instance=Stopper l\\'instance -side.by.side=C\u00F4te \u00E0 c\u00F4te -state.Accepted=Accept\u00E9 +side.by.side=C\u00f4te \u00e0 c\u00f4te +state.Accepted=Accept\u00e9 state.Active=Actif -state.Allocated=Allou\u00E9 +state.Allocated=Allou\u00e9 state.Allocating=Allocation en cours -state.BackedUp=Sauvegard\u00E9 +state.BackedUp=Sauvegard\u00e9 state.BackingUp=Sauvegarde en cours -state.Completed=Termin\u00E9 -state.Creating=Cr\u00E9ation en cours -state.Declined=Refus\u00E9 -state.Destroyed=Supprim\u00E9e -state.Disabled=D\u00E9sactiv\u00E9 +state.Completed=Termin\u00e9 +state.Creating=Cr\u00e9ation en cours +state.Declined=Refus\u00e9 +state.Destroyed=Supprim\u00e9e +state.Disabled=D\u00e9sactiv\u00e9 +state.enabled=Actifs state.Enabled=Actifs state.Error=Erreur state.Expunging=Purge en cours state.Migrating=Migration en cours state.Pending=En attente -state.Ready=Pr\u00EAt -state.Running=D\u00E9marr\u00E9e -state.Starting=D\u00E9marrage en cours -state.Stopped=Arr\u00EAt\u00E9e -state.Stopping=Arr\u00EAt en cours +state.ready=Pr\u00eat +state.Ready=Pr\u00eat +state.Running=D\u00e9marr\u00e9e +state.Starting=D\u00e9marrage en cours +state.Stopped=Arr\u00eat\u00e9e +state.Stopping=Arr\u00eat en cours state.Suspended=Suspendu -state.enabled=Actifs -state.ready=Pr\u00EAt ui.listView.filters.all=Tous ui.listView.filters.mine=Mon diff --git a/client/WEB-INF/classes/resources/messages_it_IT.properties b/client/WEB-INF/classes/resources/messages_it_IT.properties index c6bc2dba127..78323b02578 100644 --- a/client/WEB-INF/classes/resources/messages_it_IT.properties +++ b/client/WEB-INF/classes/resources/messages_it_IT.properties @@ -15,6 +15,7 @@ # specific language governing permissions and limitations # under the License. + changed.item.properties=Elementi delle propriet\u00e0 modificati confirm.enable.s3=Si prega di inserire i valori richiesti per abilitare il supporto per il Secondary Storage di tipo S3 confirm.enable.swift=Si prega di inserire i valori richiesti per abilitare il supporto per Swift @@ -432,7 +433,6 @@ label.zone.name=Nome Zona label.zones=Zone label.zone.type=Tipo di Zona label.zoneWizard.trafficType.guest=Guest\: Traffico di rete tra le virtual machine dell\\'utente finale -label.zoneWizard.trafficType.management=Management\: Traffico di rete tra le risorse interne di CloudStack, incluso qualsiasi componente che comunichi con il Management Server, come ad esempio gli host e le VM di Sistema di CloudStack label.zoneWizard.trafficType.public=Public\: Traffico di rete tra la rete internet e le virtual machine nell\\'infrastruttura cloud. label.zoneWizard.trafficType.storage=Storage\: Traffico di rete tra i server di primary e secondary storage, come ad esempio i template delle VM e le operazioni di snapshot message.acquire.new.ip=Si prega di confermare di voler acquisire un nuovo indirizzo IP per questa rete. diff --git a/client/WEB-INF/classes/resources/messages_ja.properties b/client/WEB-INF/classes/resources/messages_ja.properties index 2380e914a75..e483a97804b 100644 --- a/client/WEB-INF/classes/resources/messages_ja.properties +++ b/client/WEB-INF/classes/resources/messages_ja.properties @@ -15,873 +15,874 @@ # specific language governing permissions and limitations # under the License. -changed.item.properties=\u9805\u76EE\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u306E\u5909\u66F4 + +changed.item.properties=\u9805\u76ee\u306e\u30d7\u30ed\u30d1\u30c6\u30a3\u306e\u5909\u66f4 confirm.enable.s3=S3\u57fa\u76e4\u30bb\u30ab\u30f3\u30c0\u30ea\u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u6709\u52b9\u5316\u3059\u308b\u305f\u3081\u306b\u306f\u3001\u4ee5\u4e0b\u306e\u60c5\u5831\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044 -confirm.enable.swift=Swift1 \u306E\u30B5\u30DD\u30FC\u30C8\u3092\u6709\u52B9\u306B\u3059\u308B\u306B\u306F\u3001\u6B21\u306E\u60C5\u5831\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -error.could.not.enable.zone=\u30BE\u30FC\u30F3\u3092\u6709\u52B9\u306B\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F -error.installWizard.message=\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002\u623B\u3063\u3066\u30A8\u30E9\u30FC\u3092\u4FEE\u6B63\u3067\u304D\u307E\u3059\u3002 -error.invalid.username.password=\u7121\u52B9\u306A\u30E6\u30FC\u30B6\u30FC\u540D\u307E\u305F\u306F\u30D1\u30B9\u30EF\u30FC\u30C9 -error.login=\u30E6\u30FC\u30B6\u30FC\u540D/\u30D1\u30B9\u30EF\u30FC\u30C9\u304C\u8A18\u9332\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002 +confirm.enable.swift=Swift1 \u306e\u30b5\u30dd\u30fc\u30c8\u3092\u6709\u52b9\u306b\u3059\u308b\u306b\u306f\u3001\u6b21\u306e\u60c5\u5831\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +error.could.not.enable.zone=\u30be\u30fc\u30f3\u3092\u6709\u52b9\u306b\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f +error.installWizard.message=\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u623b\u3063\u3066\u30a8\u30e9\u30fc\u3092\u4fee\u6b63\u3067\u304d\u307e\u3059\u3002 +error.invalid.username.password=\u7121\u52b9\u306a\u30e6\u30fc\u30b6\u30fc\u540d\u307e\u305f\u306f\u30d1\u30b9\u30ef\u30fc\u30c9 +error.login=\u30e6\u30fc\u30b6\u30fc\u540d/\u30d1\u30b9\u30ef\u30fc\u30c9\u304c\u8a18\u9332\u3068\u4e00\u81f4\u3057\u307e\u305b\u3093\u3002 error.menu.select=\u00e3\u0082\u00a2\u00e3\u0082\u00a4\u00e3\u0083\u0086\u00e3\u0083\u00a0\u00e3\u0081\u008c\u00e9\u0081\u00b8\u00e6\u008a\u009e\u00e3\u0081\u0095\u00e3\u0082\u008c\u00e3\u0081\u00a6\u00e3\u0081\u0084\u00e3\u0081\u00aa\u00e3\u0081\u0084\u00e3\u0081\u009f\u00e3\u0082\u0081\u00e3\u0082\u00a2\u00e3\u0082\u00af\u00e3\u0082\u00b7\u00e3\u0083\u00a7\u00e3\u0083\u00b3\u00e3\u0082\u0092\u00e5\u00ae\u009f\u00e8\u00a1\u008c\u00e3\u0081\u0099\u00e3\u0082\u008b\u00e3\u0081\u0093\u00e3\u0081\u00a8\u00e3\u0081\u008c\u00e3\u0081\u00a7\u00e3\u0081\u008d\u00e3\u0081\u00be\u00e3\u0081\u009b\u00e3\u0082\u0093 -error.mgmt.server.inaccessible=\u7BA1\u7406\u30B5\u30FC\u30D0\u30FC\u306B\u30A2\u30AF\u30BB\u30B9\u3067\u304D\u307E\u305B\u3093\u3002\u5F8C\u3067\u518D\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -error.password.not.match=\u30D1\u30B9\u30EF\u30FC\u30C9\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093 -error.please.specify.physical.network.tags=\u3053\u306E\u7269\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u30BF\u30B0\u3092\u6307\u5B9A\u3057\u306A\u3051\u308C\u3070\u3001\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002 -error.session.expired=\u30BB\u30C3\u30B7\u30E7\u30F3\u306E\u6709\u52B9\u671F\u9650\u304C\u5207\u308C\u307E\u3057\u305F\u3002 -error.something.went.wrong.please.correct.the.following=\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002\u6B21\u306E\u5185\u5BB9\u3092\u4FEE\u6B63\u3057\u3066\u304F\u3060\u3055\u3044 -error.unable.to.reach.management.server=\u7BA1\u7406\u30B5\u30FC\u30D0\u30FC\u3068\u901A\u4FE1\u3067\u304D\u307E\u305B\u3093 +error.mgmt.server.inaccessible=\u7ba1\u7406\u30b5\u30fc\u30d0\u30fc\u306b\u30a2\u30af\u30bb\u30b9\u3067\u304d\u307e\u305b\u3093\u3002\u5f8c\u3067\u518d\u5b9f\u884c\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +error.password.not.match=\u30d1\u30b9\u30ef\u30fc\u30c9\u304c\u4e00\u81f4\u3057\u307e\u305b\u3093 +error.please.specify.physical.network.tags=\u3053\u306e\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u30bf\u30b0\u3092\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3001\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u306f\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093\u3002 +error.session.expired=\u30bb\u30c3\u30b7\u30e7\u30f3\u306e\u6709\u52b9\u671f\u9650\u304c\u5207\u308c\u307e\u3057\u305f\u3002 +error.something.went.wrong.please.correct.the.following=\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u6b21\u306e\u5185\u5bb9\u3092\u4fee\u6b63\u3057\u3066\u304f\u3060\u3055\u3044 +error.unable.to.reach.management.server=\u7ba1\u7406\u30b5\u30fc\u30d0\u30fc\u3068\u901a\u4fe1\u3067\u304d\u307e\u305b\u3093 error.unresolved.internet.name=\u3042\u306a\u305f\u306e\u30a4\u30f3\u30bf\u30fc\u30cd\u30c3\u30c8\u540d\u306f\u89e3\u6c7a\u3055\u308c\u307e\u305b\u3093\u3067\u3057\u305f\u3002 -extractable=\u62BD\u51FA\u53EF\u80FD -force.delete.domain.warning=\u8B66\u544A\: \u3053\u306E\u30AA\u30D7\u30B7\u30E7\u30F3\u3092\u9078\u629E\u3059\u308B\u3068\u3001\u3059\u3079\u3066\u306E\u5B50\u30C9\u30E1\u30A4\u30F3\u304A\u3088\u3073\u95A2\u9023\u3059\u308B\u3059\u3079\u3066\u306E\u30A2\u30AB\u30A6\u30F3\u30C8\u3068\u305D\u306E\u30EA\u30BD\u30FC\u30B9\u304C\u524A\u9664\u3055\u308C\u307E\u3059\u3002 -force.delete=\u5F37\u5236\u524A\u9664 -force.remove.host.warning=\u8B66\u544A\: \u3053\u306E\u30AA\u30D7\u30B7\u30E7\u30F3\u3092\u9078\u629E\u3059\u308B\u3068\u3001\u5B9F\u884C\u4E2D\u306E\u3059\u3079\u3066\u306E\u4EEE\u60F3\u30DE\u30B7\u30F3\u304C\u5F37\u5236\u7684\u306B\u505C\u6B62\u3055\u308C\u3001\u30AF\u30E9\u30B9\u30BF\u30FC\u304B\u3089\u3053\u306E\u30DB\u30B9\u30C8\u304C\u5F37\u5236\u7684\u306B\u89E3\u9664\u3055\u308C\u307E\u3059\u3002 -force.remove=\u5F37\u5236\u89E3\u9664 -force.stop.instance.warning=\u8B66\u544A\: \u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u5F37\u5236\u505C\u6B62\u306F\u3001\u6700\u7D42\u624B\u6BB5\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u30C7\u30FC\u30BF\u3092\u640D\u5931\u3059\u308B\u3060\u3051\u3067\u306A\u304F\u3001\u4EEE\u60F3\u30DE\u30B7\u30F3\u306E\u52D5\u4F5C\u304C\u4E00\u8CAB\u3057\u306A\u304F\u306A\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002 -force.stop=\u5F37\u5236\u505C\u6B62 -ICMP.code=ICMP \u30B3\u30FC\u30C9 -ICMP.type=ICMP \u306E\u7A2E\u985E -image.directory=\u753B\u50CF\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA -inline=\u76F4\u5217 -instances.actions.reboot.label=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u518D\u8D77\u52D5 -label.accept.project.invitation=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3078\u306E\u62DB\u5F85\u306E\u627F\u8AFE -label.account.and.security.group=\u30A2\u30AB\u30A6\u30F3\u30C8\u3001\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3 \u30B0\u30EB\u30FC\u30D7 -label.account.id=\u30A2\u30AB\u30A6\u30F3\u30C8 ID -label.account.name=\u30A2\u30AB\u30A6\u30F3\u30C8\u540D -label.account.specific=\u30A2\u30AB\u30A6\u30F3\u30C8\u56FA\u6709 -label.accounts=\u30A2\u30AB\u30A6\u30F3\u30C8 -label.account=\u30A2\u30AB\u30A6\u30F3\u30C8 -label.acquire.new.ip=\u65B0\u3057\u3044 IP \u30A2\u30C9\u30EC\u30B9\u306E\u53D6\u5F97 -label.action.attach.disk.processing=\u30C7\u30A3\u30B9\u30AF\u3092\u30A2\u30BF\u30C3\u30C1\u3057\u3066\u3044\u307E\u3059... -label.action.attach.disk=\u30C7\u30A3\u30B9\u30AF\u306E\u30A2\u30BF\u30C3\u30C1 -label.action.attach.iso=ISO \u306E\u30A2\u30BF\u30C3\u30C1 -label.action.attach.iso.processing=ISO \u3092\u30A2\u30BF\u30C3\u30C1\u3057\u3066\u3044\u307E\u3059... -label.action.cancel.maintenance.mode.processing=\u4FDD\u5B88\u30E2\u30FC\u30C9\u3092\u30AD\u30E3\u30F3\u30BB\u30EB\u3057\u3066\u3044\u307E\u3059... -label.action.cancel.maintenance.mode=\u4FDD\u5B88\u30E2\u30FC\u30C9\u306E\u30AD\u30E3\u30F3\u30BB\u30EB -label.action.change.password=\u30D1\u30B9\u30EF\u30FC\u30C9\u306E\u5909\u66F4 -label.action.change.service.processing=\u30B5\u30FC\u30D3\u30B9\u3092\u5909\u66F4\u3057\u3066\u3044\u307E\u3059... -label.action.change.service=\u30B5\u30FC\u30D3\u30B9\u306E\u5909\u66F4 -label.action.copy.ISO=ISO \u306E\u30B3\u30D4\u30FC -label.action.copy.ISO.processing=ISO \u3092\u30B3\u30D4\u30FC\u3057\u3066\u3044\u307E\u3059... -label.action.copy.template.processing=\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3092\u30B3\u30D4\u30FC\u3057\u3066\u3044\u307E\u3059... -label.action.copy.template=\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u30B3\u30D4\u30FC -label.action.create.template.from.vm=VM \u304B\u3089\u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u4F5C\u6210 -label.action.create.template.from.volume=\u30DC\u30EA\u30E5\u30FC\u30E0\u304B\u3089\u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u4F5C\u6210 -label.action.create.template.processing=\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3092\u4F5C\u6210\u3057\u3066\u3044\u307E\u3059... -label.action.create.template=\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u4F5C\u6210 -label.action.create.vm.processing=VM \u3092\u4F5C\u6210\u3057\u3066\u3044\u307E\u3059... -label.action.create.vm=VM \u306E\u4F5C\u6210 -label.action.create.volume.processing=\u30DC\u30EA\u30E5\u30FC\u30E0\u3092\u4F5C\u6210\u3057\u3066\u3044\u307E\u3059... -label.action.create.volume=\u30DC\u30EA\u30E5\u30FC\u30E0\u306E\u4F5C\u6210 -label.action.delete.account.processing=\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.delete.account=\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u524A\u9664 -label.action.delete.cluster.processing=\u30AF\u30E9\u30B9\u30BF\u30FC\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.delete.cluster=\u30AF\u30E9\u30B9\u30BF\u30FC\u306E\u524A\u9664 -label.action.delete.disk.offering.processing=\u30C7\u30A3\u30B9\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.delete.disk.offering=\u30C7\u30A3\u30B9\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u306E\u524A\u9664 -label.action.delete.domain.processing=\u30C9\u30E1\u30A4\u30F3\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.delete.domain=\u30C9\u30E1\u30A4\u30F3\u306E\u524A\u9664 -label.action.delete.firewall.processing=\u30D5\u30A1\u30A4\u30A2\u30A6\u30A9\u30FC\u30EB\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.delete.firewall=\u30D5\u30A1\u30A4\u30A2\u30A6\u30A9\u30FC\u30EB\u898F\u5247\u306E\u524A\u9664 -label.action.delete.ingress.rule.processing=\u53D7\u4FE1\u898F\u5247\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.delete.ingress.rule=\u53D7\u4FE1\u898F\u5247\u306E\u524A\u9664 -label.action.delete.IP.range=IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2\u306E\u524A\u9664 -label.action.delete.IP.range.processing=IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.delete.ISO=ISO \u306E\u524A\u9664 -label.action.delete.ISO.processing=ISO \u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.delete.load.balancer.processing=\u8CA0\u8377\u5206\u6563\u88C5\u7F6E\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.delete.load.balancer=\u8CA0\u8377\u5206\u6563\u898F\u5247\u306E\u524A\u9664 -label.action.delete.network.processing=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.delete.network=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u524A\u9664 -label.action.delete.nexusVswitch=Nexus 1000V \u306E\u524A\u9664 -label.action.delete.physical.network=\u7269\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u524A\u9664 -label.action.delete.pod.processing=\u30DD\u30C3\u30C9\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.delete.pod=\u30DD\u30C3\u30C9\u306E\u524A\u9664 -label.action.delete.primary.storage.processing=\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.delete.primary.storage=\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u306E\u524A\u9664 -label.action.delete.secondary.storage.processing=\u30BB\u30AB\u30F3\u30C0\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.delete.secondary.storage=\u30BB\u30AB\u30F3\u30C0\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u306E\u524A\u9664 -label.action.delete.security.group.processing=\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3 \u30B0\u30EB\u30FC\u30D7\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.delete.security.group=\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3 \u30B0\u30EB\u30FC\u30D7\u306E\u524A\u9664 -label.action.delete.service.offering.processing=\u30B5\u30FC\u30D3\u30B9 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.delete.service.offering=\u30B5\u30FC\u30D3\u30B9 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u306E\u524A\u9664 -label.action.delete.snapshot.processing=\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.delete.snapshot=\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u306E\u524A\u9664 -label.action.delete.system.service.offering=\u30B7\u30B9\u30C6\u30E0 \u30B5\u30FC\u30D3\u30B9 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u306E\u524A\u9664 -label.action.delete.template.processing=\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.delete.template=\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u524A\u9664 -label.action.delete.user.processing=\u30E6\u30FC\u30B6\u30FC\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.delete.user=\u30E6\u30FC\u30B6\u30FC\u306E\u524A\u9664 -label.action.delete.volume.processing=\u30DC\u30EA\u30E5\u30FC\u30E0\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.delete.volume=\u30DC\u30EA\u30E5\u30FC\u30E0\u306E\u524A\u9664 -label.action.delete.zone.processing=\u30BE\u30FC\u30F3\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.delete.zone=\u30BE\u30FC\u30F3\u306E\u524A\u9664 -label.action.destroy.instance.processing=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u7834\u68C4\u3057\u3066\u3044\u307E\u3059... -label.action.destroy.instance=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u7834\u68C4 -label.action.destroy.systemvm.processing=\u30B7\u30B9\u30C6\u30E0 VM \u3092\u7834\u68C4\u3057\u3066\u3044\u307E\u3059... -label.action.destroy.systemvm=\u30B7\u30B9\u30C6\u30E0 VM \u306E\u7834\u68C4 -label.action.detach.disk.processing=\u30C7\u30A3\u30B9\u30AF\u3092\u30C7\u30BF\u30C3\u30C1\u3057\u3066\u3044\u307E\u3059... -label.action.detach.disk=\u30C7\u30A3\u30B9\u30AF\u306E\u30C7\u30BF\u30C3\u30C1 -label.action.detach.iso=ISO \u306E\u30C7\u30BF\u30C3\u30C1 -label.action.detach.iso.processing=ISO \u3092\u30C7\u30BF\u30C3\u30C1\u3057\u3066\u3044\u307E\u3059... -label.action.disable.account.processing=\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u7121\u52B9\u306B\u3057\u3066\u3044\u307E\u3059... -label.action.disable.account=\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u7121\u52B9\u5316 -label.action.disable.cluster.processing=\u30AF\u30E9\u30B9\u30BF\u30FC\u3092\u7121\u52B9\u306B\u3057\u3066\u3044\u307E\u3059... -label.action.disable.cluster=\u30AF\u30E9\u30B9\u30BF\u30FC\u306E\u7121\u52B9\u5316 -label.action.disable.nexusVswitch=Nexus 1000V \u306E\u7121\u52B9\u5316 -label.action.disable.physical.network=\u7269\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u7121\u52B9\u5316 -label.action.disable.pod.processing=\u30DD\u30C3\u30C9\u3092\u7121\u52B9\u306B\u3057\u3066\u3044\u307E\u3059... -label.action.disable.pod=\u30DD\u30C3\u30C9\u306E\u7121\u52B9\u5316 -label.action.disable.static.NAT.processing=\u9759\u7684 NAT \u3092\u7121\u52B9\u306B\u3057\u3066\u3044\u307E\u3059... -label.action.disable.static.NAT=\u9759\u7684 NAT \u306E\u7121\u52B9\u5316 -label.action.disable.user.processing=\u30E6\u30FC\u30B6\u30FC\u3092\u7121\u52B9\u306B\u3057\u3066\u3044\u307E\u3059... -label.action.disable.user=\u30E6\u30FC\u30B6\u30FC\u306E\u7121\u52B9\u5316 -label.action.disable.zone.processing=\u30BE\u30FC\u30F3\u3092\u7121\u52B9\u306B\u3057\u3066\u3044\u307E\u3059... -label.action.disable.zone=\u30BE\u30FC\u30F3\u306E\u7121\u52B9\u5316 -label.action.download.ISO=ISO \u306E\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9 -label.action.download.template=\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9 -label.action.download.volume.processing=\u30DC\u30EA\u30E5\u30FC\u30E0\u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u3057\u3066\u3044\u307E\u3059... -label.action.download.volume=\u30DC\u30EA\u30E5\u30FC\u30E0\u306E\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9 -label.action.edit.account=\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u7DE8\u96C6 -label.action.edit.disk.offering=\u30C7\u30A3\u30B9\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u306E\u7DE8\u96C6 -label.action.edit.domain=\u30C9\u30E1\u30A4\u30F3\u306E\u7DE8\u96C6 -label.action.edit.global.setting=\u30B0\u30ED\u30FC\u30D0\u30EB\u8A2D\u5B9A\u306E\u7DE8\u96C6 -label.action.edit.host=\u30DB\u30B9\u30C8\u306E\u7DE8\u96C6 -label.action.edit.instance=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u7DE8\u96C6 -label.action.edit.ISO=ISO \u306E\u7DE8\u96C6 -label.action.edit.network.offering=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u306E\u7DE8\u96C6 -label.action.edit.network.processing=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u7DE8\u96C6\u3057\u3066\u3044\u307E\u3059... -label.action.edit.network=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u7DE8\u96C6 -label.action.edit.pod=\u30DD\u30C3\u30C9\u306E\u7DE8\u96C6 -label.action.edit.primary.storage=\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u306E\u7DE8\u96C6 -label.action.edit.resource.limits=\u30EA\u30BD\u30FC\u30B9\u5236\u9650\u306E\u7DE8\u96C6 -label.action.edit.service.offering=\u30B5\u30FC\u30D3\u30B9 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u306E\u7DE8\u96C6 -label.action.edit.template=\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u7DE8\u96C6 -label.action.edit.user=\u30E6\u30FC\u30B6\u30FC\u306E\u7DE8\u96C6 -label.action.edit.zone=\u30BE\u30FC\u30F3\u306E\u7DE8\u96C6 -label.action.enable.account.processing=\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u6709\u52B9\u306B\u3057\u3066\u3044\u307E\u3059... -label.action.enable.account=\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u6709\u52B9\u5316 -label.action.enable.cluster.processing=\u30AF\u30E9\u30B9\u30BF\u30FC\u3092\u6709\u52B9\u306B\u3057\u3066\u3044\u307E\u3059... -label.action.enable.cluster=\u30AF\u30E9\u30B9\u30BF\u30FC\u306E\u6709\u52B9\u5316 -label.action.enable.maintenance.mode.processing=\u4FDD\u5B88\u30E2\u30FC\u30C9\u3092\u6709\u52B9\u306B\u3057\u3066\u3044\u307E\u3059... -label.action.enable.maintenance.mode=\u4FDD\u5B88\u30E2\u30FC\u30C9\u306E\u6709\u52B9\u5316 -label.action.enable.nexusVswitch=Nexus 1000V \u306E\u6709\u52B9\u5316 -label.action.enable.physical.network=\u7269\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u6709\u52B9\u5316 -label.action.enable.pod.processing=\u30DD\u30C3\u30C9\u3092\u6709\u52B9\u306B\u3057\u3066\u3044\u307E\u3059... -label.action.enable.pod=\u30DD\u30C3\u30C9\u306E\u6709\u52B9\u5316 -label.action.enable.static.NAT.processing=\u9759\u7684 NAT \u3092\u6709\u52B9\u306B\u3057\u3066\u3044\u307E\u3059... -label.action.enable.static.NAT=\u9759\u7684 NAT \u306E\u6709\u52B9\u5316 -label.action.enable.user.processing=\u30E6\u30FC\u30B6\u30FC\u3092\u6709\u52B9\u306B\u3057\u3066\u3044\u307E\u3059... -label.action.enable.user=\u30E6\u30FC\u30B6\u30FC\u306E\u6709\u52B9\u5316 -label.action.enable.zone.processing=\u30BE\u30FC\u30F3\u3092\u6709\u52B9\u306B\u3057\u3066\u3044\u307E\u3059... -label.action.enable.zone=\u30BE\u30FC\u30F3\u306E\u6709\u52B9\u5316 -label.action.force.reconnect.processing=\u518D\u63A5\u7D9A\u3057\u3066\u3044\u307E\u3059... -label.action.force.reconnect=\u5F37\u5236\u518D\u63A5\u7D9A -label.action.generate.keys.processing=\u30AD\u30FC\u3092\u751F\u6210\u3057\u3066\u3044\u307E\u3059... -label.action.generate.keys=\u30AD\u30FC\u306E\u751F\u6210 -label.action.list.nexusVswitch=Nexus 1000V \u306E\u4E00\u89A7\u8868\u793A -label.action.lock.account.processing=\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u30ED\u30C3\u30AF\u3057\u3066\u3044\u307E\u3059... -label.action.lock.account=\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30ED\u30C3\u30AF -label.action.manage.cluster.processing=\u30AF\u30E9\u30B9\u30BF\u30FC\u3092\u7BA1\u7406\u5BFE\u8C61\u306B\u3057\u3066\u3044\u307E\u3059... -label.action.manage.cluster=\u30AF\u30E9\u30B9\u30BF\u30FC\u306E\u7BA1\u7406\u5BFE\u8C61\u5316 -label.action.migrate.instance.processing=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u79FB\u884C\u3057\u3066\u3044\u307E\u3059... -label.action.migrate.instance=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u79FB\u884C -label.action.migrate.router.processing=\u30EB\u30FC\u30BF\u30FC\u3092\u79FB\u884C\u3057\u3066\u3044\u307E\u3059... -label.action.migrate.router=\u30EB\u30FC\u30BF\u30FC\u306E\u79FB\u884C -label.action.migrate.systemvm.processing=\u30B7\u30B9\u30C6\u30E0 VM \u3092\u79FB\u884C\u3057\u3066\u3044\u307E\u3059... -label.action.migrate.systemvm=\u30B7\u30B9\u30C6\u30E0 VM \u306E\u79FB\u884C -label.action.reboot.instance.processing=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u518D\u8D77\u52D5\u3057\u3066\u3044\u307E\u3059... -label.action.reboot.instance=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u518D\u8D77\u52D5 -label.action.reboot.router.processing=\u30EB\u30FC\u30BF\u30FC\u3092\u518D\u8D77\u52D5\u3057\u3066\u3044\u307E\u3059... -label.action.reboot.router=\u30EB\u30FC\u30BF\u30FC\u306E\u518D\u8D77\u52D5 -label.action.reboot.systemvm.processing=\u30B7\u30B9\u30C6\u30E0 VM \u3092\u518D\u8D77\u52D5\u3057\u3066\u3044\u307E\u3059... -label.action.reboot.systemvm=\u30B7\u30B9\u30C6\u30E0 VM \u306E\u518D\u8D77\u52D5 -label.action.recurring.snapshot=\u5B9A\u671F\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8 -label.action.register.iso=ISO \u306E\u767B\u9332 -label.action.register.template=\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u767B\u9332 -label.action.release.ip=IP \u30A2\u30C9\u30EC\u30B9\u306E\u89E3\u653E -label.action.release.ip.processing=IP \u30A2\u30C9\u30EC\u30B9\u3092\u89E3\u653E\u3057\u3066\u3044\u307E\u3059... -label.action.remove.host.processing=\u30DB\u30B9\u30C8\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.action.remove.host=\u30DB\u30B9\u30C8\u306E\u524A\u9664 -label.action.reset.password.processing=\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u30EA\u30BB\u30C3\u30C8\u3057\u3066\u3044\u307E\u3059... -label.action.reset.password=\u30D1\u30B9\u30EF\u30FC\u30C9\u306E\u30EA\u30BB\u30C3\u30C8 -label.action.resource.limits=\u30EA\u30BD\u30FC\u30B9\u5236\u9650 -label.action.restore.instance.processing=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u5FA9\u5143\u3057\u3066\u3044\u307E\u3059... -label.action.restore.instance=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u5FA9\u5143 -label.action.start.instance.processing=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u8D77\u52D5\u3057\u3066\u3044\u307E\u3059... -label.action.start.instance=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u8D77\u52D5 -label.action.start.router.processing=\u30EB\u30FC\u30BF\u30FC\u3092\u8D77\u52D5\u3057\u3066\u3044\u307E\u3059... -label.action.start.router=\u30EB\u30FC\u30BF\u30FC\u306E\u8D77\u52D5 -label.action.start.systemvm.processing=\u30B7\u30B9\u30C6\u30E0 VM \u3092\u8D77\u52D5\u3057\u3066\u3044\u307E\u3059... -label.action.start.systemvm=\u30B7\u30B9\u30C6\u30E0 VM \u306E\u8D77\u52D5 -label.action.stop.instance.processing=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u505C\u6B62\u3057\u3066\u3044\u307E\u3059... -label.action.stop.instance=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u505C\u6B62 -label.action.stop.router.processing=\u30EB\u30FC\u30BF\u30FC\u3092\u505C\u6B62\u3057\u3066\u3044\u307E\u3059... -label.action.stop.router=\u30EB\u30FC\u30BF\u30FC\u306E\u505C\u6B62 -label.action.stop.systemvm.processing=\u30B7\u30B9\u30C6\u30E0 VM \u3092\u505C\u6B62\u3057\u3066\u3044\u307E\u3059... -label.action.stop.systemvm=\u30B7\u30B9\u30C6\u30E0 VM \u306E\u505C\u6B62 -label.actions=\u64CD\u4F5C -label.action.take.snapshot.processing=\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u3092\u4F5C\u6210\u3057\u3066\u3044\u307E\u3059.... -label.action.take.snapshot=\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u306E\u4F5C\u6210 -label.action.unmanage.cluster.processing=\u30AF\u30E9\u30B9\u30BF\u30FC\u3092\u975E\u7BA1\u7406\u5BFE\u8C61\u306B\u3057\u3066\u3044\u307E\u3059... -label.action.unmanage.cluster=\u30AF\u30E9\u30B9\u30BF\u30FC\u306E\u975E\u7BA1\u7406\u5BFE\u8C61\u5316 -label.action.update.OS.preference=OS \u57FA\u672C\u8A2D\u5B9A\u306E\u66F4\u65B0 -label.action.update.OS.preference.processing=OS \u57FA\u672C\u8A2D\u5B9A\u3092\u66F4\u65B0\u3057\u3066\u3044\u307E\u3059... -label.action.update.resource.count.processing=\u30EA\u30BD\u30FC\u30B9\u6570\u3092\u66F4\u65B0\u3057\u3066\u3044\u307E\u3059... -label.action.update.resource.count=\u30EA\u30BD\u30FC\u30B9\u6570\u306E\u66F4\u65B0 -label.activate.project=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u30A2\u30AF\u30C6\u30A3\u30D6\u5316 -label.active.sessions=\u30A2\u30AF\u30C6\u30A3\u30D6\u306A\u30BB\u30C3\u30B7\u30E7\u30F3 -label.add.accounts.to=\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u8FFD\u52A0\u5148\: -label.add.accounts=\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u8FFD\u52A0 -label.add.account.to.project=\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3078\u306E\u8FFD\u52A0 -label.add.account=\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u8FFD\u52A0 -label.add.ACL=ACL \u306E\u8FFD\u52A0 -label.add.by.cidr=CIDR \u3067\u8FFD\u52A0 -label.add.by.group=\u30B0\u30EB\u30FC\u30D7\u3067\u8FFD\u52A0 -label.add.by=\u8FFD\u52A0\u5358\u4F4D -label.add.cluster=\u30AF\u30E9\u30B9\u30BF\u30FC\u306E\u8FFD\u52A0 -label.add.compute.offering=\u30B3\u30F3\u30D4\u30E5\u30FC\u30C6\u30A3\u30F3\u30B0 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u306E\u8FFD\u52A0 -label.add.direct.iprange=\u76F4\u63A5 IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2\u306E\u8FFD\u52A0 -label.add.disk.offering=\u30C7\u30A3\u30B9\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u306E\u8FFD\u52A0 -label.add.domain=\u30C9\u30E1\u30A4\u30F3\u306E\u8FFD\u52A0 -label.add.egress.rule=\u9001\u4FE1\u898F\u5247\u306E\u8FFD\u52A0 -label.add.F5.device=F5 \u30C7\u30D0\u30A4\u30B9\u306E\u8FFD\u52A0 -label.add.firewall=\u30D5\u30A1\u30A4\u30A2\u30A6\u30A9\u30FC\u30EB\u898F\u5247\u306E\u8FFD\u52A0 -label.add.guest.network=\u30B2\u30B9\u30C8 \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u8FFD\u52A0 -label.add.host=\u30DB\u30B9\u30C8\u306E\u8FFD\u52A0 -label.adding.cluster=\u30AF\u30E9\u30B9\u30BF\u30FC\u3092\u8FFD\u52A0\u3057\u3066\u3044\u307E\u3059 -label.adding.failed=\u8FFD\u52A0\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F -label.adding.pod=\u30DD\u30C3\u30C9\u3092\u8FFD\u52A0\u3057\u3066\u3044\u307E\u3059 -label.adding.processing=\u8FFD\u52A0\u3057\u3066\u3044\u307E\u3059... -label.add.ingress.rule=\u53D7\u4FE1\u898F\u5247\u306E\u8FFD\u52A0 -label.adding.succeeded=\u8FFD\u52A0\u3057\u307E\u3057\u305F -label.adding=\u8FFD\u52A0\u3057\u3066\u3044\u307E\u3059 -label.adding.user=\u30E6\u30FC\u30B6\u30FC\u3092\u8FFD\u52A0\u3057\u3066\u3044\u307E\u3059 -label.adding.zone=\u30BE\u30FC\u30F3\u3092\u8FFD\u52A0\u3057\u3066\u3044\u307E\u3059 -label.add.ip.range=IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2\u306E\u8FFD\u52A0 -label.additional.networks=\u8FFD\u52A0\u306E\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF -label.add.load.balancer=\u8CA0\u8377\u5206\u6563\u88C5\u7F6E\u306E\u8FFD\u52A0 -label.add.more=\u305D\u306E\u307B\u304B\u306E\u9805\u76EE\u306E\u8FFD\u52A0 -label.add.netScaler.device=Netscaler \u30C7\u30D0\u30A4\u30B9\u306E\u8FFD\u52A0 -label.add.network.ACL=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF ACL \u306E\u8FFD\u52A0 -label.add.network.device=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30C7\u30D0\u30A4\u30B9\u306E\u8FFD\u52A0 -label.add.network.offering=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u306E\u8FFD\u52A0 -label.add.network=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u8FFD\u52A0 -label.add.new.F5=\u65B0\u3057\u3044 F5 \u306E\u8FFD\u52A0 -label.add.new.gateway=\u65B0\u3057\u3044\u30B2\u30FC\u30C8\u30A6\u30A7\u30A4\u306E\u8FFD\u52A0 -label.add.new.NetScaler=\u65B0\u3057\u3044 NetScaler \u306E\u8FFD\u52A0 -label.add.new.SRX=\u65B0\u3057\u3044 SRX \u306E\u8FFD\u52A0 -label.add.new.tier=\u65B0\u3057\u3044\u968E\u5C64\u306E\u8FFD\u52A0 +extractable=\u62bd\u51fa\u53ef\u80fd +force.delete.domain.warning=\u8b66\u544a\: \u3053\u306e\u30aa\u30d7\u30b7\u30e7\u30f3\u3092\u9078\u629e\u3059\u308b\u3068\u3001\u3059\u3079\u3066\u306e\u5b50\u30c9\u30e1\u30a4\u30f3\u304a\u3088\u3073\u95a2\u9023\u3059\u308b\u3059\u3079\u3066\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u3068\u305d\u306e\u30ea\u30bd\u30fc\u30b9\u304c\u524a\u9664\u3055\u308c\u307e\u3059\u3002 +force.delete=\u5f37\u5236\u524a\u9664 +force.remove.host.warning=\u8b66\u544a\: \u3053\u306e\u30aa\u30d7\u30b7\u30e7\u30f3\u3092\u9078\u629e\u3059\u308b\u3068\u3001\u5b9f\u884c\u4e2d\u306e\u3059\u3079\u3066\u306e\u4eee\u60f3\u30de\u30b7\u30f3\u304c\u5f37\u5236\u7684\u306b\u505c\u6b62\u3055\u308c\u3001\u30af\u30e9\u30b9\u30bf\u30fc\u304b\u3089\u3053\u306e\u30db\u30b9\u30c8\u304c\u5f37\u5236\u7684\u306b\u89e3\u9664\u3055\u308c\u307e\u3059\u3002 +force.remove=\u5f37\u5236\u89e3\u9664 +force.stop.instance.warning=\u8b66\u544a\: \u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u5f37\u5236\u505c\u6b62\u306f\u3001\u6700\u7d42\u624b\u6bb5\u306b\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u30c7\u30fc\u30bf\u3092\u640d\u5931\u3059\u308b\u3060\u3051\u3067\u306a\u304f\u3001\u4eee\u60f3\u30de\u30b7\u30f3\u306e\u52d5\u4f5c\u304c\u4e00\u8cab\u3057\u306a\u304f\u306a\u308b\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059\u3002 +force.stop=\u5f37\u5236\u505c\u6b62 +ICMP.code=ICMP \u30b3\u30fc\u30c9 +ICMP.type=ICMP \u306e\u7a2e\u985e +image.directory=\u753b\u50cf\u30c7\u30a3\u30ec\u30af\u30c8\u30ea +inline=\u76f4\u5217 +instances.actions.reboot.label=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u518d\u8d77\u52d5 +label.accept.project.invitation=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3078\u306e\u62db\u5f85\u306e\u627f\u8afe +label.account.and.security.group=\u30a2\u30ab\u30a6\u30f3\u30c8\u3001\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7 +label.account.id=\u30a2\u30ab\u30a6\u30f3\u30c8 ID +label.account.name=\u30a2\u30ab\u30a6\u30f3\u30c8\u540d +label.account.specific=\u30a2\u30ab\u30a6\u30f3\u30c8\u56fa\u6709 +label.accounts=\u30a2\u30ab\u30a6\u30f3\u30c8 +label.account=\u30a2\u30ab\u30a6\u30f3\u30c8 +label.acquire.new.ip=\u65b0\u3057\u3044 IP \u30a2\u30c9\u30ec\u30b9\u306e\u53d6\u5f97 +label.action.attach.disk.processing=\u30c7\u30a3\u30b9\u30af\u3092\u30a2\u30bf\u30c3\u30c1\u3057\u3066\u3044\u307e\u3059... +label.action.attach.disk=\u30c7\u30a3\u30b9\u30af\u306e\u30a2\u30bf\u30c3\u30c1 +label.action.attach.iso=ISO \u306e\u30a2\u30bf\u30c3\u30c1 +label.action.attach.iso.processing=ISO \u3092\u30a2\u30bf\u30c3\u30c1\u3057\u3066\u3044\u307e\u3059... +label.action.cancel.maintenance.mode.processing=\u4fdd\u5b88\u30e2\u30fc\u30c9\u3092\u30ad\u30e3\u30f3\u30bb\u30eb\u3057\u3066\u3044\u307e\u3059... +label.action.cancel.maintenance.mode=\u4fdd\u5b88\u30e2\u30fc\u30c9\u306e\u30ad\u30e3\u30f3\u30bb\u30eb +label.action.change.password=\u30d1\u30b9\u30ef\u30fc\u30c9\u306e\u5909\u66f4 +label.action.change.service.processing=\u30b5\u30fc\u30d3\u30b9\u3092\u5909\u66f4\u3057\u3066\u3044\u307e\u3059... +label.action.change.service=\u30b5\u30fc\u30d3\u30b9\u306e\u5909\u66f4 +label.action.copy.ISO=ISO \u306e\u30b3\u30d4\u30fc +label.action.copy.ISO.processing=ISO \u3092\u30b3\u30d4\u30fc\u3057\u3066\u3044\u307e\u3059... +label.action.copy.template.processing=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u30b3\u30d4\u30fc\u3057\u3066\u3044\u307e\u3059... +label.action.copy.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u30b3\u30d4\u30fc +label.action.create.template.from.vm=VM \u304b\u3089\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u4f5c\u6210 +label.action.create.template.from.volume=\u30dc\u30ea\u30e5\u30fc\u30e0\u304b\u3089\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u4f5c\u6210 +label.action.create.template.processing=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u4f5c\u6210\u3057\u3066\u3044\u307e\u3059... +label.action.create.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u4f5c\u6210 +label.action.create.vm.processing=VM \u3092\u4f5c\u6210\u3057\u3066\u3044\u307e\u3059... +label.action.create.vm=VM \u306e\u4f5c\u6210 +label.action.create.volume.processing=\u30dc\u30ea\u30e5\u30fc\u30e0\u3092\u4f5c\u6210\u3057\u3066\u3044\u307e\u3059... +label.action.create.volume=\u30dc\u30ea\u30e5\u30fc\u30e0\u306e\u4f5c\u6210 +label.action.delete.account.processing=\u30a2\u30ab\u30a6\u30f3\u30c8\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.account=\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u524a\u9664 +label.action.delete.cluster.processing=\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.cluster=\u30af\u30e9\u30b9\u30bf\u30fc\u306e\u524a\u9664 +label.action.delete.disk.offering.processing=\u30c7\u30a3\u30b9\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.disk.offering=\u30c7\u30a3\u30b9\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u306e\u524a\u9664 +label.action.delete.domain.processing=\u30c9\u30e1\u30a4\u30f3\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.domain=\u30c9\u30e1\u30a4\u30f3\u306e\u524a\u9664 +label.action.delete.firewall.processing=\u30d5\u30a1\u30a4\u30a2\u30a6\u30a9\u30fc\u30eb\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.firewall=\u30d5\u30a1\u30a4\u30a2\u30a6\u30a9\u30fc\u30eb\u898f\u5247\u306e\u524a\u9664 +label.action.delete.ingress.rule.processing=\u53d7\u4fe1\u898f\u5247\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.ingress.rule=\u53d7\u4fe1\u898f\u5247\u306e\u524a\u9664 +label.action.delete.IP.range=IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u306e\u524a\u9664 +label.action.delete.IP.range.processing=IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.ISO=ISO \u306e\u524a\u9664 +label.action.delete.ISO.processing=ISO \u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.load.balancer.processing=\u8ca0\u8377\u5206\u6563\u88c5\u7f6e\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.load.balancer=\u8ca0\u8377\u5206\u6563\u898f\u5247\u306e\u524a\u9664 +label.action.delete.network.processing=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.network=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u524a\u9664 +label.action.delete.nexusVswitch=Nexus 1000V \u306e\u524a\u9664 +label.action.delete.physical.network=\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u524a\u9664 +label.action.delete.pod.processing=\u30dd\u30c3\u30c9\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.pod=\u30dd\u30c3\u30c9\u306e\u524a\u9664 +label.action.delete.primary.storage.processing=\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.primary.storage=\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u306e\u524a\u9664 +label.action.delete.secondary.storage.processing=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.secondary.storage=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u306e\u524a\u9664 +label.action.delete.security.group.processing=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.security.group=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u306e\u524a\u9664 +label.action.delete.service.offering.processing=\u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.service.offering=\u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u306e\u524a\u9664 +label.action.delete.snapshot.processing=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.snapshot=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u306e\u524a\u9664 +label.action.delete.system.service.offering=\u30b7\u30b9\u30c6\u30e0 \u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u306e\u524a\u9664 +label.action.delete.template.processing=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u524a\u9664 +label.action.delete.user.processing=\u30e6\u30fc\u30b6\u30fc\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.user=\u30e6\u30fc\u30b6\u30fc\u306e\u524a\u9664 +label.action.delete.volume.processing=\u30dc\u30ea\u30e5\u30fc\u30e0\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.volume=\u30dc\u30ea\u30e5\u30fc\u30e0\u306e\u524a\u9664 +label.action.delete.zone.processing=\u30be\u30fc\u30f3\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.delete.zone=\u30be\u30fc\u30f3\u306e\u524a\u9664 +label.action.destroy.instance.processing=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u7834\u68c4\u3057\u3066\u3044\u307e\u3059... +label.action.destroy.instance=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u7834\u68c4 +label.action.destroy.systemvm.processing=\u30b7\u30b9\u30c6\u30e0 VM \u3092\u7834\u68c4\u3057\u3066\u3044\u307e\u3059... +label.action.destroy.systemvm=\u30b7\u30b9\u30c6\u30e0 VM \u306e\u7834\u68c4 +label.action.detach.disk.processing=\u30c7\u30a3\u30b9\u30af\u3092\u30c7\u30bf\u30c3\u30c1\u3057\u3066\u3044\u307e\u3059... +label.action.detach.disk=\u30c7\u30a3\u30b9\u30af\u306e\u30c7\u30bf\u30c3\u30c1 +label.action.detach.iso=ISO \u306e\u30c7\u30bf\u30c3\u30c1 +label.action.detach.iso.processing=ISO \u3092\u30c7\u30bf\u30c3\u30c1\u3057\u3066\u3044\u307e\u3059... +label.action.disable.account.processing=\u30a2\u30ab\u30a6\u30f3\u30c8\u3092\u7121\u52b9\u306b\u3057\u3066\u3044\u307e\u3059... +label.action.disable.account=\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u7121\u52b9\u5316 +label.action.disable.cluster.processing=\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u7121\u52b9\u306b\u3057\u3066\u3044\u307e\u3059... +label.action.disable.cluster=\u30af\u30e9\u30b9\u30bf\u30fc\u306e\u7121\u52b9\u5316 +label.action.disable.nexusVswitch=Nexus 1000V \u306e\u7121\u52b9\u5316 +label.action.disable.physical.network=\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u7121\u52b9\u5316 +label.action.disable.pod.processing=\u30dd\u30c3\u30c9\u3092\u7121\u52b9\u306b\u3057\u3066\u3044\u307e\u3059... +label.action.disable.pod=\u30dd\u30c3\u30c9\u306e\u7121\u52b9\u5316 +label.action.disable.static.NAT.processing=\u9759\u7684 NAT \u3092\u7121\u52b9\u306b\u3057\u3066\u3044\u307e\u3059... +label.action.disable.static.NAT=\u9759\u7684 NAT \u306e\u7121\u52b9\u5316 +label.action.disable.user.processing=\u30e6\u30fc\u30b6\u30fc\u3092\u7121\u52b9\u306b\u3057\u3066\u3044\u307e\u3059... +label.action.disable.user=\u30e6\u30fc\u30b6\u30fc\u306e\u7121\u52b9\u5316 +label.action.disable.zone.processing=\u30be\u30fc\u30f3\u3092\u7121\u52b9\u306b\u3057\u3066\u3044\u307e\u3059... +label.action.disable.zone=\u30be\u30fc\u30f3\u306e\u7121\u52b9\u5316 +label.action.download.ISO=ISO \u306e\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9 +label.action.download.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9 +label.action.download.volume.processing=\u30dc\u30ea\u30e5\u30fc\u30e0\u3092\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3057\u3066\u3044\u307e\u3059... +label.action.download.volume=\u30dc\u30ea\u30e5\u30fc\u30e0\u306e\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9 +label.action.edit.account=\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u7de8\u96c6 +label.action.edit.disk.offering=\u30c7\u30a3\u30b9\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u306e\u7de8\u96c6 +label.action.edit.domain=\u30c9\u30e1\u30a4\u30f3\u306e\u7de8\u96c6 +label.action.edit.global.setting=\u30b0\u30ed\u30fc\u30d0\u30eb\u8a2d\u5b9a\u306e\u7de8\u96c6 +label.action.edit.host=\u30db\u30b9\u30c8\u306e\u7de8\u96c6 +label.action.edit.instance=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u7de8\u96c6 +label.action.edit.ISO=ISO \u306e\u7de8\u96c6 +label.action.edit.network.offering=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u306e\u7de8\u96c6 +label.action.edit.network.processing=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u7de8\u96c6\u3057\u3066\u3044\u307e\u3059... +label.action.edit.network=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u7de8\u96c6 +label.action.edit.pod=\u30dd\u30c3\u30c9\u306e\u7de8\u96c6 +label.action.edit.primary.storage=\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u306e\u7de8\u96c6 +label.action.edit.resource.limits=\u30ea\u30bd\u30fc\u30b9\u5236\u9650\u306e\u7de8\u96c6 +label.action.edit.service.offering=\u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u306e\u7de8\u96c6 +label.action.edit.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u7de8\u96c6 +label.action.edit.user=\u30e6\u30fc\u30b6\u30fc\u306e\u7de8\u96c6 +label.action.edit.zone=\u30be\u30fc\u30f3\u306e\u7de8\u96c6 +label.action.enable.account.processing=\u30a2\u30ab\u30a6\u30f3\u30c8\u3092\u6709\u52b9\u306b\u3057\u3066\u3044\u307e\u3059... +label.action.enable.account=\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u6709\u52b9\u5316 +label.action.enable.cluster.processing=\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u6709\u52b9\u306b\u3057\u3066\u3044\u307e\u3059... +label.action.enable.cluster=\u30af\u30e9\u30b9\u30bf\u30fc\u306e\u6709\u52b9\u5316 +label.action.enable.maintenance.mode.processing=\u4fdd\u5b88\u30e2\u30fc\u30c9\u3092\u6709\u52b9\u306b\u3057\u3066\u3044\u307e\u3059... +label.action.enable.maintenance.mode=\u4fdd\u5b88\u30e2\u30fc\u30c9\u306e\u6709\u52b9\u5316 +label.action.enable.nexusVswitch=Nexus 1000V \u306e\u6709\u52b9\u5316 +label.action.enable.physical.network=\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u6709\u52b9\u5316 +label.action.enable.pod.processing=\u30dd\u30c3\u30c9\u3092\u6709\u52b9\u306b\u3057\u3066\u3044\u307e\u3059... +label.action.enable.pod=\u30dd\u30c3\u30c9\u306e\u6709\u52b9\u5316 +label.action.enable.static.NAT.processing=\u9759\u7684 NAT \u3092\u6709\u52b9\u306b\u3057\u3066\u3044\u307e\u3059... +label.action.enable.static.NAT=\u9759\u7684 NAT \u306e\u6709\u52b9\u5316 +label.action.enable.user.processing=\u30e6\u30fc\u30b6\u30fc\u3092\u6709\u52b9\u306b\u3057\u3066\u3044\u307e\u3059... +label.action.enable.user=\u30e6\u30fc\u30b6\u30fc\u306e\u6709\u52b9\u5316 +label.action.enable.zone.processing=\u30be\u30fc\u30f3\u3092\u6709\u52b9\u306b\u3057\u3066\u3044\u307e\u3059... +label.action.enable.zone=\u30be\u30fc\u30f3\u306e\u6709\u52b9\u5316 +label.action.force.reconnect.processing=\u518d\u63a5\u7d9a\u3057\u3066\u3044\u307e\u3059... +label.action.force.reconnect=\u5f37\u5236\u518d\u63a5\u7d9a +label.action.generate.keys.processing=\u30ad\u30fc\u3092\u751f\u6210\u3057\u3066\u3044\u307e\u3059... +label.action.generate.keys=\u30ad\u30fc\u306e\u751f\u6210 +label.action.list.nexusVswitch=Nexus 1000V \u306e\u4e00\u89a7\u8868\u793a +label.action.lock.account.processing=\u30a2\u30ab\u30a6\u30f3\u30c8\u3092\u30ed\u30c3\u30af\u3057\u3066\u3044\u307e\u3059... +label.action.lock.account=\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u30ed\u30c3\u30af +label.action.manage.cluster.processing=\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u7ba1\u7406\u5bfe\u8c61\u306b\u3057\u3066\u3044\u307e\u3059... +label.action.manage.cluster=\u30af\u30e9\u30b9\u30bf\u30fc\u306e\u7ba1\u7406\u5bfe\u8c61\u5316 +label.action.migrate.instance.processing=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u79fb\u884c\u3057\u3066\u3044\u307e\u3059... +label.action.migrate.instance=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u79fb\u884c +label.action.migrate.router.processing=\u30eb\u30fc\u30bf\u30fc\u3092\u79fb\u884c\u3057\u3066\u3044\u307e\u3059... +label.action.migrate.router=\u30eb\u30fc\u30bf\u30fc\u306e\u79fb\u884c +label.action.migrate.systemvm.processing=\u30b7\u30b9\u30c6\u30e0 VM \u3092\u79fb\u884c\u3057\u3066\u3044\u307e\u3059... +label.action.migrate.systemvm=\u30b7\u30b9\u30c6\u30e0 VM \u306e\u79fb\u884c +label.action.reboot.instance.processing=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u518d\u8d77\u52d5\u3057\u3066\u3044\u307e\u3059... +label.action.reboot.instance=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u518d\u8d77\u52d5 +label.action.reboot.router.processing=\u30eb\u30fc\u30bf\u30fc\u3092\u518d\u8d77\u52d5\u3057\u3066\u3044\u307e\u3059... +label.action.reboot.router=\u30eb\u30fc\u30bf\u30fc\u306e\u518d\u8d77\u52d5 +label.action.reboot.systemvm.processing=\u30b7\u30b9\u30c6\u30e0 VM \u3092\u518d\u8d77\u52d5\u3057\u3066\u3044\u307e\u3059... +label.action.reboot.systemvm=\u30b7\u30b9\u30c6\u30e0 VM \u306e\u518d\u8d77\u52d5 +label.action.recurring.snapshot=\u5b9a\u671f\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8 +label.action.register.iso=ISO \u306e\u767b\u9332 +label.action.register.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u767b\u9332 +label.action.release.ip=IP \u30a2\u30c9\u30ec\u30b9\u306e\u89e3\u653e +label.action.release.ip.processing=IP \u30a2\u30c9\u30ec\u30b9\u3092\u89e3\u653e\u3057\u3066\u3044\u307e\u3059... +label.action.remove.host.processing=\u30db\u30b9\u30c8\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.action.remove.host=\u30db\u30b9\u30c8\u306e\u524a\u9664 +label.action.reset.password.processing=\u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u30ea\u30bb\u30c3\u30c8\u3057\u3066\u3044\u307e\u3059... +label.action.reset.password=\u30d1\u30b9\u30ef\u30fc\u30c9\u306e\u30ea\u30bb\u30c3\u30c8 +label.action.resource.limits=\u30ea\u30bd\u30fc\u30b9\u5236\u9650 +label.action.restore.instance.processing=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u5fa9\u5143\u3057\u3066\u3044\u307e\u3059... +label.action.restore.instance=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u5fa9\u5143 +label.action.start.instance.processing=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u8d77\u52d5\u3057\u3066\u3044\u307e\u3059... +label.action.start.instance=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u8d77\u52d5 +label.action.start.router.processing=\u30eb\u30fc\u30bf\u30fc\u3092\u8d77\u52d5\u3057\u3066\u3044\u307e\u3059... +label.action.start.router=\u30eb\u30fc\u30bf\u30fc\u306e\u8d77\u52d5 +label.action.start.systemvm.processing=\u30b7\u30b9\u30c6\u30e0 VM \u3092\u8d77\u52d5\u3057\u3066\u3044\u307e\u3059... +label.action.start.systemvm=\u30b7\u30b9\u30c6\u30e0 VM \u306e\u8d77\u52d5 +label.action.stop.instance.processing=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u505c\u6b62\u3057\u3066\u3044\u307e\u3059... +label.action.stop.instance=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u505c\u6b62 +label.action.stop.router.processing=\u30eb\u30fc\u30bf\u30fc\u3092\u505c\u6b62\u3057\u3066\u3044\u307e\u3059... +label.action.stop.router=\u30eb\u30fc\u30bf\u30fc\u306e\u505c\u6b62 +label.action.stop.systemvm.processing=\u30b7\u30b9\u30c6\u30e0 VM \u3092\u505c\u6b62\u3057\u3066\u3044\u307e\u3059... +label.action.stop.systemvm=\u30b7\u30b9\u30c6\u30e0 VM \u306e\u505c\u6b62 +label.actions=\u64cd\u4f5c +label.action.take.snapshot.processing=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u3092\u4f5c\u6210\u3057\u3066\u3044\u307e\u3059.... +label.action.take.snapshot=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u306e\u4f5c\u6210 +label.action.unmanage.cluster.processing=\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u975e\u7ba1\u7406\u5bfe\u8c61\u306b\u3057\u3066\u3044\u307e\u3059... +label.action.unmanage.cluster=\u30af\u30e9\u30b9\u30bf\u30fc\u306e\u975e\u7ba1\u7406\u5bfe\u8c61\u5316 +label.action.update.OS.preference=OS \u57fa\u672c\u8a2d\u5b9a\u306e\u66f4\u65b0 +label.action.update.OS.preference.processing=OS \u57fa\u672c\u8a2d\u5b9a\u3092\u66f4\u65b0\u3057\u3066\u3044\u307e\u3059... +label.action.update.resource.count.processing=\u30ea\u30bd\u30fc\u30b9\u6570\u3092\u66f4\u65b0\u3057\u3066\u3044\u307e\u3059... +label.action.update.resource.count=\u30ea\u30bd\u30fc\u30b9\u6570\u306e\u66f4\u65b0 +label.activate.project=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u30a2\u30af\u30c6\u30a3\u30d6\u5316 +label.active.sessions=\u30a2\u30af\u30c6\u30a3\u30d6\u306a\u30bb\u30c3\u30b7\u30e7\u30f3 +label.add.accounts.to=\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u8ffd\u52a0\u5148\: +label.add.accounts=\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u8ffd\u52a0 +label.add.account.to.project=\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3078\u306e\u8ffd\u52a0 +label.add.account=\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u8ffd\u52a0 +label.add.ACL=ACL \u306e\u8ffd\u52a0 +label.add.by.cidr=CIDR \u3067\u8ffd\u52a0 +label.add.by.group=\u30b0\u30eb\u30fc\u30d7\u3067\u8ffd\u52a0 +label.add.by=\u8ffd\u52a0\u5358\u4f4d +label.add.cluster=\u30af\u30e9\u30b9\u30bf\u30fc\u306e\u8ffd\u52a0 +label.add.compute.offering=\u30b3\u30f3\u30d4\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u306e\u8ffd\u52a0 +label.add.direct.iprange=\u76f4\u63a5 IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u306e\u8ffd\u52a0 +label.add.disk.offering=\u30c7\u30a3\u30b9\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u306e\u8ffd\u52a0 +label.add.domain=\u30c9\u30e1\u30a4\u30f3\u306e\u8ffd\u52a0 +label.add.egress.rule=\u9001\u4fe1\u898f\u5247\u306e\u8ffd\u52a0 +label.add.F5.device=F5 \u30c7\u30d0\u30a4\u30b9\u306e\u8ffd\u52a0 +label.add.firewall=\u30d5\u30a1\u30a4\u30a2\u30a6\u30a9\u30fc\u30eb\u898f\u5247\u306e\u8ffd\u52a0 +label.add.guest.network=\u30b2\u30b9\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u8ffd\u52a0 +label.add.host=\u30db\u30b9\u30c8\u306e\u8ffd\u52a0 +label.adding.cluster=\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 +label.adding.failed=\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f +label.adding.pod=\u30dd\u30c3\u30c9\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 +label.adding.processing=\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059... +label.add.ingress.rule=\u53d7\u4fe1\u898f\u5247\u306e\u8ffd\u52a0 +label.adding.succeeded=\u8ffd\u52a0\u3057\u307e\u3057\u305f +label.adding=\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 +label.adding.user=\u30e6\u30fc\u30b6\u30fc\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 +label.adding.zone=\u30be\u30fc\u30f3\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 +label.add.ip.range=IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u306e\u8ffd\u52a0 +label.additional.networks=\u8ffd\u52a0\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af +label.add.load.balancer=\u8ca0\u8377\u5206\u6563\u88c5\u7f6e\u306e\u8ffd\u52a0 +label.add.more=\u305d\u306e\u307b\u304b\u306e\u9805\u76ee\u306e\u8ffd\u52a0 +label.add.netScaler.device=Netscaler \u30c7\u30d0\u30a4\u30b9\u306e\u8ffd\u52a0 +label.add.network.ACL=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af ACL \u306e\u8ffd\u52a0 +label.add.network.device=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30c7\u30d0\u30a4\u30b9\u306e\u8ffd\u52a0 +label.add.network.offering=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u306e\u8ffd\u52a0 +label.add.network=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u8ffd\u52a0 +label.add.new.F5=\u65b0\u3057\u3044 F5 \u306e\u8ffd\u52a0 +label.add.new.gateway=\u65b0\u3057\u3044\u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u306e\u8ffd\u52a0 +label.add.new.NetScaler=\u65b0\u3057\u3044 NetScaler \u306e\u8ffd\u52a0 +label.add.new.SRX=\u65b0\u3057\u3044 SRX \u306e\u8ffd\u52a0 +label.add.new.tier=\u65b0\u3057\u3044\u968e\u5c64\u306e\u8ffd\u52a0 label.add.NiciraNvp.device=NVP\u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u306e\u8ffd\u52a0 -label.add.physical.network=\u7269\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u8FFD\u52A0 -label.add.pod=\u30DD\u30C3\u30C9\u306E\u8FFD\u52A0 -label.add.port.forwarding.rule=\u30DD\u30FC\u30C8\u8EE2\u9001\u898F\u5247\u306E\u8FFD\u52A0 -label.add.primary.storage=\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u306E\u8FFD\u52A0 -label.add.resources=\u30EA\u30BD\u30FC\u30B9\u306E\u8FFD\u52A0 -label.add.route=\u30EB\u30FC\u30C8\u306E\u8FFD\u52A0 -label.add.rule=\u898F\u5247\u306E\u8FFD\u52A0 -label.add.secondary.storage=\u30BB\u30AB\u30F3\u30C0\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u306E\u8FFD\u52A0 -label.add.security.group=\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3 \u30B0\u30EB\u30FC\u30D7\u306E\u8FFD\u52A0 -label.add.service.offering=\u30B5\u30FC\u30D3\u30B9 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u306E\u8FFD\u52A0 -label.add.SRX.device=SRX \u30C7\u30D0\u30A4\u30B9\u306E\u8FFD\u52A0 -label.add.static.nat.rule=\u9759\u7684 NAT \u898F\u5247\u306E\u8FFD\u52A0 -label.add.static.route=\u9759\u7684\u30EB\u30FC\u30C8\u306E\u8FFD\u52A0 -label.add.system.service.offering=\u30B7\u30B9\u30C6\u30E0 \u30B5\u30FC\u30D3\u30B9 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u306E\u8FFD\u52A0 -label.add.template=\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u8FFD\u52A0 -label.add.to.group=\u30B0\u30EB\u30FC\u30D7\u3078\u306E\u8FFD\u52A0 -label.add=\u8FFD\u52A0 -label.add.user=\u30E6\u30FC\u30B6\u30FC\u306E\u8FFD\u52A0 -label.add.vlan=VLAN \u306E\u8FFD\u52A0 -label.add.vms.to.lb=\u8CA0\u8377\u5206\u6563\u898F\u5247\u3078\u306E VM \u306E\u8FFD\u52A0 -label.add.vms=VM \u306E\u8FFD\u52A0 -label.add.VM.to.tier=\u968E\u5C64\u3078\u306E VM \u306E\u8FFD\u52A0 -label.add.vm=VM \u306E\u8FFD\u52A0 -label.add.volume=\u30DC\u30EA\u30E5\u30FC\u30E0\u306E\u8FFD\u52A0 -label.add.vpc=VPC \u306E\u8FFD\u52A0 -label.add.vpn.customer.gateway=VPN \u30AB\u30B9\u30BF\u30DE\u30FC \u30B2\u30FC\u30C8\u30A6\u30A7\u30A4\u306E\u8FFD\u52A0 -label.add.VPN.gateway=VPN \u30B2\u30FC\u30C8\u30A6\u30A7\u30A4\u306E\u8FFD\u52A0 -label.add.vpn.user=VPN \u30E6\u30FC\u30B6\u30FC\u306E\u8FFD\u52A0 -label.add.zone=\u30BE\u30FC\u30F3\u306E\u8FFD\u52A0 -label.admin.accounts=\u7BA1\u7406\u8005\u30A2\u30AB\u30A6\u30F3\u30C8 -label.admin=\u7BA1\u7406\u8005 -label.advanced.mode=\u62E1\u5F35\u30E2\u30FC\u30C9 -label.advanced.search=\u9AD8\u5EA6\u306A\u691C\u7D22 -label.advanced=\u62E1\u5F35 -label.agent.password=\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8 \u30D1\u30B9\u30EF\u30FC\u30C9 -label.agent.username=\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8 \u30E6\u30FC\u30B6\u30FC\u540D -label.agree=\u540C\u610F\u3059\u308B -label.alert=\u30A2\u30E9\u30FC\u30C8 -label.algorithm=\u30A2\u30EB\u30B4\u30EA\u30BA\u30E0 -label.allocated=\u5272\u308A\u5F53\u3066\u6E08\u307F -label.allocation.state=\u5272\u308A\u5F53\u3066\u72B6\u614B -label.api.key=API \u30AD\u30FC +label.add.physical.network=\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u8ffd\u52a0 +label.add.pod=\u30dd\u30c3\u30c9\u306e\u8ffd\u52a0 +label.add.port.forwarding.rule=\u30dd\u30fc\u30c8\u8ee2\u9001\u898f\u5247\u306e\u8ffd\u52a0 +label.add.primary.storage=\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u306e\u8ffd\u52a0 +label.add.resources=\u30ea\u30bd\u30fc\u30b9\u306e\u8ffd\u52a0 +label.add.route=\u30eb\u30fc\u30c8\u306e\u8ffd\u52a0 +label.add.rule=\u898f\u5247\u306e\u8ffd\u52a0 +label.add.secondary.storage=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u306e\u8ffd\u52a0 +label.add.security.group=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u306e\u8ffd\u52a0 +label.add.service.offering=\u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u306e\u8ffd\u52a0 +label.add.SRX.device=SRX \u30c7\u30d0\u30a4\u30b9\u306e\u8ffd\u52a0 +label.add.static.nat.rule=\u9759\u7684 NAT \u898f\u5247\u306e\u8ffd\u52a0 +label.add.static.route=\u9759\u7684\u30eb\u30fc\u30c8\u306e\u8ffd\u52a0 +label.add.system.service.offering=\u30b7\u30b9\u30c6\u30e0 \u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u306e\u8ffd\u52a0 +label.add.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u8ffd\u52a0 +label.add.to.group=\u30b0\u30eb\u30fc\u30d7\u3078\u306e\u8ffd\u52a0 +label.add=\u8ffd\u52a0 +label.add.user=\u30e6\u30fc\u30b6\u30fc\u306e\u8ffd\u52a0 +label.add.vlan=VLAN \u306e\u8ffd\u52a0 +label.add.vms.to.lb=\u8ca0\u8377\u5206\u6563\u898f\u5247\u3078\u306e VM \u306e\u8ffd\u52a0 +label.add.vms=VM \u306e\u8ffd\u52a0 +label.add.VM.to.tier=\u968e\u5c64\u3078\u306e VM \u306e\u8ffd\u52a0 +label.add.vm=VM \u306e\u8ffd\u52a0 +label.add.volume=\u30dc\u30ea\u30e5\u30fc\u30e0\u306e\u8ffd\u52a0 +label.add.vpc=VPC \u306e\u8ffd\u52a0 +label.add.vpn.customer.gateway=VPN \u30ab\u30b9\u30bf\u30de\u30fc \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u306e\u8ffd\u52a0 +label.add.VPN.gateway=VPN \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u306e\u8ffd\u52a0 +label.add.vpn.user=VPN \u30e6\u30fc\u30b6\u30fc\u306e\u8ffd\u52a0 +label.add.zone=\u30be\u30fc\u30f3\u306e\u8ffd\u52a0 +label.admin.accounts=\u7ba1\u7406\u8005\u30a2\u30ab\u30a6\u30f3\u30c8 +label.admin=\u7ba1\u7406\u8005 +label.advanced.mode=\u62e1\u5f35\u30e2\u30fc\u30c9 +label.advanced.search=\u9ad8\u5ea6\u306a\u691c\u7d22 +label.advanced=\u62e1\u5f35 +label.agent.password=\u30a8\u30fc\u30b8\u30a7\u30f3\u30c8 \u30d1\u30b9\u30ef\u30fc\u30c9 +label.agent.username=\u30a8\u30fc\u30b8\u30a7\u30f3\u30c8 \u30e6\u30fc\u30b6\u30fc\u540d +label.agree=\u540c\u610f\u3059\u308b +label.alert=\u30a2\u30e9\u30fc\u30c8 +label.algorithm=\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0 +label.allocated=\u5272\u308a\u5f53\u3066\u6e08\u307f +label.allocation.state=\u5272\u308a\u5f53\u3066\u72b6\u614b +label.api.key=API \u30ad\u30fc label.apply=\u9069\u7528 -label.assign.to.load.balancer=\u8CA0\u8377\u5206\u6563\u88C5\u7F6E\u306B\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u5272\u308A\u5F53\u3066\u3066\u3044\u307E\u3059 -label.assign=\u5272\u308A\u5F53\u3066 -label.associated.network.id=\u95A2\u9023\u3065\u3051\u3089\u308C\u305F\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF ID -label.associated.network=\u95A2\u9023\u3065\u3051\u3089\u308C\u305F\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF -label.attached.iso=\u30A2\u30BF\u30C3\u30C1\u3055\u308C\u305F ISO -label.availability=\u53EF\u7528\u6027 -label.availability.zone=\u5229\u7528\u53EF\u80FD\u30BE\u30FC\u30F3 -label.available.public.ips=\u4F7F\u7528\u3067\u304D\u308B\u30D1\u30D6\u30EA\u30C3\u30AF IP \u30A2\u30C9\u30EC\u30B9 -label.available=\u4F7F\u7528\u53EF\u80FD -label.back=\u623B\u308B -label.bandwidth=\u5E2F\u57DF\u5E45 -label.basic.mode=\u57FA\u672C\u30E2\u30FC\u30C9 -label.basic=\u57FA\u672C -label.bootable=\u8D77\u52D5\u53EF\u80FD -label.broadcast.domain.range=\u30D6\u30ED\u30FC\u30C9\u30AD\u30E3\u30B9\u30C8 \u30C9\u30E1\u30A4\u30F3\u306E\u7BC4\u56F2 -label.broadcast.domain.type=\u30D6\u30ED\u30FC\u30C9\u30AD\u30E3\u30B9\u30C8 \u30C9\u30E1\u30A4\u30F3\u306E\u7A2E\u985E +label.assign.to.load.balancer=\u8ca0\u8377\u5206\u6563\u88c5\u7f6e\u306b\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u5272\u308a\u5f53\u3066\u3066\u3044\u307e\u3059 +label.assign=\u5272\u308a\u5f53\u3066 +label.associated.network.id=\u95a2\u9023\u3065\u3051\u3089\u308c\u305f\u30cd\u30c3\u30c8\u30ef\u30fc\u30af ID +label.associated.network=\u95a2\u9023\u3065\u3051\u3089\u308c\u305f\u30cd\u30c3\u30c8\u30ef\u30fc\u30af +label.attached.iso=\u30a2\u30bf\u30c3\u30c1\u3055\u308c\u305f ISO +label.availability=\u53ef\u7528\u6027 +label.availability.zone=\u5229\u7528\u53ef\u80fd\u30be\u30fc\u30f3 +label.available.public.ips=\u4f7f\u7528\u3067\u304d\u308b\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9 +label.available=\u4f7f\u7528\u53ef\u80fd +label.back=\u623b\u308b +label.bandwidth=\u5e2f\u57df\u5e45 +label.basic.mode=\u57fa\u672c\u30e2\u30fc\u30c9 +label.basic=\u57fa\u672c +label.bootable=\u8d77\u52d5\u53ef\u80fd +label.broadcast.domain.range=\u30d6\u30ed\u30fc\u30c9\u30ad\u30e3\u30b9\u30c8 \u30c9\u30e1\u30a4\u30f3\u306e\u7bc4\u56f2 +label.broadcast.domain.type=\u30d6\u30ed\u30fc\u30c9\u30ad\u30e3\u30b9\u30c8 \u30c9\u30e1\u30a4\u30f3\u306e\u7a2e\u985e label.broadcast.uri=Broadcast URI -label.by.account=\u30A2\u30AB\u30A6\u30F3\u30C8 -label.by.availability=\u53EF\u7528\u6027 -label.by.domain=\u30C9\u30E1\u30A4\u30F3 -label.by.end.date=\u7D42\u4E86\u65E5 -label.by.level=\u30EC\u30D9\u30EB -label.by.pod=\u30DD\u30C3\u30C9 -label.by.role=\u5F79\u5272 -label.by.start.date=\u958B\u59CB\u65E5 -label.by.state=\u72B6\u614B -label.bytes.received=\u53D7\u4FE1\u30D0\u30A4\u30C8 -label.bytes.sent=\u9001\u4FE1\u30D0\u30A4\u30C8 -label.by.traffic.type=\u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u306E\u7A2E\u985E -label.by.type.id=\u7A2E\u985E ID -label.by.type=\u7A2E\u985E -label.by.zone=\u30BE\u30FC\u30F3 -label.cancel=\u30AD\u30E3\u30F3\u30BB\u30EB -label.capacity=\u51E6\u7406\u80FD\u529B -label.certificate=\u8A3C\u660E\u66F8 -label.change.service.offering=\u30B5\u30FC\u30D3\u30B9 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u306E\u5909\u66F4 -label.change.value=\u5024\u306E\u5909\u66F4 -label.character=\u6587\u5B57 -label.checksum=MD5 \u30C1\u30A7\u30C3\u30AF\u30B5\u30E0 -label.cidr.account=CIDR \u307E\u305F\u306F\u30A2\u30AB\u30A6\u30F3\u30C8/\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3 \u30B0\u30EB\u30FC\u30D7 +label.by.account=\u30a2\u30ab\u30a6\u30f3\u30c8 +label.by.availability=\u53ef\u7528\u6027 +label.by.domain=\u30c9\u30e1\u30a4\u30f3 +label.by.end.date=\u7d42\u4e86\u65e5 +label.by.level=\u30ec\u30d9\u30eb +label.by.pod=\u30dd\u30c3\u30c9 +label.by.role=\u5f79\u5272 +label.by.start.date=\u958b\u59cb\u65e5 +label.by.state=\u72b6\u614b +label.bytes.received=\u53d7\u4fe1\u30d0\u30a4\u30c8 +label.bytes.sent=\u9001\u4fe1\u30d0\u30a4\u30c8 +label.by.traffic.type=\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e\u7a2e\u985e +label.by.type.id=\u7a2e\u985e ID +label.by.type=\u7a2e\u985e +label.by.zone=\u30be\u30fc\u30f3 +label.cancel=\u30ad\u30e3\u30f3\u30bb\u30eb +label.capacity=\u51e6\u7406\u80fd\u529b +label.certificate=\u8a3c\u660e\u66f8 +label.change.service.offering=\u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u306e\u5909\u66f4 +label.change.value=\u5024\u306e\u5909\u66f4 +label.character=\u6587\u5b57 +label.checksum=MD5 \u30c1\u30a7\u30c3\u30af\u30b5\u30e0 +label.cidr.account=CIDR \u307e\u305f\u306f\u30a2\u30ab\u30a6\u30f3\u30c8/\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7 label.cidr=CIDR -label.CIDR.list=CIDR \u4E00\u89A7 -label.cidr.list=\u9001\u4FE1\u5143 CIDR -label.CIDR.of.destination.network=\u5B9B\u5148\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E CIDR -label.clean.up=\u30AF\u30EA\u30FC\u30F3 \u30A2\u30C3\u30D7 -label.clear.list=\u4E00\u89A7\u306E\u6D88\u53BB -label.close=\u9589\u3058\u308B -label.cloud.console=\u30AF\u30E9\u30A6\u30C9\u7BA1\u7406\u30B3\u30F3\u30BD\u30FC\u30EB -label.cloud.managed=Cloud.com \u306B\u3088\u308B\u7BA1\u7406 -label.cluster.name=\u30AF\u30E9\u30B9\u30BF\u30FC\u540D -label.clusters=\u30AF\u30E9\u30B9\u30BF\u30FC -label.cluster.type=\u30AF\u30E9\u30B9\u30BF\u30FC\u306E\u7A2E\u985E -label.cluster=\u30AF\u30E9\u30B9\u30BF\u30FC +label.CIDR.list=CIDR \u4e00\u89a7 +label.cidr.list=\u9001\u4fe1\u5143 CIDR +label.CIDR.of.destination.network=\u5b9b\u5148\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e CIDR +label.clean.up=\u30af\u30ea\u30fc\u30f3 \u30a2\u30c3\u30d7 +label.clear.list=\u4e00\u89a7\u306e\u6d88\u53bb +label.close=\u9589\u3058\u308b +label.cloud.console=\u30af\u30e9\u30a6\u30c9\u7ba1\u7406\u30b3\u30f3\u30bd\u30fc\u30eb +label.cloud.managed=Cloud.com \u306b\u3088\u308b\u7ba1\u7406 +label.cluster.name=\u30af\u30e9\u30b9\u30bf\u30fc\u540d +label.clusters=\u30af\u30e9\u30b9\u30bf\u30fc +label.cluster.type=\u30af\u30e9\u30b9\u30bf\u30fc\u306e\u7a2e\u985e +label.cluster=\u30af\u30e9\u30b9\u30bf\u30fc label.clvm=CLVM -label.code=\u30B3\u30FC\u30C9 -label.community=\u30B3\u30DF\u30E5\u30CB\u30C6\u30A3 -label.compute.and.storage=\u30B3\u30F3\u30D4\u30E5\u30FC\u30C6\u30A3\u30F3\u30B0\u3068\u30B9\u30C8\u30EC\u30FC\u30B8 -label.compute.offerings=\u30B3\u30F3\u30D4\u30E5\u30FC\u30C6\u30A3\u30F3\u30B0 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0 -label.compute.offering=\u30B3\u30F3\u30D4\u30E5\u30FC\u30C6\u30A3\u30F3\u30B0 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0 -label.compute=\u30B3\u30F3\u30D4\u30E5\u30FC\u30C6\u30A3\u30F3\u30B0 -label.configuration=\u69CB\u6210 -label.configure.network.ACLs=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF ACL \u306E\u69CB\u6210 -label.configure=\u69CB\u6210 -label.configure.vpc=VPC \u306E\u69CB\u6210 -label.confirmation=\u78BA\u8A8D -label.confirm.password=\u30D1\u30B9\u30EF\u30FC\u30C9\u306E\u78BA\u8A8D\u5165\u529B -label.congratulations=\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u306F\u3053\u308C\u3067\u5B8C\u4E86\u3067\u3059\u3002 -label.conserve.mode=\u7BC0\u7D04\u30E2\u30FC\u30C9 -label.console.proxy=\u30B3\u30F3\u30BD\u30FC\u30EB \u30D7\u30ED\u30AD\u30B7 -label.continue.basic.install=\u57FA\u672C\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3092\u7D9A\u884C\u3059\u308B -label.continue=\u7D9A\u884C -label.corrections.saved=\u63A5\u7D9A\u304C\u4FDD\u5B58\u3055\u308C\u307E\u3057\u305F -label.cpu.allocated.for.VMs=VM \u306B\u5272\u308A\u5F53\u3066\u6E08\u307F\u306E CPU -label.cpu.allocated=\u5272\u308A\u5F53\u3066\u6E08\u307F\u306E CPU +label.code=\u30b3\u30fc\u30c9 +label.community=\u30b3\u30df\u30e5\u30cb\u30c6\u30a3 +label.compute.and.storage=\u30b3\u30f3\u30d4\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0\u3068\u30b9\u30c8\u30ec\u30fc\u30b8 +label.compute.offerings=\u30b3\u30f3\u30d4\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 +label.compute.offering=\u30b3\u30f3\u30d4\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 +label.compute=\u30b3\u30f3\u30d4\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0 +label.configuration=\u69cb\u6210 +label.configure.network.ACLs=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af ACL \u306e\u69cb\u6210 +label.configure=\u69cb\u6210 +label.configure.vpc=VPC \u306e\u69cb\u6210 +label.confirmation=\u78ba\u8a8d +label.confirm.password=\u30d1\u30b9\u30ef\u30fc\u30c9\u306e\u78ba\u8a8d\u5165\u529b +label.congratulations=\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u306f\u3053\u308c\u3067\u5b8c\u4e86\u3067\u3059\u3002 +label.conserve.mode=\u7bc0\u7d04\u30e2\u30fc\u30c9 +label.console.proxy=\u30b3\u30f3\u30bd\u30fc\u30eb \u30d7\u30ed\u30ad\u30b7 +label.continue.basic.install=\u57fa\u672c\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3092\u7d9a\u884c\u3059\u308b +label.continue=\u7d9a\u884c +label.corrections.saved=\u63a5\u7d9a\u304c\u4fdd\u5b58\u3055\u308c\u307e\u3057\u305f +label.cpu.allocated.for.VMs=VM \u306b\u5272\u308a\u5f53\u3066\u6e08\u307f\u306e CPU +label.cpu.allocated=\u5272\u308a\u5f53\u3066\u6e08\u307f\u306e CPU label.CPU.cap=CPU \u5236\u9650 label.cpu=CPU label.cpu.mhz=CPU (MHz) -label.cpu.utilized=CPU \u4F7F\u7528\u7387 -label.created.by.system=\u30B7\u30B9\u30C6\u30E0\u4F5C\u6210 -label.created=\u4F5C\u6210\u65E5\u6642 -label.create.project=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u4F5C\u6210 -label.create.template=\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u4F5C\u6210 -label.create.VPN.connection=VPN \u63A5\u7D9A\u306E\u4F5C\u6210 -label.cross.zones=\u30AF\u30ED\u30B9 \u30BE\u30FC\u30F3 -label.custom.disk.size=\u30AB\u30B9\u30BF\u30E0 \u30C7\u30A3\u30B9\u30AF \u30B5\u30A4\u30BA -label.daily=\u6BCE\u65E5 -label.data.disk.offering=\u30C7\u30FC\u30BF \u30C7\u30A3\u30B9\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0 -label.date=\u65E5\u6642 -label.day.of.month=\u6BCE\u6708\u6307\u5B9A\u65E5 -label.day.of.week=\u6BCE\u9031\u6307\u5B9A\u65E5 -label.dead.peer.detection=\u505C\u6B62\u30D4\u30A2\u306E\u691C\u51FA -label.decline.invitation=\u62DB\u5F85\u306E\u8F9E\u9000 -label.dedicated=\u5C02\u7528 -label.default=\u30C7\u30D5\u30A9\u30EB\u30C8 -label.default.use=\u30C7\u30D5\u30A9\u30EB\u30C8\u4F7F\u7528 -label.default.view=\u30C7\u30D5\u30A9\u30EB\u30C8 \u30D3\u30E5\u30FC -label.delete.F5=F5 \u306E\u524A\u9664 -label.delete.gateway=\u30B2\u30FC\u30C8\u30A6\u30A7\u30A4\u306E\u524A\u9664 -label.delete.NetScaler=NetScaler \u306E\u524A\u9664 +label.cpu.utilized=CPU \u4f7f\u7528\u7387 +label.created.by.system=\u30b7\u30b9\u30c6\u30e0\u4f5c\u6210 +label.created=\u4f5c\u6210\u65e5\u6642 +label.create.project=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u4f5c\u6210 +label.create.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u4f5c\u6210 +label.create.VPN.connection=VPN \u63a5\u7d9a\u306e\u4f5c\u6210 +label.cross.zones=\u30af\u30ed\u30b9 \u30be\u30fc\u30f3 +label.custom.disk.size=\u30ab\u30b9\u30bf\u30e0 \u30c7\u30a3\u30b9\u30af \u30b5\u30a4\u30ba +label.daily=\u6bce\u65e5 +label.data.disk.offering=\u30c7\u30fc\u30bf \u30c7\u30a3\u30b9\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 +label.date=\u65e5\u6642 +label.day.of.month=\u6bce\u6708\u6307\u5b9a\u65e5 +label.day.of.week=\u6bce\u9031\u6307\u5b9a\u65e5 +label.dead.peer.detection=\u505c\u6b62\u30d4\u30a2\u306e\u691c\u51fa +label.decline.invitation=\u62db\u5f85\u306e\u8f9e\u9000 +label.dedicated=\u5c02\u7528 +label.default=\u30c7\u30d5\u30a9\u30eb\u30c8 +label.default.use=\u30c7\u30d5\u30a9\u30eb\u30c8\u4f7f\u7528 +label.default.view=\u30c7\u30d5\u30a9\u30eb\u30c8 \u30d3\u30e5\u30fc +label.delete.F5=F5 \u306e\u524a\u9664 +label.delete.gateway=\u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u306e\u524a\u9664 +label.delete.NetScaler=NetScaler \u306e\u524a\u9664 label.delete.NiciraNvp=NVP\u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u306e\u524a\u9664 -label.delete.project=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u524A\u9664 -label.delete.SRX=SRX \u306E\u524A\u9664 -label.delete=\u524A\u9664 -label.delete.VPN.connection=VPN \u63A5\u7D9A\u306E\u524A\u9664 -label.delete.VPN.customer.gateway=VPN \u30AB\u30B9\u30BF\u30DE\u30FC \u30B2\u30FC\u30C8\u30A6\u30A7\u30A4\u306E\u524A\u9664 -label.delete.VPN.gateway=VPN \u30B2\u30FC\u30C8\u30A6\u30A7\u30A4\u306E\u524A\u9664 -label.delete.vpn.user=VPN \u30E6\u30FC\u30B6\u30FC\u306E\u524A\u9664 -label.deleting.failed=\u524A\u9664\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F -label.deleting.processing=\u524A\u9664\u3057\u3066\u3044\u307E\u3059... -label.description=\u8AAC\u660E -label.destination.physical.network.id=\u30D6\u30EA\u30C3\u30B8\u5148\u7269\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF ID -label.destination.zone=\u30B3\u30D4\u30FC\u5148\u30BE\u30FC\u30F3 -label.destroy.router=\u30EB\u30FC\u30BF\u30FC\u306E\u7834\u68C4 +label.delete.project=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u524a\u9664 +label.delete.SRX=SRX \u306e\u524a\u9664 +label.delete=\u524a\u9664 +label.delete.VPN.connection=VPN \u63a5\u7d9a\u306e\u524a\u9664 +label.delete.VPN.customer.gateway=VPN \u30ab\u30b9\u30bf\u30de\u30fc \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u306e\u524a\u9664 +label.delete.VPN.gateway=VPN \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u306e\u524a\u9664 +label.delete.vpn.user=VPN \u30e6\u30fc\u30b6\u30fc\u306e\u524a\u9664 +label.deleting.failed=\u524a\u9664\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f +label.deleting.processing=\u524a\u9664\u3057\u3066\u3044\u307e\u3059... +label.description=\u8aac\u660e +label.destination.physical.network.id=\u30d6\u30ea\u30c3\u30b8\u5148\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af ID +label.destination.zone=\u30b3\u30d4\u30fc\u5148\u30be\u30fc\u30f3 +label.destroy.router=\u30eb\u30fc\u30bf\u30fc\u306e\u7834\u68c4 label.destroy=\u7834\u68c4 -label.detaching.disk=\u30C7\u30A3\u30B9\u30AF\u3092\u30C7\u30BF\u30C3\u30C1\u3057\u3066\u3044\u307E\u3059 -label.details=\u8A73\u7D30 -label.device.id=\u30C7\u30D0\u30A4\u30B9 ID -label.devices=\u30C7\u30D0\u30A4\u30B9 +label.detaching.disk=\u30c7\u30a3\u30b9\u30af\u3092\u30c7\u30bf\u30c3\u30c1\u3057\u3066\u3044\u307e\u3059 +label.details=\u8a73\u7d30 +label.device.id=\u30c7\u30d0\u30a4\u30b9 ID +label.devices=\u30c7\u30d0\u30a4\u30b9 label.dhcp=DHCP -label.DHCP.server.type=DHCP \u30B5\u30FC\u30D0\u30FC\u306E\u7A2E\u985E -label.direct.ips=\u76F4\u63A5 IP \u30A2\u30C9\u30EC\u30B9 -label.disabled=\u7121\u52B9 -label.disable.provider=\u30D7\u30ED\u30D0\u30A4\u30C0\u30FC\u306E\u7121\u52B9\u5316 -label.disable.vpn=VPN \u306E\u7121\u52B9\u5316 -label.disabling.vpn.access=VPN \u30A2\u30AF\u30BB\u30B9\u3092\u7121\u52B9\u306B\u3057\u3066\u3044\u307E\u3059 -label.disk.allocated=\u5272\u308A\u5F53\u3066\u6E08\u307F\u306E\u30C7\u30A3\u30B9\u30AF -label.disk.offering=\u30C7\u30A3\u30B9\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0 -label.disk.size.gb=\u30C7\u30A3\u30B9\u30AF \u30B5\u30A4\u30BA (GB \u5358\u4F4D) -label.disk.size=\u30C7\u30A3\u30B9\u30AF \u30B5\u30A4\u30BA -label.disk.total=\u30C7\u30A3\u30B9\u30AF\u5408\u8A08 -label.disk.volume=\u30C7\u30A3\u30B9\u30AF \u30DC\u30EA\u30E5\u30FC\u30E0 -label.display.name=\u8868\u793A\u540D -label.display.text=\u8868\u793A\u30C6\u30AD\u30B9\u30C8 +label.DHCP.server.type=DHCP \u30b5\u30fc\u30d0\u30fc\u306e\u7a2e\u985e +label.direct.ips=\u76f4\u63a5 IP \u30a2\u30c9\u30ec\u30b9 +label.disabled=\u7121\u52b9 +label.disable.provider=\u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u306e\u7121\u52b9\u5316 +label.disable.vpn=VPN \u306e\u7121\u52b9\u5316 +label.disabling.vpn.access=VPN \u30a2\u30af\u30bb\u30b9\u3092\u7121\u52b9\u306b\u3057\u3066\u3044\u307e\u3059 +label.disk.allocated=\u5272\u308a\u5f53\u3066\u6e08\u307f\u306e\u30c7\u30a3\u30b9\u30af +label.disk.offering=\u30c7\u30a3\u30b9\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 +label.disk.size.gb=\u30c7\u30a3\u30b9\u30af \u30b5\u30a4\u30ba (GB \u5358\u4f4d) +label.disk.size=\u30c7\u30a3\u30b9\u30af \u30b5\u30a4\u30ba +label.disk.total=\u30c7\u30a3\u30b9\u30af\u5408\u8a08 +label.disk.volume=\u30c7\u30a3\u30b9\u30af \u30dc\u30ea\u30e5\u30fc\u30e0 +label.display.name=\u8868\u793a\u540d +label.display.text=\u8868\u793a\u30c6\u30ad\u30b9\u30c8 label.dns.1=DNS 1 label.dns.2=DNS 2 label.dns=DNS -label.DNS.domain.for.guest.networks=\u30B2\u30B9\u30C8 \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E DNS \u30C9\u30E1\u30A4\u30F3 -label.domain.admin=\u30C9\u30E1\u30A4\u30F3\u7BA1\u7406\u8005 -label.domain.id=\u30C9\u30E1\u30A4\u30F3 ID -label.domain.name=\u30C9\u30E1\u30A4\u30F3\u540D -label.domain.router=\u30C9\u30E1\u30A4\u30F3 \u30EB\u30FC\u30BF\u30FC -label.domain.suffix=DNS \u30C9\u30E1\u30A4\u30F3 \u30B5\u30D5\u30A3\u30C3\u30AF\u30B9 (\u4F8B\: xyz.com) -label.domain=\u30C9\u30E1\u30A4\u30F3 -label.done=\u5B8C\u4E86 -label.double.quotes.are.not.allowed=\u4E8C\u91CD\u5F15\u7528\u7B26\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093 -label.download.progress=\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u306E\u9032\u6357\u72B6\u6CC1 -label.drag.new.position=\u65B0\u3057\u3044\u4F4D\u7F6E\u306B\u30C9\u30E9\u30C3\u30B0 -label.edit.lb.rule=\u8CA0\u8377\u5206\u6563\u898F\u5247\u306E\u7DE8\u96C6 -label.edit.network.details=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u8A73\u7D30\u306E\u7DE8\u96C6 -label.edit.project.details=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u8A73\u7D30\u306E\u7DE8\u96C6 -label.edit.tags=\u30BF\u30B0\u306E\u7DE8\u96C6 -label.edit.traffic.type=\u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u306E\u7A2E\u985E\u306E\u7DE8\u96C6 -label.edit=\u7DE8\u96C6 -label.edit.vpc=VPC \u306E\u7DE8\u96C6 +label.DNS.domain.for.guest.networks=\u30b2\u30b9\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e DNS \u30c9\u30e1\u30a4\u30f3 +label.domain.admin=\u30c9\u30e1\u30a4\u30f3\u7ba1\u7406\u8005 +label.domain.id=\u30c9\u30e1\u30a4\u30f3 ID +label.domain.name=\u30c9\u30e1\u30a4\u30f3\u540d +label.domain.router=\u30c9\u30e1\u30a4\u30f3 \u30eb\u30fc\u30bf\u30fc +label.domain.suffix=DNS \u30c9\u30e1\u30a4\u30f3 \u30b5\u30d5\u30a3\u30c3\u30af\u30b9 (\u4f8b\: xyz.com) +label.domain=\u30c9\u30e1\u30a4\u30f3 +label.done=\u5b8c\u4e86 +label.double.quotes.are.not.allowed=\u4e8c\u91cd\u5f15\u7528\u7b26\u306f\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093 +label.download.progress=\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u306e\u9032\u6357\u72b6\u6cc1 +label.drag.new.position=\u65b0\u3057\u3044\u4f4d\u7f6e\u306b\u30c9\u30e9\u30c3\u30b0 +label.edit.lb.rule=\u8ca0\u8377\u5206\u6563\u898f\u5247\u306e\u7de8\u96c6 +label.edit.network.details=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u8a73\u7d30\u306e\u7de8\u96c6 +label.edit.project.details=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u8a73\u7d30\u306e\u7de8\u96c6 +label.edit.tags=\u30bf\u30b0\u306e\u7de8\u96c6 +label.edit.traffic.type=\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e\u7a2e\u985e\u306e\u7de8\u96c6 +label.edit=\u7de8\u96c6 +label.edit.vpc=VPC \u306e\u7de8\u96c6 label.egress.rules=\u9001\u4fe1\u30eb\u30fc\u30eb -label.egress.rule=\u9001\u4FE1\u898F\u5247 -label.elastic.IP=\u30A8\u30E9\u30B9\u30C6\u30A3\u30C3\u30AF IP \u30A2\u30C9\u30EC\u30B9 -label.elastic.LB=\u30A8\u30E9\u30B9\u30C6\u30A3\u30C3\u30AF\u8CA0\u8377\u5206\u6563 -label.elastic=\u30A8\u30E9\u30B9\u30C6\u30A3\u30C3\u30AF -label.email=\u96FB\u5B50\u30E1\u30FC\u30EB -label.enable.provider=\u30D7\u30ED\u30D0\u30A4\u30C0\u30FC\u306E\u6709\u52B9\u5316 +label.egress.rule=\u9001\u4fe1\u898f\u5247 +label.elastic.IP=\u30a8\u30e9\u30b9\u30c6\u30a3\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9 +label.elastic.LB=\u30a8\u30e9\u30b9\u30c6\u30a3\u30c3\u30af\u8ca0\u8377\u5206\u6563 +label.elastic=\u30a8\u30e9\u30b9\u30c6\u30a3\u30c3\u30af +label.email=\u96fb\u5b50\u30e1\u30fc\u30eb +label.enable.provider=\u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u306e\u6709\u52b9\u5316 label.enable.s3=S3\u57fa\u76e4\u30bb\u30ab\u30f3\u30c0\u30ea\u30b9\u30c8\u30ec\u30fc\u30b8\u306e\u6709\u52b9\u5316 -label.enable.swift=Swift \u306E\u6709\u52B9\u5316 -label.enable.vpn=VPN \u306E\u6709\u52B9\u5316 -label.enabling.vpn.access=VPN \u30A2\u30AF\u30BB\u30B9\u3092\u6709\u52B9\u306B\u3057\u3066\u3044\u307E\u3059 -label.enabling.vpn=VPN \u3092\u6709\u52B9\u306B\u3057\u3066\u3044\u307E\u3059 -label.end.IP=\u7D42\u4E86 IP \u30A2\u30C9\u30EC\u30B9 -label.endpoint.or.operation=\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u307E\u305F\u306F\u64CD\u4F5C +label.enable.swift=Swift \u306e\u6709\u52b9\u5316 +label.enable.vpn=VPN \u306e\u6709\u52b9\u5316 +label.enabling.vpn.access=VPN \u30a2\u30af\u30bb\u30b9\u3092\u6709\u52b9\u306b\u3057\u3066\u3044\u307e\u3059 +label.enabling.vpn=VPN \u3092\u6709\u52b9\u306b\u3057\u3066\u3044\u307e\u3059 +label.end.IP=\u7d42\u4e86 IP \u30a2\u30c9\u30ec\u30b9 +label.endpoint.or.operation=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u307e\u305f\u306f\u64cd\u4f5c label.endpoint=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8 -label.end.port=\u7D42\u4E86\u30DD\u30FC\u30C8 -label.end.reserved.system.IP=\u4E88\u7D04\u6E08\u307F\u7D42\u4E86\u30B7\u30B9\u30C6\u30E0 IP \u30A2\u30C9\u30EC\u30B9 -label.end.vlan=\u7D42\u4E86 VLAN -label.enter.token=\u30C8\u30FC\u30AF\u30F3\u306E\u5165\u529B -label.error.code=\u30A8\u30E9\u30FC \u30B3\u30FC\u30C9 -label.error=\u30A8\u30E9\u30FC -label.ESP.encryption=ESP \u6697\u53F7\u5316 -label.ESP.hash=ESP \u30CF\u30C3\u30B7\u30E5 -label.ESP.policy=ESP \u30DD\u30EA\u30B7\u30FC -label.esx.host=ESX/ESXi \u30DB\u30B9\u30C8 -label.example=\u4F8B +label.end.port=\u7d42\u4e86\u30dd\u30fc\u30c8 +label.end.reserved.system.IP=\u4e88\u7d04\u6e08\u307f\u7d42\u4e86\u30b7\u30b9\u30c6\u30e0 IP \u30a2\u30c9\u30ec\u30b9 +label.end.vlan=\u7d42\u4e86 VLAN +label.enter.token=\u30c8\u30fc\u30af\u30f3\u306e\u5165\u529b +label.error.code=\u30a8\u30e9\u30fc \u30b3\u30fc\u30c9 +label.error=\u30a8\u30e9\u30fc +label.ESP.encryption=ESP \u6697\u53f7\u5316 +label.ESP.hash=ESP \u30cf\u30c3\u30b7\u30e5 +label.ESP.policy=ESP \u30dd\u30ea\u30b7\u30fc +label.esx.host=ESX/ESXi \u30db\u30b9\u30c8 +label.example=\u4f8b label.f5=F5 label.failed=\u5931\u6557 -label.featured=\u304A\u3059\u3059\u3081 -label.fetch.latest=\u6700\u65B0\u60C5\u5831\u306E\u53D6\u5F97 -label.filterBy=\u30D5\u30A3\u30EB\u30BF\u30FC -label.firewall=\u30D5\u30A1\u30A4\u30A2\u30A6\u30A9\u30FC\u30EB -label.first.name=\u540D -label.format=\u5F62\u5F0F -label.friday=\u91D1\u66DC\u65E5 -label.full.path=\u30D5\u30EB \u30D1\u30B9 -label.full=\u5B8C\u5168 -label.gateway=\u30B2\u30FC\u30C8\u30A6\u30A7\u30A4 -label.general.alerts=\u4E00\u822C\u30A2\u30E9\u30FC\u30C8 -label.generating.url=URL \u3092\u751F\u6210\u3057\u3066\u3044\u307E\u3059 -label.go.step.2=\u624B\u9806 2 \u306B\u9032\u3080 -label.go.step.3=\u624B\u9806 3 \u306B\u9032\u3080 -label.go.step.4=\u624B\u9806 4 \u306B\u9032\u3080 -label.go.step.5=\u624B\u9806 5 \u306B\u9032\u3080 -label.group.optional=\u30B0\u30EB\u30FC\u30D7 (\u30AA\u30D7\u30B7\u30E7\u30F3) -label.group=\u30B0\u30EB\u30FC\u30D7 -label.guest.cidr=\u30B2\u30B9\u30C8 CIDR -label.guest.end.ip=\u30B2\u30B9\u30C8\u306E\u7D42\u4E86 IP \u30A2\u30C9\u30EC\u30B9 -label.guest.gateway=\u30B2\u30B9\u30C8 \u30B2\u30FC\u30C8\u30A6\u30A7\u30A4 -label.guest.ip.range=\u30B2\u30B9\u30C8 IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2 -label.guest.ip=\u30B2\u30B9\u30C8 IP \u30A2\u30C9\u30EC\u30B9 -label.guest.netmask=\u30B2\u30B9\u30C8 \u30CD\u30C3\u30C8\u30DE\u30B9\u30AF -label.guest.networks=\u30B2\u30B9\u30C8 \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF -label.guest.start.ip=\u30B2\u30B9\u30C8\u306E\u958B\u59CB IP \u30A2\u30C9\u30EC\u30B9 -label.guest.traffic=\u30B2\u30B9\u30C8 \u30C8\u30E9\u30D5\u30A3\u30C3\u30AF -label.guest.type=\u30B2\u30B9\u30C8\u306E\u7A2E\u985E -label.guest=\u30B2\u30B9\u30C8 -label.ha.enabled=\u9AD8\u53EF\u7528\u6027\u6709\u52B9 -label.help=\u30D8\u30EB\u30D7 -label.hide.ingress.rule=\u53D7\u4FE1\u898F\u5247\u3092\u96A0\u3059 -label.hints=\u30D2\u30F3\u30C8 -label.host.alerts=\u30DB\u30B9\u30C8 \u30A2\u30E9\u30FC\u30C8 -label.host.MAC=\u30DB\u30B9\u30C8\u306E MAC -label.host.name=\u30DB\u30B9\u30C8\u540D -label.hosts=\u30DB\u30B9\u30C8 +label.featured=\u304a\u3059\u3059\u3081 +label.fetch.latest=\u6700\u65b0\u60c5\u5831\u306e\u53d6\u5f97 +label.filterBy=\u30d5\u30a3\u30eb\u30bf\u30fc +label.firewall=\u30d5\u30a1\u30a4\u30a2\u30a6\u30a9\u30fc\u30eb +label.first.name=\u540d +label.format=\u5f62\u5f0f +label.friday=\u91d1\u66dc\u65e5 +label.full.path=\u30d5\u30eb \u30d1\u30b9 +label.full=\u5b8c\u5168 +label.gateway=\u30b2\u30fc\u30c8\u30a6\u30a7\u30a4 +label.general.alerts=\u4e00\u822c\u30a2\u30e9\u30fc\u30c8 +label.generating.url=URL \u3092\u751f\u6210\u3057\u3066\u3044\u307e\u3059 +label.go.step.2=\u624b\u9806 2 \u306b\u9032\u3080 +label.go.step.3=\u624b\u9806 3 \u306b\u9032\u3080 +label.go.step.4=\u624b\u9806 4 \u306b\u9032\u3080 +label.go.step.5=\u624b\u9806 5 \u306b\u9032\u3080 +label.group.optional=\u30b0\u30eb\u30fc\u30d7 (\u30aa\u30d7\u30b7\u30e7\u30f3) +label.group=\u30b0\u30eb\u30fc\u30d7 +label.guest.cidr=\u30b2\u30b9\u30c8 CIDR +label.guest.end.ip=\u30b2\u30b9\u30c8\u306e\u7d42\u4e86 IP \u30a2\u30c9\u30ec\u30b9 +label.guest.gateway=\u30b2\u30b9\u30c8 \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4 +label.guest.ip.range=\u30b2\u30b9\u30c8 IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2 +label.guest.ip=\u30b2\u30b9\u30c8 IP \u30a2\u30c9\u30ec\u30b9 +label.guest.netmask=\u30b2\u30b9\u30c8 \u30cd\u30c3\u30c8\u30de\u30b9\u30af +label.guest.networks=\u30b2\u30b9\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af +label.guest.start.ip=\u30b2\u30b9\u30c8\u306e\u958b\u59cb IP \u30a2\u30c9\u30ec\u30b9 +label.guest.traffic=\u30b2\u30b9\u30c8 \u30c8\u30e9\u30d5\u30a3\u30c3\u30af +label.guest.type=\u30b2\u30b9\u30c8\u306e\u7a2e\u985e +label.guest=\u30b2\u30b9\u30c8 +label.ha.enabled=\u9ad8\u53ef\u7528\u6027\u6709\u52b9 +label.help=\u30d8\u30eb\u30d7 +label.hide.ingress.rule=\u53d7\u4fe1\u898f\u5247\u3092\u96a0\u3059 +label.hints=\u30d2\u30f3\u30c8 +label.host.alerts=\u30db\u30b9\u30c8 \u30a2\u30e9\u30fc\u30c8 +label.host.MAC=\u30db\u30b9\u30c8\u306e MAC +label.host.name=\u30db\u30b9\u30c8\u540d +label.hosts=\u30db\u30b9\u30c8 label.host.tags=\u00e3\u0083\u009b\u00e3\u0082\u00b9\u00e3\u0083\u0088\u00e3\u0082\u00bf\u00e3\u0082\u00b0 -label.host=\u30DB\u30B9\u30C8 -label.hourly=\u6BCE\u6642 -label.hypervisor.capabilities=\u30CF\u30A4\u30D1\u30FC\u30D0\u30A4\u30B6\u30FC\u306E\u6A5F\u80FD -label.hypervisor.type=\u30CF\u30A4\u30D1\u30FC\u30D0\u30A4\u30B6\u30FC\u306E\u7A2E\u985E -label.hypervisor=\u30CF\u30A4\u30D1\u30FC\u30D0\u30A4\u30B6\u30FC -label.hypervisor.version=\u30CF\u30A4\u30D1\u30FC\u30D0\u30A4\u30B6\u30FC\u306E\u30D0\u30FC\u30B8\u30E7\u30F3 +label.host=\u30db\u30b9\u30c8 +label.hourly=\u6bce\u6642 +label.hypervisor.capabilities=\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc\u306e\u6a5f\u80fd +label.hypervisor.type=\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc\u306e\u7a2e\u985e +label.hypervisor=\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc +label.hypervisor.version=\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc\u306e\u30d0\u30fc\u30b8\u30e7\u30f3 label.id=ID label.IKE.DH=IKE DH -label.IKE.encryption=IKE \u6697\u53F7\u5316 -label.IKE.hash=IKE \u30CF\u30C3\u30B7\u30E5 -label.IKE.policy=IKE \u30DD\u30EA\u30B7\u30FC -label.info=\u60C5\u5831 -label.ingress.rule=\u53D7\u4FE1\u898F\u5247 -label.initiated.by=\u958B\u59CB\u30E6\u30FC\u30B6\u30FC -label.installWizard.addClusterIntro.subtitle=\u30AF\u30E9\u30B9\u30BF\u30FC\u306B\u3064\u3044\u3066 -label.installWizard.addClusterIntro.title=\u30AF\u30E9\u30B9\u30BF\u30FC\u3092\u8FFD\u52A0\u3057\u307E\u3057\u3087\u3046 -label.installWizard.addHostIntro.subtitle=\u30DB\u30B9\u30C8\u306B\u3064\u3044\u3066 -label.installWizard.addHostIntro.title=\u30DB\u30B9\u30C8\u3092\u8FFD\u52A0\u3057\u307E\u3057\u3087\u3046 -label.installWizard.addPodIntro.subtitle=\u30DD\u30C3\u30C9\u306B\u3064\u3044\u3066 -label.installWizard.addPodIntro.title=\u30DD\u30C3\u30C9\u3092\u8FFD\u52A0\u3057\u307E\u3057\u3087\u3046 -label.installWizard.addPrimaryStorageIntro.subtitle=\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u306B\u3064\u3044\u3066 -label.installWizard.addPrimaryStorageIntro.title=\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u3092\u8FFD\u52A0\u3057\u307E\u3057\u3087\u3046 +label.IKE.encryption=IKE \u6697\u53f7\u5316 +label.IKE.hash=IKE \u30cf\u30c3\u30b7\u30e5 +label.IKE.policy=IKE \u30dd\u30ea\u30b7\u30fc +label.info=\u60c5\u5831 +label.ingress.rule=\u53d7\u4fe1\u898f\u5247 +label.initiated.by=\u958b\u59cb\u30e6\u30fc\u30b6\u30fc +label.installWizard.addClusterIntro.subtitle=\u30af\u30e9\u30b9\u30bf\u30fc\u306b\u3064\u3044\u3066 +label.installWizard.addClusterIntro.title=\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u8ffd\u52a0\u3057\u307e\u3057\u3087\u3046 +label.installWizard.addHostIntro.subtitle=\u30db\u30b9\u30c8\u306b\u3064\u3044\u3066 +label.installWizard.addHostIntro.title=\u30db\u30b9\u30c8\u3092\u8ffd\u52a0\u3057\u307e\u3057\u3087\u3046 +label.installWizard.addPodIntro.subtitle=\u30dd\u30c3\u30c9\u306b\u3064\u3044\u3066 +label.installWizard.addPodIntro.title=\u30dd\u30c3\u30c9\u3092\u8ffd\u52a0\u3057\u307e\u3057\u3087\u3046 +label.installWizard.addPrimaryStorageIntro.subtitle=\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u306b\u3064\u3044\u3066 +label.installWizard.addPrimaryStorageIntro.title=\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u8ffd\u52a0\u3057\u307e\u3057\u3087\u3046 label.installWizard.addSecondaryStorageIntro.subtitle=\u30bb\u30ab\u30f3\u30c0\u30ea\u30fc\u30b9\u30c8\u30ec\u30fc\u30b8\u3068\u306f\uff1f -label.installWizard.addSecondaryStorageIntro.title=\u30BB\u30AB\u30F3\u30C0\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u3092\u8FFD\u52A0\u3057\u307E\u3057\u3087\u3046 -label.installWizard.addZoneIntro.subtitle=\u30BE\u30FC\u30F3\u306B\u3064\u3044\u3066 -label.installWizard.addZoneIntro.title=\u30BE\u30FC\u30F3\u3092\u8FFD\u52A0\u3057\u307E\u3057\u3087\u3046 -label.installWizard.addZone.title=\u30BE\u30FC\u30F3\u306E\u8FFD\u52A0 -label.installWizard.click.launch=[\u8D77\u52D5] \u3092\u30AF\u30EA\u30C3\u30AF\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -label.installWizard.subtitle=\u3053\u306E\u30AC\u30A4\u30C9 \u30C4\u30A2\u30FC\u306F CloudStack&\#8482; \u74B0\u5883\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u306B\u5F79\u7ACB\u3061\u307E\u3059 -label.installWizard.title=CloudStack&\#8482; \u3078\u3088\u3046\u3053\u305D -label.instance.limits=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u5236\u9650 -label.instance.name=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u540D -label.instances=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9 -label.instance=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9 -label.internal.dns.1=\u5185\u90E8 DNS 1 -label.internal.dns.2=\u5185\u90E8 DNS 2 -label.internal.name=\u5185\u90E8\u540D -label.interval.type=\u9593\u9694\u306E\u7A2E\u985E -label.introduction.to.cloudstack=CloudStack&\#8482; \u306E\u7D39\u4ECB -label.invalid.integer=\u7121\u52B9\u306A\u6574\u6570 -label.invalid.number=\u7121\u52B9\u306A\u6570 -label.invitations=\u62DB\u5F85\u72B6 -label.invited.accounts=\u62DB\u5F85\u6E08\u307F\u30A2\u30AB\u30A6\u30F3\u30C8 -label.invite.to=\u62DB\u5F85\u3059\u308B\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\: -label.invite=\u62DB\u5F85 -label.ip.address=IP \u30A2\u30C9\u30EC\u30B9 -label.ipaddress=IP \u30A2\u30C9\u30EC\u30B9 -label.ip.allocations=IP \u30A2\u30C9\u30EC\u30B9\u306E\u5272\u308A\u5F53\u3066 +label.installWizard.addSecondaryStorageIntro.title=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u8ffd\u52a0\u3057\u307e\u3057\u3087\u3046 +label.installWizard.addZoneIntro.subtitle=\u30be\u30fc\u30f3\u306b\u3064\u3044\u3066 +label.installWizard.addZoneIntro.title=\u30be\u30fc\u30f3\u3092\u8ffd\u52a0\u3057\u307e\u3057\u3087\u3046 +label.installWizard.addZone.title=\u30be\u30fc\u30f3\u306e\u8ffd\u52a0 +label.installWizard.click.launch=[\u8d77\u52d5] \u3092\u30af\u30ea\u30c3\u30af\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +label.installWizard.subtitle=\u3053\u306e\u30ac\u30a4\u30c9 \u30c4\u30a2\u30fc\u306f CloudStack&\#8482; \u74b0\u5883\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u306b\u5f79\u7acb\u3061\u307e\u3059 +label.installWizard.title=CloudStack&\#8482; \u3078\u3088\u3046\u3053\u305d +label.instance.limits=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u5236\u9650 +label.instance.name=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u540d +label.instances=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9 +label.instance=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9 +label.internal.dns.1=\u5185\u90e8 DNS 1 +label.internal.dns.2=\u5185\u90e8 DNS 2 +label.internal.name=\u5185\u90e8\u540d +label.interval.type=\u9593\u9694\u306e\u7a2e\u985e +label.introduction.to.cloudstack=CloudStack&\#8482; \u306e\u7d39\u4ecb +label.invalid.integer=\u7121\u52b9\u306a\u6574\u6570 +label.invalid.number=\u7121\u52b9\u306a\u6570 +label.invitations=\u62db\u5f85\u72b6 +label.invited.accounts=\u62db\u5f85\u6e08\u307f\u30a2\u30ab\u30a6\u30f3\u30c8 +label.invite.to=\u62db\u5f85\u3059\u308b\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\: +label.invite=\u62db\u5f85 +label.ip.address=IP \u30a2\u30c9\u30ec\u30b9 +label.ipaddress=IP \u30a2\u30c9\u30ec\u30b9 +label.ip.allocations=IP \u30a2\u30c9\u30ec\u30b9\u306e\u5272\u308a\u5f53\u3066 label.ip=IP -label.ip.limits=\u30D1\u30D6\u30EA\u30C3\u30AF IP \u30A2\u30C9\u30EC\u30B9\u306E\u5236\u9650 -label.ip.or.fqdn=IP \u30A2\u30C9\u30EC\u30B9\u307E\u305F\u306F FQDN -label.ip.range=IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2 -label.ip.ranges=IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2 -label.IPsec.preshared.key=IPsec \u4E8B\u524D\u5171\u6709\u30AD\u30FC +label.ip.limits=\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9\u306e\u5236\u9650 +label.ip.or.fqdn=IP \u30a2\u30c9\u30ec\u30b9\u307e\u305f\u306f FQDN +label.ip.range=IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2 +label.ip.ranges=IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2 +label.IPsec.preshared.key=IPsec \u4e8b\u524d\u5171\u6709\u30ad\u30fc label.ips=IP label.iscsi=iSCSI -label.is.default=\u30C7\u30D5\u30A9\u30EB\u30C8 -label.iso.boot=ISO \u8D77\u52D5 +label.is.default=\u30c7\u30d5\u30a9\u30eb\u30c8 +label.iso.boot=ISO \u8d77\u52d5 label.iso=ISO -label.isolated.networks=\u5206\u96E2\u3055\u308C\u305F\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF -label.isolation.method=\u5206\u96E2\u65B9\u6CD5 -label.isolation.mode=\u5206\u96E2\u30E2\u30FC\u30C9 +label.isolated.networks=\u5206\u96e2\u3055\u308c\u305f\u30cd\u30c3\u30c8\u30ef\u30fc\u30af +label.isolation.method=\u5206\u96e2\u65b9\u6cd5 +label.isolation.mode=\u5206\u96e2\u30e2\u30fc\u30c9 label.isolation.uri=Isolation URI label.is.redundant.router=\u5197\u9577 label.is.shared=\u5171\u6709 -label.is.system=\u30B7\u30B9\u30C6\u30E0 -label.item.listing=\u9805\u76EE\u4E00\u89A7 -label.keep=\u7DAD\u6301 -label.keyboard.type=\u30AD\u30FC\u30DC\u30FC\u30C9\u306E\u7A2E\u985E -label.key=\u30AD\u30FC -label.kvm.traffic.label=KVM \u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u306E\u30E9\u30D9\u30EB -label.label=\u30E9\u30D9\u30EB +label.is.system=\u30b7\u30b9\u30c6\u30e0 +label.item.listing=\u9805\u76ee\u4e00\u89a7 +label.keep=\u7dad\u6301 +label.keyboard.type=\u30ad\u30fc\u30dc\u30fc\u30c9\u306e\u7a2e\u985e +label.key=\u30ad\u30fc +label.kvm.traffic.label=KVM \u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e\u30e9\u30d9\u30eb +label.label=\u30e9\u30d9\u30eb label.lang.brportugese=Brazilian Portugese -label.lang.chinese=\u7C21\u4F53\u5B57\u4E2D\u56FD\u8A9E -label.lang.english=\u82F1\u8A9E +label.lang.chinese=\u7c21\u4f53\u5b57\u4e2d\u56fd\u8a9e +label.lang.english=\u82f1\u8a9e label.lang.french=French -label.lang.japanese=\u65E5\u672C\u8A9E +label.lang.japanese=\u65e5\u672c\u8a9e label.lang.russian=Russian -label.lang.spanish=\u30B9\u30DA\u30A4\u30F3\u8A9E -label.last.disconnected=\u6700\u7D42\u5207\u65AD\u65E5\u6642 -label.last.name=\u59D3 -label.latest.events=\u6700\u65B0\u30A4\u30D9\u30F3\u30C8 -label.launch=\u8D77\u52D5 -label.launch.vm=VM \u306E\u8D77\u52D5 -label.LB.isolation=\u8CA0\u8377\u5206\u6563\u5206\u96E2 -label.least.connections=\u6700\u5C0F\u63A5\u7D9A -label.level=\u30EC\u30D9\u30EB -label.linklocal.ip=\u30EA\u30F3\u30AF \u30ED\u30FC\u30AB\u30EB IP \u30A2\u30C9\u30EC\u30B9 -label.load.balancer=\u8CA0\u8377\u5206\u6563\u88C5\u7F6E -label.load.balancing.policies=\u8CA0\u8377\u5206\u6563\u30DD\u30EA\u30B7\u30FC -label.load.balancing=\u8CA0\u8377\u5206\u6563 -label.loading=\u30ED\u30FC\u30C9\u3057\u3066\u3044\u307E\u3059 -label.local.storage.enabled=\u30ED\u30FC\u30AB\u30EB \u30B9\u30C8\u30EC\u30FC\u30B8\u306F\u6709\u52B9\u3067\u3059 -label.local.storage=\u30ED\u30FC\u30AB\u30EB \u30B9\u30C8\u30EC\u30FC\u30B8 -label.local=\u30ED\u30FC\u30AB\u30EB -label.login=\u30ED\u30B0\u30AA\u30F3 -label.logout=\u30ED\u30B0\u30AA\u30D5 +label.lang.spanish=\u30b9\u30da\u30a4\u30f3\u8a9e +label.last.disconnected=\u6700\u7d42\u5207\u65ad\u65e5\u6642 +label.last.name=\u59d3 +label.latest.events=\u6700\u65b0\u30a4\u30d9\u30f3\u30c8 +label.launch=\u8d77\u52d5 +label.launch.vm=VM \u306e\u8d77\u52d5 +label.LB.isolation=\u8ca0\u8377\u5206\u6563\u5206\u96e2 +label.least.connections=\u6700\u5c0f\u63a5\u7d9a +label.level=\u30ec\u30d9\u30eb +label.linklocal.ip=\u30ea\u30f3\u30af \u30ed\u30fc\u30ab\u30eb IP \u30a2\u30c9\u30ec\u30b9 +label.load.balancer=\u8ca0\u8377\u5206\u6563\u88c5\u7f6e +label.load.balancing.policies=\u8ca0\u8377\u5206\u6563\u30dd\u30ea\u30b7\u30fc +label.load.balancing=\u8ca0\u8377\u5206\u6563 +label.loading=\u30ed\u30fc\u30c9\u3057\u3066\u3044\u307e\u3059 +label.local.storage.enabled=\u30ed\u30fc\u30ab\u30eb \u30b9\u30c8\u30ec\u30fc\u30b8\u306f\u6709\u52b9\u3067\u3059 +label.local.storage=\u30ed\u30fc\u30ab\u30eb \u30b9\u30c8\u30ec\u30fc\u30b8 +label.local=\u30ed\u30fc\u30ab\u30eb +label.login=\u30ed\u30b0\u30aa\u30f3 +label.logout=\u30ed\u30b0\u30aa\u30d5 label.lun=LUN -label.LUN.number=LUN \u756A\u53F7 -label.make.project.owner=\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u6240\u6709\u8005\u5316 -label.management.ips=\u7BA1\u7406 IP \u30A2\u30C9\u30EC\u30B9 -label.management=\u7BA1\u7406 -label.manage.resources=\u30EA\u30BD\u30FC\u30B9\u306E\u7BA1\u7406 -label.manage=\u7BA1\u7406 -label.max.guest.limit=\u6700\u5927\u30B2\u30B9\u30C8\u5236\u9650 +label.LUN.number=LUN \u756a\u53f7 +label.make.project.owner=\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u6240\u6709\u8005\u5316 +label.management.ips=\u7ba1\u7406 IP \u30a2\u30c9\u30ec\u30b9 +label.management=\u7ba1\u7406 +label.manage.resources=\u30ea\u30bd\u30fc\u30b9\u306e\u7ba1\u7406 +label.manage=\u7ba1\u7406 +label.max.guest.limit=\u6700\u5927\u30b2\u30b9\u30c8\u5236\u9650 label.maximum=\u6700\u5927 -label.max.networks=\u6700\u5927\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u6570 -label.max.public.ips=\u6700\u5927\u30D1\u30D6\u30EA\u30C3\u30AF IP \u30A2\u30C9\u30EC\u30B9\u6570 -label.max.snapshots=\u6700\u5927\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u6570 -label.max.templates=\u6700\u5927\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u6570 -label.max.vms=\u6700\u5927\u30E6\u30FC\u30B6\u30FC VM \u6570 -label.max.volumes=\u6700\u5927\u30DC\u30EA\u30E5\u30FC\u30E0\u6570 +label.max.networks=\u6700\u5927\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u6570 +label.max.public.ips=\u6700\u5927\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9\u6570 +label.max.snapshots=\u6700\u5927\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u6570 +label.max.templates=\u6700\u5927\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u6570 +label.max.vms=\u6700\u5927\u30e6\u30fc\u30b6\u30fc VM \u6570 +label.max.volumes=\u6700\u5927\u30dc\u30ea\u30e5\u30fc\u30e0\u6570 label.max.vpcs=Max. VPCs -label.may.continue=\u7D9A\u884C\u3067\u304D\u307E\u3059\u3002 -label.memory.allocated=\u5272\u308A\u5F53\u3066\u6E08\u307F\u306E\u30E1\u30E2\u30EA -label.memory.mb=\u30E1\u30E2\u30EA (MB) -label.memory.total=\u30E1\u30E2\u30EA\u5408\u8A08 -label.memory=\u30E1\u30E2\u30EA -label.memory.used=\u30E1\u30E2\u30EA\u4F7F\u7528\u91CF -label.menu.accounts=\u30A2\u30AB\u30A6\u30F3\u30C8 -label.menu.alerts=\u30A2\u30E9\u30FC\u30C8 -label.menu.all.accounts=\u3059\u3079\u3066\u306E\u30A2\u30AB\u30A6\u30F3\u30C8 -label.menu.all.instances=\u3059\u3079\u3066\u306E\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9 -label.menu.community.isos=\u30B3\u30DF\u30E5\u30CB\u30C6\u30A3 ISO -label.menu.community.templates=\u30B3\u30DF\u30E5\u30CB\u30C6\u30A3 \u30C6\u30F3\u30D7\u30EC\u30FC\u30C8 -label.menu.configuration=\u69CB\u6210 -label.menu.dashboard=\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9 -label.menu.destroyed.instances=\u7834\u68C4\u3055\u308C\u305F\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9 -label.menu.disk.offerings=\u30C7\u30A3\u30B9\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0 -label.menu.domains=\u30C9\u30E1\u30A4\u30F3 -label.menu.events=\u30A4\u30D9\u30F3\u30C8 -label.menu.featured.isos=\u304A\u3059\u3059\u3081\u306E ISO -label.menu.featured.templates=\u304A\u3059\u3059\u3081\u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8 -label.menu.global.settings=\u30B0\u30ED\u30FC\u30D0\u30EB\u8A2D\u5B9A -label.menu.infrastructure=\u30A4\u30F3\u30D5\u30E9\u30B9\u30C8\u30E9\u30AF\u30C1\u30E3 -label.menu.instances=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9 -label.menu.ipaddresses=IP \u30A2\u30C9\u30EC\u30B9 +label.may.continue=\u7d9a\u884c\u3067\u304d\u307e\u3059\u3002 +label.memory.allocated=\u5272\u308a\u5f53\u3066\u6e08\u307f\u306e\u30e1\u30e2\u30ea +label.memory.mb=\u30e1\u30e2\u30ea (MB) +label.memory.total=\u30e1\u30e2\u30ea\u5408\u8a08 +label.memory=\u30e1\u30e2\u30ea +label.memory.used=\u30e1\u30e2\u30ea\u4f7f\u7528\u91cf +label.menu.accounts=\u30a2\u30ab\u30a6\u30f3\u30c8 +label.menu.alerts=\u30a2\u30e9\u30fc\u30c8 +label.menu.all.accounts=\u3059\u3079\u3066\u306e\u30a2\u30ab\u30a6\u30f3\u30c8 +label.menu.all.instances=\u3059\u3079\u3066\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9 +label.menu.community.isos=\u30b3\u30df\u30e5\u30cb\u30c6\u30a3 ISO +label.menu.community.templates=\u30b3\u30df\u30e5\u30cb\u30c6\u30a3 \u30c6\u30f3\u30d7\u30ec\u30fc\u30c8 +label.menu.configuration=\u69cb\u6210 +label.menu.dashboard=\u30c0\u30c3\u30b7\u30e5\u30dc\u30fc\u30c9 +label.menu.destroyed.instances=\u7834\u68c4\u3055\u308c\u305f\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9 +label.menu.disk.offerings=\u30c7\u30a3\u30b9\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 +label.menu.domains=\u30c9\u30e1\u30a4\u30f3 +label.menu.events=\u30a4\u30d9\u30f3\u30c8 +label.menu.featured.isos=\u304a\u3059\u3059\u3081\u306e ISO +label.menu.featured.templates=\u304a\u3059\u3059\u3081\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8 +label.menu.global.settings=\u30b0\u30ed\u30fc\u30d0\u30eb\u8a2d\u5b9a +label.menu.infrastructure=\u30a4\u30f3\u30d5\u30e9\u30b9\u30c8\u30e9\u30af\u30c1\u30e3 +label.menu.instances=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9 +label.menu.ipaddresses=IP \u30a2\u30c9\u30ec\u30b9 label.menu.isos=ISO -label.menu.my.accounts=\u30DE\u30A4 \u30A2\u30AB\u30A6\u30F3\u30C8 -label.menu.my.instances=\u30DE\u30A4 \u30A4\u30F3\u30B9\u30BF\u30F3\u30B9 -label.menu.my.isos=\u30DE\u30A4 ISO -label.menu.my.templates=\u30DE\u30A4 \u30C6\u30F3\u30D7\u30EC\u30FC\u30C8 -label.menu.network.offerings=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0 -label.menu.network=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF -label.menu.physical.resources=\u7269\u7406\u30EA\u30BD\u30FC\u30B9 -label.menu.running.instances=\u5B9F\u884C\u4E2D\u306E\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9 -label.menu.security.groups=\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3 \u30B0\u30EB\u30FC\u30D7 -label.menu.service.offerings=\u30B5\u30FC\u30D3\u30B9 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0 -label.menu.snapshots=\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8 -label.menu.stopped.instances=\u505C\u6B62\u3055\u308C\u305F\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9 -label.menu.storage=\u30B9\u30C8\u30EC\u30FC\u30B8 -label.menu.system.service.offerings=\u30B7\u30B9\u30C6\u30E0 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0 -label.menu.system=\u30B7\u30B9\u30C6\u30E0 -label.menu.system.vms=\u30B7\u30B9\u30C6\u30E0 VM -label.menu.templates=\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8 -label.menu.virtual.appliances=\u4EEE\u60F3\u30A2\u30D7\u30E9\u30A4\u30A2\u30F3\u30B9 -label.menu.virtual.resources=\u4EEE\u60F3\u30EA\u30BD\u30FC\u30B9 -label.menu.volumes=\u30DC\u30EA\u30E5\u30FC\u30E0 -label.migrate.instance.to.host=\u5225\u306E\u30DB\u30B9\u30C8\u3078\u306E\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u79FB\u884C -label.migrate.instance.to.ps=\u5225\u306E\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u3078\u306E\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u79FB\u884C -label.migrate.instance.to=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u79FB\u884C\u5148\: -label.migrate.router.to=\u30EB\u30FC\u30BF\u30FC\u306E\u79FB\u884C\u5148\: -label.migrate.systemvm.to=\u30B7\u30B9\u30C6\u30E0 VM \u306E\u79FB\u884C\u5148\: +label.menu.my.accounts=\u30de\u30a4 \u30a2\u30ab\u30a6\u30f3\u30c8 +label.menu.my.instances=\u30de\u30a4 \u30a4\u30f3\u30b9\u30bf\u30f3\u30b9 +label.menu.my.isos=\u30de\u30a4 ISO +label.menu.my.templates=\u30de\u30a4 \u30c6\u30f3\u30d7\u30ec\u30fc\u30c8 +label.menu.network.offerings=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 +label.menu.network=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af +label.menu.physical.resources=\u7269\u7406\u30ea\u30bd\u30fc\u30b9 +label.menu.running.instances=\u5b9f\u884c\u4e2d\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9 +label.menu.security.groups=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7 +label.menu.service.offerings=\u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 +label.menu.snapshots=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8 +label.menu.stopped.instances=\u505c\u6b62\u3055\u308c\u305f\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9 +label.menu.storage=\u30b9\u30c8\u30ec\u30fc\u30b8 +label.menu.system.service.offerings=\u30b7\u30b9\u30c6\u30e0 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 +label.menu.system=\u30b7\u30b9\u30c6\u30e0 +label.menu.system.vms=\u30b7\u30b9\u30c6\u30e0 VM +label.menu.templates=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8 +label.menu.virtual.appliances=\u4eee\u60f3\u30a2\u30d7\u30e9\u30a4\u30a2\u30f3\u30b9 +label.menu.virtual.resources=\u4eee\u60f3\u30ea\u30bd\u30fc\u30b9 +label.menu.volumes=\u30dc\u30ea\u30e5\u30fc\u30e0 +label.migrate.instance.to.host=\u5225\u306e\u30db\u30b9\u30c8\u3078\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u79fb\u884c +label.migrate.instance.to.ps=\u5225\u306e\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3078\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u79fb\u884c +label.migrate.instance.to=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u79fb\u884c\u5148\: +label.migrate.router.to=\u30eb\u30fc\u30bf\u30fc\u306e\u79fb\u884c\u5148\: +label.migrate.systemvm.to=\u30b7\u30b9\u30c6\u30e0 VM \u306e\u79fb\u884c\u5148\: label.migrate.to.host=\u30db\u30b9\u30c8\u3078\u79fb\u884c label.migrate.to.storage=\u30b9\u30c8\u30ec\u30fc\u30b8\u3078\u79fb\u884c -label.migrate.volume=\u5225\u306E\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u3078\u306E\u30DC\u30EA\u30E5\u30FC\u30E0\u306E\u79FB\u884C -label.minimum=\u6700\u5C0F -label.minute.past.hour=\u5206 (\u6BCE\u6642) -label.monday=\u6708\u66DC\u65E5 -label.monthly=\u6BCE\u6708 -label.more.templates=\u305D\u306E\u307B\u304B\u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8 -label.move.down.row=1 \u884C\u4E0B\u306B\u79FB\u52D5 -label.move.to.bottom=\u6700\u4E0B\u4F4D\u306B\u79FB\u52D5 -label.move.to.top=\u6700\u4E0A\u4F4D\u306B\u79FB\u52D5 -label.move.up.row=1 \u884C\u4E0A\u306B\u79FB\u52D5 -label.my.account=\u30DE\u30A4 \u30A2\u30AB\u30A6\u30F3\u30C8 -label.my.network=\u30DE\u30A4 \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF -label.my.templates=\u30DE\u30A4 \u30C6\u30F3\u30D7\u30EC\u30FC\u30C8 -label.name.optional=\u540D\u524D (\u30AA\u30D7\u30B7\u30E7\u30F3) -label.name=\u540D\u524D -label.nat.port.range=NAT \u30DD\u30FC\u30C8\u306E\u7BC4\u56F2 -label.netmask=\u30CD\u30C3\u30C8\u30DE\u30B9\u30AF +label.migrate.volume=\u5225\u306e\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3078\u306e\u30dc\u30ea\u30e5\u30fc\u30e0\u306e\u79fb\u884c +label.minimum=\u6700\u5c0f +label.minute.past.hour=\u5206 (\u6bce\u6642) +label.monday=\u6708\u66dc\u65e5 +label.monthly=\u6bce\u6708 +label.more.templates=\u305d\u306e\u307b\u304b\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8 +label.move.down.row=1 \u884c\u4e0b\u306b\u79fb\u52d5 +label.move.to.bottom=\u6700\u4e0b\u4f4d\u306b\u79fb\u52d5 +label.move.to.top=\u6700\u4e0a\u4f4d\u306b\u79fb\u52d5 +label.move.up.row=1 \u884c\u4e0a\u306b\u79fb\u52d5 +label.my.account=\u30de\u30a4 \u30a2\u30ab\u30a6\u30f3\u30c8 +label.my.network=\u30de\u30a4 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af +label.my.templates=\u30de\u30a4 \u30c6\u30f3\u30d7\u30ec\u30fc\u30c8 +label.name.optional=\u540d\u524d (\u30aa\u30d7\u30b7\u30e7\u30f3) +label.name=\u540d\u524d +label.nat.port.range=NAT \u30dd\u30fc\u30c8\u306e\u7bc4\u56f2 +label.netmask=\u30cd\u30c3\u30c8\u30de\u30b9\u30af label.netScaler=NetScaler -label.network.ACLs=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF ACL -label.network.ACL.total=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF ACL \u5408\u8A08 -label.network.ACL=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF ACL -label.network.desc=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u8AAC\u660E -label.network.device.type=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30C7\u30D0\u30A4\u30B9\u306E\u7A2E\u985E -label.network.device=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30C7\u30D0\u30A4\u30B9 -label.network.domain.text=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30C9\u30E1\u30A4\u30F3 -label.network.domain=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30C9\u30E1\u30A4\u30F3 -label.network.id=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF ID -label.networking.and.security=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3068\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3 -label.network.label.display.for.blank.value=\u30C7\u30D5\u30A9\u30EB\u30C8 \u30B2\u30FC\u30C8\u30A6\u30A7\u30A4\u3092\u4F7F\u7528 -label.network.name=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u540D -label.network.offering.display.text=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u8868\u793A\u30C6\u30AD\u30B9\u30C8 -label.network.offering.id=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0 ID -label.network.offering.name=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u540D -label.network.offering=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0 -label.network.rate.megabytes=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u901F\u5EA6 (MB/\u79D2) -label.network.rate=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u901F\u5EA6 -label.network.read=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u8AAD\u307F\u53D6\u308A -label.network.service.providers=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30B5\u30FC\u30D3\u30B9 \u30D7\u30ED\u30D0\u30A4\u30C0\u30FC -label.networks=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF -label.network.type=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u7A2E\u985E -label.network=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF -label.network.write=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u66F8\u304D\u8FBC\u307F -label.new.password=\u65B0\u3057\u3044\u30D1\u30B9\u30EF\u30FC\u30C9 -label.new.project=\u65B0\u3057\u3044\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8 -label.new=\u65B0\u898F -label.new.vm=\u65B0\u3057\u3044 VM -label.next=\u6B21\u3078 +label.network.ACLs=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af ACL +label.network.ACL.total=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af ACL \u5408\u8a08 +label.network.ACL=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af ACL +label.network.desc=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u8aac\u660e +label.network.device.type=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30c7\u30d0\u30a4\u30b9\u306e\u7a2e\u985e +label.network.device=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30c7\u30d0\u30a4\u30b9 +label.network.domain.text=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30c9\u30e1\u30a4\u30f3 +label.network.domain=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30c9\u30e1\u30a4\u30f3 +label.network.id=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af ID +label.networking.and.security=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3068\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 +label.network.label.display.for.blank.value=\u30c7\u30d5\u30a9\u30eb\u30c8 \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u3092\u4f7f\u7528 +label.network.name=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u540d +label.network.offering.display.text=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u8868\u793a\u30c6\u30ad\u30b9\u30c8 +label.network.offering.id=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 ID +label.network.offering.name=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u540d +label.network.offering=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 +label.network.rate.megabytes=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u901f\u5ea6 (MB/\u79d2) +label.network.rate=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u901f\u5ea6 +label.network.read=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u8aad\u307f\u53d6\u308a +label.network.service.providers=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30b5\u30fc\u30d3\u30b9 \u30d7\u30ed\u30d0\u30a4\u30c0\u30fc +label.networks=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af +label.network.type=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u7a2e\u985e +label.network=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af +label.network.write=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u66f8\u304d\u8fbc\u307f +label.new.password=\u65b0\u3057\u3044\u30d1\u30b9\u30ef\u30fc\u30c9 +label.new.project=\u65b0\u3057\u3044\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 +label.new=\u65b0\u898f +label.new.vm=\u65b0\u3057\u3044 VM +label.next=\u6b21\u3078 label.nexusVswitch=Nexus 1000V label.nfs=NFS -label.nfs.server=NFS \u30B5\u30FC\u30D0\u30FC -label.nfs.storage=NFS \u30B9\u30C8\u30EC\u30FC\u30B8 -label.nic.adapter.type=NIC \u30A2\u30C0\u30D7\u30BF\u30FC\u306E\u7A2E\u985E +label.nfs.server=NFS \u30b5\u30fc\u30d0\u30fc +label.nfs.storage=NFS \u30b9\u30c8\u30ec\u30fc\u30b8 +label.nic.adapter.type=NIC \u30a2\u30c0\u30d7\u30bf\u30fc\u306e\u7a2e\u985e label.nicira.controller.address=\u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u306e\u30a2\u30c9\u30ec\u30b9 label.nicira.l3gatewayserviceuuid=L3 \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u30b5\u30fc\u30d3\u30b9UUID label.nicira.transportzoneuuid=Transport Zone Uuid label.nics=NIC -label.no.actions=\u5B9F\u884C\u3067\u304D\u308B\u64CD\u4F5C\u306F\u3042\u308A\u307E\u305B\u3093 -label.no.alerts=\u6700\u8FD1\u306E\u30A2\u30E9\u30FC\u30C8\u306F\u3042\u308A\u307E\u305B\u3093 -label.no.data=\u8868\u793A\u3059\u308B\u30C7\u30FC\u30BF\u304C\u3042\u308A\u307E\u305B\u3093 -label.no.errors=\u6700\u8FD1\u306E\u30A8\u30E9\u30FC\u306F\u3042\u308A\u307E\u305B\u3093 -label.no.isos=\u4F7F\u7528\u3067\u304D\u308B ISO \u306F\u3042\u308A\u307E\u305B\u3093 -label.no.items=\u4F7F\u7528\u3067\u304D\u308B\u9805\u76EE\u306F\u3042\u308A\u307E\u305B\u3093 -label.none=\u306A\u3057 -label.no.security.groups=\u4F7F\u7528\u3067\u304D\u308B\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3 \u30B0\u30EB\u30FC\u30D7\u306F\u3042\u308A\u307E\u305B\u3093 -label.not.found=\u898B\u3064\u304B\u308A\u307E\u305B\u3093 -label.no.thanks=\u8A2D\u5B9A\u3057\u306A\u3044 -label.notifications=\u901A\u77E5 +label.no.actions=\u5b9f\u884c\u3067\u304d\u308b\u64cd\u4f5c\u306f\u3042\u308a\u307e\u305b\u3093 +label.no.alerts=\u6700\u8fd1\u306e\u30a2\u30e9\u30fc\u30c8\u306f\u3042\u308a\u307e\u305b\u3093 +label.no.data=\u8868\u793a\u3059\u308b\u30c7\u30fc\u30bf\u304c\u3042\u308a\u307e\u305b\u3093 +label.no.errors=\u6700\u8fd1\u306e\u30a8\u30e9\u30fc\u306f\u3042\u308a\u307e\u305b\u3093 +label.no.isos=\u4f7f\u7528\u3067\u304d\u308b ISO \u306f\u3042\u308a\u307e\u305b\u3093 +label.no.items=\u4f7f\u7528\u3067\u304d\u308b\u9805\u76ee\u306f\u3042\u308a\u307e\u305b\u3093 +label.none=\u306a\u3057 +label.no.security.groups=\u4f7f\u7528\u3067\u304d\u308b\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u306f\u3042\u308a\u307e\u305b\u3093 +label.not.found=\u898b\u3064\u304b\u308a\u307e\u305b\u3093 +label.no.thanks=\u8a2d\u5b9a\u3057\u306a\u3044 +label.notifications=\u901a\u77e5 label.no=\u3044\u3044\u3048 -label.number.of.clusters=\u30AF\u30E9\u30B9\u30BF\u30FC\u6570 -label.number.of.hosts=\u30DB\u30B9\u30C8\u6570 -label.number.of.pods=\u30DD\u30C3\u30C9\u6570 -label.number.of.system.vms=\u30B7\u30B9\u30C6\u30E0 VM \u6570 -label.number.of.virtual.routers=\u4EEE\u60F3\u30EB\u30FC\u30BF\u30FC\u6570 -label.number.of.zones=\u30BE\u30FC\u30F3\u6570 -label.num.cpu.cores=CPU \u30B3\u30A2\u6570 -label.numretries=\u518D\u8A66\u884C\u56DE\u6570 +label.number.of.clusters=\u30af\u30e9\u30b9\u30bf\u30fc\u6570 +label.number.of.hosts=\u30db\u30b9\u30c8\u6570 +label.number.of.pods=\u30dd\u30c3\u30c9\u6570 +label.number.of.system.vms=\u30b7\u30b9\u30c6\u30e0 VM \u6570 +label.number.of.virtual.routers=\u4eee\u60f3\u30eb\u30fc\u30bf\u30fc\u6570 +label.number.of.zones=\u30be\u30fc\u30f3\u6570 +label.num.cpu.cores=CPU \u30b3\u30a2\u6570 +label.numretries=\u518d\u8a66\u884c\u56de\u6570 label.ocfs2=OCFS2 -label.offer.ha=\u9AD8\u53EF\u7528\u6027\u306E\u63D0\u4F9B +label.offer.ha=\u9ad8\u53ef\u7528\u6027\u306e\u63d0\u4f9b label.ok=OK -label.optional=\u30AA\u30D7\u30B7\u30E7\u30F3 -label.order=\u9806\u5E8F -label.os.preference=OS \u57FA\u672C\u8A2D\u5B9A -label.os.type=OS \u306E\u7A2E\u985E -label.owned.public.ips=\u6240\u6709\u3059\u308B\u30D1\u30D6\u30EA\u30C3\u30AF IP \u30A2\u30C9\u30EC\u30B9 -label.owner.account=\u6240\u6709\u8005\u30A2\u30AB\u30A6\u30F3\u30C8 -label.owner.domain=\u00e6\u0089\u0080\u00e6\u009c\u0089\u00e8\u0080\u0085\u00e3\u0083\u0089\u00e3\u0083\u00a1\u00e3\u0082\u00a4\u00e3\u0083\u00b3 -label.parent.domain=\u89AA\u30C9\u30E1\u30A4\u30F3 -label.password.enabled=\u30D1\u30B9\u30EF\u30FC\u30C9\u7BA1\u7406\u6709\u52B9 -label.password=\u30D1\u30B9\u30EF\u30FC\u30C9 -label.path=\u30D1\u30B9 +label.optional=\u30aa\u30d7\u30b7\u30e7\u30f3 +label.order=\u9806\u5e8f +label.os.preference=OS \u57fa\u672c\u8a2d\u5b9a +label.os.type=OS \u306e\u7a2e\u985e +label.owned.public.ips=\u6240\u6709\u3059\u308b\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9 +label.owner.account=\u6240\u6709\u8005\u30a2\u30ab\u30a6\u30f3\u30c8 +label.owner.domain=\u00e6\u0089\u0080\u00e6\u009c\u0089\u00e8\u0080 +label.parent.domain=\u89aa\u30c9\u30e1\u30a4\u30f3 +label.password.enabled=\u30d1\u30b9\u30ef\u30fc\u30c9\u7ba1\u7406\u6709\u52b9 +label.password=\u30d1\u30b9\u30ef\u30fc\u30c9 +label.path=\u30d1\u30b9 label.perfect.forward.secrecy=Perfect Forward Secrecy -label.physical.network.ID=\u7269\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF ID -label.PING.CIFS.password=PING CIFS \u30D1\u30B9\u30EF\u30FC\u30C9 -label.PING.CIFS.username=PING CIFS \u30E6\u30FC\u30B6\u30FC\u540D -label.PING.dir=PING \u30C7\u30A3\u30EC\u30AF\u30C8\u30EA -label.PING.storage.IP=PING \u5BFE\u8C61\u306E\u30B9\u30C8\u30EC\u30FC\u30B8 IP \u30A2\u30C9\u30EC\u30B9 -label.please.specify.netscaler.info=Netscaler \u60C5\u5831\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044 -label.please.wait=\u304A\u5F85\u3061\u304F\u3060\u3055\u3044 -label.pod.name=\u30DD\u30C3\u30C9\u540D -label.pods=\u30DD\u30C3\u30C9 -label.pod=\u30DD\u30C3\u30C9 -label.port.forwarding.policies=\u30DD\u30FC\u30C8\u8EE2\u9001\u30DD\u30EA\u30B7\u30FC -label.port.forwarding=\u30DD\u30FC\u30C8\u8EE2\u9001 -label.port.range=\u30DD\u30FC\u30C8\u306E\u7BC4\u56F2 +label.physical.network.ID=\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af ID +label.PING.CIFS.password=PING CIFS \u30d1\u30b9\u30ef\u30fc\u30c9 +label.PING.CIFS.username=PING CIFS \u30e6\u30fc\u30b6\u30fc\u540d +label.PING.dir=PING \u30c7\u30a3\u30ec\u30af\u30c8\u30ea +label.PING.storage.IP=PING \u5bfe\u8c61\u306e\u30b9\u30c8\u30ec\u30fc\u30b8 IP \u30a2\u30c9\u30ec\u30b9 +label.please.specify.netscaler.info=Netscaler \u60c5\u5831\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044 +label.please.wait=\u304a\u5f85\u3061\u304f\u3060\u3055\u3044 +label.pod.name=\u30dd\u30c3\u30c9\u540d +label.pods=\u30dd\u30c3\u30c9 +label.pod=\u30dd\u30c3\u30c9 +label.port.forwarding.policies=\u30dd\u30fc\u30c8\u8ee2\u9001\u30dd\u30ea\u30b7\u30fc +label.port.forwarding=\u30dd\u30fc\u30c8\u8ee2\u9001 +label.port.range=\u30dd\u30fc\u30c8\u306e\u7bc4\u56f2 label.PreSetup=PreSetup -label.previous=\u623B\u308B -label.prev=\u623B\u308B -label.primary.allocated=\u5272\u308A\u5F53\u3066\u6E08\u307F\u306E\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8 -label.primary.network=\u30D7\u30E9\u30A4\u30DE\u30EA \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF -label.primary.storage.count=\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8 \u30D7\u30FC\u30EB -label.primary.storage=\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8 -label.primary.used=\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u4F7F\u7528\u91CF -label.private.Gateway=\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8 \u30B2\u30FC\u30C8\u30A6\u30A7\u30A4 -label.private.interface=\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8 \u30A4\u30F3\u30BF\u30FC\u30D5\u30A7\u30A4\u30B9 -label.private.ip.range=\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8 IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2 -label.private.ips=\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8 IP \u30A2\u30C9\u30EC\u30B9 -label.private.ip=\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8 IP \u30A2\u30C9\u30EC\u30B9 -label.privatekey=PKC\#8 \u79D8\u5BC6\u30AD\u30FC -label.private.network=\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8 \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF -label.private.port=\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8 \u30DD\u30FC\u30C8 -label.private.zone=\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8 \u30BE\u30FC\u30F3 -label.project.dashboard=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8 \u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9 -label.project.id=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8 ID -label.project.invite=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3078\u306E\u62DB\u5F85 -label.project.name=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u540D -label.projects=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8 -label.project=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8 -label.project.view=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8 \u30D3\u30E5\u30FC -label.protocol=\u30D7\u30ED\u30C8\u30B3\u30EB -label.providers=\u30D7\u30ED\u30D0\u30A4\u30C0\u30FC -label.public.interface=\u30D1\u30D6\u30EA\u30C3\u30AF \u30A4\u30F3\u30BF\u30FC\u30D5\u30A7\u30A4\u30B9 -label.public.ips=\u30D1\u30D6\u30EA\u30C3\u30AF IP \u30A2\u30C9\u30EC\u30B9 -label.public.ip=\u30D1\u30D6\u30EA\u30C3\u30AF IP \u30A2\u30C9\u30EC\u30B9 -label.public.network=\u30D1\u30D6\u30EA\u30C3\u30AF \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF -label.public.port=\u30D1\u30D6\u30EA\u30C3\u30AF \u30DD\u30FC\u30C8 -label.public=\u30D1\u30D6\u30EA\u30C3\u30AF -label.public.zone=\u30D1\u30D6\u30EA\u30C3\u30AF \u30BE\u30FC\u30F3 -label.purpose=\u76EE\u7684 -label.Pxe.server.type=PXE \u30B5\u30FC\u30D0\u30FC\u306E\u7A2E\u985E +label.previous=\u623b\u308b +label.prev=\u623b\u308b +label.primary.allocated=\u5272\u308a\u5f53\u3066\u6e08\u307f\u306e\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 +label.primary.network=\u30d7\u30e9\u30a4\u30de\u30ea \u30cd\u30c3\u30c8\u30ef\u30fc\u30af +label.primary.storage.count=\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 \u30d7\u30fc\u30eb +label.primary.storage=\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 +label.primary.used=\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u4f7f\u7528\u91cf +label.private.Gateway=\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4 +label.private.interface=\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 \u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30a4\u30b9 +label.private.ip.range=\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2 +label.private.ips=\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 IP \u30a2\u30c9\u30ec\u30b9 +label.private.ip=\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 IP \u30a2\u30c9\u30ec\u30b9 +label.privatekey=PKC\#8 \u79d8\u5bc6\u30ad\u30fc +label.private.network=\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af +label.private.port=\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 \u30dd\u30fc\u30c8 +label.private.zone=\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 \u30be\u30fc\u30f3 +label.project.dashboard=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 \u30c0\u30c3\u30b7\u30e5\u30dc\u30fc\u30c9 +label.project.id=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 ID +label.project.invite=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3078\u306e\u62db\u5f85 +label.project.name=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u540d +label.projects=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 +label.project=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 +label.project.view=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 \u30d3\u30e5\u30fc +label.protocol=\u30d7\u30ed\u30c8\u30b3\u30eb +label.providers=\u30d7\u30ed\u30d0\u30a4\u30c0\u30fc +label.public.interface=\u30d1\u30d6\u30ea\u30c3\u30af \u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30a4\u30b9 +label.public.ips=\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9 +label.public.ip=\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9 +label.public.network=\u30d1\u30d6\u30ea\u30c3\u30af \u30cd\u30c3\u30c8\u30ef\u30fc\u30af +label.public.port=\u30d1\u30d6\u30ea\u30c3\u30af \u30dd\u30fc\u30c8 +label.public=\u30d1\u30d6\u30ea\u30c3\u30af +label.public.zone=\u30d1\u30d6\u30ea\u30c3\u30af \u30be\u30fc\u30f3 +label.purpose=\u76ee\u7684 +label.Pxe.server.type=PXE \u30b5\u30fc\u30d0\u30fc\u306e\u7a2e\u985e label.quickview=\u30af\u30a4\u30c3\u30af\u30d3\u30e5\u30fc label.reboot=\u518d\u8d77\u52d5 -label.recent.errors=\u6700\u8FD1\u306E\u30A8\u30E9\u30FC -label.redundant.router.capability=\u5197\u9577\u30EB\u30FC\u30BF\u30FC\u6A5F\u80FD -label.redundant.router=\u5197\u9577\u30EB\u30FC\u30BF\u30FC -label.redundant.state=\u5197\u9577\u72B6\u614B -label.refresh=\u66F4\u65B0 -label.related=\u95A2\u9023 -label.remind.later=\u30A2\u30E9\u30FC\u30E0\u3092\u8868\u793A\u3059\u308B -label.remove.ACL=ACL \u306E\u524A\u9664 -label.remove.egress.rule=\u9001\u4FE1\u898F\u5247\u306E\u524A\u9664 -label.remove.from.load.balancer=\u8CA0\u8377\u5206\u6563\u88C5\u7F6E\u304B\u3089\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059 -label.remove.ingress.rule=\u53D7\u4FE1\u898F\u5247\u306E\u524A\u9664 -label.remove.ip.range=IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2\u306E\u524A\u9664 -label.remove.pf=\u30DD\u30FC\u30C8\u8EE2\u9001\u898F\u5247\u306E\u524A\u9664 -label.remove.rule=\u898F\u5247\u306E\u524A\u9664 -label.remove.static.nat.rule=\u9759\u7684 NAT \u898F\u5247\u306E\u524A\u9664 -label.remove.static.route=\u9759\u7684\u30EB\u30FC\u30C8\u306E\u524A\u9664 -label.remove.tier=\u968E\u5C64\u306E\u524A\u9664 -label.remove.vm.from.lb=\u8CA0\u8377\u5206\u6563\u898F\u5247\u304B\u3089\u306E VM \u306E\u524A\u9664 -label.remove.vpc=VPC \u306E\u524A\u9664 -label.removing=\u524A\u9664\u3057\u3066\u3044\u307E\u3059 -label.removing.user=\u30E6\u30FC\u30B6\u30FC\u3092\u524A\u9664\u3057\u3066\u3044\u307E\u3059 -label.required=\u5FC5\u9808\u3067\u3059 -label.reserved.system.gateway=\u4E88\u7D04\u6E08\u307F\u30B7\u30B9\u30C6\u30E0 \u30B2\u30FC\u30C8\u30A6\u30A7\u30A4 -label.reserved.system.ip=\u4E88\u7D04\u6E08\u307F\u30B7\u30B9\u30C6\u30E0 IP \u30A2\u30C9\u30EC\u30B9 -label.reserved.system.netmask=\u4E88\u7D04\u6E08\u307F\u30B7\u30B9\u30C6\u30E0 \u30CD\u30C3\u30C8\u30DE\u30B9\u30AF -label.reset.VPN.connection=VPN \u63A5\u7D9A\u306E\u30EA\u30BB\u30C3\u30C8 -label.resource.limits=\u30EA\u30BD\u30FC\u30B9\u5236\u9650 -label.resource.state=\u30EA\u30BD\u30FC\u30B9\u306E\u72B6\u614B -label.resources=\u30EA\u30BD\u30FC\u30B9 -label.resource=\u30EA\u30BD\u30FC\u30B9 -label.restart.network=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u518D\u8D77\u52D5 -label.restart.required=\u518D\u8D77\u52D5\u304C\u5FC5\u8981 -label.restart.vpc=VPC \u306E\u518D\u8D77\u52D5 +label.recent.errors=\u6700\u8fd1\u306e\u30a8\u30e9\u30fc +label.redundant.router.capability=\u5197\u9577\u30eb\u30fc\u30bf\u30fc\u6a5f\u80fd +label.redundant.router=\u5197\u9577\u30eb\u30fc\u30bf\u30fc +label.redundant.state=\u5197\u9577\u72b6\u614b +label.refresh=\u66f4\u65b0 +label.related=\u95a2\u9023 +label.remind.later=\u30a2\u30e9\u30fc\u30e0\u3092\u8868\u793a\u3059\u308b +label.remove.ACL=ACL \u306e\u524a\u9664 +label.remove.egress.rule=\u9001\u4fe1\u898f\u5247\u306e\u524a\u9664 +label.remove.from.load.balancer=\u8ca0\u8377\u5206\u6563\u88c5\u7f6e\u304b\u3089\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059 +label.remove.ingress.rule=\u53d7\u4fe1\u898f\u5247\u306e\u524a\u9664 +label.remove.ip.range=IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u306e\u524a\u9664 +label.remove.pf=\u30dd\u30fc\u30c8\u8ee2\u9001\u898f\u5247\u306e\u524a\u9664 +label.remove.rule=\u898f\u5247\u306e\u524a\u9664 +label.remove.static.nat.rule=\u9759\u7684 NAT \u898f\u5247\u306e\u524a\u9664 +label.remove.static.route=\u9759\u7684\u30eb\u30fc\u30c8\u306e\u524a\u9664 +label.remove.tier=\u968e\u5c64\u306e\u524a\u9664 +label.remove.vm.from.lb=\u8ca0\u8377\u5206\u6563\u898f\u5247\u304b\u3089\u306e VM \u306e\u524a\u9664 +label.remove.vpc=VPC \u306e\u524a\u9664 +label.removing=\u524a\u9664\u3057\u3066\u3044\u307e\u3059 +label.removing.user=\u30e6\u30fc\u30b6\u30fc\u3092\u524a\u9664\u3057\u3066\u3044\u307e\u3059 +label.required=\u5fc5\u9808\u3067\u3059 +label.reserved.system.gateway=\u4e88\u7d04\u6e08\u307f\u30b7\u30b9\u30c6\u30e0 \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4 +label.reserved.system.ip=\u4e88\u7d04\u6e08\u307f\u30b7\u30b9\u30c6\u30e0 IP \u30a2\u30c9\u30ec\u30b9 +label.reserved.system.netmask=\u4e88\u7d04\u6e08\u307f\u30b7\u30b9\u30c6\u30e0 \u30cd\u30c3\u30c8\u30de\u30b9\u30af +label.reset.VPN.connection=VPN \u63a5\u7d9a\u306e\u30ea\u30bb\u30c3\u30c8 +label.resource.limits=\u30ea\u30bd\u30fc\u30b9\u5236\u9650 +label.resource.state=\u30ea\u30bd\u30fc\u30b9\u306e\u72b6\u614b +label.resources=\u30ea\u30bd\u30fc\u30b9 +label.resource=\u30ea\u30bd\u30fc\u30b9 +label.restart.network=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u518d\u8d77\u52d5 +label.restart.required=\u518d\u8d77\u52d5\u304c\u5fc5\u8981 +label.restart.vpc=VPC \u306e\u518d\u8d77\u52d5 label.restore=\u30ea\u30b9\u30c8\u30a2 -label.review=\u78BA\u8A8D -label.revoke.project.invite=\u62DB\u5F85\u306E\u53D6\u308A\u6D88\u3057 -label.role=\u5F79\u5272 -label.root.disk.controller=\u30EB\u30FC\u30C8 \u30C7\u30A3\u30B9\u30AF \u30B3\u30F3\u30C8\u30ED\u30FC\u30E9\u30FC -label.root.disk.offering=\u30EB\u30FC\u30C8 \u30C7\u30A3\u30B9\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0 -label.round.robin=\u30E9\u30A6\u30F3\u30C9\u30ED\u30D3\u30F3 -label.rules=\u898F\u5247 -label.running.vms=\u5B9F\u884C\u4E2D\u306E VM +label.review=\u78ba\u8a8d +label.revoke.project.invite=\u62db\u5f85\u306e\u53d6\u308a\u6d88\u3057 +label.role=\u5f79\u5272 +label.root.disk.controller=\u30eb\u30fc\u30c8 \u30c7\u30a3\u30b9\u30af \u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc +label.root.disk.offering=\u30eb\u30fc\u30c8 \u30c7\u30a3\u30b9\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 +label.round.robin=\u30e9\u30a6\u30f3\u30c9\u30ed\u30d3\u30f3 +label.rules=\u898f\u5247 +label.running.vms=\u5b9f\u884c\u4e2d\u306e VM label.s3.access_key=\u30a2\u30af\u30bb\u30b9\u30ad\u30fc label.s3.bucket=\u30d0\u30b1\u30c3\u30c8 label.s3.connection_timeout=\u30b3\u30cd\u30af\u30b7\u30e7\u30f3\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8 @@ -890,569 +891,565 @@ label.s3.max_error_retry=\u30a8\u30e9\u30fc\u6642\u306e\u6700\u5927\u30ea\u30c8\ label.s3.secret_key=\u79d8\u5bc6\u9375 label.s3.socket_timeout=\u30bd\u30b1\u30c3\u30c8\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8 label.s3.use_https=HTTPS\u306e\u4f7f\u7528 -label.saturday=\u571F\u66DC\u65E5 -label.save.and.continue=\u4FDD\u5B58\u3057\u3066\u7D9A\u884C -label.save=\u4FDD\u5B58 -label.saving.processing=\u4FDD\u5B58\u3057\u3066\u3044\u307E\u3059... -label.scope=\u30B9\u30B3\u30FC\u30D7 -label.search=\u691C\u7D22 -label.secondary.storage.count=\u30BB\u30AB\u30F3\u30C0\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8 \u30D7\u30FC\u30EB -label.secondary.storage=\u30BB\u30AB\u30F3\u30C0\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8 -label.secondary.storage.vm=\u30BB\u30AB\u30F3\u30C0\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8 VM -label.secondary.used=\u30BB\u30AB\u30F3\u30C0\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u4F7F\u7528\u91CF +label.saturday=\u571f\u66dc\u65e5 +label.save.and.continue=\u4fdd\u5b58\u3057\u3066\u7d9a\u884c +label.save=\u4fdd\u5b58 +label.saving.processing=\u4fdd\u5b58\u3057\u3066\u3044\u307e\u3059... +label.scope=\u30b9\u30b3\u30fc\u30d7 +label.search=\u691c\u7d22 +label.secondary.storage.count=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 \u30d7\u30fc\u30eb +label.secondary.storage=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 +label.secondary.storage.vm=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 VM +label.secondary.used=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u4f7f\u7528\u91cf label.secret.key=\u79d8\u5bc6\u9375 -label.security.group.name=\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3 \u30B0\u30EB\u30FC\u30D7\u540D -label.security.groups.enabled=\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3 \u30B0\u30EB\u30FC\u30D7\u6709\u52B9 -label.security.groups=\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3 \u30B0\u30EB\u30FC\u30D7 -label.security.group=\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3 \u30B0\u30EB\u30FC\u30D7 -label.select.a.template=\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u9078\u629E -label.select.a.zone=\u30BE\u30FC\u30F3\u306E\u9078\u629E -label.select.instance.to.attach.volume.to=\u30DC\u30EA\u30E5\u30FC\u30E0\u3092\u30A2\u30BF\u30C3\u30C1\u3059\u308B\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044 -label.select.instance=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u9078\u629E -label.select.iso.or.template=ISO \u307E\u305F\u306F\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u9078\u629E -label.select.offering=\u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u306E\u9078\u629E -label.select.project=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u9078\u629E -label.select.tier=\u968E\u5C64\u306E\u9078\u629E -label.select=\u9078\u629E -label.select-view=\u30D3\u30E5\u30FC\u306E\u9078\u629E -label.select.vm.for.static.nat=\u9759\u7684 NAT \u7528 VM \u306E\u9078\u629E -label.sent=\u9001\u4FE1\u6E08\u307F -label.server=\u30B5\u30FC\u30D0\u30FC -label.service.capabilities=\u30B5\u30FC\u30D3\u30B9\u306E\u6A5F\u80FD -label.service.offering=\u30B5\u30FC\u30D3\u30B9 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0 -label.session.expired=\u30BB\u30C3\u30B7\u30E7\u30F3\u306E\u6709\u52B9\u671F\u9650\u304C\u5207\u308C\u307E\u3057\u305F -label.setup.network=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7 -label.setup=\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7 -label.set.up.zone.type=\u30BE\u30FC\u30F3\u306E\u7A2E\u985E\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7 -label.setup.zone=\u30BE\u30FC\u30F3\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7 +label.security.group.name=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u540d +label.security.groups.enabled=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u6709\u52b9 +label.security.groups=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7 +label.security.group=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7 +label.select.a.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u9078\u629e +label.select.a.zone=\u30be\u30fc\u30f3\u306e\u9078\u629e +label.select.instance.to.attach.volume.to=\u30dc\u30ea\u30e5\u30fc\u30e0\u3092\u30a2\u30bf\u30c3\u30c1\u3059\u308b\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044 +label.select.instance=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u9078\u629e +label.select.iso.or.template=ISO \u307e\u305f\u306f\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u9078\u629e +label.select.offering=\u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u306e\u9078\u629e +label.select.project=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u9078\u629e +label.select.tier=\u968e\u5c64\u306e\u9078\u629e +label.select=\u9078\u629e +label.select-view=\u30d3\u30e5\u30fc\u306e\u9078\u629e +label.select.vm.for.static.nat=\u9759\u7684 NAT \u7528 VM \u306e\u9078\u629e +label.sent=\u9001\u4fe1\u6e08\u307f +label.server=\u30b5\u30fc\u30d0\u30fc +label.service.capabilities=\u30b5\u30fc\u30d3\u30b9\u306e\u6a5f\u80fd +label.service.offering=\u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 +label.session.expired=\u30bb\u30c3\u30b7\u30e7\u30f3\u306e\u6709\u52b9\u671f\u9650\u304c\u5207\u308c\u307e\u3057\u305f +label.setup.network=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7 +label.setup=\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7 +label.set.up.zone.type=\u30be\u30fc\u30f3\u306e\u7a2e\u985e\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7 +label.setup.zone=\u30be\u30fc\u30f3\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7 label.SharedMountPoint=SharedMountPoint label.shared=\u5171\u6709 -label.show.ingress.rule=\u53D7\u4FE1\u898F\u5247\u306E\u8868\u793A -label.shutdown.provider=\u30D7\u30ED\u30D0\u30A4\u30C0\u30FC\u306E\u30B7\u30E3\u30C3\u30C8\u30C0\u30A6\u30F3 -label.site.to.site.VPN=\u30B5\u30A4\u30C8\u9593 VPN -label.size=\u30B5\u30A4\u30BA -label.skip.guide=CloudStack \u3092\u4F7F\u7528\u3057\u305F\u3053\u3068\u304C\u3042\u308B\u306E\u3067\u3001\u3053\u306E\u30AC\u30A4\u30C9\u3092\u30B9\u30AD\u30C3\u30D7\u3059\u308B -label.snapshot.limits=\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u5236\u9650 -label.snapshot.name=\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u540D -label.snapshot.schedule=\u5B9A\u671F\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7 -label.snapshot.s=\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8 -label.snapshots=\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8 -label.snapshot=\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8 -label.source.nat=\u9001\u4FE1\u5143 NAT -label.source=\u9001\u4FE1\u5143 -label.specify.IP.ranges=IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2\u306E\u6307\u5B9A -label.specify.vlan=VLAN \u306E\u6307\u5B9A -label.SR.name = SR \u540D\u30E9\u30D9\u30EB +label.show.ingress.rule=\u53d7\u4fe1\u898f\u5247\u306e\u8868\u793a +label.shutdown.provider=\u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u306e\u30b7\u30e3\u30c3\u30c8\u30c0\u30a6\u30f3 +label.site.to.site.VPN=\u30b5\u30a4\u30c8\u9593 VPN +label.size=\u30b5\u30a4\u30ba +label.skip.guide=CloudStack \u3092\u4f7f\u7528\u3057\u305f\u3053\u3068\u304c\u3042\u308b\u306e\u3067\u3001\u3053\u306e\u30ac\u30a4\u30c9\u3092\u30b9\u30ad\u30c3\u30d7\u3059\u308b +label.snapshot.limits=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u5236\u9650 +label.snapshot.name=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u540d +label.snapshot.schedule=\u5b9a\u671f\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7 +label.snapshot.s=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8 +label.snapshots=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8 +label.snapshot=\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8 +label.source.nat=\u9001\u4fe1\u5143 NAT +label.source=\u9001\u4fe1\u5143 +label.specify.IP.ranges=IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u306e\u6307\u5b9a +label.specify.vlan=VLAN \u306e\u6307\u5b9a +label.SR.name = SR \u540d\u30e9\u30d9\u30eb label.srx=SRX -label.start.IP=\u958B\u59CB IP \u30A2\u30C9\u30EC\u30B9 -label.start.port=\u958B\u59CB\u30DD\u30FC\u30C8 -label.start.reserved.system.IP=\u4E88\u7D04\u6E08\u307F\u958B\u59CB\u30B7\u30B9\u30C6\u30E0 IP \u30A2\u30C9\u30EC\u30B9 -label.start.vlan=\u958B\u59CB VLAN -label.state=\u72B6\u614B -label.static.nat.enabled=\u9759\u7684 NAT \u6709\u52B9 -label.static.nat.to=\u9759\u7684 NAT \u306E\u8A2D\u5B9A\u5148\: +label.start.IP=\u958b\u59cb IP \u30a2\u30c9\u30ec\u30b9 +label.start.port=\u958b\u59cb\u30dd\u30fc\u30c8 +label.start.reserved.system.IP=\u4e88\u7d04\u6e08\u307f\u958b\u59cb\u30b7\u30b9\u30c6\u30e0 IP \u30a2\u30c9\u30ec\u30b9 +label.start.vlan=\u958b\u59cb VLAN +label.state=\u72b6\u614b +label.static.nat.enabled=\u9759\u7684 NAT \u6709\u52b9 +label.static.nat.to=\u9759\u7684 NAT \u306e\u8a2d\u5b9a\u5148\: label.static.nat=\u9759\u7684 NAT -label.static.nat.vm.details=\u9759\u7684 NAT VM \u306E\u8A73\u7D30 -label.statistics=\u7D71\u8A08 -label.status=\u72B6\u614B -label.step.1.title=\u624B\u9806 1. \u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u9078\u629E -label.step.1=\u624B\u9806 1 -label.step.2.title=\u624B\u9806 2. \u30B5\u30FC\u30D3\u30B9 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0 -label.step.2=\u624B\u9806 2 -label.step.3.title=\u624B\u9806 3. \u30C7\u30A3\u30B9\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u306E\u9078\u629E -label.step.3=\u624B\u9806 3 -label.step.4.title=\u624B\u9806 4. \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF -label.step.4=\u624B\u9806 4 -label.step.5.title=\u624B\u9806 5. \u78BA\u8A8D -label.step.5=\u624B\u9806 5 -label.stickiness=\u6301\u7D9A\u6027 -label.sticky.cookie-name=Cookie \u540D -label.sticky.domain=\u30C9\u30E1\u30A4\u30F3 -label.sticky.expire=\u5931\u52B9 -label.sticky.holdtime=\u4FDD\u6301\u6642\u9593 -label.sticky.indirect=\u9593\u63A5 +label.static.nat.vm.details=\u9759\u7684 NAT VM \u306e\u8a73\u7d30 +label.statistics=\u7d71\u8a08 +label.status=\u72b6\u614b +label.step.1.title=\u624b\u9806 1. \u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u9078\u629e +label.step.1=\u624b\u9806 1 +label.step.2.title=\u624b\u9806 2. \u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 +label.step.2=\u624b\u9806 2 +label.step.3.title=\u624b\u9806 3. \u30c7\u30a3\u30b9\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u306e\u9078\u629e +label.step.3=\u624b\u9806 3 +label.step.4.title=\u624b\u9806 4. \u30cd\u30c3\u30c8\u30ef\u30fc\u30af +label.step.4=\u624b\u9806 4 +label.step.5.title=\u624b\u9806 5. \u78ba\u8a8d +label.step.5=\u624b\u9806 5 +label.stickiness=\u6301\u7d9a\u6027 +label.sticky.cookie-name=Cookie \u540d +label.sticky.domain=\u30c9\u30e1\u30a4\u30f3 +label.sticky.expire=\u5931\u52b9 +label.sticky.holdtime=\u4fdd\u6301\u6642\u9593 +label.sticky.indirect=\u9593\u63a5 label.sticky.length=\u9577\u3055 -label.sticky.mode=\u30E2\u30FC\u30C9 -label.sticky.nocache=\u30AD\u30E3\u30C3\u30B7\u30E5\u306A\u3057 -label.sticky.postonly=\u30DD\u30B9\u30C8\u306E\u307F -label.sticky.prefix=\u30D7\u30EC\u30D5\u30A3\u30C3\u30AF\u30B9 -label.sticky.request-learn=\u30E9\u30FC\u30CB\u30F3\u30B0\u306E\u8981\u6C42 -label.sticky.tablesize=\u30C6\u30FC\u30D6\u30EB \u30B5\u30A4\u30BA -label.stopped.vms=\u505C\u6B62\u4E2D\u306E VM +label.sticky.mode=\u30e2\u30fc\u30c9 +label.sticky.nocache=\u30ad\u30e3\u30c3\u30b7\u30e5\u306a\u3057 +label.sticky.postonly=\u30dd\u30b9\u30c8\u306e\u307f +label.sticky.prefix=\u30d7\u30ec\u30d5\u30a3\u30c3\u30af\u30b9 +label.sticky.request-learn=\u30e9\u30fc\u30cb\u30f3\u30b0\u306e\u8981\u6c42 +label.sticky.tablesize=\u30c6\u30fc\u30d6\u30eb \u30b5\u30a4\u30ba +label.stopped.vms=\u505c\u6b62\u4e2d\u306e VM label.stop=\u505c\u6b62 -label.storage.tags=\u30B9\u30C8\u30EC\u30FC\u30B8 \u30BF\u30B0 -label.storage.traffic=\u30B9\u30C8\u30EC\u30FC\u30B8 \u30C8\u30E9\u30D5\u30A3\u30C3\u30AF -label.storage.type=\u30B9\u30C8\u30EC\u30FC\u30B8\u306E\u7A2E\u985E -label.storage=\u30B9\u30C8\u30EC\u30FC\u30B8 -label.subdomain.access=\u30B5\u30D6\u30C9\u30E1\u30A4\u30F3 \u30A2\u30AF\u30BB\u30B9 -label.submitted.by=[\u9001\u4FE1\u30E6\u30FC\u30B6\u30FC\: ] -label.submit=\u9001\u4FE1 -label.succeeded=\u6210\u529F -label.sunday=\u65E5\u66DC\u65E5 -label.super.cidr.for.guest.networks=\u30B2\u30B9\u30C8 \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u30B9\u30FC\u30D1\u30FC CIDR -label.supported.services=\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u308B\u30B5\u30FC\u30D3\u30B9 -label.supported.source.NAT.type=\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u308B\u9001\u4FE1\u5143 NAT \u306E\u7A2E\u985E -label.suspend.project=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u4E00\u6642\u505C\u6B62 -label.system.capacity=\u30B7\u30B9\u30C6\u30E0\u306E\u51E6\u7406\u80FD\u529B -label.system.offering=\u30B7\u30B9\u30C6\u30E0 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0 -label.system.service.offering=\u30B7\u30B9\u30C6\u30E0 \u30B5\u30FC\u30D3\u30B9 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0 -label.system.vms=\u30B7\u30B9\u30C6\u30E0 VM -label.system.vm.type=\u30B7\u30B9\u30C6\u30E0 VM \u306E\u7A2E\u985E -label.system.vm=\u30B7\u30B9\u30C6\u30E0 VM -label.system.wide.capacity=\u30B7\u30B9\u30C6\u30E0\u5168\u4F53\u306E\u51E6\u7406\u80FD\u529B -label.tagged=\u30BF\u30B0\u3042\u308A -label.tags=\u30BF\u30B0 -label.target.iqn=\u30BF\u30FC\u30B2\u30C3\u30C8 IQN -label.task.completed=\u30BF\u30B9\u30AF\u304C\u5B8C\u4E86\u3057\u307E\u3057\u305F -label.template.limits=\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u5236\u9650 -label.template=\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8 -label.TFTP.dir=TFTP \u30C7\u30A3\u30EC\u30AF\u30C8\u30EA -label.theme.default=\u30C7\u30D5\u30A9\u30EB\u30C8 \u30C6\u30FC\u30DE -label.theme.grey=\u30AB\u30B9\u30BF\u30E0 - \u30B0\u30EC\u30FC -label.theme.lightblue=\u30AB\u30B9\u30BF\u30E0 - \u30E9\u30A4\u30C8 \u30D6\u30EB\u30FC -label.thursday=\u6728\u66DC\u65E5 -label.tier.details=\u968E\u5C64\u306E\u8A73\u7D30 -label.tier=\u968E\u5C64 -label.timeout.in.second = \u30BF\u30A4\u30E0\u30A2\u30A6\u30C8 (\u79D2) -label.timeout=\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8 -label.time=\u6642\u523B -label.time.zone=\u30BF\u30A4\u30E0\u30BE\u30FC\u30F3 -label.timezone=\u30BF\u30A4\u30E0\u30BE\u30FC\u30F3 -label.token=\u30C8\u30FC\u30AF\u30F3 -label.total.cpu=CPU \u5408\u8A08 -label.total.CPU=CPU \u5408\u8A08 -label.total.hosts=\u30DB\u30B9\u30C8\u5408\u8A08 -label.total.memory=\u30E1\u30E2\u30EA\u5408\u8A08 -label.total.of.ip=IP \u30A2\u30C9\u30EC\u30B9\u5408\u8A08 -label.total.of.vm=VM \u5408\u8A08 -label.total.storage=\u30B9\u30C8\u30EC\u30FC\u30B8\u5408\u8A08 -label.total.vms=VM \u5408\u8A08 -label.traffic.label=\u30C8\u30E9\u30D5\u30A3\u30C3\u30AF \u30E9\u30D9\u30EB -label.traffic.types=\u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u306E\u7A2E\u985E -label.traffic.type=\u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u306E\u7A2E\u985E -label.tuesday=\u706B\u66DC\u65E5 -label.type.id=\u7A2E\u985E ID -label.type=\u7A2E\u985E -label.unavailable=\u4F7F\u7528\u4E0D\u80FD +label.storage.tags=\u30b9\u30c8\u30ec\u30fc\u30b8 \u30bf\u30b0 +label.storage.traffic=\u30b9\u30c8\u30ec\u30fc\u30b8 \u30c8\u30e9\u30d5\u30a3\u30c3\u30af +label.storage.type=\u30b9\u30c8\u30ec\u30fc\u30b8\u306e\u7a2e\u985e +label.storage=\u30b9\u30c8\u30ec\u30fc\u30b8 +label.subdomain.access=\u30b5\u30d6\u30c9\u30e1\u30a4\u30f3 \u30a2\u30af\u30bb\u30b9 +label.submitted.by=[\u9001\u4fe1\u30e6\u30fc\u30b6\u30fc\: ] +label.submit=\u9001\u4fe1 +label.succeeded=\u6210\u529f +label.sunday=\u65e5\u66dc\u65e5 +label.super.cidr.for.guest.networks=\u30b2\u30b9\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u30b9\u30fc\u30d1\u30fc CIDR +label.supported.services=\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u308b\u30b5\u30fc\u30d3\u30b9 +label.supported.source.NAT.type=\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u308b\u9001\u4fe1\u5143 NAT \u306e\u7a2e\u985e +label.suspend.project=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u4e00\u6642\u505c\u6b62 +label.system.capacity=\u30b7\u30b9\u30c6\u30e0\u306e\u51e6\u7406\u80fd\u529b +label.system.offering=\u30b7\u30b9\u30c6\u30e0 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 +label.system.service.offering=\u30b7\u30b9\u30c6\u30e0 \u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 +label.system.vms=\u30b7\u30b9\u30c6\u30e0 VM +label.system.vm.type=\u30b7\u30b9\u30c6\u30e0 VM \u306e\u7a2e\u985e +label.system.vm=\u30b7\u30b9\u30c6\u30e0 VM +label.system.wide.capacity=\u30b7\u30b9\u30c6\u30e0\u5168\u4f53\u306e\u51e6\u7406\u80fd\u529b +label.tagged=\u30bf\u30b0\u3042\u308a +label.tags=\u30bf\u30b0 +label.target.iqn=\u30bf\u30fc\u30b2\u30c3\u30c8 IQN +label.task.completed=\u30bf\u30b9\u30af\u304c\u5b8c\u4e86\u3057\u307e\u3057\u305f +label.template.limits=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u5236\u9650 +label.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8 +label.TFTP.dir=TFTP \u30c7\u30a3\u30ec\u30af\u30c8\u30ea +label.theme.default=\u30c7\u30d5\u30a9\u30eb\u30c8 \u30c6\u30fc\u30de +label.theme.grey=\u30ab\u30b9\u30bf\u30e0 - \u30b0\u30ec\u30fc +label.theme.lightblue=\u30ab\u30b9\u30bf\u30e0 - \u30e9\u30a4\u30c8 \u30d6\u30eb\u30fc +label.thursday=\u6728\u66dc\u65e5 +label.tier.details=\u968e\u5c64\u306e\u8a73\u7d30 +label.tier=\u968e\u5c64 +label.timeout.in.second = \u30bf\u30a4\u30e0\u30a2\u30a6\u30c8 (\u79d2) +label.timeout=\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8 +label.time=\u6642\u523b +label.time.zone=\u30bf\u30a4\u30e0\u30be\u30fc\u30f3 +label.timezone=\u30bf\u30a4\u30e0\u30be\u30fc\u30f3 +label.token=\u30c8\u30fc\u30af\u30f3 +label.total.cpu=CPU \u5408\u8a08 +label.total.CPU=CPU \u5408\u8a08 +label.total.hosts=\u30db\u30b9\u30c8\u5408\u8a08 +label.total.memory=\u30e1\u30e2\u30ea\u5408\u8a08 +label.total.of.ip=IP \u30a2\u30c9\u30ec\u30b9\u5408\u8a08 +label.total.of.vm=VM \u5408\u8a08 +label.total.storage=\u30b9\u30c8\u30ec\u30fc\u30b8\u5408\u8a08 +label.total.vms=VM \u5408\u8a08 +label.traffic.label=\u30c8\u30e9\u30d5\u30a3\u30c3\u30af \u30e9\u30d9\u30eb +label.traffic.types=\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e\u7a2e\u985e +label.traffic.type=\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e\u7a2e\u985e +label.tuesday=\u706b\u66dc\u65e5 +label.type.id=\u7a2e\u985e ID +label.type=\u7a2e\u985e +label.unavailable=\u4f7f\u7528\u4e0d\u80fd label.unlimited=\u7121\u5236\u9650 -label.untagged=\u30BF\u30B0\u306A\u3057 -label.update.project.resources=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8 \u30EA\u30BD\u30FC\u30B9\u306E\u66F4\u65B0 -label.update.ssl.cert= SSL \u8A3C\u660E\u66F8\u306E\u66F4\u65B0 -label.update.ssl= SSL \u8A3C\u660E\u66F8\u306E\u66F4\u65B0 -label.updating=\u66F4\u65B0\u3057\u3066\u3044\u307E\u3059 -label.upload=\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9 -label.upload.volume=\u30DC\u30EA\u30E5\u30FC\u30E0\u306E\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9 +label.untagged=\u30bf\u30b0\u306a\u3057 +label.update.project.resources=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 \u30ea\u30bd\u30fc\u30b9\u306e\u66f4\u65b0 +label.update.ssl.cert= SSL \u8a3c\u660e\u66f8\u306e\u66f4\u65b0 +label.update.ssl= SSL \u8a3c\u660e\u66f8\u306e\u66f4\u65b0 +label.updating=\u66f4\u65b0\u3057\u3066\u3044\u307e\u3059 +label.upload=\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9 +label.upload.volume=\u30dc\u30ea\u30e5\u30fc\u30e0\u306e\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9 label.url=URL -label.usage.interface=\u4F7F\u7528\u72B6\u6CC1\u6E2C\u5B9A\u30A4\u30F3\u30BF\u30FC\u30D5\u30A7\u30A4\u30B9 -label.used=\u4F7F\u7528\u4E2D -label.username=\u30E6\u30FC\u30B6\u30FC\u540D -label.users=\u30E6\u30FC\u30B6\u30FC -label.user=\u30E6\u30FC\u30B6\u30FC +label.usage.interface=\u4f7f\u7528\u72b6\u6cc1\u6e2c\u5b9a\u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30a4\u30b9 +label.used=\u4f7f\u7528\u4e2d +label.username=\u30e6\u30fc\u30b6\u30fc\u540d +label.users=\u30e6\u30fc\u30b6\u30fc +label.user=\u30e6\u30fc\u30b6\u30fc label.value=\u5024 -label.vcdcname=vCenter DC \u540D -label.vcenter.cluster=vCenter \u30AF\u30E9\u30B9\u30BF\u30FC -label.vcenter.datacenter=vCenter \u30C7\u30FC\u30BF\u30BB\u30F3\u30BF\u30FC -label.vcenter.datastore=vCenter \u30C7\u30FC\u30BF\u30B9\u30C8\u30A2 -label.vcenter.host=vCenter \u30DB\u30B9\u30C8 -label.vcenter.password=vCenter \u30D1\u30B9\u30EF\u30FC\u30C9 -label.vcenter.username=vCenter \u30E6\u30FC\u30B6\u30FC\u540D -label.vcipaddress=vCenter IP \u30A2\u30C9\u30EC\u30B9 -label.version=\u30D0\u30FC\u30B8\u30E7\u30F3 -label.view.all=\u3059\u3079\u3066\u8868\u793A -label.view.console=\u30B3\u30F3\u30BD\u30FC\u30EB\u306E\u8868\u793A -label.viewing=\u8868\u793A\u9805\u76EE\: -label.view.more=\u8A73\u7D30\u8868\u793A -label.view=\u8868\u793A - -label.virtual.appliances=\u4EEE\u60F3\u30A2\u30D7\u30E9\u30A4\u30A2\u30F3\u30B9 -label.virtual.appliance=\u4EEE\u60F3\u30A2\u30D7\u30E9\u30A4\u30A2\u30F3\u30B9 -label.virtual.machines=\u4EEE\u60F3\u30DE\u30B7\u30F3 -label.virtual.network=\u4EEE\u60F3\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF -label.virtual.routers=\u4EEE\u60F3\u30EB\u30FC\u30BF\u30FC -label.virtual.router=\u4EEE\u60F3\u30EB\u30FC\u30BF\u30FC +label.vcdcname=vCenter DC \u540d +label.vcenter.cluster=vCenter \u30af\u30e9\u30b9\u30bf\u30fc +label.vcenter.datacenter=vCenter \u30c7\u30fc\u30bf\u30bb\u30f3\u30bf\u30fc +label.vcenter.datastore=vCenter \u30c7\u30fc\u30bf\u30b9\u30c8\u30a2 +label.vcenter.host=vCenter \u30db\u30b9\u30c8 +label.vcenter.password=vCenter \u30d1\u30b9\u30ef\u30fc\u30c9 +label.vcenter.username=vCenter \u30e6\u30fc\u30b6\u30fc\u540d +label.vcipaddress=vCenter IP \u30a2\u30c9\u30ec\u30b9 +label.version=\u30d0\u30fc\u30b8\u30e7\u30f3 +label.view.all=\u3059\u3079\u3066\u8868\u793a +label.view.console=\u30b3\u30f3\u30bd\u30fc\u30eb\u306e\u8868\u793a +label.viewing=\u8868\u793a\u9805\u76ee\: +label.view.more=\u8a73\u7d30\u8868\u793a +label.view=\u8868\u793a - +label.virtual.appliances=\u4eee\u60f3\u30a2\u30d7\u30e9\u30a4\u30a2\u30f3\u30b9 +label.virtual.appliance=\u4eee\u60f3\u30a2\u30d7\u30e9\u30a4\u30a2\u30f3\u30b9 +label.virtual.machines=\u4eee\u60f3\u30de\u30b7\u30f3 +label.virtual.network=\u4eee\u60f3\u30cd\u30c3\u30c8\u30ef\u30fc\u30af +label.virtual.routers=\u4eee\u60f3\u30eb\u30fc\u30bf\u30fc +label.virtual.router=\u4eee\u60f3\u30eb\u30fc\u30bf\u30fc label.vlan.id=VLAN ID -label.vlan.range=VLAN \u306E\u7BC4\u56F2 +label.vlan.range=VLAN \u306e\u7bc4\u56f2 label.vlan=VLAN -label.vm.add=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u8FFD\u52A0 +label.vm.add=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u8ffd\u52a0 label.vm.destroy=\u7834\u68c4 -label.vm.display.name=VM \u8868\u793A\u540D -label.VMFS.datastore=VMFS \u30C7\u30FC\u30BF\u30B9\u30C8\u30A2 +label.vm.display.name=VM \u8868\u793a\u540d +label.VMFS.datastore=VMFS \u30c7\u30fc\u30bf\u30b9\u30c8\u30a2 label.vmfs=VMFS -label.vm.name=VM \u540D +label.vm.name=VM \u540d label.vm.reboot=\u518d\u8d77\u52d5 -label.VMs.in.tier=\u968E\u5C64\u5185\u306E VM -label.vmsnapshot.type=\u7A2E\u985E -label.vm.start=\u8D77\u52D5 -label.vm.state=VM \u306E\u72B6\u614B +label.VMs.in.tier=\u968e\u5c64\u5185\u306e VM +label.vmsnapshot.type=\u7a2e\u985e +label.vm.start=\u8d77\u52d5 +label.vm.state=VM \u306e\u72b6\u614b label.vm.stop=\u505c\u6b62 label.vms=VM -label.vmware.traffic.label=VMware \u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u306E\u30E9\u30D9\u30EB -label.volgroup=\u30DC\u30EA\u30E5\u30FC\u30E0 \u30B0\u30EB\u30FC\u30D7 -label.volume.limits=\u30DC\u30EA\u30E5\u30FC\u30E0\u5236\u9650 -label.volume.name=\u30DC\u30EA\u30E5\u30FC\u30E0\u540D -label.volumes=\u30DC\u30EA\u30E5\u30FC\u30E0 -label.volume=\u30DC\u30EA\u30E5\u30FC\u30E0 +label.vmware.traffic.label=VMware \u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e\u30e9\u30d9\u30eb +label.volgroup=\u30dc\u30ea\u30e5\u30fc\u30e0 \u30b0\u30eb\u30fc\u30d7 +label.volume.limits=\u30dc\u30ea\u30e5\u30fc\u30e0\u5236\u9650 +label.volume.name=\u30dc\u30ea\u30e5\u30fc\u30e0\u540d +label.volumes=\u30dc\u30ea\u30e5\u30fc\u30e0 +label.volume=\u30dc\u30ea\u30e5\u30fc\u30e0 label.vpc.id=VPC ID -label.VPC.router.details=VPC \u30EB\u30FC\u30BF\u30FC\u306E\u8A73\u7D30 +label.VPC.router.details=VPC \u30eb\u30fc\u30bf\u30fc\u306e\u8a73\u7d30 label.vpc=VPC -label.VPN.connection=VPN \u63A5\u7D9A -label.vpn.customer.gateway=VPN \u30AB\u30B9\u30BF\u30DE\u30FC \u30B2\u30FC\u30C8\u30A6\u30A7\u30A4 -label.VPN.customer.gateway=VPN \u30AB\u30B9\u30BF\u30DE\u30FC \u30B2\u30FC\u30C8\u30A6\u30A7\u30A4 -label.VPN.gateway=VPN \u30B2\u30FC\u30C8\u30A6\u30A7\u30A4 +label.VPN.connection=VPN \u63a5\u7d9a +label.vpn.customer.gateway=VPN \u30ab\u30b9\u30bf\u30de\u30fc \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4 +label.VPN.customer.gateway=VPN \u30ab\u30b9\u30bf\u30de\u30fc \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4 +label.VPN.gateway=VPN \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4 label.vpn=VPN -label.vsmctrlvlanid=\u30B3\u30F3\u30C8\u30ED\u30FC\u30EB VLAN ID -label.vsmpktvlanid=\u30D1\u30B1\u30C3\u30C8 VLAN ID -label.vsmstoragevlanid=\u30B9\u30C8\u30EC\u30FC\u30B8 VLAN ID -label.vsphere.managed=vSphere \u306B\u3088\u308B\u7BA1\u7406 -label.waiting=\u5F85\u6A5F\u3057\u3066\u3044\u307E\u3059 -label.warn=\u8B66\u544A -label.wednesday=\u6C34\u66DC\u65E5 -label.weekly=\u6BCE\u9031 -label.welcome.cloud.console=\u7BA1\u7406\u30B3\u30F3\u30BD\u30FC\u30EB\u3078\u3088\u3046\u3053\u305D -label.welcome=\u3088\u3046\u3053\u305D -label.what.is.cloudstack=CloudStack&\#8482; \u306B\u3064\u3044\u3066 -label.xen.traffic.label=XenServer \u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u306E\u30E9\u30D9\u30EB -label.yes=\u306F\u3044 -label.zone.details=\u30BE\u30FC\u30F3\u306E\u8A73\u7D30 -label.zone.id=\u30BE\u30FC\u30F3 ID -label.zone.name=\u30BE\u30FC\u30F3\u540D -label.zone.step.1.title=\u624B\u9806 1. \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u9078\u629E -label.zone.step.2.title=\u624B\u9806 2. \u30BE\u30FC\u30F3\u306E\u8FFD\u52A0 -label.zone.step.3.title=\u624B\u9806 3. \u30DD\u30C3\u30C9\u306E\u8FFD\u52A0 -label.zone.step.4.title=\u624B\u9806 4. IP \u30A2\u30C9\u30EC\u30B9\u7BC4\u56F2\u306E\u8FFD\u52A0 -label.zones=\u30BE\u30FC\u30F3 -label.zone.type=\u30BE\u30FC\u30F3\u306E\u7A2E\u985E -label.zone=\u30BE\u30FC\u30F3 -label.zone.wide=\u30BE\u30FC\u30F3\u5168\u4F53 +label.vsmctrlvlanid=\u30b3\u30f3\u30c8\u30ed\u30fc\u30eb VLAN ID +label.vsmpktvlanid=\u30d1\u30b1\u30c3\u30c8 VLAN ID +label.vsmstoragevlanid=\u30b9\u30c8\u30ec\u30fc\u30b8 VLAN ID +label.vsphere.managed=vSphere \u306b\u3088\u308b\u7ba1\u7406 +label.waiting=\u5f85\u6a5f\u3057\u3066\u3044\u307e\u3059 +label.warn=\u8b66\u544a +label.wednesday=\u6c34\u66dc\u65e5 +label.weekly=\u6bce\u9031 +label.welcome.cloud.console=\u7ba1\u7406\u30b3\u30f3\u30bd\u30fc\u30eb\u3078\u3088\u3046\u3053\u305d +label.welcome=\u3088\u3046\u3053\u305d +label.what.is.cloudstack=CloudStack&\#8482; \u306b\u3064\u3044\u3066 +label.xen.traffic.label=XenServer \u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e\u30e9\u30d9\u30eb +label.yes=\u306f\u3044 +label.zone.details=\u30be\u30fc\u30f3\u306e\u8a73\u7d30 +label.zone.id=\u30be\u30fc\u30f3 ID +label.zone.name=\u30be\u30fc\u30f3\u540d +label.zone.step.1.title=\u624b\u9806 1. \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u9078\u629e +label.zone.step.2.title=\u624b\u9806 2. \u30be\u30fc\u30f3\u306e\u8ffd\u52a0 +label.zone.step.3.title=\u624b\u9806 3. \u30dd\u30c3\u30c9\u306e\u8ffd\u52a0 +label.zone.step.4.title=\u624b\u9806 4. IP \u30a2\u30c9\u30ec\u30b9\u7bc4\u56f2\u306e\u8ffd\u52a0 +label.zones=\u30be\u30fc\u30f3 +label.zone.type=\u30be\u30fc\u30f3\u306e\u7a2e\u985e +label.zone=\u30be\u30fc\u30f3 +label.zone.wide=\u30be\u30fc\u30f3\u5168\u4f53 label.zoneWizard.trafficType.guest=\u30b2\u30b9\u30c8\: \u30a8\u30f3\u30c9\u30e6\u30fc\u30b6\u30fc\u4eee\u60f3\u30de\u30b7\u30f3\u9593\u306e\u30c8\u30e9\u30d5\u30a3\u30c3\u30af -label.zoneWizard.trafficType.management=\u7ba1\u7406\: \u30db\u30b9\u30c8\u3084\u30b7\u30b9\u30c6\u30e0VM\u306a\u3069\u3001\u7ba1\u7406\u30b5\u30fc\u30d0\u30fc\u3068\u901a\u4fe1\u3059\u308b\u3042\u3089\u3086\u308b\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u3092\u542b\u3081\u305f\u3001CloudStack\u5185\u90e8\u306e\u30ea\u30bd\u30fc\u30b9\u9593\u306e\u30c8\u30e9\u30d5\u30a3\u30c3\u30af label.zoneWizard.trafficType.public=\u30d1\u30d6\u30ea\u30c3\u30af\: \u30a4\u30f3\u30bf\u30fc\u30cd\u30c3\u30c8\u3068\u30af\u30e9\u30a6\u30c9\u5185\u306e\u4eee\u60f3\u30de\u30b7\u30f3\u306e\u9593\u306e\u30c8\u30e9\u30d5\u30a3\u30c3\u30af label.zoneWizard.trafficType.storage=\u30b9\u30c8\u30ec\u30fc\u30b8\: VM\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3068\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u306e\u3088\u3046\u306a\u3001\u30d7\u30e9\u30a4\u30de\u30ea\u3068\u30bb\u30ab\u30f3\u30c0\u30ea\u306e\u30b9\u30c8\u30ec\u30fc\u30b8\u30b5\u30fc\u30d0\u30fc\u9593\u306e\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u3002 -managed.state=\u7BA1\u7406\u5BFE\u8C61\u72B6\u614B -message.acquire.new.ip=\u3053\u306E\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u65B0\u3057\u3044 IP \u30A2\u30C9\u30EC\u30B9\u3092\u53D6\u5F97\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? +managed.state=\u7ba1\u7406\u5bfe\u8c61\u72b6\u614b +message.acquire.new.ip=\u3053\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u65b0\u3057\u3044 IP \u30a2\u30c9\u30ec\u30b9\u3092\u53d6\u5f97\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.acquire.new.ip.vpc=VPC\u306e\u65b0\u3057\u3044IP\u3092\u53d6\u5f97\u3059\u308b\u3053\u3068\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002 -message.acquire.public.ip=\u65B0\u3057\u3044 IP \u30A2\u30C9\u30EC\u30B9\u3092\u53D6\u5F97\u3059\u308B\u30BE\u30FC\u30F3\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.action.cancel.maintenance.mode=\u3053\u306E\u4FDD\u5B88\u3092\u30AD\u30E3\u30F3\u30BB\u30EB\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.cancel.maintenance=\u30DB\u30B9\u30C8\u306E\u4FDD\u5B88\u306F\u6B63\u5E38\u306B\u30AD\u30E3\u30F3\u30BB\u30EB\u3055\u308C\u307E\u3057\u305F\u3002\u3053\u306E\u51E6\u7406\u306B\u306F\u6570\u5206\u304B\u304B\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002 -message.action.change.service.warning.for.instance=\u73FE\u5728\u306E\u30B5\u30FC\u30D3\u30B9 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u3092\u5909\u66F4\u3059\u308B\u524D\u306B\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u505C\u6B62\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -message.action.change.service.warning.for.router=\u73FE\u5728\u306E\u30B5\u30FC\u30D3\u30B9 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u3092\u5909\u66F4\u3059\u308B\u524D\u306B\u30EB\u30FC\u30BF\u30FC\u3092\u505C\u6B62\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -message.action.delete.cluster=\u3053\u306E\u30AF\u30E9\u30B9\u30BF\u30FC\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.delete.disk.offering=\u3053\u306E\u30C7\u30A3\u30B9\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.delete.domain=\u3053\u306E\u30C9\u30E1\u30A4\u30F3\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.delete.external.firewall=\u3053\u306E\u5916\u90E8\u30D5\u30A1\u30A4\u30A2\u30A6\u30A9\u30FC\u30EB\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? \u8B66\u544A\: \u540C\u3058\u5916\u90E8\u30D5\u30A1\u30A4\u30A2\u30A6\u30A9\u30FC\u30EB\u3092\u518D\u5EA6\u8FFD\u52A0\u3059\u308B\u4E88\u5B9A\u3067\u3042\u308B\u5834\u5408\u306F\u3001\u30C7\u30D0\u30A4\u30B9\u306E\u4F7F\u7528\u72B6\u6CC1\u30C7\u30FC\u30BF\u3092\u30EA\u30BB\u30C3\u30C8\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -message.action.delete.external.load.balancer=\u3053\u306E\u5916\u90E8\u8CA0\u8377\u5206\u6563\u88C5\u7F6E\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? \u8B66\u544A\: \u540C\u3058\u5916\u90E8\u8CA0\u8377\u5206\u6563\u88C5\u7F6E\u3092\u518D\u5EA6\u8FFD\u52A0\u3059\u308B\u4E88\u5B9A\u3067\u3042\u308B\u5834\u5408\u306F\u3001\u30C7\u30D0\u30A4\u30B9\u306E\u4F7F\u7528\u72B6\u6CC1\u30C7\u30FC\u30BF\u3092\u30EA\u30BB\u30C3\u30C8\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -message.action.delete.ingress.rule=\u3053\u306E\u53D7\u4FE1\u898F\u5247\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.delete.ISO.for.all.zones=\u305D\u306E ISO \u306F\u3059\u3079\u3066\u306E\u30BE\u30FC\u30F3\u3067\u4F7F\u7528\u3055\u308C\u3066\u3044\u307E\u3059\u3002\u3059\u3079\u3066\u306E\u30BE\u30FC\u30F3\u304B\u3089\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.delete.ISO=\u3053\u306E ISO \u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.delete.network=\u3053\u306E\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.delete.nexusVswitch=\u3053\u306E Nexus 1000V \u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.delete.physical.network=\u3053\u306E\u7269\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.delete.pod=\u3053\u306E\u30DD\u30C3\u30C9\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.delete.primary.storage=\u3053\u306E\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.delete.secondary.storage=\u3053\u306E\u30BB\u30AB\u30F3\u30C0\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.delete.security.group=\u3053\u306E\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3 \u30B0\u30EB\u30FC\u30D7\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.delete.service.offering=\u3053\u306E\u30B5\u30FC\u30D3\u30B9 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.delete.snapshot=\u3053\u306E\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.delete.system.service.offering=\u3053\u306E\u30B7\u30B9\u30C6\u30E0 \u30B5\u30FC\u30D3\u30B9 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.delete.template.for.all.zones=\u305D\u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306F\u3059\u3079\u3066\u306E\u30BE\u30FC\u30F3\u3067\u4F7F\u7528\u3055\u308C\u3066\u3044\u307E\u3059\u3002\u3059\u3079\u3066\u306E\u30BE\u30FC\u30F3\u304B\u3089\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.delete.template=\u3053\u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.delete.volume=\u3053\u306E\u30DC\u30EA\u30E5\u30FC\u30E0\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.delete.zone=\u3053\u306E\u30BE\u30FC\u30F3\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.destroy.instance=\u3053\u306E\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u7834\u68C4\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.destroy.systemvm=\u3053\u306E\u30B7\u30B9\u30C6\u30E0 VM \u3092\u7834\u68C4\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.disable.cluster=\u3053\u306E\u30AF\u30E9\u30B9\u30BF\u30FC\u3092\u7121\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.disable.nexusVswitch=\u3053\u306E Nexus 1000V \u3092\u7121\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.disable.physical.network=\u3053\u306E\u7269\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u7121\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.disable.pod=\u3053\u306E\u30DD\u30C3\u30C9\u3092\u7121\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.disable.static.NAT=\u9759\u7684 NAT \u3092\u7121\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.disable.zone=\u3053\u306E\u30BE\u30FC\u30F3\u3092\u7121\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.download.iso=\u3053\u306E ISO \u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.download.template=\u3053\u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.enable.cluster=\u3053\u306E\u30AF\u30E9\u30B9\u30BF\u30FC\u3092\u6709\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.enable.maintenance=\u30DB\u30B9\u30C8\u3092\u4FDD\u5B88\u3059\u308B\u6E96\u5099\u304C\u3067\u304D\u307E\u3057\u305F\u3002\u3053\u306E\u30DB\u30B9\u30C8\u4E0A\u306E VM \u6570\u306B\u3088\u3063\u3066\u306F\u3001\u3053\u306E\u51E6\u7406\u306B\u306F\u6570\u5206\u4EE5\u4E0A\u304B\u304B\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002 -message.action.enable.nexusVswitch=\u3053\u306E Nexus 1000V \u3092\u6709\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.enable.physical.network=\u3053\u306E\u7269\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u6709\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.enable.pod=\u3053\u306E\u30DD\u30C3\u30C9\u3092\u6709\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.enable.zone=\u3053\u306E\u30BE\u30FC\u30F3\u3092\u6709\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.force.reconnect=\u30DB\u30B9\u30C8\u306F\u5F37\u5236\u7684\u306B\u518D\u63A5\u7D9A\u3057\u307E\u3057\u305F\u3002\u3053\u306E\u51E6\u7406\u306B\u306F\u6570\u5206\u304B\u304B\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002 -message.action.host.enable.maintenance.mode=\u4FDD\u5B88\u30E2\u30FC\u30C9\u3092\u6709\u52B9\u306B\u3059\u308B\u3068\u3001\u3053\u306E\u30DB\u30B9\u30C8\u3067\u5B9F\u884C\u4E2D\u306E\u3059\u3079\u3066\u306E\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u304C\u307B\u304B\u306E\u4F7F\u7528\u3067\u304D\u308B\u30DB\u30B9\u30C8\u306B\u30E9\u30A4\u30D6 \u30DE\u30A4\u30B0\u30EC\u30FC\u30B7\u30E7\u30F3\u3055\u308C\u307E\u3059\u3002 +message.acquire.public.ip=\u65b0\u3057\u3044 IP \u30a2\u30c9\u30ec\u30b9\u3092\u53d6\u5f97\u3059\u308b\u30be\u30fc\u30f3\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.action.cancel.maintenance.mode=\u3053\u306e\u4fdd\u5b88\u3092\u30ad\u30e3\u30f3\u30bb\u30eb\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.cancel.maintenance=\u30db\u30b9\u30c8\u306e\u4fdd\u5b88\u306f\u6b63\u5e38\u306b\u30ad\u30e3\u30f3\u30bb\u30eb\u3055\u308c\u307e\u3057\u305f\u3002\u3053\u306e\u51e6\u7406\u306b\u306f\u6570\u5206\u304b\u304b\u308b\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059\u3002 +message.action.change.service.warning.for.instance=\u73fe\u5728\u306e\u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u5909\u66f4\u3059\u308b\u524d\u306b\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u505c\u6b62\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +message.action.change.service.warning.for.router=\u73fe\u5728\u306e\u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u5909\u66f4\u3059\u308b\u524d\u306b\u30eb\u30fc\u30bf\u30fc\u3092\u505c\u6b62\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +message.action.delete.cluster=\u3053\u306e\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.delete.disk.offering=\u3053\u306e\u30c7\u30a3\u30b9\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.delete.domain=\u3053\u306e\u30c9\u30e1\u30a4\u30f3\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.delete.external.firewall=\u3053\u306e\u5916\u90e8\u30d5\u30a1\u30a4\u30a2\u30a6\u30a9\u30fc\u30eb\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? \u8b66\u544a\: \u540c\u3058\u5916\u90e8\u30d5\u30a1\u30a4\u30a2\u30a6\u30a9\u30fc\u30eb\u3092\u518d\u5ea6\u8ffd\u52a0\u3059\u308b\u4e88\u5b9a\u3067\u3042\u308b\u5834\u5408\u306f\u3001\u30c7\u30d0\u30a4\u30b9\u306e\u4f7f\u7528\u72b6\u6cc1\u30c7\u30fc\u30bf\u3092\u30ea\u30bb\u30c3\u30c8\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +message.action.delete.external.load.balancer=\u3053\u306e\u5916\u90e8\u8ca0\u8377\u5206\u6563\u88c5\u7f6e\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? \u8b66\u544a\: \u540c\u3058\u5916\u90e8\u8ca0\u8377\u5206\u6563\u88c5\u7f6e\u3092\u518d\u5ea6\u8ffd\u52a0\u3059\u308b\u4e88\u5b9a\u3067\u3042\u308b\u5834\u5408\u306f\u3001\u30c7\u30d0\u30a4\u30b9\u306e\u4f7f\u7528\u72b6\u6cc1\u30c7\u30fc\u30bf\u3092\u30ea\u30bb\u30c3\u30c8\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +message.action.delete.ingress.rule=\u3053\u306e\u53d7\u4fe1\u898f\u5247\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.delete.ISO.for.all.zones=\u305d\u306e ISO \u306f\u3059\u3079\u3066\u306e\u30be\u30fc\u30f3\u3067\u4f7f\u7528\u3055\u308c\u3066\u3044\u307e\u3059\u3002\u3059\u3079\u3066\u306e\u30be\u30fc\u30f3\u304b\u3089\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.delete.ISO=\u3053\u306e ISO \u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.delete.network=\u3053\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.delete.nexusVswitch=\u3053\u306e Nexus 1000V \u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.delete.physical.network=\u3053\u306e\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.delete.pod=\u3053\u306e\u30dd\u30c3\u30c9\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.delete.primary.storage=\u3053\u306e\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.delete.secondary.storage=\u3053\u306e\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.delete.security.group=\u3053\u306e\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.delete.service.offering=\u3053\u306e\u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.delete.snapshot=\u3053\u306e\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.delete.system.service.offering=\u3053\u306e\u30b7\u30b9\u30c6\u30e0 \u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.delete.template.for.all.zones=\u305d\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306f\u3059\u3079\u3066\u306e\u30be\u30fc\u30f3\u3067\u4f7f\u7528\u3055\u308c\u3066\u3044\u307e\u3059\u3002\u3059\u3079\u3066\u306e\u30be\u30fc\u30f3\u304b\u3089\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.delete.template=\u3053\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.delete.volume=\u3053\u306e\u30dc\u30ea\u30e5\u30fc\u30e0\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.delete.zone=\u3053\u306e\u30be\u30fc\u30f3\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.destroy.instance=\u3053\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u7834\u68c4\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.destroy.systemvm=\u3053\u306e\u30b7\u30b9\u30c6\u30e0 VM \u3092\u7834\u68c4\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.disable.cluster=\u3053\u306e\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u7121\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.disable.nexusVswitch=\u3053\u306e Nexus 1000V \u3092\u7121\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.disable.physical.network=\u3053\u306e\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u7121\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.disable.pod=\u3053\u306e\u30dd\u30c3\u30c9\u3092\u7121\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.disable.static.NAT=\u9759\u7684 NAT \u3092\u7121\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.disable.zone=\u3053\u306e\u30be\u30fc\u30f3\u3092\u7121\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.download.iso=\u3053\u306e ISO \u3092\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.download.template=\u3053\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.enable.cluster=\u3053\u306e\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.enable.maintenance=\u30db\u30b9\u30c8\u3092\u4fdd\u5b88\u3059\u308b\u6e96\u5099\u304c\u3067\u304d\u307e\u3057\u305f\u3002\u3053\u306e\u30db\u30b9\u30c8\u4e0a\u306e VM \u6570\u306b\u3088\u3063\u3066\u306f\u3001\u3053\u306e\u51e6\u7406\u306b\u306f\u6570\u5206\u4ee5\u4e0a\u304b\u304b\u308b\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059\u3002 +message.action.enable.nexusVswitch=\u3053\u306e Nexus 1000V \u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.enable.physical.network=\u3053\u306e\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.enable.pod=\u3053\u306e\u30dd\u30c3\u30c9\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.enable.zone=\u3053\u306e\u30be\u30fc\u30f3\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.force.reconnect=\u30db\u30b9\u30c8\u306f\u5f37\u5236\u7684\u306b\u518d\u63a5\u7d9a\u3057\u307e\u3057\u305f\u3002\u3053\u306e\u51e6\u7406\u306b\u306f\u6570\u5206\u304b\u304b\u308b\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059\u3002 +message.action.host.enable.maintenance.mode=\u4fdd\u5b88\u30e2\u30fc\u30c9\u3092\u6709\u52b9\u306b\u3059\u308b\u3068\u3001\u3053\u306e\u30db\u30b9\u30c8\u3067\u5b9f\u884c\u4e2d\u306e\u3059\u3079\u3066\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u304c\u307b\u304b\u306e\u4f7f\u7528\u3067\u304d\u308b\u30db\u30b9\u30c8\u306b\u30e9\u30a4\u30d6 \u30de\u30a4\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u3055\u308c\u307e\u3059\u3002 message.action.instance.reset.password=\u00e3\u0081\u0093\u00e3\u0081\u00ae\u00e4\u00bb\u00ae\u00e6\u0083\u00b3\u00e3\u0083\u009e\u00e3\u0082\u00b7\u00e3\u0083\u00b3\u00e3\u0081\u00ae\u00e3\u0083\u00ab\u00e3\u0083\u00bc\u00e3\u0083\u0088\u00e3\u0083\u0091\u00e3\u0082\u00b9\u00e3\u0083\u00af\u00e3\u0083\u00bc\u00e3\u0083\u0089\u00e3\u0082\u0092\u00e5\u00a4\u0089\u00e6\u009b\u00b4\u00e3\u0081\u0097\u00e3\u0081\u00a6\u00e3\u0082\u0082\u00e3\u0082\u0088\u00e3\u0082\u008d\u00e3\u0081\u0097\u00e3\u0081\u0084\u00e3\u0081\u00a7\u00e3\u0081\u0099\u00e3\u0081\u008b? -message.action.manage.cluster=\u30AF\u30E9\u30B9\u30BF\u30FC\u3092\u7BA1\u7406\u5BFE\u8C61\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.primarystorage.enable.maintenance.mode=\u8B66\u544A\: \u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u3092\u4FDD\u5B88\u30E2\u30FC\u30C9\u306B\u3059\u308B\u3068\u3001\u305D\u306E\u30B9\u30C8\u30EC\u30FC\u30B8\u4E0A\u306E\u30DC\u30EA\u30E5\u30FC\u30E0\u3092\u4F7F\u7528\u3059\u308B\u3059\u3079\u3066\u306E VM \u304C\u505C\u6B62\u3057\u307E\u3059\u3002\u7D9A\u884C\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.reboot.instance=\u3053\u306E\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u518D\u8D77\u52D5\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.reboot.router=\u3053\u306E\u4EEE\u60F3\u30EB\u30FC\u30BF\u30FC\u3067\u63D0\u4F9B\u3059\u308B\u3059\u3079\u3066\u306E\u30B5\u30FC\u30D3\u30B9\u304C\u4E2D\u65AD\u3055\u308C\u307E\u3059\u3002\u3053\u306E\u30EB\u30FC\u30BF\u30FC\u3092\u518D\u8D77\u52D5\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.reboot.systemvm=\u3053\u306E\u30B7\u30B9\u30C6\u30E0 VM \u3092\u518D\u8D77\u52D5\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.release.ip=\u3053\u306E IP \u30A2\u30C9\u30EC\u30B9\u3092\u89E3\u653E\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.remove.host=\u3053\u306E\u30DB\u30B9\u30C8\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.reset.password.off=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306F\u73FE\u5728\u3053\u306E\u6A5F\u80FD\u3092\u30B5\u30DD\u30FC\u30C8\u3057\u3066\u3044\u307E\u305B\u3093\u3002 -message.action.reset.password.warning=\u73FE\u5728\u306E\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u5909\u66F4\u3059\u308B\u524D\u306B\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u505C\u6B62\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -message.action.restore.instance=\u3053\u306E\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u5FA9\u5143\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.start.instance=\u3053\u306E\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u8D77\u52D5\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.start.router=\u3053\u306E\u30EB\u30FC\u30BF\u30FC\u3092\u8D77\u52D5\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.start.systemvm=\u3053\u306E\u30B7\u30B9\u30C6\u30E0 VM \u3092\u8D77\u52D5\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.stop.instance=\u3053\u306E\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u505C\u6B62\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.stop.router=\u3053\u306E\u4EEE\u60F3\u30EB\u30FC\u30BF\u30FC\u3067\u63D0\u4F9B\u3059\u308B\u3059\u3079\u3066\u306E\u30B5\u30FC\u30D3\u30B9\u304C\u4E2D\u65AD\u3055\u308C\u307E\u3059\u3002\u3053\u306E\u30EB\u30FC\u30BF\u30FC\u3092\u505C\u6B62\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.stop.systemvm=\u3053\u306E\u30B7\u30B9\u30C6\u30E0 VM \u3092\u505C\u6B62\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.take.snapshot=\u3053\u306E\u30DC\u30EA\u30E5\u30FC\u30E0\u306E\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u3092\u4F5C\u6210\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.action.unmanage.cluster=\u30AF\u30E9\u30B9\u30BF\u30FC\u3092\u975E\u7BA1\u7406\u5BFE\u8C61\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.activate.project=\u3053\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u30A2\u30AF\u30C6\u30A3\u30D6\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.add.cluster=\u30BE\u30FC\u30F3 \u306E\u30DD\u30C3\u30C9 \u306B\u30CF\u30A4\u30D1\u30FC\u30D0\u30A4\u30B6\u30FC\u3067\u7BA1\u7406\u3055\u308C\u308B\u30AF\u30E9\u30B9\u30BF\u30FC\u3092\u8FFD\u52A0\u3057\u307E\u3059 -message.add.cluster.zone=\u30BE\u30FC\u30F3 \u306B\u30CF\u30A4\u30D1\u30FC\u30D0\u30A4\u30B6\u30FC\u3067\u7BA1\u7406\u3055\u308C\u308B\u30AF\u30E9\u30B9\u30BF\u30FC\u3092\u8FFD\u52A0\u3057\u307E\u3059 -message.add.disk.offering=\u65B0\u3057\u3044\u30C7\u30A3\u30B9\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u3092\u8FFD\u52A0\u3059\u308B\u305F\u3081\u306B\u3001\u6B21\u306E\u30D1\u30E9\u30E1\u30FC\u30BF\u30FC\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.add.domain=\u3053\u306E\u30C9\u30E1\u30A4\u30F3\u306B\u4F5C\u6210\u3059\u308B\u30B5\u30D6\u30C9\u30E1\u30A4\u30F3\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.add.firewall=\u30BE\u30FC\u30F3\u306B\u30D5\u30A1\u30A4\u30A2\u30A6\u30A9\u30FC\u30EB\u3092\u8FFD\u52A0\u3057\u307E\u3059 -message.add.guest.network=\u30B2\u30B9\u30C8 \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u8FFD\u52A0\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.add.host=\u65B0\u3057\u3044\u30DB\u30B9\u30C8\u3092\u8FFD\u52A0\u3059\u308B\u305F\u3081\u306B\u3001\u6B21\u306E\u30D1\u30E9\u30E1\u30FC\u30BF\u30FC\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.adding.host=\u30DB\u30B9\u30C8\u3092\u8FFD\u52A0\u3057\u3066\u3044\u307E\u3059 -message.adding.Netscaler.device=Netscaler \u30C7\u30D0\u30A4\u30B9\u3092\u8FFD\u52A0\u3057\u3066\u3044\u307E\u3059 -message.adding.Netscaler.provider=Netscaler \u30D7\u30ED\u30D0\u30A4\u30C0\u30FC\u3092\u8FFD\u52A0\u3057\u3066\u3044\u307E\u3059 -message.add.ip.range.direct.network=\u30BE\u30FC\u30F3 \u306E\u76F4\u63A5\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u306B IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2\u3092\u8FFD\u52A0\u3057\u307E\u3059 -message.add.ip.range.to.pod=

\u30DD\u30C3\u30C9 \u306B IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2\u3092\u8FFD\u52A0\u3057\u307E\u3059

-message.add.ip.range=\u30BE\u30FC\u30F3\u306E\u30D1\u30D6\u30EA\u30C3\u30AF \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306B IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2\u3092\u8FFD\u52A0\u3057\u307E\u3059 -message.additional.networks.desc=\u4EEE\u60F3\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u304C\u63A5\u7D9A\u3059\u308B\u8FFD\u52A0\u306E\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.add.load.balancer=\u30BE\u30FC\u30F3\u306B\u8CA0\u8377\u5206\u6563\u88C5\u7F6E\u3092\u8FFD\u52A0\u3057\u307E\u3059 -message.add.load.balancer.under.ip=\u8CA0\u8377\u5206\u6563\u898F\u5247\u304C\u6B21\u306E IP \u30A2\u30C9\u30EC\u30B9\u306B\u5BFE\u3057\u3066\u8FFD\u52A0\u3055\u308C\u307E\u3057\u305F\: -message.add.network=\u30BE\u30FC\u30F3 \u306B\u65B0\u3057\u3044\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u8FFD\u52A0\u3057\u307E\u3059 -message.add.new.gateway.to.vpc=\u3053\u306E VPC \u306B\u65B0\u3057\u3044\u30B2\u30FC\u30C8\u30A6\u30A7\u30A4\u3092\u8FFD\u52A0\u3059\u308B\u305F\u3081\u306E\u60C5\u5831\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.add.pod.during.zone.creation=\u5404\u30BE\u30FC\u30F3\u306B\u306F 1 \u3064\u4EE5\u4E0A\u306E\u30DD\u30C3\u30C9\u304C\u5FC5\u8981\u3067\u3059\u3002\u4ECA\u3053\u3053\u3067\u6700\u521D\u306E\u30DD\u30C3\u30C9\u3092\u8FFD\u52A0\u3057\u307E\u3059\u3002\u30DD\u30C3\u30C9\u306F\u30DB\u30B9\u30C8\u3068\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8 \u30B5\u30FC\u30D0\u30FC\u304B\u3089\u69CB\u6210\u3055\u308C\u307E\u3059\u304C\u3001\u3053\u308C\u3089\u306F\u5F8C\u306E\u624B\u9806\u3067\u8FFD\u52A0\u3057\u307E\u3059\u3002\u6700\u521D\u306B\u3001CloudStack \u306E\u5185\u90E8\u7BA1\u7406\u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u306E\u305F\u3081\u306B IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2\u3092\u4E88\u7D04\u3057\u307E\u3059\u3002IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2\u306F\u3001\u30AF\u30E9\u30A6\u30C9\u5185\u306E\u5404\u30BE\u30FC\u30F3\u3067\u91CD\u8907\u3057\u306A\u3044\u3088\u3046\u306B\u4E88\u7D04\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -message.add.pod=\u30BE\u30FC\u30F3 \u306B\u65B0\u3057\u3044\u30DD\u30C3\u30C9\u3092\u8FFD\u52A0\u3057\u307E\u3059 -message.add.primary.storage=\u30BE\u30FC\u30F3 \u306E\u30DD\u30C3\u30C9 \u306B\u65B0\u3057\u3044\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u3092\u8FFD\u52A0\u3057\u307E\u3059 -message.add.primary=\u65B0\u3057\u3044\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u3092\u8FFD\u52A0\u3059\u308B\u305F\u3081\u306B\u3001\u6B21\u306E\u30D1\u30E9\u30E1\u30FC\u30BF\u30FC\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.add.secondary.storage=\u30BE\u30FC\u30F3 \u306B\u65B0\u3057\u3044\u30B9\u30C8\u30EC\u30FC\u30B8\u3092\u8FFD\u52A0\u3057\u307E\u3059 -message.add.service.offering=\u65B0\u3057\u3044\u30B3\u30F3\u30D4\u30E5\u30FC\u30C6\u30A3\u30F3\u30B0 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u3092\u8FFD\u52A0\u3059\u308B\u305F\u3081\u306B\u3001\u6B21\u306E\u30C7\u30FC\u30BF\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.add.system.service.offering=\u65B0\u3057\u3044\u30B7\u30B9\u30C6\u30E0 \u30B5\u30FC\u30D3\u30B9 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u3092\u8FFD\u52A0\u3059\u308B\u305F\u3081\u306B\u3001\u6B21\u306E\u30C7\u30FC\u30BF\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.add.template=\u65B0\u3057\u3044\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3092\u4F5C\u6210\u3059\u308B\u305F\u3081\u306B\u3001\u6B21\u306E\u30C7\u30FC\u30BF\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.add.volume=\u65B0\u3057\u3044\u30DC\u30EA\u30E5\u30FC\u30E0\u3092\u8FFD\u52A0\u3059\u308B\u305F\u3081\u306B\u3001\u6B21\u306E\u30C7\u30FC\u30BF\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.add.VPN.gateway=VPN \u30B2\u30FC\u30C8\u30A6\u30A7\u30A4\u3092\u8FFD\u52A0\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.advanced.mode.desc=VLAN \u30B5\u30DD\u30FC\u30C8\u3092\u6709\u52B9\u306B\u3059\u308B\u5834\u5408\u306F\u3001\u3053\u306E\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30E2\u30C7\u30EB\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u3053\u306E\u30E2\u30C7\u30EB\u3067\u306F\u6700\u3082\u67D4\u8EDF\u306B\u30AB\u30B9\u30BF\u30E0 \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u3092\u63D0\u4F9B\u3067\u304D\u3001\u30D5\u30A1\u30A4\u30A2\u30A6\u30A9\u30FC\u30EB\u3001VPN\u3001\u8CA0\u8377\u5206\u6563\u88C5\u7F6E\u306E\u30B5\u30DD\u30FC\u30C8\u306E\u307B\u304B\u306B\u3001\u76F4\u63A5\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3068\u4EEE\u60F3\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3082\u6709\u52B9\u306B\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002 -message.advanced.security.group=\u30B2\u30B9\u30C8 VM \u3092\u5206\u96E2\u3059\u308B\u305F\u3081\u306B\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3 \u30B0\u30EB\u30FC\u30D7\u3092\u4F7F\u7528\u3059\u308B\u5834\u5408\u306F\u3001\u3053\u306E\u30AA\u30D7\u30B7\u30E7\u30F3\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.advanced.virtual=\u30B2\u30B9\u30C8 VM \u3092\u5206\u96E2\u3059\u308B\u305F\u3081\u306B\u30BE\u30FC\u30F3\u5168\u4F53\u306E VLAN \u3092\u4F7F\u7528\u3059\u308B\u5834\u5408\u306F\u3001\u3053\u306E\u30AA\u30D7\u30B7\u30E7\u30F3\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002 +message.action.manage.cluster=\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u7ba1\u7406\u5bfe\u8c61\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.primarystorage.enable.maintenance.mode=\u8b66\u544a\: \u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u4fdd\u5b88\u30e2\u30fc\u30c9\u306b\u3059\u308b\u3068\u3001\u305d\u306e\u30b9\u30c8\u30ec\u30fc\u30b8\u4e0a\u306e\u30dc\u30ea\u30e5\u30fc\u30e0\u3092\u4f7f\u7528\u3059\u308b\u3059\u3079\u3066\u306e VM \u304c\u505c\u6b62\u3057\u307e\u3059\u3002\u7d9a\u884c\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.reboot.instance=\u3053\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u518d\u8d77\u52d5\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.reboot.router=\u3053\u306e\u4eee\u60f3\u30eb\u30fc\u30bf\u30fc\u3067\u63d0\u4f9b\u3059\u308b\u3059\u3079\u3066\u306e\u30b5\u30fc\u30d3\u30b9\u304c\u4e2d\u65ad\u3055\u308c\u307e\u3059\u3002\u3053\u306e\u30eb\u30fc\u30bf\u30fc\u3092\u518d\u8d77\u52d5\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.reboot.systemvm=\u3053\u306e\u30b7\u30b9\u30c6\u30e0 VM \u3092\u518d\u8d77\u52d5\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.release.ip=\u3053\u306e IP \u30a2\u30c9\u30ec\u30b9\u3092\u89e3\u653e\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.remove.host=\u3053\u306e\u30db\u30b9\u30c8\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.reset.password.off=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306f\u73fe\u5728\u3053\u306e\u6a5f\u80fd\u3092\u30b5\u30dd\u30fc\u30c8\u3057\u3066\u3044\u307e\u305b\u3093\u3002 +message.action.reset.password.warning=\u73fe\u5728\u306e\u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u5909\u66f4\u3059\u308b\u524d\u306b\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u505c\u6b62\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +message.action.restore.instance=\u3053\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u5fa9\u5143\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.start.instance=\u3053\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u8d77\u52d5\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.start.router=\u3053\u306e\u30eb\u30fc\u30bf\u30fc\u3092\u8d77\u52d5\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.start.systemvm=\u3053\u306e\u30b7\u30b9\u30c6\u30e0 VM \u3092\u8d77\u52d5\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.stop.instance=\u3053\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u505c\u6b62\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.stop.router=\u3053\u306e\u4eee\u60f3\u30eb\u30fc\u30bf\u30fc\u3067\u63d0\u4f9b\u3059\u308b\u3059\u3079\u3066\u306e\u30b5\u30fc\u30d3\u30b9\u304c\u4e2d\u65ad\u3055\u308c\u307e\u3059\u3002\u3053\u306e\u30eb\u30fc\u30bf\u30fc\u3092\u505c\u6b62\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.stop.systemvm=\u3053\u306e\u30b7\u30b9\u30c6\u30e0 VM \u3092\u505c\u6b62\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.take.snapshot=\u3053\u306e\u30dc\u30ea\u30e5\u30fc\u30e0\u306e\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u3092\u4f5c\u6210\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.action.unmanage.cluster=\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u975e\u7ba1\u7406\u5bfe\u8c61\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.activate.project=\u3053\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3092\u30a2\u30af\u30c6\u30a3\u30d6\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.add.cluster=\u30be\u30fc\u30f3 \u306e\u30dd\u30c3\u30c9 \u306b\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc\u3067\u7ba1\u7406\u3055\u308c\u308b\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u8ffd\u52a0\u3057\u307e\u3059 +message.add.cluster.zone=\u30be\u30fc\u30f3 \u306b\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc\u3067\u7ba1\u7406\u3055\u308c\u308b\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u8ffd\u52a0\u3057\u307e\u3059 +message.add.disk.offering=\u65b0\u3057\u3044\u30c7\u30a3\u30b9\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u8ffd\u52a0\u3059\u308b\u305f\u3081\u306b\u3001\u6b21\u306e\u30d1\u30e9\u30e1\u30fc\u30bf\u30fc\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.add.domain=\u3053\u306e\u30c9\u30e1\u30a4\u30f3\u306b\u4f5c\u6210\u3059\u308b\u30b5\u30d6\u30c9\u30e1\u30a4\u30f3\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.add.firewall=\u30be\u30fc\u30f3\u306b\u30d5\u30a1\u30a4\u30a2\u30a6\u30a9\u30fc\u30eb\u3092\u8ffd\u52a0\u3057\u307e\u3059 +message.add.guest.network=\u30b2\u30b9\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u8ffd\u52a0\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.add.host=\u65b0\u3057\u3044\u30db\u30b9\u30c8\u3092\u8ffd\u52a0\u3059\u308b\u305f\u3081\u306b\u3001\u6b21\u306e\u30d1\u30e9\u30e1\u30fc\u30bf\u30fc\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.adding.host=\u30db\u30b9\u30c8\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 +message.adding.Netscaler.device=Netscaler \u30c7\u30d0\u30a4\u30b9\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 +message.adding.Netscaler.provider=Netscaler \u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u3092\u8ffd\u52a0\u3057\u3066\u3044\u307e\u3059 +message.add.ip.range.direct.network=\u30be\u30fc\u30f3 \u306e\u76f4\u63a5\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u306b IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u3092\u8ffd\u52a0\u3057\u307e\u3059 +message.add.ip.range.to.pod=

\u30dd\u30c3\u30c9 \u306b IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u3092\u8ffd\u52a0\u3057\u307e\u3059

+message.add.ip.range=\u30be\u30fc\u30f3\u306e\u30d1\u30d6\u30ea\u30c3\u30af \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306b IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u3092\u8ffd\u52a0\u3057\u307e\u3059 +message.additional.networks.desc=\u4eee\u60f3\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u304c\u63a5\u7d9a\u3059\u308b\u8ffd\u52a0\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.add.load.balancer=\u30be\u30fc\u30f3\u306b\u8ca0\u8377\u5206\u6563\u88c5\u7f6e\u3092\u8ffd\u52a0\u3057\u307e\u3059 +message.add.load.balancer.under.ip=\u8ca0\u8377\u5206\u6563\u898f\u5247\u304c\u6b21\u306e IP \u30a2\u30c9\u30ec\u30b9\u306b\u5bfe\u3057\u3066\u8ffd\u52a0\u3055\u308c\u307e\u3057\u305f\: +message.add.network=\u30be\u30fc\u30f3 \u306b\u65b0\u3057\u3044\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u8ffd\u52a0\u3057\u307e\u3059 +message.add.new.gateway.to.vpc=\u3053\u306e VPC \u306b\u65b0\u3057\u3044\u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u3092\u8ffd\u52a0\u3059\u308b\u305f\u3081\u306e\u60c5\u5831\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.add.pod=\u30be\u30fc\u30f3 \u306b\u65b0\u3057\u3044\u30dd\u30c3\u30c9\u3092\u8ffd\u52a0\u3057\u307e\u3059 +message.add.primary.storage=\u30be\u30fc\u30f3 \u306e\u30dd\u30c3\u30c9 \u306b\u65b0\u3057\u3044\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u8ffd\u52a0\u3057\u307e\u3059 +message.add.primary=\u65b0\u3057\u3044\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u8ffd\u52a0\u3059\u308b\u305f\u3081\u306b\u3001\u6b21\u306e\u30d1\u30e9\u30e1\u30fc\u30bf\u30fc\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.add.secondary.storage=\u30be\u30fc\u30f3 \u306b\u65b0\u3057\u3044\u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u8ffd\u52a0\u3057\u307e\u3059 +message.add.service.offering=\u65b0\u3057\u3044\u30b3\u30f3\u30d4\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u8ffd\u52a0\u3059\u308b\u305f\u3081\u306b\u3001\u6b21\u306e\u30c7\u30fc\u30bf\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.add.system.service.offering=\u65b0\u3057\u3044\u30b7\u30b9\u30c6\u30e0 \u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u8ffd\u52a0\u3059\u308b\u305f\u3081\u306b\u3001\u6b21\u306e\u30c7\u30fc\u30bf\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.add.template=\u65b0\u3057\u3044\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u4f5c\u6210\u3059\u308b\u305f\u3081\u306b\u3001\u6b21\u306e\u30c7\u30fc\u30bf\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.add.volume=\u65b0\u3057\u3044\u30dc\u30ea\u30e5\u30fc\u30e0\u3092\u8ffd\u52a0\u3059\u308b\u305f\u3081\u306b\u3001\u6b21\u306e\u30c7\u30fc\u30bf\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.add.VPN.gateway=VPN \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u3092\u8ffd\u52a0\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.advanced.mode.desc=VLAN \u30b5\u30dd\u30fc\u30c8\u3092\u6709\u52b9\u306b\u3059\u308b\u5834\u5408\u306f\u3001\u3053\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30e2\u30c7\u30eb\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u3053\u306e\u30e2\u30c7\u30eb\u3067\u306f\u6700\u3082\u67d4\u8edf\u306b\u30ab\u30b9\u30bf\u30e0 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u63d0\u4f9b\u3067\u304d\u3001\u30d5\u30a1\u30a4\u30a2\u30a6\u30a9\u30fc\u30eb\u3001VPN\u3001\u8ca0\u8377\u5206\u6563\u88c5\u7f6e\u306e\u30b5\u30dd\u30fc\u30c8\u306e\u307b\u304b\u306b\u3001\u76f4\u63a5\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3068\u4eee\u60f3\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3082\u6709\u52b9\u306b\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002 +message.advanced.security.group=\u30b2\u30b9\u30c8 VM \u3092\u5206\u96e2\u3059\u308b\u305f\u3081\u306b\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u3092\u4f7f\u7528\u3059\u308b\u5834\u5408\u306f\u3001\u3053\u306e\u30aa\u30d7\u30b7\u30e7\u30f3\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.advanced.virtual=\u30b2\u30b9\u30c8 VM \u3092\u5206\u96e2\u3059\u308b\u305f\u3081\u306b\u30be\u30fc\u30f3\u5168\u4f53\u306e VLAN \u3092\u4f7f\u7528\u3059\u308b\u5834\u5408\u306f\u3001\u3053\u306e\u30aa\u30d7\u30b7\u30e7\u30f3\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 message.after.enable.s3=S3\u57fa\u76e4\u30bb\u30ab\u30f3\u30c0\u30ea\u30b9\u30c8\u30ec\u30fc\u30b8\u304c\u8a2d\u5b9a\u3055\u308c\u307e\u3057\u305f\u3002 \u30ce\u30fc\u30c8\:\u3053\u306e\u30da\u30fc\u30b8\u3092\u9589\u3058\u308b\u3068S3\u3092\u518d\u8a2d\u5b9a\u3067\u304d\u307e\u305b\u3093\u3002 -message.after.enable.swift=Swift \u304C\u69CB\u6210\u3055\u308C\u307E\u3057\u305F\u3002\u6CE8\: \u3053\u306E\u30DA\u30FC\u30B8\u3092\u9589\u3058\u308B\u3068\u3001Swift \u3092\u518D\u69CB\u6210\u3059\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093\u3002 -message.alert.state.detected=\u30A2\u30E9\u30FC\u30C8\u72B6\u614B\u304C\u691C\u51FA\u3055\u308C\u307E\u3057\u305F -message.allow.vpn.access=VPN \u30A2\u30AF\u30BB\u30B9\u3092\u8A31\u53EF\u3059\u308B\u30E6\u30FC\u30B6\u30FC\u306E\u30E6\u30FC\u30B6\u30FC\u540D\u3068\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.apply.snapshot.policy=\u73FE\u5728\u306E\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8 \u30DD\u30EA\u30B7\u30FC\u3092\u66F4\u65B0\u3057\u307E\u3057\u305F\u3002 -message.attach.iso.confirm=\u3053\u306E\u4EEE\u60F3\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306B ISO \u30D5\u30A1\u30A4\u30EB\u3092\u30A2\u30BF\u30C3\u30C1\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.attach.volume=\u65B0\u3057\u3044\u30DC\u30EA\u30E5\u30FC\u30E0\u3092\u30A2\u30BF\u30C3\u30C1\u3059\u308B\u305F\u3081\u306B\u3001\u6B21\u306E\u30C7\u30FC\u30BF\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002Windows \u30D9\u30FC\u30B9\u306E\u4EEE\u60F3\u30DE\u30B7\u30F3\u306B\u30C7\u30A3\u30B9\u30AF \u30DC\u30EA\u30E5\u30FC\u30E0\u3092\u30A2\u30BF\u30C3\u30C1\u3059\u308B\u5834\u5408\u306F\u3001\u30A2\u30BF\u30C3\u30C1\u3057\u305F\u30C7\u30A3\u30B9\u30AF\u3092\u8A8D\u8B58\u3059\u308B\u305F\u3081\u306B\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u518D\u8D77\u52D5\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -message.basic.mode.desc=VLAN \u30B5\u30DD\u30FC\u30C8\u304C\u4E0D\u8981\u3067\u3042\u308B\u5834\u5408\u306F\u3001\u3053\u306E\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30E2\u30C7\u30EB\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u3053\u306E\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30E2\u30C7\u30EB\u3067\u4F5C\u6210\u3055\u308C\u308B\u3059\u3079\u3066\u306E\u4EEE\u60F3\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306B\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u304B\u3089\u76F4\u63A5 IP \u30A2\u30C9\u30EC\u30B9\u304C\u5272\u308A\u5F53\u3066\u3089\u308C\u3001\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3 \u30B0\u30EB\u30FC\u30D7\u3092\u4F7F\u7528\u3057\u3066\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3\u3068\u5206\u96E2\u304C\u63D0\u4F9B\u3055\u308C\u307E\u3059\u3002 -message.change.offering.confirm=\u3053\u306E\u4EEE\u60F3\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u30B5\u30FC\u30D3\u30B9 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u3092\u5909\u66F4\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.change.password=\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u5909\u66F4\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.configure.all.traffic.types=\u8907\u6570\u306E\u7269\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u304C\u3042\u308A\u307E\u3059\u3002[\u7DE8\u96C6] \u3092\u30AF\u30EA\u30C3\u30AF\u3057\u3066\u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u306E\u7A2E\u985E\u3054\u3068\u306B\u30E9\u30D9\u30EB\u3092\u69CB\u6210\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.configuring.guest.traffic=\u30B2\u30B9\u30C8 \u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u3092\u69CB\u6210\u3057\u3066\u3044\u307E\u3059 -message.configuring.physical.networks=\u7269\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u69CB\u6210\u3057\u3066\u3044\u307E\u3059 -message.configuring.public.traffic=\u30D1\u30D6\u30EA\u30C3\u30AF \u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u3092\u69CB\u6210\u3057\u3066\u3044\u307E\u3059 -message.configuring.storage.traffic=\u30B9\u30C8\u30EC\u30FC\u30B8 \u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u3092\u69CB\u6210\u3057\u3066\u3044\u307E\u3059 -message.confirm.action.force.reconnect=\u3053\u306E\u30DB\u30B9\u30C8\u3092\u5F37\u5236\u518D\u63A5\u7D9A\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.confirm.delete.F5=F5 \u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.confirm.delete.NetScaler=NetScaler \u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.confirm.delete.SRX=SRX \u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.confirm.destroy.router=\u3053\u306E\u30EB\u30FC\u30BF\u30FC\u3092\u7834\u68C4\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.confirm.disable.provider=\u3053\u306E\u30D7\u30ED\u30D0\u30A4\u30C0\u30FC\u3092\u7121\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.confirm.enable.provider=\u3053\u306E\u30D7\u30ED\u30D0\u30A4\u30C0\u30FC\u3092\u6709\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.confirm.join.project=\u3053\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306B\u53C2\u52A0\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.confirm.remove.IP.range=\u3053\u306E IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.confirm.shutdown.provider=\u3053\u306E\u30D7\u30ED\u30D0\u30A4\u30C0\u30FC\u3092\u30B7\u30E3\u30C3\u30C8\u30C0\u30A6\u30F3\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.copy.iso.confirm=ISO \u3092\u6B21\u306E\u5834\u6240\u306B\u30B3\u30D4\u30FC\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.copy.template=\u30BE\u30FC\u30F3 \u304B\u3089\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8 XXX \u3092\u6B21\u306E\u5834\u6240\u306B\u30B3\u30D4\u30FC\u3057\u307E\u3059\: -message.create.template=\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3092\u4F5C\u6210\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.create.template.vm=\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8 \u304B\u3089 VM \u3092\u4F5C\u6210\u3057\u307E\u3059 -message.create.template.volume=\u30C7\u30A3\u30B9\u30AF \u30DC\u30EA\u30E5\u30FC\u30E0 \u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3092\u4F5C\u6210\u3059\u308B\u524D\u306B\u3001\u6B21\u306E\u60C5\u5831\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u30DC\u30EA\u30E5\u30FC\u30E0 \u30B5\u30A4\u30BA\u306B\u3088\u3063\u3066\u306F\u3001\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u4F5C\u6210\u306B\u306F\u6570\u5206\u4EE5\u4E0A\u304B\u304B\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002 -message.creating.cluster=\u30AF\u30E9\u30B9\u30BF\u30FC\u3092\u4F5C\u6210\u3057\u3066\u3044\u307E\u3059 -message.creating.guest.network=\u30B2\u30B9\u30C8 \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u4F5C\u6210\u3057\u3066\u3044\u307E\u3059 -message.creating.physical.networks=\u7269\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u4F5C\u6210\u3057\u3066\u3044\u307E\u3059 -message.creating.pod=\u30DD\u30C3\u30C9\u3092\u4F5C\u6210\u3057\u3066\u3044\u307E\u3059 -message.creating.primary.storage=\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u3092\u4F5C\u6210\u3057\u3066\u3044\u307E\u3059 -message.creating.secondary.storage=\u30BB\u30AB\u30F3\u30C0\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u3092\u4F5C\u6210\u3057\u3066\u3044\u307E\u3059 -message.creating.zone=\u30BE\u30FC\u30F3\u3092\u4F5C\u6210\u3057\u3066\u3044\u307E\u3059 -message.decline.invitation=\u3053\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3078\u306E\u62DB\u5F85\u3092\u8F9E\u9000\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.delete.account=\u3053\u306E\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.delete.gateway=\u3053\u306E\u30B2\u30FC\u30C8\u30A6\u30A7\u30A4\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.delete.project=\u3053\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.delete.user=\u3053\u306E\u30E6\u30FC\u30B6\u30FC\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.delete.VPN.connection=VPN \u63A5\u7D9A\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.delete.VPN.customer.gateway=\u3053\u306E VPN \u30AB\u30B9\u30BF\u30DE\u30FC \u30B2\u30FC\u30C8\u30A6\u30A7\u30A4\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.delete.VPN.gateway=\u3053\u306E VPN \u30B2\u30FC\u30C8\u30A6\u30A7\u30A4\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.desc.advanced.zone=\u3088\u308A\u6D17\u7DF4\u3055\u308C\u305F\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u6280\u8853\u3092\u30B5\u30DD\u30FC\u30C8\u3057\u307E\u3059\u3002\u3053\u306E\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30E2\u30C7\u30EB\u3092\u9078\u629E\u3059\u308B\u3068\u3001\u3088\u308A\u67D4\u8EDF\u306B\u30B2\u30B9\u30C8\u306E\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u5B9A\u7FA9\u3057\u3001\u30D5\u30A1\u30A4\u30A2\u30A6\u30A9\u30FC\u30EB\u3001VPN\u3001\u8CA0\u8377\u5206\u6563\u88C5\u7F6E\u306E\u30B5\u30DD\u30FC\u30C8\u306E\u3088\u3046\u306A\u30AB\u30B9\u30BF\u30DE\u30A4\u30BA\u3057\u305F\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u3092\u63D0\u4F9B\u3067\u304D\u307E\u3059\u3002 -message.desc.basic.zone=\u5404 VM \u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306B IP \u30A2\u30C9\u30EC\u30B9\u304C\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u304B\u3089\u76F4\u63A5\u5272\u308A\u5F53\u3066\u3089\u308C\u308B\u3001\u5358\u4E00\u306E\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u63D0\u4F9B\u3057\u307E\u3059\u3002\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3 \u30B0\u30EB\u30FC\u30D7 (\u9001\u4FE1\u5143 IP \u30A2\u30C9\u30EC\u30B9\u306E\u30D5\u30A3\u30EB\u30BF\u30FC) \u306E\u3088\u3046\u306A\u30EC\u30A4\u30E4\u30FC 3 \u30EC\u30D9\u30EB\u306E\u65B9\u6CD5\u3067\u30B2\u30B9\u30C8\u3092\u5206\u96E2\u3067\u304D\u307E\u3059\u3002 -message.desc.cluster=\u5404\u30DD\u30C3\u30C9\u306B\u306F 1 \u3064\u4EE5\u4E0A\u306E\u30AF\u30E9\u30B9\u30BF\u30FC\u304C\u5FC5\u8981\u3067\u3059\u3002\u4ECA\u3053\u3053\u3067\u6700\u521D\u306E\u30AF\u30E9\u30B9\u30BF\u30FC\u3092\u8FFD\u52A0\u3057\u307E\u3059\u3002\u30AF\u30E9\u30B9\u30BF\u30FC\u306F\u30DB\u30B9\u30C8\u3092\u30B0\u30EB\u30FC\u30D7\u5316\u3059\u308B\u65B9\u6CD5\u3067\u3059\u30021 \u3064\u306E\u30AF\u30E9\u30B9\u30BF\u30FC\u5185\u306E\u30DB\u30B9\u30C8\u306F\u3059\u3079\u3066\u540C\u4E00\u306E\u30CF\u30FC\u30C9\u30A6\u30A7\u30A2\u304B\u3089\u69CB\u6210\u3055\u308C\u3001\u540C\u3058\u30CF\u30A4\u30D1\u30FC\u30D0\u30A4\u30B6\u30FC\u3092\u5B9F\u884C\u3057\u3001\u540C\u3058\u30B5\u30D6\u30CD\u30C3\u30C8\u4E0A\u306B\u3042\u308A\u3001\u540C\u3058\u5171\u6709\u30B9\u30C8\u30EC\u30FC\u30B8\u306B\u30A2\u30AF\u30BB\u30B9\u3057\u307E\u3059\u3002\u5404\u30AF\u30E9\u30B9\u30BF\u30FC\u306F 1 \u3064\u4EE5\u4E0A\u306E\u30DB\u30B9\u30C8\u3068 1 \u3064\u4EE5\u4E0A\u306E\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8 \u30B5\u30FC\u30D0\u30FC\u304B\u3089\u69CB\u6210\u3055\u308C\u307E\u3059\u3002 -message.desc.host=\u5404\u30AF\u30E9\u30B9\u30BF\u30FC\u306B\u306F\u5C11\u306A\u304F\u3068\u3082 1 \u3064\u3001\u30B2\u30B9\u30C8 VM \u3092\u5B9F\u884C\u3059\u308B\u305F\u3081\u306E\u30DB\u30B9\u30C8 (\u30B3\u30F3\u30D4\u30E5\u30FC\u30BF\u30FC) \u304C\u5FC5\u8981\u3067\u3059\u3002\u4ECA\u3053\u3053\u3067\u6700\u521D\u306E\u30DB\u30B9\u30C8\u3092\u8FFD\u52A0\u3057\u307E\u3059\u3002CloudStack \u3067\u30DB\u30B9\u30C8\u3092\u6A5F\u80FD\u3055\u305B\u308B\u306B\u306F\u3001\u30DB\u30B9\u30C8\u306B\u30CF\u30A4\u30D1\u30FC\u30D0\u30A4\u30B6\u30FC\u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3057\u3066 IP \u30A2\u30C9\u30EC\u30B9\u3092\u5272\u308A\u5F53\u3066\u3001\u30DB\u30B9\u30C8\u304C CloudStack \u7BA1\u7406\u30B5\u30FC\u30D0\u30FC\u306B\u63A5\u7D9A\u3057\u3066\u3044\u308B\u3053\u3068\u3092\u78BA\u8A8D\u3057\u307E\u3059\u3002

\u30DB\u30B9\u30C8\u306E DNS \u540D\u307E\u305F\u306F IP \u30A2\u30C9\u30EC\u30B9\u3001\u30E6\u30FC\u30B6\u30FC\u540D (\u901A\u5E38\u306F root) \u3068\u30D1\u30B9\u30EF\u30FC\u30C9\u3001\u304A\u3088\u3073\u30DB\u30B9\u30C8\u306E\u5206\u985E\u306B\u4F7F\u7528\u3059\u308B\u30E9\u30D9\u30EB\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.desc.primary.storage=\u5404\u30AF\u30E9\u30B9\u30BF\u30FC\u306B\u306F\u5C11\u306A\u304F\u3068\u3082 1 \u3064\u3001\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8 \u30B5\u30FC\u30D0\u30FC\u304C\u5FC5\u8981\u3067\u3059\u3002\u4ECA\u3053\u3053\u3067\u6700\u521D\u306E\u30B5\u30FC\u30D0\u30FC\u3092\u8FFD\u52A0\u3057\u307E\u3059\u3002\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u306F\u3001\u30AF\u30E9\u30B9\u30BF\u30FC\u5185\u306E\u30DB\u30B9\u30C8\u4E0A\u3067\u52D5\u4F5C\u3059\u308B\u3059\u3079\u3066\u306E VM \u306E\u30C7\u30A3\u30B9\u30AF \u30DC\u30EA\u30E5\u30FC\u30E0\u3092\u683C\u7D0D\u3057\u307E\u3059\u3002\u57FA\u790E\u3068\u306A\u308B\u30CF\u30A4\u30D1\u30FC\u30D0\u30A4\u30B6\u30FC\u3067\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u308B\u3001\u6A19\u6E96\u306B\u6E96\u62E0\u3057\u305F\u30D7\u30ED\u30C8\u30B3\u30EB\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.desc.secondary.storage=\u5404\u30BE\u30FC\u30F3\u306B\u306F\u5C11\u306A\u304F\u3068\u3082 1 \u3064\u3001NFS \u3064\u307E\u308A\u30BB\u30AB\u30F3\u30C0\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8 \u30B5\u30FC\u30D0\u30FC\u304C\u5FC5\u8981\u3067\u3059\u3002\u4ECA\u3053\u3053\u3067\u6700\u521D\u306E\u30B5\u30FC\u30D0\u30FC\u3092\u8FFD\u52A0\u3057\u307E\u3059\u3002\u30BB\u30AB\u30F3\u30C0\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u306F VM \u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3001ISO \u30A4\u30E1\u30FC\u30B8\u3001\u304A\u3088\u3073VM \u30C7\u30A3\u30B9\u30AF \u30DC\u30EA\u30E5\u30FC\u30E0\u306E\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u3092\u683C\u7D0D\u3057\u307E\u3059\u3002\u3053\u306E\u30B5\u30FC\u30D0\u30FC\u306F\u30BE\u30FC\u30F3\u5185\u306E\u3059\u3079\u3066\u306E\u30DB\u30B9\u30C8\u3067\u4F7F\u7528\u3067\u304D\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002

IP \u30A2\u30C9\u30EC\u30B9\u3068\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8\u3055\u308C\u305F\u30D1\u30B9\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.desc.zone=\u30BE\u30FC\u30F3\u306F CloudStack \u74B0\u5883\u5185\u306E\u6700\u5927\u306E\u7D44\u7E54\u5358\u4F4D\u3067\u3001\u901A\u5E38\u3001\u5358\u4E00\u306E\u30C7\u30FC\u30BF\u30BB\u30F3\u30BF\u30FC\u306B\u76F8\u5F53\u3057\u307E\u3059\u3002\u30BE\u30FC\u30F3\u306B\u3088\u3063\u3066\u7269\u7406\u7684\u306A\u5206\u96E2\u3068\u5197\u9577\u6027\u304C\u63D0\u4F9B\u3055\u308C\u307E\u3059\u3002\u30BE\u30FC\u30F3\u306F 1 \u3064\u4EE5\u4E0A\u306E\u30DD\u30C3\u30C9 (\u5404\u30DD\u30C3\u30C9\u306F\u30DB\u30B9\u30C8\u3068\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8 \u30B5\u30FC\u30D0\u30FC\u304B\u3089\u69CB\u6210\u3055\u308C\u307E\u3059) \u3068\u3001\u30BE\u30FC\u30F3\u5185\u306E\u3059\u3079\u3066\u306E\u30DD\u30C3\u30C9\u3067\u5171\u6709\u3055\u308C\u308B\u30BB\u30AB\u30F3\u30C0\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8 \u30B5\u30FC\u30D0\u30FC\u304B\u3089\u69CB\u6210\u3055\u308C\u307E\u3059\u3002 -message.detach.disk=\u3053\u306E\u30C7\u30A3\u30B9\u30AF\u3092\u30C7\u30BF\u30C3\u30C1\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.detach.iso.confirm=\u3053\u306E\u4EEE\u60F3\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u304B\u3089 ISO \u30D5\u30A1\u30A4\u30EB\u3092\u30C7\u30BF\u30C3\u30C1\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? +message.after.enable.swift=Swift \u304c\u69cb\u6210\u3055\u308c\u307e\u3057\u305f\u3002\u6ce8\: \u3053\u306e\u30da\u30fc\u30b8\u3092\u9589\u3058\u308b\u3068\u3001Swift \u3092\u518d\u69cb\u6210\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093\u3002 +message.alert.state.detected=\u30a2\u30e9\u30fc\u30c8\u72b6\u614b\u304c\u691c\u51fa\u3055\u308c\u307e\u3057\u305f +message.allow.vpn.access=VPN \u30a2\u30af\u30bb\u30b9\u3092\u8a31\u53ef\u3059\u308b\u30e6\u30fc\u30b6\u30fc\u306e\u30e6\u30fc\u30b6\u30fc\u540d\u3068\u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.apply.snapshot.policy=\u73fe\u5728\u306e\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8 \u30dd\u30ea\u30b7\u30fc\u3092\u66f4\u65b0\u3057\u307e\u3057\u305f\u3002 +message.attach.iso.confirm=\u3053\u306e\u4eee\u60f3\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b ISO \u30d5\u30a1\u30a4\u30eb\u3092\u30a2\u30bf\u30c3\u30c1\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.attach.volume=\u65b0\u3057\u3044\u30dc\u30ea\u30e5\u30fc\u30e0\u3092\u30a2\u30bf\u30c3\u30c1\u3059\u308b\u305f\u3081\u306b\u3001\u6b21\u306e\u30c7\u30fc\u30bf\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002Windows \u30d9\u30fc\u30b9\u306e\u4eee\u60f3\u30de\u30b7\u30f3\u306b\u30c7\u30a3\u30b9\u30af \u30dc\u30ea\u30e5\u30fc\u30e0\u3092\u30a2\u30bf\u30c3\u30c1\u3059\u308b\u5834\u5408\u306f\u3001\u30a2\u30bf\u30c3\u30c1\u3057\u305f\u30c7\u30a3\u30b9\u30af\u3092\u8a8d\u8b58\u3059\u308b\u305f\u3081\u306b\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u518d\u8d77\u52d5\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +message.basic.mode.desc=VLAN \u30b5\u30dd\u30fc\u30c8\u304c\u4e0d\u8981\u3067\u3042\u308b\u5834\u5408\u306f\u3001\u3053\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30e2\u30c7\u30eb\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u3053\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30e2\u30c7\u30eb\u3067\u4f5c\u6210\u3055\u308c\u308b\u3059\u3079\u3066\u306e\u4eee\u60f3\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u304b\u3089\u76f4\u63a5 IP \u30a2\u30c9\u30ec\u30b9\u304c\u5272\u308a\u5f53\u3066\u3089\u308c\u3001\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u3092\u4f7f\u7528\u3057\u3066\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u3068\u5206\u96e2\u304c\u63d0\u4f9b\u3055\u308c\u307e\u3059\u3002 +message.change.offering.confirm=\u3053\u306e\u4eee\u60f3\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u5909\u66f4\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.change.password=\u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u5909\u66f4\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.configure.all.traffic.types=\u8907\u6570\u306e\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u304c\u3042\u308a\u307e\u3059\u3002[\u7de8\u96c6] \u3092\u30af\u30ea\u30c3\u30af\u3057\u3066\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e\u7a2e\u985e\u3054\u3068\u306b\u30e9\u30d9\u30eb\u3092\u69cb\u6210\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.configuring.guest.traffic=\u30b2\u30b9\u30c8 \u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u3092\u69cb\u6210\u3057\u3066\u3044\u307e\u3059 +message.configuring.physical.networks=\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u69cb\u6210\u3057\u3066\u3044\u307e\u3059 +message.configuring.public.traffic=\u30d1\u30d6\u30ea\u30c3\u30af \u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u3092\u69cb\u6210\u3057\u3066\u3044\u307e\u3059 +message.configuring.storage.traffic=\u30b9\u30c8\u30ec\u30fc\u30b8 \u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u3092\u69cb\u6210\u3057\u3066\u3044\u307e\u3059 +message.confirm.action.force.reconnect=\u3053\u306e\u30db\u30b9\u30c8\u3092\u5f37\u5236\u518d\u63a5\u7d9a\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.delete.F5=F5 \u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.delete.NetScaler=NetScaler \u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.delete.SRX=SRX \u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.destroy.router=\u3053\u306e\u30eb\u30fc\u30bf\u30fc\u3092\u7834\u68c4\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.disable.provider=\u3053\u306e\u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u3092\u7121\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.enable.provider=\u3053\u306e\u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.join.project=\u3053\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306b\u53c2\u52a0\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.remove.IP.range=\u3053\u306e IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.shutdown.provider=\u3053\u306e\u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u3092\u30b7\u30e3\u30c3\u30c8\u30c0\u30a6\u30f3\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.copy.iso.confirm=ISO \u3092\u6b21\u306e\u5834\u6240\u306b\u30b3\u30d4\u30fc\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.copy.template=\u30be\u30fc\u30f3 \u304b\u3089\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8 XXX \u3092\u6b21\u306e\u5834\u6240\u306b\u30b3\u30d4\u30fc\u3057\u307e\u3059\: +message.create.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u4f5c\u6210\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.create.template.vm=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8 \u304b\u3089 VM \u3092\u4f5c\u6210\u3057\u307e\u3059 +message.create.template.volume=\u30c7\u30a3\u30b9\u30af \u30dc\u30ea\u30e5\u30fc\u30e0 \u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u4f5c\u6210\u3059\u308b\u524d\u306b\u3001\u6b21\u306e\u60c5\u5831\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u30dc\u30ea\u30e5\u30fc\u30e0 \u30b5\u30a4\u30ba\u306b\u3088\u3063\u3066\u306f\u3001\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u4f5c\u6210\u306b\u306f\u6570\u5206\u4ee5\u4e0a\u304b\u304b\u308b\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059\u3002 +message.creating.cluster=\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u4f5c\u6210\u3057\u3066\u3044\u307e\u3059 +message.creating.guest.network=\u30b2\u30b9\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u4f5c\u6210\u3057\u3066\u3044\u307e\u3059 +message.creating.physical.networks=\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u4f5c\u6210\u3057\u3066\u3044\u307e\u3059 +message.creating.pod=\u30dd\u30c3\u30c9\u3092\u4f5c\u6210\u3057\u3066\u3044\u307e\u3059 +message.creating.primary.storage=\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u4f5c\u6210\u3057\u3066\u3044\u307e\u3059 +message.creating.secondary.storage=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u4f5c\u6210\u3057\u3066\u3044\u307e\u3059 +message.creating.zone=\u30be\u30fc\u30f3\u3092\u4f5c\u6210\u3057\u3066\u3044\u307e\u3059 +message.decline.invitation=\u3053\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3078\u306e\u62db\u5f85\u3092\u8f9e\u9000\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.delete.account=\u3053\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.delete.gateway=\u3053\u306e\u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.delete.project=\u3053\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.delete.user=\u3053\u306e\u30e6\u30fc\u30b6\u30fc\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.delete.VPN.connection=VPN \u63a5\u7d9a\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.delete.VPN.customer.gateway=\u3053\u306e VPN \u30ab\u30b9\u30bf\u30de\u30fc \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.delete.VPN.gateway=\u3053\u306e VPN \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.desc.advanced.zone=\u3088\u308a\u6d17\u7df4\u3055\u308c\u305f\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u6280\u8853\u3092\u30b5\u30dd\u30fc\u30c8\u3057\u307e\u3059\u3002\u3053\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30e2\u30c7\u30eb\u3092\u9078\u629e\u3059\u308b\u3068\u3001\u3088\u308a\u67d4\u8edf\u306b\u30b2\u30b9\u30c8\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u5b9a\u7fa9\u3057\u3001\u30d5\u30a1\u30a4\u30a2\u30a6\u30a9\u30fc\u30eb\u3001VPN\u3001\u8ca0\u8377\u5206\u6563\u88c5\u7f6e\u306e\u30b5\u30dd\u30fc\u30c8\u306e\u3088\u3046\u306a\u30ab\u30b9\u30bf\u30de\u30a4\u30ba\u3057\u305f\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u63d0\u4f9b\u3067\u304d\u307e\u3059\u3002 +message.desc.basic.zone=\u5404 VM \u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b IP \u30a2\u30c9\u30ec\u30b9\u304c\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u304b\u3089\u76f4\u63a5\u5272\u308a\u5f53\u3066\u3089\u308c\u308b\u3001\u5358\u4e00\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u63d0\u4f9b\u3057\u307e\u3059\u3002\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7 (\u9001\u4fe1\u5143 IP \u30a2\u30c9\u30ec\u30b9\u306e\u30d5\u30a3\u30eb\u30bf\u30fc) \u306e\u3088\u3046\u306a\u30ec\u30a4\u30e4\u30fc 3 \u30ec\u30d9\u30eb\u306e\u65b9\u6cd5\u3067\u30b2\u30b9\u30c8\u3092\u5206\u96e2\u3067\u304d\u307e\u3059\u3002 +message.desc.cluster=\u5404\u30dd\u30c3\u30c9\u306b\u306f 1 \u3064\u4ee5\u4e0a\u306e\u30af\u30e9\u30b9\u30bf\u30fc\u304c\u5fc5\u8981\u3067\u3059\u3002\u4eca\u3053\u3053\u3067\u6700\u521d\u306e\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u8ffd\u52a0\u3057\u307e\u3059\u3002\u30af\u30e9\u30b9\u30bf\u30fc\u306f\u30db\u30b9\u30c8\u3092\u30b0\u30eb\u30fc\u30d7\u5316\u3059\u308b\u65b9\u6cd5\u3067\u3059\u30021 \u3064\u306e\u30af\u30e9\u30b9\u30bf\u30fc\u5185\u306e\u30db\u30b9\u30c8\u306f\u3059\u3079\u3066\u540c\u4e00\u306e\u30cf\u30fc\u30c9\u30a6\u30a7\u30a2\u304b\u3089\u69cb\u6210\u3055\u308c\u3001\u540c\u3058\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc\u3092\u5b9f\u884c\u3057\u3001\u540c\u3058\u30b5\u30d6\u30cd\u30c3\u30c8\u4e0a\u306b\u3042\u308a\u3001\u540c\u3058\u5171\u6709\u30b9\u30c8\u30ec\u30fc\u30b8\u306b\u30a2\u30af\u30bb\u30b9\u3057\u307e\u3059\u3002\u5404\u30af\u30e9\u30b9\u30bf\u30fc\u306f 1 \u3064\u4ee5\u4e0a\u306e\u30db\u30b9\u30c8\u3068 1 \u3064\u4ee5\u4e0a\u306e\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 \u30b5\u30fc\u30d0\u30fc\u304b\u3089\u69cb\u6210\u3055\u308c\u307e\u3059\u3002 +message.desc.primary.storage=\u5404\u30af\u30e9\u30b9\u30bf\u30fc\u306b\u306f\u5c11\u306a\u304f\u3068\u3082 1 \u3064\u3001\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 \u30b5\u30fc\u30d0\u30fc\u304c\u5fc5\u8981\u3067\u3059\u3002\u4eca\u3053\u3053\u3067\u6700\u521d\u306e\u30b5\u30fc\u30d0\u30fc\u3092\u8ffd\u52a0\u3057\u307e\u3059\u3002\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u306f\u3001\u30af\u30e9\u30b9\u30bf\u30fc\u5185\u306e\u30db\u30b9\u30c8\u4e0a\u3067\u52d5\u4f5c\u3059\u308b\u3059\u3079\u3066\u306e VM \u306e\u30c7\u30a3\u30b9\u30af \u30dc\u30ea\u30e5\u30fc\u30e0\u3092\u683c\u7d0d\u3057\u307e\u3059\u3002\u57fa\u790e\u3068\u306a\u308b\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc\u3067\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u308b\u3001\u6a19\u6e96\u306b\u6e96\u62e0\u3057\u305f\u30d7\u30ed\u30c8\u30b3\u30eb\u3092\u4f7f\u7528\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.desc.secondary.storage=\u5404\u30be\u30fc\u30f3\u306b\u306f\u5c11\u306a\u304f\u3068\u3082 1 \u3064\u3001NFS \u3064\u307e\u308a\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 \u30b5\u30fc\u30d0\u30fc\u304c\u5fc5\u8981\u3067\u3059\u3002\u4eca\u3053\u3053\u3067\u6700\u521d\u306e\u30b5\u30fc\u30d0\u30fc\u3092\u8ffd\u52a0\u3057\u307e\u3059\u3002\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u306f VM \u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3001ISO \u30a4\u30e1\u30fc\u30b8\u3001\u304a\u3088\u3073VM \u30c7\u30a3\u30b9\u30af \u30dc\u30ea\u30e5\u30fc\u30e0\u306e\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u3092\u683c\u7d0d\u3057\u307e\u3059\u3002\u3053\u306e\u30b5\u30fc\u30d0\u30fc\u306f\u30be\u30fc\u30f3\u5185\u306e\u3059\u3079\u3066\u306e\u30db\u30b9\u30c8\u3067\u4f7f\u7528\u3067\u304d\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002

IP \u30a2\u30c9\u30ec\u30b9\u3068\u30a8\u30af\u30b9\u30dd\u30fc\u30c8\u3055\u308c\u305f\u30d1\u30b9\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.desc.zone=\u30be\u30fc\u30f3\u306f CloudStack \u74b0\u5883\u5185\u306e\u6700\u5927\u306e\u7d44\u7e54\u5358\u4f4d\u3067\u3001\u901a\u5e38\u3001\u5358\u4e00\u306e\u30c7\u30fc\u30bf\u30bb\u30f3\u30bf\u30fc\u306b\u76f8\u5f53\u3057\u307e\u3059\u3002\u30be\u30fc\u30f3\u306b\u3088\u3063\u3066\u7269\u7406\u7684\u306a\u5206\u96e2\u3068\u5197\u9577\u6027\u304c\u63d0\u4f9b\u3055\u308c\u307e\u3059\u3002\u30be\u30fc\u30f3\u306f 1 \u3064\u4ee5\u4e0a\u306e\u30dd\u30c3\u30c9 (\u5404\u30dd\u30c3\u30c9\u306f\u30db\u30b9\u30c8\u3068\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 \u30b5\u30fc\u30d0\u30fc\u304b\u3089\u69cb\u6210\u3055\u308c\u307e\u3059) \u3068\u3001\u30be\u30fc\u30f3\u5185\u306e\u3059\u3079\u3066\u306e\u30dd\u30c3\u30c9\u3067\u5171\u6709\u3055\u308c\u308b\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 \u30b5\u30fc\u30d0\u30fc\u304b\u3089\u69cb\u6210\u3055\u308c\u307e\u3059\u3002 +message.detach.disk=\u3053\u306e\u30c7\u30a3\u30b9\u30af\u3092\u30c7\u30bf\u30c3\u30c1\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.detach.iso.confirm=\u3053\u306e\u4eee\u60f3\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u304b\u3089 ISO \u30d5\u30a1\u30a4\u30eb\u3092\u30c7\u30bf\u30c3\u30c1\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.disable.account=\u00e3\u0081\u0093\u00e3\u0081\u00ae\u00e3\u0082\u00a2\u00e3\u0082\u00ab\u00e3\u0082\u00a6\u00e3\u0083\u00b3\u00e3\u0083\u0088\u00e3\u0082\u0092\u00e7\u0084\u00a1\u00e5\u008a\u00b9\u00e3\u0081\u00ab\u00e3\u0081\u0097\u00e3\u0081\u00a6\u00e3\u0082\u0082\u00e3\u0082\u0088\u00e3\u0082\u008d\u00e3\u0081\u0097\u00e3\u0081\u0084\u00e3\u0081\u00a7\u00e3\u0081\u0099\u00e3\u0081\u008b? \u00e3\u0082\u00a2\u00e3\u0082\u00ab\u00e3\u0082\u00a6\u00e3\u0083\u00b3\u00e3\u0083\u0088\u00e3\u0082\u0092\u00e7\u0084\u00a1\u00e5\u008a\u00b9\u00e3\u0081\u00ab\u00e3\u0081\u0099\u00e3\u0082\u008b\u00e3\u0081\u0093\u00e3\u0081\u00a8\u00e3\u0081\u00ab\u00e3\u0082\u0088\u00e3\u0082\u008a\u00e3\u0080\u0081\u00e3\u0081\u0093\u00e3\u0081\u00ae\u00e3\u0082\u00a2\u00e3\u0082\u00ab\u00e3\u0082\u00a6\u00e3\u0083\u00b3\u00e3\u0083\u0088\u00e3\u0081\u00ae\u00e3\u0081\u0099\u00e3\u0081\u00b9\u00e3\u0081\u00a6\u00e3\u0081\u00ae\u00e3\u0083\u00a6\u00e3\u0083\u00bc\u00e3\u0082\u00b6\u00e3\u0083\u00bc\u00e3\u0081\u00af\u00e3\u0082\u00af\u00e3\u0083\u00a9\u00e3\u0082\u00a6\u00e3\u0083\u0089\u00e3\u0083\u00aa\u00e3\u0082\u00bd\u00e3\u0083\u00bc\u00e3\u0082\u00b9\u00e3\u0081\u00ab\u00e3\u0082\u00a2\u00e3\u0082\u00af\u00e3\u0082\u00bb\u00e3\u0082\u00b9\u00e3\u0081\u00a7\u00e3\u0081\u008d\u00e3\u0081\u00aa\u00e3\u0081\u008f\u00e3\u0081\u00aa\u00e3\u0082\u008a\u00e3\u0081\u00be\u00e3\u0081\u0099\u00e3\u0080\u0082\u00e5\u00ae\u009f\u00e8\u00a1\u008c\u00e4\u00b8\u00ad\u00e3\u0081\u00ae\u00e3\u0081\u0099\u00e3\u0081\u00b9\u00e3\u0081\u00a6\u00e3\u0081\u00ae\u00e4\u00bb\u00ae\u00e6\u0083\u00b3\u00e3\u0083\u009e\u00e3\u0082\u00b7\u00e3\u0083\u00b3\u00e3\u0081\u00af\u00e3\u0081\u0099\u00e3\u0081\u0090\u00e3\u0081\u00ab\u00e3\u0082\u00b7\u00e3\u0083\u00a3\u00e3\u0083\u0083\u00e3\u0083\u0088\u00e3\u0083\u0080\u00e3\u0082\u00a6\u00e3\u0083\u00b3\u00e3\u0081\u0095\u00e3\u0082\u008c\u00e3\u0081\u00be\u00e3\u0081\u0099\u00e3\u0080\u0082 -message.disable.snapshot.policy=\u73FE\u5728\u306E\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8 \u30DD\u30EA\u30B7\u30FC\u3092\u7121\u52B9\u306B\u3057\u307E\u3057\u305F\u3002 -message.disable.user=\u3053\u306E\u30E6\u30FC\u30B6\u30FC\u3092\u7121\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.disable.vpn.access=VPN \u30A2\u30AF\u30BB\u30B9\u3092\u7121\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.disable.vpn=VPN \u3092\u7121\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? +message.disable.snapshot.policy=\u73fe\u5728\u306e\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8 \u30dd\u30ea\u30b7\u30fc\u3092\u7121\u52b9\u306b\u3057\u307e\u3057\u305f\u3002 +message.disable.user=\u3053\u306e\u30e6\u30fc\u30b6\u30fc\u3092\u7121\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.disable.vpn.access=VPN \u30a2\u30af\u30bb\u30b9\u3092\u7121\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.disable.vpn=VPN \u3092\u7121\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.download.ISO=ISO\u00e3\u0082\u0092\u00e3\u0083\u0080\u00e3\u0082\u00a6\u00e3\u0083\u00b3\u00e3\u0083\u00ad\u00e3\u0083\u00bc\u00e3\u0083\u0089\u00e3\u0081\u0099\u00e3\u0082\u008b\u00e3\u0081\u009f\u00e3\u0082\u0081\u00e3\u0081\u00ab00000\u00e3\u0082\u0092\u00e3\u0082\u00af\u00e3\u0083\u00aa\u00e3\u0083\u0083\u00e3\u0082\u00af\u00e3\u0081\u0097\u00e3\u0081\u00a6\u00e3\u0081\u008f\u00e3\u0081\u00a0\u00e3\u0081\u0095\u00e3\u0081\u0084\u00e3\u0080\u0082 message.download.template=\u00e3\u0083\u0086\u00e3\u0083\u00b3\u00e3\u0083\u0097\u00e3\u0083\u00ac\u00e3\u0083\u00bc\u00e3\u0083\u0088\u00e3\u0082\u0092\u00e3\u0083\u0080\u00e3\u0082\u00a6\u00e3\u0083\u00b3\u00e3\u0083\u00ad\u00e3\u0083\u00bc\u00e3\u0083\u0089\u00e3\u0081\u0099\u00e3\u0082\u008b\u00e3\u0081\u009f\u00e3\u0082\u0081\u00e3\u0081\u00ab00000\u00e3\u0082\u0092\u00e3\u0082\u00af\u00e3\u0083\u00aa\u00e3\u0083\u0083\u00e3\u0082\u00af\u00e3\u0081\u0097\u00e3\u0081\u00a6\u00e3\u0081\u008f\u00e3\u0081\u00a0\u00e3\u0081\u0095\u00e3\u0081\u0084\u00e3\u0080\u0082 -message.download.volume.confirm=\u3053\u306E\u30DC\u30EA\u30E5\u30FC\u30E0\u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.download.volume=\u30DC\u30EA\u30E5\u30FC\u30E0\u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u3059\u308B\u306B\u306F 00000 \u3092\u30AF\u30EA\u30C3\u30AF\u3057\u307E\u3059 -message.edit.account=\u7DE8\u96C6 ("-1" \u306F\u3001\u30EA\u30BD\u30FC\u30B9\u4F5C\u6210\u306E\u91CF\u306B\u5236\u9650\u304C\u306A\u3044\u3053\u3068\u3092\u793A\u3057\u307E\u3059) -message.edit.confirm=[\u4FDD\u5B58] \u3092\u30AF\u30EA\u30C3\u30AF\u3059\u308B\u524D\u306B\u5909\u66F4\u5185\u5BB9\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.edit.limits=\u6B21\u306E\u30EA\u30BD\u30FC\u30B9\u306B\u5236\u9650\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u300C-1\u300D\u306F\u3001\u30EA\u30BD\u30FC\u30B9\u4F5C\u6210\u306B\u5236\u9650\u304C\u306A\u3044\u3053\u3068\u3092\u793A\u3057\u307E\u3059\u3002 -message.edit.traffic.type=\u3053\u306E\u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u306E\u7A2E\u985E\u306B\u95A2\u9023\u4ED8\u3051\u308B\u30C8\u30E9\u30D5\u30A3\u30C3\u30AF \u30E9\u30D9\u30EB\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.enable.account=\u3053\u306E\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u6709\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.enabled.vpn.ip.sec=IPSec \u4E8B\u524D\u5171\u6709\u30AD\u30FC\: -message.enabled.vpn=\u73FE\u5728\u3001VPN \u30A2\u30AF\u30BB\u30B9\u304C\u6709\u52B9\u306B\u306A\u3063\u3066\u3044\u307E\u3059\u3002\u6B21\u306E IP \u30A2\u30C9\u30EC\u30B9\u7D4C\u7531\u3067\u30A2\u30AF\u30BB\u30B9\u3067\u304D\u307E\u3059\u3002 -message.enable.user=\u3053\u306E\u30E6\u30FC\u30B6\u30FC\u3092\u6709\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.enable.vpn.access=\u73FE\u5728\u3053\u306E IP \u30A2\u30C9\u30EC\u30B9\u306B\u5BFE\u3059\u308B VPN \u306F\u7121\u52B9\u3067\u3059\u3002VPN \u30A2\u30AF\u30BB\u30B9\u3092\u6709\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.enable.vpn=\u3053\u306E IP \u30A2\u30C9\u30EC\u30B9\u306B\u5BFE\u3059\u308B VPN \u30A2\u30AF\u30BB\u30B9\u3092\u6709\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.enabling.security.group.provider=\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3 \u30B0\u30EB\u30FC\u30D7 \u30D7\u30ED\u30D0\u30A4\u30C0\u30FC\u3092\u6709\u52B9\u306B\u3057\u3066\u3044\u307E\u3059 -message.enabling.zone=\u30BE\u30FC\u30F3\u3092\u6709\u52B9\u306B\u3057\u3066\u3044\u307E\u3059 -message.enter.token=\u96FB\u5B50\u30E1\u30FC\u30EB\u306E\u62DB\u5F85\u72B6\u306B\u8A18\u8F09\u3055\u308C\u3066\u3044\u308B\u30C8\u30FC\u30AF\u30F3\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.generate.keys=\u3053\u306E\u30E6\u30FC\u30B6\u30FC\u306B\u65B0\u3057\u3044\u30AD\u30FC\u3092\u751F\u6210\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.guest.traffic.in.advanced.zone=\u30B2\u30B9\u30C8 \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u306F\u3001\u30A8\u30F3\u30C9 \u30E6\u30FC\u30B6\u30FC\u306E\u4EEE\u60F3\u30DE\u30B7\u30F3\u9593\u306E\u901A\u4FE1\u3067\u3059\u3002\u5404\u7269\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u30B2\u30B9\u30C8 \u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u3092\u901A\u4FE1\u3059\u308B\u305F\u3081\u306E VLAN ID \u306E\u7BC4\u56F2\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.guest.traffic.in.basic.zone=\u30B2\u30B9\u30C8 \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u306F\u3001\u30A8\u30F3\u30C9 \u30E6\u30FC\u30B6\u30FC\u306E\u4EEE\u60F3\u30DE\u30B7\u30F3\u9593\u306E\u901A\u4FE1\u3067\u3059\u3002CloudStack \u3067\u30B2\u30B9\u30C8 VM \u306B\u5272\u308A\u5F53\u3066\u3089\u308C\u308B IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u3053\u306E\u7BC4\u56F2\u304C\u4E88\u7D04\u6E08\u307F\u306E\u30B7\u30B9\u30C6\u30E0 IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2\u3068\u91CD\u8907\u3057\u306A\u3044\u3088\u3046\u306B\u6CE8\u610F\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.installWizard.click.retry=\u8D77\u52D5\u3092\u518D\u8A66\u884C\u3059\u308B\u306B\u306F\u30DC\u30BF\u30F3\u3092\u30AF\u30EA\u30C3\u30AF\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.installWizard.copy.whatIsAPod=\u901A\u5E38\u30011 \u3064\u306E\u30DD\u30C3\u30C9\u306F\u5358\u4E00\u306E\u30E9\u30C3\u30AF\u3092\u8868\u3057\u307E\u3059\u3002\u540C\u3058\u30DD\u30C3\u30C9\u5185\u306E\u30DB\u30B9\u30C8\u306F\u540C\u3058\u30B5\u30D6\u30CD\u30C3\u30C8\u306B\u542B\u307E\u308C\u307E\u3059\u3002

\u30DD\u30C3\u30C9\u306F CloudStack&\#8482; \u74B0\u5883\u5185\u306E 2 \u756A\u76EE\u306B\u5927\u304D\u306A\u7D44\u7E54\u5358\u4F4D\u3067\u3059\u3002\u30DD\u30C3\u30C9\u306F\u30BE\u30FC\u30F3\u306B\u542B\u307E\u308C\u307E\u3059\u3002\u5404\u30BE\u30FC\u30F3\u306F 1 \u3064\u4EE5\u4E0A\u306E\u30DD\u30C3\u30C9\u3092\u542B\u3080\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002\u57FA\u672C\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3067\u306F\u3001\u30BE\u30FC\u30F3\u5185\u306E\u30DD\u30C3\u30C9\u306F 1 \u3064\u3067\u3059\u3002 -message.installWizard.copy.whatIsAZone=\u30BE\u30FC\u30F3\u306F CloudStack&\#8482; \u74B0\u5883\u5185\u306E\u6700\u5927\u306E\u7D44\u7E54\u5358\u4F4D\u3067\u3059\u30021 \u3064\u306E\u30C7\u30FC\u30BF\u30BB\u30F3\u30BF\u30FC\u5185\u306B\u8907\u6570\u306E\u30BE\u30FC\u30F3\u3092\u8A2D\u5B9A\u3067\u304D\u307E\u3059\u304C\u3001\u901A\u5E38\u3001\u30BE\u30FC\u30F3\u306F\u5358\u4E00\u306E\u30C7\u30FC\u30BF\u30BB\u30F3\u30BF\u30FC\u306B\u76F8\u5F53\u3057\u307E\u3059\u3002\u30A4\u30F3\u30D5\u30E9\u30B9\u30C8\u30E9\u30AF\u30C1\u30E3\u3092\u30BE\u30FC\u30F3\u306B\u7D44\u7E54\u5316\u3059\u308B\u3068\u3001\u30BE\u30FC\u30F3\u3092\u7269\u7406\u7684\u306B\u5206\u96E2\u3057\u3066\u5197\u9577\u5316\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002\u305F\u3068\u3048\u3070\u3001\u5404\u30BE\u30FC\u30F3\u306B\u96FB\u6E90\u3068\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30A2\u30C3\u30D7\u30EA\u30F3\u30AF\u3092\u914D\u5099\u3057\u307E\u3059\u3002\u5FC5\u9808\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u304C\u3001\u30BE\u30FC\u30F3\u306F\u9060\u9694\u5730\u306B\u5206\u6563\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002 -message.installWizard.copy.whatIsSecondaryStorage=\u30BB\u30AB\u30F3\u30C0\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u306F\u30BE\u30FC\u30F3\u3068\u95A2\u9023\u4ED8\u3051\u3089\u308C\u3001\u6B21\u306E\u9805\u76EE\u3092\u683C\u7D0D\u3057\u307E\u3059\u3002
  • \u30C6\u30F3\u30D7\u30EC\u30FC\u30C8 - VM \u306E\u8D77\u52D5\u306B\u4F7F\u7528\u3067\u304D\u308B OS \u30A4\u30E1\u30FC\u30B8\u3067\u3001\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u306E\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u306A\u3069\u8FFD\u52A0\u306E\u69CB\u6210\u3092\u542B\u3081\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002
  • ISO \u30A4\u30E1\u30FC\u30B8 - \u8D77\u52D5\u53EF\u80FD\u307E\u305F\u306F\u8D77\u52D5\u4E0D\u53EF\u306E OS \u30A4\u30E1\u30FC\u30B8\u3067\u3059\u3002
  • \u30C7\u30A3\u30B9\u30AF \u30DC\u30EA\u30E5\u30FC\u30E0\u306E\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8 - VM \u30C7\u30FC\u30BF\u306E\u4FDD\u5B58\u30B3\u30D4\u30FC\u3067\u3059\u3002\u30C7\u30FC\u30BF\u306E\u5FA9\u5143\u307E\u305F\u306F\u65B0\u3057\u3044\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u4F5C\u6210\u306B\u4F7F\u7528\u3067\u304D\u307E\u3059\u3002
-message.installWizard.tooltip.addCluster.name=\u30AF\u30E9\u30B9\u30BF\u30FC\u306E\u540D\u524D\u3067\u3059\u3002CloudStack \u3067\u4F7F\u7528\u3055\u308C\u3066\u3044\u306A\u3044\u3001\u4EFB\u610F\u306E\u30C6\u30AD\u30B9\u30C8\u3092\u6307\u5B9A\u3067\u304D\u307E\u3059\u3002 -message.installWizard.tooltip.addHost.hostname=\u30DB\u30B9\u30C8\u306E DNS \u540D\u307E\u305F\u306F IP \u30A2\u30C9\u30EC\u30B9\u3067\u3059\u3002 -message.installWizard.tooltip.addHost.password=XenServer \u5074\u3067\u6307\u5B9A\u3057\u305F\u3001\u4E0A\u306E\u30E6\u30FC\u30B6\u30FC\u540D\u306B\u5BFE\u3059\u308B\u30D1\u30B9\u30EF\u30FC\u30C9\u3067\u3059\u3002 -message.installWizard.tooltip.addHost.username=\u901A\u5E38\u306F root \u3067\u3059\u3002 -message.installWizard.tooltip.addPod.name=\u30DD\u30C3\u30C9\u306E\u540D\u524D\u3067\u3059\u3002 -message.installWizard.tooltip.addPod.reservedSystemEndIp=\u3053\u308C\u306F\u3001\u30BB\u30AB\u30F3\u30C0\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8 VM \u304A\u3088\u3073\u30B3\u30F3\u30BD\u30FC\u30EB \u30D7\u30ED\u30AD\u30B7 VM \u3092\u7BA1\u7406\u3059\u308B\u305F\u3081\u306B CloudStack \u3067\u4F7F\u7528\u3059\u308B\u3001\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8 \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u5185\u306E IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2\u3067\u3059\u3002\u3053\u308C\u3089\u306E IP \u30A2\u30C9\u30EC\u30B9\u306F\u30B3\u30F3\u30D4\u30E5\u30FC\u30C6\u30A3\u30F3\u30B0 \u30B5\u30FC\u30D0\u30FC\u3068\u540C\u3058\u30B5\u30D6\u30CD\u30C3\u30C8\u304B\u3089\u5272\u308A\u5F53\u3066\u307E\u3059\u3002 -message.installWizard.tooltip.addPod.reservedSystemGateway=\u3053\u306E\u30DD\u30C3\u30C9\u5185\u306E\u30DB\u30B9\u30C8\u306E\u30B2\u30FC\u30C8\u30A6\u30A7\u30A4\u3067\u3059\u3002 -message.installWizard.tooltip.addPod.reservedSystemNetmask=\u30B2\u30B9\u30C8\u306E\u4F7F\u7528\u3059\u308B\u30B5\u30D6\u30CD\u30C3\u30C8\u4E0A\u3067\u4F7F\u7528\u3055\u308C\u308B\u30CD\u30C3\u30C8\u30DE\u30B9\u30AF\u3067\u3059\u3002 -message.installWizard.tooltip.addPod.reservedSystemStartIp=\u3053\u308C\u306F\u3001\u30BB\u30AB\u30F3\u30C0\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8 VM \u304A\u3088\u3073\u30B3\u30F3\u30BD\u30FC\u30EB \u30D7\u30ED\u30AD\u30B7 VM \u3092\u7BA1\u7406\u3059\u308B\u305F\u3081\u306B CloudStack \u3067\u4F7F\u7528\u3059\u308B\u3001\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8 \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u5185\u306E IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2\u3067\u3059\u3002\u3053\u308C\u3089\u306E IP \u30A2\u30C9\u30EC\u30B9\u306F\u30B3\u30F3\u30D4\u30E5\u30FC\u30C6\u30A3\u30F3\u30B0 \u30B5\u30FC\u30D0\u30FC\u3068\u540C\u3058\u30B5\u30D6\u30CD\u30C3\u30C8\u304B\u3089\u5272\u308A\u5F53\u3066\u307E\u3059\u3002 -message.installWizard.tooltip.addPrimaryStorage.name=\u30B9\u30C8\u30EC\u30FC\u30B8 \u30C7\u30D0\u30A4\u30B9\u306E\u540D\u524D\u3067\u3059\u3002 -message.installWizard.tooltip.addPrimaryStorage.path=(NFS \u306E\u5834\u5408) \u30B5\u30FC\u30D0\u30FC\u304B\u3089\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8\u3055\u308C\u305F\u30D1\u30B9\u3067\u3059\u3002(SharedMountPoint \u306E\u5834\u5408) \u30D1\u30B9\u3067\u3059\u3002KVM \u3067\u306F\u3053\u306E\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u304C\u30DE\u30A6\u30F3\u30C8\u3055\u308C\u308B\u5404\u30DB\u30B9\u30C8\u4E0A\u306E\u30D1\u30B9\u3067\u3059\u3002\u305F\u3068\u3048\u3070\u3001/mnt/primary \u3067\u3059\u3002 -message.installWizard.tooltip.addPrimaryStorage.server=(NFS\u3001iSCSI\u3001\u307E\u305F\u306F PreSetup \u306E\u5834\u5408) \u30B9\u30C8\u30EC\u30FC\u30B8 \u30C7\u30D0\u30A4\u30B9\u306E IP \u30A2\u30C9\u30EC\u30B9\u307E\u305F\u306F DNS \u540D\u3067\u3059\u3002 -message.installWizard.tooltip.addSecondaryStorage.nfsServer=\u30BB\u30AB\u30F3\u30C0\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u3092\u30DB\u30B9\u30C8\u3059\u308B NFS \u30B5\u30FC\u30D0\u30FC\u306E IP \u30A2\u30C9\u30EC\u30B9\u3067\u3059\u3002 -message.installWizard.tooltip.addSecondaryStorage.path=\u4E0A\u306B\u6307\u5B9A\u3057\u305F\u30B5\u30FC\u30D0\u30FC\u306B\u5B58\u5728\u3059\u308B\u3001\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8\u3055\u308C\u305F\u30D1\u30B9\u3067\u3059\u3002 -message.installWizard.tooltip.addZone.dns1=\u30BE\u30FC\u30F3\u5185\u306E\u30B2\u30B9\u30C8 VM \u3067\u4F7F\u7528\u3059\u308B DNS \u30B5\u30FC\u30D0\u30FC\u3067\u3059\u3002\u3053\u308C\u3089\u306E DNS \u30B5\u30FC\u30D0\u30FC\u306B\u306F\u3001\u5F8C\u3067\u8FFD\u52A0\u3059\u308B\u30D1\u30D6\u30EA\u30C3\u30AF \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u7D4C\u7531\u3067\u30A2\u30AF\u30BB\u30B9\u3057\u307E\u3059\u3002\u30BE\u30FC\u30F3\u306E\u30D1\u30D6\u30EA\u30C3\u30AF IP \u30A2\u30C9\u30EC\u30B9\u304B\u3089\u3001\u3053\u3053\u3067\u6307\u5B9A\u3059\u308B\u30D1\u30D6\u30EA\u30C3\u30AF DNS \u30B5\u30FC\u30D0\u30FC\u306B\u901A\u4FE1\u3067\u304D\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -message.installWizard.tooltip.addZone.dns2=\u30BE\u30FC\u30F3\u5185\u306E\u30B2\u30B9\u30C8 VM \u3067\u4F7F\u7528\u3059\u308B DNS \u30B5\u30FC\u30D0\u30FC\u3067\u3059\u3002\u3053\u308C\u3089\u306E DNS \u30B5\u30FC\u30D0\u30FC\u306B\u306F\u3001\u5F8C\u3067\u8FFD\u52A0\u3059\u308B\u30D1\u30D6\u30EA\u30C3\u30AF \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u7D4C\u7531\u3067\u30A2\u30AF\u30BB\u30B9\u3057\u307E\u3059\u3002\u30BE\u30FC\u30F3\u306E\u30D1\u30D6\u30EA\u30C3\u30AF IP \u30A2\u30C9\u30EC\u30B9\u304B\u3089\u3001\u3053\u3053\u3067\u6307\u5B9A\u3059\u308B\u30D1\u30D6\u30EA\u30C3\u30AF DNS \u30B5\u30FC\u30D0\u30FC\u306B\u901A\u4FE1\u3067\u304D\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -message.installWizard.tooltip.addZone.internaldns1=\u30BE\u30FC\u30F3\u5185\u306E\u30B7\u30B9\u30C6\u30E0 VM \u3067\u4F7F\u7528\u3059\u308B DNS \u30B5\u30FC\u30D0\u30FC\u3067\u3059\u3002\u3053\u308C\u3089\u306E DNS \u30B5\u30FC\u30D0\u30FC\u306F\u3001\u30B7\u30B9\u30C6\u30E0 VM \u306E\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8 \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30A4\u30F3\u30BF\u30FC\u30D5\u30A7\u30A4\u30B9\u3092\u4ECB\u3057\u3066\u30A2\u30AF\u30BB\u30B9\u3055\u308C\u307E\u3059\u3002\u30DD\u30C3\u30C9\u306E\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8 IP \u30A2\u30C9\u30EC\u30B9\u304B\u3089\u3001\u3053\u3053\u3067\u6307\u5B9A\u3059\u308B DNS \u30B5\u30FC\u30D0\u30FC\u306B\u901A\u4FE1\u3067\u304D\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -message.installWizard.tooltip.addZone.internaldns2=\u30BE\u30FC\u30F3\u5185\u306E\u30B7\u30B9\u30C6\u30E0 VM \u3067\u4F7F\u7528\u3059\u308B DNS \u30B5\u30FC\u30D0\u30FC\u3067\u3059\u3002\u3053\u308C\u3089\u306E DNS \u30B5\u30FC\u30D0\u30FC\u306F\u3001\u30B7\u30B9\u30C6\u30E0 VM \u306E\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8 \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30A4\u30F3\u30BF\u30FC\u30D5\u30A7\u30A4\u30B9\u3092\u4ECB\u3057\u3066\u30A2\u30AF\u30BB\u30B9\u3055\u308C\u307E\u3059\u3002\u30DD\u30C3\u30C9\u306E\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8 IP \u30A2\u30C9\u30EC\u30B9\u304B\u3089\u3001\u3053\u3053\u3067\u6307\u5B9A\u3059\u308B DNS \u30B5\u30FC\u30D0\u30FC\u306B\u901A\u4FE1\u3067\u304D\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -message.installWizard.tooltip.addZone.name=\u30BE\u30FC\u30F3\u306E\u540D\u524D\u3067\u3059\u3002 -message.installWizard.tooltip.configureGuestTraffic.description=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u8AAC\u660E\u3067\u3059\u3002 -message.installWizard.tooltip.configureGuestTraffic.guestEndIp=\u3053\u306E\u30BE\u30FC\u30F3\u306E\u30B2\u30B9\u30C8\u306B\u5272\u308A\u5F53\u3066\u308B\u3053\u3068\u304C\u3067\u304D\u308B IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2\u3067\u3059\u3002\u4F7F\u7528\u3059\u308B NIC \u304C 1 \u3064\u306E\u5834\u5408\u306F\u3001\u3053\u308C\u3089\u306E IP \u30A2\u30C9\u30EC\u30B9\u306F\u30DD\u30C3\u30C9\u306E CIDR \u3068\u540C\u3058 CIDR \u306B\u542B\u307E\u308C\u3066\u3044\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -message.installWizard.tooltip.configureGuestTraffic.guestGateway=\u30B2\u30B9\u30C8\u306E\u4F7F\u7528\u3059\u308B\u30B2\u30FC\u30C8\u30A6\u30A7\u30A4\u3067\u3059\u3002 -message.installWizard.tooltip.configureGuestTraffic.guestNetmask=\u30B2\u30B9\u30C8\u306E\u4F7F\u7528\u3059\u308B\u30B5\u30D6\u30CD\u30C3\u30C8\u4E0A\u3067\u4F7F\u7528\u3055\u308C\u308B\u30CD\u30C3\u30C8\u30DE\u30B9\u30AF\u3067\u3059\u3002 -message.installWizard.tooltip.configureGuestTraffic.guestStartIp=\u3053\u306E\u30BE\u30FC\u30F3\u306E\u30B2\u30B9\u30C8\u306B\u5272\u308A\u5F53\u3066\u308B\u3053\u3068\u304C\u3067\u304D\u308B IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2\u3067\u3059\u3002\u4F7F\u7528\u3059\u308B NIC \u304C 1 \u3064\u306E\u5834\u5408\u306F\u3001\u3053\u308C\u3089\u306E IP \u30A2\u30C9\u30EC\u30B9\u306F\u30DD\u30C3\u30C9\u306E CIDR \u3068\u540C\u3058 CIDR \u306B\u542B\u307E\u308C\u3066\u3044\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -message.installWizard.tooltip.configureGuestTraffic.name=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u540D\u524D\u3067\u3059\u3002 -message.instanceWizard.noTemplates=\u4F7F\u7528\u53EF\u80FD\u306A\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u304C\u3042\u308A\u307E\u305B\u3093\u3002\u4E92\u63DB\u6027\u306E\u3042\u308B\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3092\u8FFD\u52A0\u3057\u3066\u3001\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9 \u30A6\u30A3\u30B6\u30FC\u30C9\u3092\u518D\u8D77\u52D5\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.ip.address.changed=\u304A\u4F7F\u3044\u306E IP \u30A2\u30C9\u30EC\u30B9\u304C\u5909\u66F4\u3055\u308C\u3066\u3044\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002\u4E00\u89A7\u3092\u66F4\u65B0\u3057\u307E\u3059\u304B? \u305D\u306E\u5834\u5408\u306F\u3001\u8A73\u7D30\u30DA\u30A4\u30F3\u304C\u9589\u3058\u308B\u3053\u3068\u306B\u6CE8\u610F\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.iso.desc=\u30C7\u30FC\u30BF\u307E\u305F\u306F OS \u8D77\u52D5\u53EF\u80FD\u30E1\u30C7\u30A3\u30A2\u3092\u542B\u3080\u30C7\u30A3\u30B9\u30AF \u30A4\u30E1\u30FC\u30B8 -message.join.project=\u3053\u308C\u3067\u3001\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306B\u53C2\u52A0\u3057\u307E\u3057\u305F\u3002\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u53C2\u7167\u3059\u308B\u306B\u306F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8 \u30D3\u30E5\u30FC\u306B\u5207\u308A\u66FF\u3048\u3066\u304F\u3060\u3055\u3044\u3002 -message.launch.zone=\u30BE\u30FC\u30F3\u3092\u8D77\u52D5\u3059\u308B\u6E96\u5099\u304C\u3067\u304D\u307E\u3057\u305F\u3002\u6B21\u306E\u624B\u9806\u306B\u9032\u3093\u3067\u304F\u3060\u3055\u3044\u3002 -message.lock.account=\u3053\u306E\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u30ED\u30C3\u30AF\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? \u3053\u306E\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u3059\u3079\u3066\u306E\u30E6\u30FC\u30B6\u30FC\u304C\u30AF\u30E9\u30A6\u30C9 \u30EA\u30BD\u30FC\u30B9\u3092\u7BA1\u7406\u3067\u304D\u306A\u304F\u306A\u308A\u307E\u3059\u3002\u305D\u306E\u5F8C\u3082\u65E2\u5B58\u306E\u30EA\u30BD\u30FC\u30B9\u306B\u306F\u30A2\u30AF\u30BB\u30B9\u3067\u304D\u307E\u3059\u3002 -message.migrate.instance.confirm=\u4EEE\u60F3\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u79FB\u884C\u5148\u306F\u6B21\u306E\u30DB\u30B9\u30C8\u3067\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.migrate.instance.to.host=\u5225\u306E\u30DB\u30B9\u30C8\u306B\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u79FB\u884C\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.migrate.instance.to.ps=\u5225\u306E\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u306B\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u79FB\u884C\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.migrate.router.confirm=\u30EB\u30FC\u30BF\u30FC\u306E\u79FB\u884C\u5148\u306F\u6B21\u306E\u30DB\u30B9\u30C8\u3067\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.migrate.systemvm.confirm=\u30B7\u30B9\u30C6\u30E0 VM \u306E\u79FB\u884C\u5148\u306F\u6B21\u306E\u30DB\u30B9\u30C8\u3067\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.migrate.volume=\u5225\u306E\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u306B\u30DC\u30EA\u30E5\u30FC\u30E0\u3092\u79FB\u884C\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.new.user=\u00e3\u0082\u00a2\u00e3\u0082\u00ab\u00e3\u0082\u00a6\u00e3\u0083\u00b3\u00e3\u0083\u0088\u00e3\u0081\u00ab\u00e6\u0096\u00b0\u00e3\u0081\u0097\u00e3\u0081\u0084\u00e3\u0083\u00a6\u00e3\u0083\u00bc\u00e3\u0082\u00b6\u00e3\u0083\u00bc\u00e3\u0082\u0092\u00e8\u00bf\u00bd\u00e5\u008a\u00a0\u00e3\u0081\u0099\u00e3\u0082\u008b\u00e3\u0081\u009f\u00e3\u0082\u0081\u00e3\u0081\u00ab\u00e3\u0080\u0081\u00e6\u00ac\u00a1\u00e3\u0081\u00ae\u00e6\u0083\u0085\u00e5\u00a0\u00b1\u00e3\u0082\u0092\u00e8\u00a8\u00ad\u00e5\u00ae\u009a\u00e3\u0081\u0097\u00e3\u0081\u00a6\u00e3\u0081\u008f\u00e3\u0081\u00a0\u00e3\u0081\u0095\u00e3\u0081\u0084 -message.no.network.support.configuration.not.true=\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3 \u30B0\u30EB\u30FC\u30D7\u304C\u6709\u52B9\u306A\u30BE\u30FC\u30F3\u304C\u7121\u3044\u305F\u3081\u3001\u8FFD\u52A0\u306E\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u6A5F\u80FD\u306F\u3042\u308A\u307E\u305B\u3093\u3002\u624B\u9806 5. \u306B\u9032\u3093\u3067\u304F\u3060\u3055\u3044\u3002 -message.no.network.support=\u30CF\u30A4\u30D1\u30FC\u30D0\u30A4\u30B6\u30FC\u3068\u3057\u3066 vSphere \u3092\u9078\u629E\u3057\u307E\u3057\u305F\u304C\u3001\u3053\u306E\u30CF\u30A4\u30D1\u30FC\u30D0\u30A4\u30B6\u30FC\u306B\u8FFD\u52A0\u306E\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u6A5F\u80FD\u306F\u3042\u308A\u307E\u305B\u3093\u3002\u624B\u9806 5. \u306B\u9032\u3093\u3067\u304F\u3060\u3055\u3044\u3002 -message.no.projects.adminOnly=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u304C\u3042\u308A\u307E\u305B\u3093\u3002
\u7BA1\u7406\u8005\u306B\u65B0\u3057\u3044\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u4F5C\u6210\u3092\u4F9D\u983C\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.no.projects=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u304C\u3042\u308A\u307E\u305B\u3093\u3002
\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8 \u30BB\u30AF\u30B7\u30E7\u30F3\u304B\u3089\u65B0\u3057\u3044\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u4F5C\u6210\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.number.clusters=

\u30AF\u30E9\u30B9\u30BF\u30FC\u6570

-message.number.hosts=

\u30DB\u30B9\u30C8\u6570

-message.number.pods=

\u30DD\u30C3\u30C9\u6570

-message.number.storage=

\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8 \u30DC\u30EA\u30E5\u30FC\u30E0\u6570

-message.number.zones=

\u30BE\u30FC\u30F3\u6570

-message.pending.projects.1=\u4FDD\u7559\u4E2D\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u62DB\u5F85\u72B6\u304C\u3042\u308A\u307E\u3059\u3002 -message.pending.projects.2=\u8868\u793A\u3059\u308B\u306B\u306F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8 \u30BB\u30AF\u30B7\u30E7\u30F3\u306B\u79FB\u52D5\u3057\u3066\u3001\u4E00\u89A7\u304B\u3089\u62DB\u5F85\u72B6\u3092\u9078\u629E\u3057\u307E\u3059\u3002 -message.please.add.at.lease.one.traffic.range=\u5C11\u306A\u304F\u3068\u3082 1 \u3064\u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u306E\u7BC4\u56F2\u3092\u8FFD\u52A0\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.please.proceed=\u6B21\u306E\u624B\u9806\u306B\u9032\u3093\u3067\u304F\u3060\u3055\u3044\u3002 -message.please.select.a.configuration.for.your.zone=\u30BE\u30FC\u30F3\u306E\u69CB\u6210\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.please.select.a.different.public.and.management.network.before.removing=\u524A\u9664\u306E\u524D\u306B\u7570\u306A\u308B\u30D1\u30D6\u30EA\u30C3\u30AF\u304A\u3088\u3073\u7BA1\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.please.select.networks=\u4EEE\u60F3\u30DE\u30B7\u30F3\u306E\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.please.wait.while.zone.is.being.created=\u30BE\u30FC\u30F3\u304C\u4F5C\u6210\u3055\u308C\u308B\u307E\u3067\u3057\u3070\u3089\u304F\u304A\u5F85\u3061\u304F\u3060\u3055\u3044... -message.project.invite.sent=\u30E6\u30FC\u30B6\u30FC\u306B\u62DB\u5F85\u72B6\u304C\u9001\u4FE1\u3055\u308C\u307E\u3057\u305F\u3002\u30E6\u30FC\u30B6\u30FC\u304C\u62DB\u5F85\u3092\u627F\u8AFE\u3059\u308B\u3068\u3001\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306B\u8FFD\u52A0\u3055\u308C\u307E\u3059\u3002 -message.public.traffic.in.advanced.zone=\u30AF\u30E9\u30A6\u30C9\u5185\u306E VM \u304C\u30A4\u30F3\u30BF\u30FC\u30CD\u30C3\u30C8\u306B\u30A2\u30AF\u30BB\u30B9\u3059\u308B\u3068\u3001\u30D1\u30D6\u30EA\u30C3\u30AF \u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u304C\u751F\u6210\u3055\u308C\u307E\u3059\u3002\u3053\u306E\u305F\u3081\u306B\u3001\u4E00\u822C\u306B\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A IP \u30A2\u30C9\u30EC\u30B9\u3092\u5272\u308A\u5F53\u3066\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002\u30A8\u30F3\u30C9 \u30E6\u30FC\u30B6\u30FC\u306F CloudStack \u306E\u30E6\u30FC\u30B6\u30FC \u30A4\u30F3\u30BF\u30FC\u30D5\u30A7\u30A4\u30B9\u3092\u4F7F\u7528\u3057\u3066\u3053\u308C\u3089\u306E IP \u30A2\u30C9\u30EC\u30B9\u3092\u53D6\u5F97\u3057\u3001\u30B2\u30B9\u30C8 \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3068\u30D1\u30D6\u30EA\u30C3\u30AF \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u9593\u306B NAT \u3092\u5B9F\u88C5\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002

\u30A4\u30F3\u30BF\u30FC\u30CD\u30C3\u30C8 \u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u306E\u305F\u3081\u306B\u3001\u5C11\u306A\u304F\u3068\u3082 1 \u3064 IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.public.traffic.in.basic.zone=\u30AF\u30E9\u30A6\u30C9\u5185\u306E VM \u304C\u30A4\u30F3\u30BF\u30FC\u30CD\u30C3\u30C8\u306B\u30A2\u30AF\u30BB\u30B9\u3059\u308B\u304B\u30A4\u30F3\u30BF\u30FC\u30CD\u30C3\u30C8\u7D4C\u7531\u3067\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u306B\u30B5\u30FC\u30D3\u30B9\u3092\u63D0\u4F9B\u3059\u308B\u3068\u3001\u30D1\u30D6\u30EA\u30C3\u30AF \u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u304C\u751F\u6210\u3055\u308C\u307E\u3059\u3002\u3053\u306E\u305F\u3081\u306B\u3001\u4E00\u822C\u306B\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A IP \u30A2\u30C9\u30EC\u30B9\u3092\u5272\u308A\u5F53\u3066\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u4F5C\u6210\u3059\u308B\u3068\u3001\u30B2\u30B9\u30C8 IP \u30A2\u30C9\u30EC\u30B9\u306E\u307B\u304B\u306B\u3053\u306E\u30D1\u30D6\u30EA\u30C3\u30AF IP \u30A2\u30C9\u30EC\u30B9\u306E\u7BC4\u56F2\u304B\u3089\u30A2\u30C9\u30EC\u30B9\u304C 1 \u3064\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306B\u5272\u308A\u5F53\u3066\u3089\u308C\u307E\u3059\u3002\u30D1\u30D6\u30EA\u30C3\u30AF IP \u30A2\u30C9\u30EC\u30B9\u3068\u30B2\u30B9\u30C8 IP \u30A2\u30C9\u30EC\u30B9\u306E\u9593\u306B\u3001\u9759\u7684\u306A 1 \u5BFE 1 \u306E NAT \u304C\u81EA\u52D5\u7684\u306B\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3055\u308C\u307E\u3059\u3002\u30A8\u30F3\u30C9 \u30E6\u30FC\u30B6\u30FC\u306F CloudStack \u306E\u30E6\u30FC\u30B6\u30FC \u30A4\u30F3\u30BF\u30FC\u30D5\u30A7\u30A4\u30B9\u3092\u4F7F\u7528\u3057\u3066\u8FFD\u52A0\u306E IP \u30A2\u30C9\u30EC\u30B9\u3092\u53D6\u5F97\u3057\u3001\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3068\u30D1\u30D6\u30EA\u30C3\u30AF IP \u30A2\u30C9\u30EC\u30B9\u306E\u9593\u306B\u9759\u7684 NAT \u3092\u5B9F\u88C5\u3059\u308B\u3053\u3068\u3082\u3067\u304D\u307E\u3059\u3002 -message.remove.vpc=VPC \u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.remove.vpn.access=\u6B21\u306E\u30E6\u30FC\u30B6\u30FC\u304B\u3089 VPN \u30A2\u30AF\u30BB\u30B9\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.reset.password.warning.notPasswordEnabled=\u3053\u306E\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306F\u3001\u30D1\u30B9\u30EF\u30FC\u30C9\u7BA1\u7406\u3092\u6709\u52B9\u306B\u305B\u305A\u306B\u4F5C\u6210\u3055\u308C\u307E\u3057\u305F\u3002 -message.reset.password.warning.notStopped=\u73FE\u5728\u306E\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u5909\u66F4\u3059\u308B\u524D\u306B\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u505C\u6B62\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -message.reset.VPN.connection=VPN \u63A5\u7D9A\u3092\u30EA\u30BB\u30C3\u30C8\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.restart.mgmt.server=\u65B0\u3057\u3044\u8A2D\u5B9A\u3092\u6709\u52B9\u306B\u3059\u308B\u305F\u3081\u306B\u3001\u7BA1\u7406\u30B5\u30FC\u30D0\u30FC\u3092\u518D\u8D77\u52D5\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.restart.mgmt.usage.server=\u65B0\u3057\u3044\u8A2D\u5B9A\u3092\u6709\u52B9\u306B\u3059\u308B\u305F\u3081\u306B\u3001\u7BA1\u7406\u30B5\u30FC\u30D0\u30FC\u3068\u4F7F\u7528\u72B6\u6CC1\u6E2C\u5B9A\u30B5\u30FC\u30D0\u30FC\u3092\u518D\u8D77\u52D5\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.restart.network=\u3053\u306E\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3067\u63D0\u4F9B\u3059\u308B\u3059\u3079\u3066\u306E\u30B5\u30FC\u30D3\u30B9\u304C\u4E2D\u65AD\u3055\u308C\u307E\u3059\u3002\u3053\u306E\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u518D\u8D77\u52D5\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.restart.vpc=VPC \u3092\u518D\u8D77\u52D5\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.security.group.usage=(\u8A72\u5F53\u3059\u308B\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3 \u30B0\u30EB\u30FC\u30D7\u3092\u3059\u3079\u3066\u9078\u629E\u3059\u308B\u306B\u306F\u3001Ctrl \u30AD\u30FC\u3092\u62BC\u3057\u306A\u304C\u3089\u30AF\u30EA\u30C3\u30AF\u3057\u3066\u304F\u3060\u3055\u3044) -message.select.a.zone=\u30BE\u30FC\u30F3\u306F\u901A\u5E38\u3001\u5358\u4E00\u306E\u30C7\u30FC\u30BF\u30BB\u30F3\u30BF\u30FC\u306B\u76F8\u5F53\u3057\u307E\u3059\u3002\u8907\u6570\u306E\u30BE\u30FC\u30F3\u3092\u8A2D\u5B9A\u3057\u3001\u7269\u7406\u7684\u306B\u5206\u96E2\u3057\u3066\u5197\u9577\u6027\u3092\u6301\u305F\u305B\u308B\u3053\u3068\u306B\u3088\u308A\u3001\u30AF\u30E9\u30A6\u30C9\u306E\u4FE1\u983C\u6027\u3092\u9AD8\u3081\u307E\u3059\u3002 -message.select.instance=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.select.iso=\u65B0\u3057\u3044\u4EEE\u60F3\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E ISO \u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.select.item=\u9805\u76EE\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.select.security.groups=\u65B0\u3057\u3044\u4EEE\u60F3\u30DE\u30B7\u30F3\u306E\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3 \u30B0\u30EB\u30FC\u30D7\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.select.template=\u65B0\u3057\u3044\u4EEE\u60F3\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.setup.physical.network.during.zone.creation.basic=\u57FA\u672C\u30BE\u30FC\u30F3\u3092\u8FFD\u52A0\u3059\u308B\u3068\u304D\u306F\u3001\u30CF\u30A4\u30D1\u30FC\u30D0\u30A4\u30B6\u30FC\u4E0A\u306E NIC \u306B\u5BFE\u5FDC\u3059\u308B 1 \u3064\u306E\u7269\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3067\u304D\u307E\u3059\u3002\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306F\u3044\u304F\u3064\u304B\u306E\u7A2E\u985E\u306E\u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u3092\u4F1D\u9001\u3057\u307E\u3059\u3002

\u7269\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306B\u307B\u304B\u306E\u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u306E\u7A2E\u985E\u3092\u30C9\u30E9\u30C3\u30B0 \u30A2\u30F3\u30C9 \u30C9\u30ED\u30C3\u30D7\u3059\u308B\u3053\u3068\u3082\u3067\u304D\u307E\u3059\u3002 -message.setup.physical.network.during.zone.creation=\u62E1\u5F35\u30BE\u30FC\u30F3\u3092\u8FFD\u52A0\u3059\u308B\u3068\u304D\u306F\u30011 \u3064\u4EE5\u4E0A\u306E\u7269\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002\u5404\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306F\u30CF\u30A4\u30D1\u30FC\u30D0\u30A4\u30B6\u30FC\u4E0A\u306E 1 \u3064\u306E NIC \u306B\u5BFE\u5FDC\u3057\u307E\u3059\u3002\u5404\u7269\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3067\u306F\u3001\u7D44\u307F\u5408\u308F\u305B\u306B\u5236\u9650\u304C\u3042\u308A\u307E\u3059\u304C\u30011 \u3064\u4EE5\u4E0A\u306E\u7A2E\u985E\u306E\u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u3092\u901A\u4FE1\u3067\u304D\u307E\u3059\u3002

\u5404\u7269\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306B\u5BFE\u3057\u3066\u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u306E\u7A2E\u985E\u3092\u30C9\u30E9\u30C3\u30B0 \u30A2\u30F3\u30C9 \u30C9\u30ED\u30C3\u30D7\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.setup.successful=\u30AF\u30E9\u30A6\u30C9\u304C\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3055\u308C\u307E\u3057\u305F\u3002 -message.snapshot.schedule=\u6B21\u306E\u30AA\u30D7\u30B7\u30E7\u30F3\u304B\u3089\u9078\u629E\u3057\u3066\u30DD\u30EA\u30B7\u30FC\u306E\u57FA\u672C\u8A2D\u5B9A\u3092\u9069\u7528\u3059\u308B\u3053\u3068\u306B\u3088\u308A\u3001\u5B9A\u671F\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u306E\u30B9\u30B1\u30B8\u30E5\u30FC\u30EB\u3092\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3067\u304D\u307E\u3059\u3002 -message.specify.url=URL \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044 -message.step.1.continue=\u7D9A\u884C\u3059\u308B\u306B\u306F\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u307E\u305F\u306F ISO \u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044 -message.step.1.desc=\u65B0\u3057\u3044\u4EEE\u60F3\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u7528\u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002ISO \u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3067\u304D\u308B\u7A7A\u767D\u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3092\u9078\u629E\u3059\u308B\u3053\u3068\u3082\u3067\u304D\u307E\u3059\u3002 -message.step.2.continue=\u7D9A\u884C\u3059\u308B\u306B\u306F\u30B5\u30FC\u30D3\u30B9 \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044 +message.download.volume.confirm=\u3053\u306e\u30dc\u30ea\u30e5\u30fc\u30e0\u3092\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.download.volume=\u30dc\u30ea\u30e5\u30fc\u30e0\u3092\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3059\u308b\u306b\u306f 00000 \u3092\u30af\u30ea\u30c3\u30af\u3057\u307e\u3059 +message.edit.account=\u7de8\u96c6 ("-1" \u306f\u3001\u30ea\u30bd\u30fc\u30b9\u4f5c\u6210\u306e\u91cf\u306b\u5236\u9650\u304c\u306a\u3044\u3053\u3068\u3092\u793a\u3057\u307e\u3059) +message.edit.confirm=[\u4fdd\u5b58] \u3092\u30af\u30ea\u30c3\u30af\u3059\u308b\u524d\u306b\u5909\u66f4\u5185\u5bb9\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.edit.limits=\u6b21\u306e\u30ea\u30bd\u30fc\u30b9\u306b\u5236\u9650\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u300c-1\u300d\u306f\u3001\u30ea\u30bd\u30fc\u30b9\u4f5c\u6210\u306b\u5236\u9650\u304c\u306a\u3044\u3053\u3068\u3092\u793a\u3057\u307e\u3059\u3002 +message.edit.traffic.type=\u3053\u306e\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e\u7a2e\u985e\u306b\u95a2\u9023\u4ed8\u3051\u308b\u30c8\u30e9\u30d5\u30a3\u30c3\u30af \u30e9\u30d9\u30eb\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.enable.account=\u3053\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.enabled.vpn.ip.sec=IPSec \u4e8b\u524d\u5171\u6709\u30ad\u30fc\: +message.enabled.vpn=\u73fe\u5728\u3001VPN \u30a2\u30af\u30bb\u30b9\u304c\u6709\u52b9\u306b\u306a\u3063\u3066\u3044\u307e\u3059\u3002\u6b21\u306e IP \u30a2\u30c9\u30ec\u30b9\u7d4c\u7531\u3067\u30a2\u30af\u30bb\u30b9\u3067\u304d\u307e\u3059\u3002 +message.enable.user=\u3053\u306e\u30e6\u30fc\u30b6\u30fc\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.enable.vpn.access=\u73fe\u5728\u3053\u306e IP \u30a2\u30c9\u30ec\u30b9\u306b\u5bfe\u3059\u308b VPN \u306f\u7121\u52b9\u3067\u3059\u3002VPN \u30a2\u30af\u30bb\u30b9\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.enable.vpn=\u3053\u306e IP \u30a2\u30c9\u30ec\u30b9\u306b\u5bfe\u3059\u308b VPN \u30a2\u30af\u30bb\u30b9\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.enabling.security.group.provider=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7 \u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u3092\u6709\u52b9\u306b\u3057\u3066\u3044\u307e\u3059 +message.enabling.zone=\u30be\u30fc\u30f3\u3092\u6709\u52b9\u306b\u3057\u3066\u3044\u307e\u3059 +message.enter.token=\u96fb\u5b50\u30e1\u30fc\u30eb\u306e\u62db\u5f85\u72b6\u306b\u8a18\u8f09\u3055\u308c\u3066\u3044\u308b\u30c8\u30fc\u30af\u30f3\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.generate.keys=\u3053\u306e\u30e6\u30fc\u30b6\u30fc\u306b\u65b0\u3057\u3044\u30ad\u30fc\u3092\u751f\u6210\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.guest.traffic.in.advanced.zone=\u30b2\u30b9\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306f\u3001\u30a8\u30f3\u30c9 \u30e6\u30fc\u30b6\u30fc\u306e\u4eee\u60f3\u30de\u30b7\u30f3\u9593\u306e\u901a\u4fe1\u3067\u3059\u3002\u5404\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u30b2\u30b9\u30c8 \u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u3092\u901a\u4fe1\u3059\u308b\u305f\u3081\u306e VLAN ID \u306e\u7bc4\u56f2\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.guest.traffic.in.basic.zone=\u30b2\u30b9\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306f\u3001\u30a8\u30f3\u30c9 \u30e6\u30fc\u30b6\u30fc\u306e\u4eee\u60f3\u30de\u30b7\u30f3\u9593\u306e\u901a\u4fe1\u3067\u3059\u3002CloudStack \u3067\u30b2\u30b9\u30c8 VM \u306b\u5272\u308a\u5f53\u3066\u3089\u308c\u308b IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u3053\u306e\u7bc4\u56f2\u304c\u4e88\u7d04\u6e08\u307f\u306e\u30b7\u30b9\u30c6\u30e0 IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u3068\u91cd\u8907\u3057\u306a\u3044\u3088\u3046\u306b\u6ce8\u610f\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.installWizard.click.retry=\u8d77\u52d5\u3092\u518d\u8a66\u884c\u3059\u308b\u306b\u306f\u30dc\u30bf\u30f3\u3092\u30af\u30ea\u30c3\u30af\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.installWizard.copy.whatIsAPod=\u901a\u5e38\u30011 \u3064\u306e\u30dd\u30c3\u30c9\u306f\u5358\u4e00\u306e\u30e9\u30c3\u30af\u3092\u8868\u3057\u307e\u3059\u3002\u540c\u3058\u30dd\u30c3\u30c9\u5185\u306e\u30db\u30b9\u30c8\u306f\u540c\u3058\u30b5\u30d6\u30cd\u30c3\u30c8\u306b\u542b\u307e\u308c\u307e\u3059\u3002

\u30dd\u30c3\u30c9\u306f CloudStack&\#8482; \u74b0\u5883\u5185\u306e 2 \u756a\u76ee\u306b\u5927\u304d\u306a\u7d44\u7e54\u5358\u4f4d\u3067\u3059\u3002\u30dd\u30c3\u30c9\u306f\u30be\u30fc\u30f3\u306b\u542b\u307e\u308c\u307e\u3059\u3002\u5404\u30be\u30fc\u30f3\u306f 1 \u3064\u4ee5\u4e0a\u306e\u30dd\u30c3\u30c9\u3092\u542b\u3080\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002\u57fa\u672c\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3067\u306f\u3001\u30be\u30fc\u30f3\u5185\u306e\u30dd\u30c3\u30c9\u306f 1 \u3064\u3067\u3059\u3002 +message.installWizard.copy.whatIsAZone=\u30be\u30fc\u30f3\u306f CloudStack&\#8482; \u74b0\u5883\u5185\u306e\u6700\u5927\u306e\u7d44\u7e54\u5358\u4f4d\u3067\u3059\u30021 \u3064\u306e\u30c7\u30fc\u30bf\u30bb\u30f3\u30bf\u30fc\u5185\u306b\u8907\u6570\u306e\u30be\u30fc\u30f3\u3092\u8a2d\u5b9a\u3067\u304d\u307e\u3059\u304c\u3001\u901a\u5e38\u3001\u30be\u30fc\u30f3\u306f\u5358\u4e00\u306e\u30c7\u30fc\u30bf\u30bb\u30f3\u30bf\u30fc\u306b\u76f8\u5f53\u3057\u307e\u3059\u3002\u30a4\u30f3\u30d5\u30e9\u30b9\u30c8\u30e9\u30af\u30c1\u30e3\u3092\u30be\u30fc\u30f3\u306b\u7d44\u7e54\u5316\u3059\u308b\u3068\u3001\u30be\u30fc\u30f3\u3092\u7269\u7406\u7684\u306b\u5206\u96e2\u3057\u3066\u5197\u9577\u5316\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002\u305f\u3068\u3048\u3070\u3001\u5404\u30be\u30fc\u30f3\u306b\u96fb\u6e90\u3068\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30a2\u30c3\u30d7\u30ea\u30f3\u30af\u3092\u914d\u5099\u3057\u307e\u3059\u3002\u5fc5\u9808\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u304c\u3001\u30be\u30fc\u30f3\u306f\u9060\u9694\u5730\u306b\u5206\u6563\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002 +message.installWizard.copy.whatIsSecondaryStorage=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u306f\u30be\u30fc\u30f3\u3068\u95a2\u9023\u4ed8\u3051\u3089\u308c\u3001\u6b21\u306e\u9805\u76ee\u3092\u683c\u7d0d\u3057\u307e\u3059\u3002
  • \u30c6\u30f3\u30d7\u30ec\u30fc\u30c8 - VM \u306e\u8d77\u52d5\u306b\u4f7f\u7528\u3067\u304d\u308b OS \u30a4\u30e1\u30fc\u30b8\u3067\u3001\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u306a\u3069\u8ffd\u52a0\u306e\u69cb\u6210\u3092\u542b\u3081\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002
  • ISO \u30a4\u30e1\u30fc\u30b8 - \u8d77\u52d5\u53ef\u80fd\u307e\u305f\u306f\u8d77\u52d5\u4e0d\u53ef\u306e OS \u30a4\u30e1\u30fc\u30b8\u3067\u3059\u3002
  • \u30c7\u30a3\u30b9\u30af \u30dc\u30ea\u30e5\u30fc\u30e0\u306e\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8 - VM \u30c7\u30fc\u30bf\u306e\u4fdd\u5b58\u30b3\u30d4\u30fc\u3067\u3059\u3002\u30c7\u30fc\u30bf\u306e\u5fa9\u5143\u307e\u305f\u306f\u65b0\u3057\u3044\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u4f5c\u6210\u306b\u4f7f\u7528\u3067\u304d\u307e\u3059\u3002
+message.installWizard.tooltip.addCluster.name=\u30af\u30e9\u30b9\u30bf\u30fc\u306e\u540d\u524d\u3067\u3059\u3002CloudStack \u3067\u4f7f\u7528\u3055\u308c\u3066\u3044\u306a\u3044\u3001\u4efb\u610f\u306e\u30c6\u30ad\u30b9\u30c8\u3092\u6307\u5b9a\u3067\u304d\u307e\u3059\u3002 +message.installWizard.tooltip.addHost.hostname=\u30db\u30b9\u30c8\u306e DNS \u540d\u307e\u305f\u306f IP \u30a2\u30c9\u30ec\u30b9\u3067\u3059\u3002 +message.installWizard.tooltip.addHost.password=XenServer \u5074\u3067\u6307\u5b9a\u3057\u305f\u3001\u4e0a\u306e\u30e6\u30fc\u30b6\u30fc\u540d\u306b\u5bfe\u3059\u308b\u30d1\u30b9\u30ef\u30fc\u30c9\u3067\u3059\u3002 +message.installWizard.tooltip.addHost.username=\u901a\u5e38\u306f root \u3067\u3059\u3002 +message.installWizard.tooltip.addPod.name=\u30dd\u30c3\u30c9\u306e\u540d\u524d\u3067\u3059\u3002 +message.installWizard.tooltip.addPod.reservedSystemEndIp=\u3053\u308c\u306f\u3001\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 VM \u304a\u3088\u3073\u30b3\u30f3\u30bd\u30fc\u30eb \u30d7\u30ed\u30ad\u30b7 VM \u3092\u7ba1\u7406\u3059\u308b\u305f\u3081\u306b CloudStack \u3067\u4f7f\u7528\u3059\u308b\u3001\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u5185\u306e IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u3067\u3059\u3002\u3053\u308c\u3089\u306e IP \u30a2\u30c9\u30ec\u30b9\u306f\u30b3\u30f3\u30d4\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0 \u30b5\u30fc\u30d0\u30fc\u3068\u540c\u3058\u30b5\u30d6\u30cd\u30c3\u30c8\u304b\u3089\u5272\u308a\u5f53\u3066\u307e\u3059\u3002 +message.installWizard.tooltip.addPod.reservedSystemGateway=\u3053\u306e\u30dd\u30c3\u30c9\u5185\u306e\u30db\u30b9\u30c8\u306e\u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u3067\u3059\u3002 +message.installWizard.tooltip.addPod.reservedSystemNetmask=\u30b2\u30b9\u30c8\u306e\u4f7f\u7528\u3059\u308b\u30b5\u30d6\u30cd\u30c3\u30c8\u4e0a\u3067\u4f7f\u7528\u3055\u308c\u308b\u30cd\u30c3\u30c8\u30de\u30b9\u30af\u3067\u3059\u3002 +message.installWizard.tooltip.addPod.reservedSystemStartIp=\u3053\u308c\u306f\u3001\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 VM \u304a\u3088\u3073\u30b3\u30f3\u30bd\u30fc\u30eb \u30d7\u30ed\u30ad\u30b7 VM \u3092\u7ba1\u7406\u3059\u308b\u305f\u3081\u306b CloudStack \u3067\u4f7f\u7528\u3059\u308b\u3001\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u5185\u306e IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u3067\u3059\u3002\u3053\u308c\u3089\u306e IP \u30a2\u30c9\u30ec\u30b9\u306f\u30b3\u30f3\u30d4\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0 \u30b5\u30fc\u30d0\u30fc\u3068\u540c\u3058\u30b5\u30d6\u30cd\u30c3\u30c8\u304b\u3089\u5272\u308a\u5f53\u3066\u307e\u3059\u3002 +message.installWizard.tooltip.addPrimaryStorage.name=\u30b9\u30c8\u30ec\u30fc\u30b8 \u30c7\u30d0\u30a4\u30b9\u306e\u540d\u524d\u3067\u3059\u3002 +message.installWizard.tooltip.addPrimaryStorage.path=(NFS \u306e\u5834\u5408) \u30b5\u30fc\u30d0\u30fc\u304b\u3089\u30a8\u30af\u30b9\u30dd\u30fc\u30c8\u3055\u308c\u305f\u30d1\u30b9\u3067\u3059\u3002(SharedMountPoint \u306e\u5834\u5408) \u30d1\u30b9\u3067\u3059\u3002KVM \u3067\u306f\u3053\u306e\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u304c\u30de\u30a6\u30f3\u30c8\u3055\u308c\u308b\u5404\u30db\u30b9\u30c8\u4e0a\u306e\u30d1\u30b9\u3067\u3059\u3002\u305f\u3068\u3048\u3070\u3001/mnt/primary \u3067\u3059\u3002 +message.installWizard.tooltip.addPrimaryStorage.server=(NFS\u3001iSCSI\u3001\u307e\u305f\u306f PreSetup \u306e\u5834\u5408) \u30b9\u30c8\u30ec\u30fc\u30b8 \u30c7\u30d0\u30a4\u30b9\u306e IP \u30a2\u30c9\u30ec\u30b9\u307e\u305f\u306f DNS \u540d\u3067\u3059\u3002 +message.installWizard.tooltip.addSecondaryStorage.nfsServer=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u30db\u30b9\u30c8\u3059\u308b NFS \u30b5\u30fc\u30d0\u30fc\u306e IP \u30a2\u30c9\u30ec\u30b9\u3067\u3059\u3002 +message.installWizard.tooltip.addSecondaryStorage.path=\u4e0a\u306b\u6307\u5b9a\u3057\u305f\u30b5\u30fc\u30d0\u30fc\u306b\u5b58\u5728\u3059\u308b\u3001\u30a8\u30af\u30b9\u30dd\u30fc\u30c8\u3055\u308c\u305f\u30d1\u30b9\u3067\u3059\u3002 +message.installWizard.tooltip.addZone.dns1=\u30be\u30fc\u30f3\u5185\u306e\u30b2\u30b9\u30c8 VM \u3067\u4f7f\u7528\u3059\u308b DNS \u30b5\u30fc\u30d0\u30fc\u3067\u3059\u3002\u3053\u308c\u3089\u306e DNS \u30b5\u30fc\u30d0\u30fc\u306b\u306f\u3001\u5f8c\u3067\u8ffd\u52a0\u3059\u308b\u30d1\u30d6\u30ea\u30c3\u30af \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u7d4c\u7531\u3067\u30a2\u30af\u30bb\u30b9\u3057\u307e\u3059\u3002\u30be\u30fc\u30f3\u306e\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9\u304b\u3089\u3001\u3053\u3053\u3067\u6307\u5b9a\u3059\u308b\u30d1\u30d6\u30ea\u30c3\u30af DNS \u30b5\u30fc\u30d0\u30fc\u306b\u901a\u4fe1\u3067\u304d\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +message.installWizard.tooltip.addZone.dns2=\u30be\u30fc\u30f3\u5185\u306e\u30b2\u30b9\u30c8 VM \u3067\u4f7f\u7528\u3059\u308b DNS \u30b5\u30fc\u30d0\u30fc\u3067\u3059\u3002\u3053\u308c\u3089\u306e DNS \u30b5\u30fc\u30d0\u30fc\u306b\u306f\u3001\u5f8c\u3067\u8ffd\u52a0\u3059\u308b\u30d1\u30d6\u30ea\u30c3\u30af \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u7d4c\u7531\u3067\u30a2\u30af\u30bb\u30b9\u3057\u307e\u3059\u3002\u30be\u30fc\u30f3\u306e\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9\u304b\u3089\u3001\u3053\u3053\u3067\u6307\u5b9a\u3059\u308b\u30d1\u30d6\u30ea\u30c3\u30af DNS \u30b5\u30fc\u30d0\u30fc\u306b\u901a\u4fe1\u3067\u304d\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +message.installWizard.tooltip.addZone.internaldns1=\u30be\u30fc\u30f3\u5185\u306e\u30b7\u30b9\u30c6\u30e0 VM \u3067\u4f7f\u7528\u3059\u308b DNS \u30b5\u30fc\u30d0\u30fc\u3067\u3059\u3002\u3053\u308c\u3089\u306e DNS \u30b5\u30fc\u30d0\u30fc\u306f\u3001\u30b7\u30b9\u30c6\u30e0 VM \u306e\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30a4\u30b9\u3092\u4ecb\u3057\u3066\u30a2\u30af\u30bb\u30b9\u3055\u308c\u307e\u3059\u3002\u30dd\u30c3\u30c9\u306e\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 IP \u30a2\u30c9\u30ec\u30b9\u304b\u3089\u3001\u3053\u3053\u3067\u6307\u5b9a\u3059\u308b DNS \u30b5\u30fc\u30d0\u30fc\u306b\u901a\u4fe1\u3067\u304d\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +message.installWizard.tooltip.addZone.internaldns2=\u30be\u30fc\u30f3\u5185\u306e\u30b7\u30b9\u30c6\u30e0 VM \u3067\u4f7f\u7528\u3059\u308b DNS \u30b5\u30fc\u30d0\u30fc\u3067\u3059\u3002\u3053\u308c\u3089\u306e DNS \u30b5\u30fc\u30d0\u30fc\u306f\u3001\u30b7\u30b9\u30c6\u30e0 VM \u306e\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30a4\u30b9\u3092\u4ecb\u3057\u3066\u30a2\u30af\u30bb\u30b9\u3055\u308c\u307e\u3059\u3002\u30dd\u30c3\u30c9\u306e\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 IP \u30a2\u30c9\u30ec\u30b9\u304b\u3089\u3001\u3053\u3053\u3067\u6307\u5b9a\u3059\u308b DNS \u30b5\u30fc\u30d0\u30fc\u306b\u901a\u4fe1\u3067\u304d\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +message.installWizard.tooltip.addZone.name=\u30be\u30fc\u30f3\u306e\u540d\u524d\u3067\u3059\u3002 +message.installWizard.tooltip.configureGuestTraffic.description=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u8aac\u660e\u3067\u3059\u3002 +message.installWizard.tooltip.configureGuestTraffic.guestEndIp=\u3053\u306e\u30be\u30fc\u30f3\u306e\u30b2\u30b9\u30c8\u306b\u5272\u308a\u5f53\u3066\u308b\u3053\u3068\u304c\u3067\u304d\u308b IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u3067\u3059\u3002\u4f7f\u7528\u3059\u308b NIC \u304c 1 \u3064\u306e\u5834\u5408\u306f\u3001\u3053\u308c\u3089\u306e IP \u30a2\u30c9\u30ec\u30b9\u306f\u30dd\u30c3\u30c9\u306e CIDR \u3068\u540c\u3058 CIDR \u306b\u542b\u307e\u308c\u3066\u3044\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +message.installWizard.tooltip.configureGuestTraffic.guestGateway=\u30b2\u30b9\u30c8\u306e\u4f7f\u7528\u3059\u308b\u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u3067\u3059\u3002 +message.installWizard.tooltip.configureGuestTraffic.guestNetmask=\u30b2\u30b9\u30c8\u306e\u4f7f\u7528\u3059\u308b\u30b5\u30d6\u30cd\u30c3\u30c8\u4e0a\u3067\u4f7f\u7528\u3055\u308c\u308b\u30cd\u30c3\u30c8\u30de\u30b9\u30af\u3067\u3059\u3002 +message.installWizard.tooltip.configureGuestTraffic.guestStartIp=\u3053\u306e\u30be\u30fc\u30f3\u306e\u30b2\u30b9\u30c8\u306b\u5272\u308a\u5f53\u3066\u308b\u3053\u3068\u304c\u3067\u304d\u308b IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u3067\u3059\u3002\u4f7f\u7528\u3059\u308b NIC \u304c 1 \u3064\u306e\u5834\u5408\u306f\u3001\u3053\u308c\u3089\u306e IP \u30a2\u30c9\u30ec\u30b9\u306f\u30dd\u30c3\u30c9\u306e CIDR \u3068\u540c\u3058 CIDR \u306b\u542b\u307e\u308c\u3066\u3044\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +message.installWizard.tooltip.configureGuestTraffic.name=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u540d\u524d\u3067\u3059\u3002 +message.instanceWizard.noTemplates=\u4f7f\u7528\u53ef\u80fd\u306a\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u304c\u3042\u308a\u307e\u305b\u3093\u3002\u4e92\u63db\u6027\u306e\u3042\u308b\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u8ffd\u52a0\u3057\u3066\u3001\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9 \u30a6\u30a3\u30b6\u30fc\u30c9\u3092\u518d\u8d77\u52d5\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.ip.address.changed=\u304a\u4f7f\u3044\u306e IP \u30a2\u30c9\u30ec\u30b9\u304c\u5909\u66f4\u3055\u308c\u3066\u3044\u308b\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059\u3002\u4e00\u89a7\u3092\u66f4\u65b0\u3057\u307e\u3059\u304b? \u305d\u306e\u5834\u5408\u306f\u3001\u8a73\u7d30\u30da\u30a4\u30f3\u304c\u9589\u3058\u308b\u3053\u3068\u306b\u6ce8\u610f\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.iso.desc=\u30c7\u30fc\u30bf\u307e\u305f\u306f OS \u8d77\u52d5\u53ef\u80fd\u30e1\u30c7\u30a3\u30a2\u3092\u542b\u3080\u30c7\u30a3\u30b9\u30af \u30a4\u30e1\u30fc\u30b8 +message.join.project=\u3053\u308c\u3067\u3001\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306b\u53c2\u52a0\u3057\u307e\u3057\u305f\u3002\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3092\u53c2\u7167\u3059\u308b\u306b\u306f\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 \u30d3\u30e5\u30fc\u306b\u5207\u308a\u66ff\u3048\u3066\u304f\u3060\u3055\u3044\u3002 +message.launch.zone=\u30be\u30fc\u30f3\u3092\u8d77\u52d5\u3059\u308b\u6e96\u5099\u304c\u3067\u304d\u307e\u3057\u305f\u3002\u6b21\u306e\u624b\u9806\u306b\u9032\u3093\u3067\u304f\u3060\u3055\u3044\u3002 +message.lock.account=\u3053\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u3092\u30ed\u30c3\u30af\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? \u3053\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u3059\u3079\u3066\u306e\u30e6\u30fc\u30b6\u30fc\u304c\u30af\u30e9\u30a6\u30c9 \u30ea\u30bd\u30fc\u30b9\u3092\u7ba1\u7406\u3067\u304d\u306a\u304f\u306a\u308a\u307e\u3059\u3002\u305d\u306e\u5f8c\u3082\u65e2\u5b58\u306e\u30ea\u30bd\u30fc\u30b9\u306b\u306f\u30a2\u30af\u30bb\u30b9\u3067\u304d\u307e\u3059\u3002 +message.migrate.instance.confirm=\u4eee\u60f3\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u79fb\u884c\u5148\u306f\u6b21\u306e\u30db\u30b9\u30c8\u3067\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.migrate.instance.to.host=\u5225\u306e\u30db\u30b9\u30c8\u306b\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u79fb\u884c\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.migrate.instance.to.ps=\u5225\u306e\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u306b\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u79fb\u884c\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.migrate.router.confirm=\u30eb\u30fc\u30bf\u30fc\u306e\u79fb\u884c\u5148\u306f\u6b21\u306e\u30db\u30b9\u30c8\u3067\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.migrate.systemvm.confirm=\u30b7\u30b9\u30c6\u30e0 VM \u306e\u79fb\u884c\u5148\u306f\u6b21\u306e\u30db\u30b9\u30c8\u3067\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.migrate.volume=\u5225\u306e\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u306b\u30dc\u30ea\u30e5\u30fc\u30e0\u3092\u79fb\u884c\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.new.user=\u00e3\u0082\u00a2\u00e3\u0082\u00ab\u00e3\u0082\u00a6\u00e3\u0083\u00b3\u00e3\u0083\u0088\u00e3\u0081\u00ab\u00e6\u0096\u00b0\u00e3\u0081\u0097\u00e3\u0081\u0084\u00e3\u0083\u00a6\u00e3\u0083\u00bc\u00e3\u0082\u00b6\u00e3\u0083\u00bc\u00e3\u0082\u0092\u00e8\u00bf\u00bd\u00e5\u008a\u00a0\u00e3\u0081\u0099\u00e3\u0082\u008b\u00e3\u0081\u009f\u00e3\u0082\u0081\u00e3\u0081\u00ab\u00e3\u0080\u0081\u00e6\u00ac\u00a1\u00e3\u0081\u00ae\u00e6\u0083 +message.no.network.support.configuration.not.true=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u304c\u6709\u52b9\u306a\u30be\u30fc\u30f3\u304c\u7121\u3044\u305f\u3081\u3001\u8ffd\u52a0\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u6a5f\u80fd\u306f\u3042\u308a\u307e\u305b\u3093\u3002\u624b\u9806 5. \u306b\u9032\u3093\u3067\u304f\u3060\u3055\u3044\u3002 +message.no.network.support=\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc\u3068\u3057\u3066 vSphere \u3092\u9078\u629e\u3057\u307e\u3057\u305f\u304c\u3001\u3053\u306e\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc\u306b\u8ffd\u52a0\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u6a5f\u80fd\u306f\u3042\u308a\u307e\u305b\u3093\u3002\u624b\u9806 5. \u306b\u9032\u3093\u3067\u304f\u3060\u3055\u3044\u3002 +message.no.projects.adminOnly=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u304c\u3042\u308a\u307e\u305b\u3093\u3002
\u7ba1\u7406\u8005\u306b\u65b0\u3057\u3044\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u4f5c\u6210\u3092\u4f9d\u983c\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.no.projects=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u304c\u3042\u308a\u307e\u305b\u3093\u3002
\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 \u30bb\u30af\u30b7\u30e7\u30f3\u304b\u3089\u65b0\u3057\u3044\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3092\u4f5c\u6210\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.number.clusters=

\u30af\u30e9\u30b9\u30bf\u30fc\u6570

+message.number.hosts=

\u30db\u30b9\u30c8\u6570

+message.number.pods=

\u30dd\u30c3\u30c9\u6570

+message.number.storage=

\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8 \u30dc\u30ea\u30e5\u30fc\u30e0\u6570

+message.number.zones=

\u30be\u30fc\u30f3\u6570

+message.pending.projects.1=\u4fdd\u7559\u4e2d\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u62db\u5f85\u72b6\u304c\u3042\u308a\u307e\u3059\u3002 +message.pending.projects.2=\u8868\u793a\u3059\u308b\u306b\u306f\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 \u30bb\u30af\u30b7\u30e7\u30f3\u306b\u79fb\u52d5\u3057\u3066\u3001\u4e00\u89a7\u304b\u3089\u62db\u5f85\u72b6\u3092\u9078\u629e\u3057\u307e\u3059\u3002 +message.please.add.at.lease.one.traffic.range=\u5c11\u306a\u304f\u3068\u3082 1 \u3064\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e\u7bc4\u56f2\u3092\u8ffd\u52a0\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.please.proceed=\u6b21\u306e\u624b\u9806\u306b\u9032\u3093\u3067\u304f\u3060\u3055\u3044\u3002 +message.please.select.a.configuration.for.your.zone=\u30be\u30fc\u30f3\u306e\u69cb\u6210\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.please.select.a.different.public.and.management.network.before.removing=\u524a\u9664\u306e\u524d\u306b\u7570\u306a\u308b\u30d1\u30d6\u30ea\u30c3\u30af\u304a\u3088\u3073\u7ba1\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.please.select.networks=\u4eee\u60f3\u30de\u30b7\u30f3\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.please.wait.while.zone.is.being.created=\u30be\u30fc\u30f3\u304c\u4f5c\u6210\u3055\u308c\u308b\u307e\u3067\u3057\u3070\u3089\u304f\u304a\u5f85\u3061\u304f\u3060\u3055\u3044... +message.project.invite.sent=\u30e6\u30fc\u30b6\u30fc\u306b\u62db\u5f85\u72b6\u304c\u9001\u4fe1\u3055\u308c\u307e\u3057\u305f\u3002\u30e6\u30fc\u30b6\u30fc\u304c\u62db\u5f85\u3092\u627f\u8afe\u3059\u308b\u3068\u3001\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306b\u8ffd\u52a0\u3055\u308c\u307e\u3059\u3002 +message.public.traffic.in.advanced.zone=\u30af\u30e9\u30a6\u30c9\u5185\u306e VM \u304c\u30a4\u30f3\u30bf\u30fc\u30cd\u30c3\u30c8\u306b\u30a2\u30af\u30bb\u30b9\u3059\u308b\u3068\u3001\u30d1\u30d6\u30ea\u30c3\u30af \u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u304c\u751f\u6210\u3055\u308c\u307e\u3059\u3002\u3053\u306e\u305f\u3081\u306b\u3001\u4e00\u822c\u306b\u30a2\u30af\u30bb\u30b9\u53ef\u80fd\u306a IP \u30a2\u30c9\u30ec\u30b9\u3092\u5272\u308a\u5f53\u3066\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002\u30a8\u30f3\u30c9 \u30e6\u30fc\u30b6\u30fc\u306f CloudStack \u306e\u30e6\u30fc\u30b6\u30fc \u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30a4\u30b9\u3092\u4f7f\u7528\u3057\u3066\u3053\u308c\u3089\u306e IP \u30a2\u30c9\u30ec\u30b9\u3092\u53d6\u5f97\u3057\u3001\u30b2\u30b9\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3068\u30d1\u30d6\u30ea\u30c3\u30af \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u9593\u306b NAT \u3092\u5b9f\u88c5\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002

\u30a4\u30f3\u30bf\u30fc\u30cd\u30c3\u30c8 \u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e\u305f\u3081\u306b\u3001\u5c11\u306a\u304f\u3068\u3082 1 \u3064 IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.public.traffic.in.basic.zone=\u30af\u30e9\u30a6\u30c9\u5185\u306e VM \u304c\u30a4\u30f3\u30bf\u30fc\u30cd\u30c3\u30c8\u306b\u30a2\u30af\u30bb\u30b9\u3059\u308b\u304b\u30a4\u30f3\u30bf\u30fc\u30cd\u30c3\u30c8\u7d4c\u7531\u3067\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u306b\u30b5\u30fc\u30d3\u30b9\u3092\u63d0\u4f9b\u3059\u308b\u3068\u3001\u30d1\u30d6\u30ea\u30c3\u30af \u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u304c\u751f\u6210\u3055\u308c\u307e\u3059\u3002\u3053\u306e\u305f\u3081\u306b\u3001\u4e00\u822c\u306b\u30a2\u30af\u30bb\u30b9\u53ef\u80fd\u306a IP \u30a2\u30c9\u30ec\u30b9\u3092\u5272\u308a\u5f53\u3066\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u4f5c\u6210\u3059\u308b\u3068\u3001\u30b2\u30b9\u30c8 IP \u30a2\u30c9\u30ec\u30b9\u306e\u307b\u304b\u306b\u3053\u306e\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u304b\u3089\u30a2\u30c9\u30ec\u30b9\u304c 1 \u3064\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u5272\u308a\u5f53\u3066\u3089\u308c\u307e\u3059\u3002\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9\u3068\u30b2\u30b9\u30c8 IP \u30a2\u30c9\u30ec\u30b9\u306e\u9593\u306b\u3001\u9759\u7684\u306a 1 \u5bfe 1 \u306e NAT \u304c\u81ea\u52d5\u7684\u306b\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u3055\u308c\u307e\u3059\u3002\u30a8\u30f3\u30c9 \u30e6\u30fc\u30b6\u30fc\u306f CloudStack \u306e\u30e6\u30fc\u30b6\u30fc \u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30a4\u30b9\u3092\u4f7f\u7528\u3057\u3066\u8ffd\u52a0\u306e IP \u30a2\u30c9\u30ec\u30b9\u3092\u53d6\u5f97\u3057\u3001\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3068\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9\u306e\u9593\u306b\u9759\u7684 NAT \u3092\u5b9f\u88c5\u3059\u308b\u3053\u3068\u3082\u3067\u304d\u307e\u3059\u3002 +message.remove.vpc=VPC \u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.remove.vpn.access=\u6b21\u306e\u30e6\u30fc\u30b6\u30fc\u304b\u3089 VPN \u30a2\u30af\u30bb\u30b9\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.reset.password.warning.notPasswordEnabled=\u3053\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306f\u3001\u30d1\u30b9\u30ef\u30fc\u30c9\u7ba1\u7406\u3092\u6709\u52b9\u306b\u305b\u305a\u306b\u4f5c\u6210\u3055\u308c\u307e\u3057\u305f\u3002 +message.reset.password.warning.notStopped=\u73fe\u5728\u306e\u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u5909\u66f4\u3059\u308b\u524d\u306b\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u505c\u6b62\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +message.reset.VPN.connection=VPN \u63a5\u7d9a\u3092\u30ea\u30bb\u30c3\u30c8\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.restart.mgmt.server=\u65b0\u3057\u3044\u8a2d\u5b9a\u3092\u6709\u52b9\u306b\u3059\u308b\u305f\u3081\u306b\u3001\u7ba1\u7406\u30b5\u30fc\u30d0\u30fc\u3092\u518d\u8d77\u52d5\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.restart.mgmt.usage.server=\u65b0\u3057\u3044\u8a2d\u5b9a\u3092\u6709\u52b9\u306b\u3059\u308b\u305f\u3081\u306b\u3001\u7ba1\u7406\u30b5\u30fc\u30d0\u30fc\u3068\u4f7f\u7528\u72b6\u6cc1\u6e2c\u5b9a\u30b5\u30fc\u30d0\u30fc\u3092\u518d\u8d77\u52d5\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.restart.network=\u3053\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3067\u63d0\u4f9b\u3059\u308b\u3059\u3079\u3066\u306e\u30b5\u30fc\u30d3\u30b9\u304c\u4e2d\u65ad\u3055\u308c\u307e\u3059\u3002\u3053\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u518d\u8d77\u52d5\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.restart.vpc=VPC \u3092\u518d\u8d77\u52d5\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.security.group.usage=(\u8a72\u5f53\u3059\u308b\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u3092\u3059\u3079\u3066\u9078\u629e\u3059\u308b\u306b\u306f\u3001Ctrl \u30ad\u30fc\u3092\u62bc\u3057\u306a\u304c\u3089\u30af\u30ea\u30c3\u30af\u3057\u3066\u304f\u3060\u3055\u3044) +message.select.a.zone=\u30be\u30fc\u30f3\u306f\u901a\u5e38\u3001\u5358\u4e00\u306e\u30c7\u30fc\u30bf\u30bb\u30f3\u30bf\u30fc\u306b\u76f8\u5f53\u3057\u307e\u3059\u3002\u8907\u6570\u306e\u30be\u30fc\u30f3\u3092\u8a2d\u5b9a\u3057\u3001\u7269\u7406\u7684\u306b\u5206\u96e2\u3057\u3066\u5197\u9577\u6027\u3092\u6301\u305f\u305b\u308b\u3053\u3068\u306b\u3088\u308a\u3001\u30af\u30e9\u30a6\u30c9\u306e\u4fe1\u983c\u6027\u3092\u9ad8\u3081\u307e\u3059\u3002 +message.select.instance=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.select.iso=\u65b0\u3057\u3044\u4eee\u60f3\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e ISO \u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.select.item=\u9805\u76ee\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.select.security.groups=\u65b0\u3057\u3044\u4eee\u60f3\u30de\u30b7\u30f3\u306e\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.select.template=\u65b0\u3057\u3044\u4eee\u60f3\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.setup.physical.network.during.zone.creation.basic=\u57fa\u672c\u30be\u30fc\u30f3\u3092\u8ffd\u52a0\u3059\u308b\u3068\u304d\u306f\u3001\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc\u4e0a\u306e NIC \u306b\u5bfe\u5fdc\u3059\u308b 1 \u3064\u306e\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u3067\u304d\u307e\u3059\u3002\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306f\u3044\u304f\u3064\u304b\u306e\u7a2e\u985e\u306e\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u3092\u4f1d\u9001\u3057\u307e\u3059\u3002

\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306b\u307b\u304b\u306e\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e\u7a2e\u985e\u3092\u30c9\u30e9\u30c3\u30b0 \u30a2\u30f3\u30c9 \u30c9\u30ed\u30c3\u30d7\u3059\u308b\u3053\u3068\u3082\u3067\u304d\u307e\u3059\u3002 +message.setup.physical.network.during.zone.creation=\u62e1\u5f35\u30be\u30fc\u30f3\u3092\u8ffd\u52a0\u3059\u308b\u3068\u304d\u306f\u30011 \u3064\u4ee5\u4e0a\u306e\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002\u5404\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306f\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc\u4e0a\u306e 1 \u3064\u306e NIC \u306b\u5bfe\u5fdc\u3057\u307e\u3059\u3002\u5404\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3067\u306f\u3001\u7d44\u307f\u5408\u308f\u305b\u306b\u5236\u9650\u304c\u3042\u308a\u307e\u3059\u304c\u30011 \u3064\u4ee5\u4e0a\u306e\u7a2e\u985e\u306e\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u3092\u901a\u4fe1\u3067\u304d\u307e\u3059\u3002

\u5404\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306b\u5bfe\u3057\u3066\u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e\u7a2e\u985e\u3092\u30c9\u30e9\u30c3\u30b0 \u30a2\u30f3\u30c9 \u30c9\u30ed\u30c3\u30d7\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.setup.successful=\u30af\u30e9\u30a6\u30c9\u304c\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u3055\u308c\u307e\u3057\u305f\u3002 +message.snapshot.schedule=\u6b21\u306e\u30aa\u30d7\u30b7\u30e7\u30f3\u304b\u3089\u9078\u629e\u3057\u3066\u30dd\u30ea\u30b7\u30fc\u306e\u57fa\u672c\u8a2d\u5b9a\u3092\u9069\u7528\u3059\u308b\u3053\u3068\u306b\u3088\u308a\u3001\u5b9a\u671f\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u306e\u30b9\u30b1\u30b8\u30e5\u30fc\u30eb\u3092\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u3067\u304d\u307e\u3059\u3002 +message.specify.url=URL \u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044 +message.step.1.continue=\u7d9a\u884c\u3059\u308b\u306b\u306f\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u307e\u305f\u306f ISO \u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044 +message.step.1.desc=\u65b0\u3057\u3044\u4eee\u60f3\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u7528\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002ISO \u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3067\u304d\u308b\u7a7a\u767d\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u9078\u629e\u3059\u308b\u3053\u3068\u3082\u3067\u304d\u307e\u3059\u3002 +message.step.2.continue=\u7d9a\u884c\u3059\u308b\u306b\u306f\u30b5\u30fc\u30d3\u30b9 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044 message.step.2.desc= -message.step.3.continue=\u7D9A\u884C\u3059\u308B\u306B\u306F\u30C7\u30A3\u30B9\u30AF \u30AA\u30D5\u30A1\u30EA\u30F3\u30B0\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044 +message.step.3.continue=\u7d9a\u884c\u3059\u308b\u306b\u306f\u30c7\u30a3\u30b9\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044 message.step.3.desc= -message.step.4.continue=\u7D9A\u884C\u3059\u308B\u306B\u306F\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u5C11\u306A\u304F\u3068\u3082 1 \u3064\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044 -message.step.4.desc=\u4EEE\u60F3\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u304C\u63A5\u7D9A\u3059\u308B\u30D7\u30E9\u30A4\u30DE\u30EA \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.storage.traffic=\u30DB\u30B9\u30C8\u3084 CloudStack \u30B7\u30B9\u30C6\u30E0 VM \u306A\u3069\u3001\u7BA1\u7406\u30B5\u30FC\u30D0\u30FC\u3068\u901A\u4FE1\u3059\u308B CloudStack \u306E\u5185\u90E8\u30EA\u30BD\u30FC\u30B9\u9593\u306E\u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u3067\u3059\u3002\u3053\u3053\u3067\u30B9\u30C8\u30EC\u30FC\u30B8 \u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u3092\u69CB\u6210\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.suspend.project=\u3053\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u4E00\u6642\u505C\u6B62\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.template.desc=VM \u306E\u8D77\u52D5\u306B\u4F7F\u7528\u3067\u304D\u308B OS \u30A4\u30E1\u30FC\u30B8 -message.tooltip.dns.1=\u30BE\u30FC\u30F3\u5185\u306E VM \u3067\u4F7F\u7528\u3059\u308B DNS \u30B5\u30FC\u30D0\u30FC\u306E\u540D\u524D\u3067\u3059\u3002\u30BE\u30FC\u30F3\u306E\u30D1\u30D6\u30EA\u30C3\u30AF IP \u30A2\u30C9\u30EC\u30B9\u304B\u3089\u3001\u3053\u306E\u30B5\u30FC\u30D0\u30FC\u306B\u901A\u4FE1\u3067\u304D\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -message.tooltip.dns.2=\u30BE\u30FC\u30F3\u5185\u306E VM \u3067\u4F7F\u7528\u3059\u308B 2 \u756A\u76EE\u306E DNS \u30B5\u30FC\u30D0\u30FC\u306E\u540D\u524D\u3067\u3059\u3002\u30BE\u30FC\u30F3\u306E\u30D1\u30D6\u30EA\u30C3\u30AF IP \u30A2\u30C9\u30EC\u30B9\u304B\u3089\u3001\u3053\u306E\u30B5\u30FC\u30D0\u30FC\u306B\u901A\u4FE1\u3067\u304D\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -message.tooltip.internal.dns.1=\u30BE\u30FC\u30F3\u5185\u306E CloudStack \u5185\u90E8\u30B7\u30B9\u30C6\u30E0 VM \u3067\u4F7F\u7528\u3059\u308B DNS \u30B5\u30FC\u30D0\u30FC\u306E\u540D\u524D\u3067\u3059\u3002\u30DD\u30C3\u30C9\u306E\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8 IP \u30A2\u30C9\u30EC\u30B9\u304B\u3089\u3001\u3053\u306E\u30B5\u30FC\u30D0\u30FC\u306B\u901A\u4FE1\u3067\u304D\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -message.tooltip.internal.dns.2=\u30BE\u30FC\u30F3\u5185\u306E CloudStack \u5185\u90E8\u30B7\u30B9\u30C6\u30E0 VM \u3067\u4F7F\u7528\u3059\u308B DNS \u30B5\u30FC\u30D0\u30FC\u306E\u540D\u524D\u3067\u3059\u3002\u30DD\u30C3\u30C9\u306E\u30D7\u30E9\u30A4\u30D9\u30FC\u30C8 IP \u30A2\u30C9\u30EC\u30B9\u304B\u3089\u3001\u3053\u306E\u30B5\u30FC\u30D0\u30FC\u306B\u901A\u4FE1\u3067\u304D\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -message.tooltip.network.domain=DNS \u30B5\u30D5\u30A3\u30C3\u30AF\u30B9\u3067\u3059\u3002\u3053\u306E\u30B5\u30D5\u30A3\u30C3\u30AF\u30B9\u304B\u3089\u30B2\u30B9\u30C8 VM \u3067\u30A2\u30AF\u30BB\u30B9\u3059\u308B\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u306E\u30AB\u30B9\u30BF\u30E0 \u30C9\u30E1\u30A4\u30F3\u540D\u304C\u4F5C\u6210\u3055\u308C\u307E\u3059\u3002 -message.tooltip.pod.name=\u3053\u306E\u30DD\u30C3\u30C9\u306E\u540D\u524D\u3067\u3059\u3002 -message.tooltip.reserved.system.gateway=\u30DD\u30C3\u30C9\u5185\u306E\u30DB\u30B9\u30C8\u306E\u30B2\u30FC\u30C8\u30A6\u30A7\u30A4\u3067\u3059\u3002 -message.tooltip.reserved.system.netmask=\u30DD\u30C3\u30C9\u306E\u30B5\u30D6\u30CD\u30C3\u30C8\u3092\u5B9A\u7FA9\u3059\u308B\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30D7\u30EC\u30D5\u30A3\u30C3\u30AF\u30B9\u3067\u3059\u3002CIDR \u8868\u8A18\u3092\u4F7F\u7528\u3057\u307E\u3059\u3002 -message.tooltip.zone.name=\u30BE\u30FC\u30F3\u306E\u540D\u524D\u3067\u3059\u3002 -message.update.os.preference=\u3053\u306E\u30DB\u30B9\u30C8\u306E OS \u57FA\u672C\u8A2D\u5B9A\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u540C\u69D8\u306E\u57FA\u672C\u8A2D\u5B9A\u3092\u6301\u3064\u3059\u3079\u3066\u306E\u4EEE\u60F3\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306F\u3001\u5225\u306E\u30DB\u30B9\u30C8\u3092\u9078\u629E\u3059\u308B\u524D\u306B\u307E\u305A\u3053\u306E\u30DB\u30B9\u30C8\u306B\u5272\u308A\u5F53\u3066\u3089\u308C\u307E\u3059\u3002 -message.update.resource.count=\u3053\u306E\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30EA\u30BD\u30FC\u30B9\u6570\u3092\u66F4\u65B0\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.update.ssl=\u5404\u30B3\u30F3\u30BD\u30FC\u30EB \u30D7\u30ED\u30AD\u30B7\u306E\u4EEE\u60F3\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3067\u66F4\u65B0\u3059\u308B\u3001X.509 \u6E96\u62E0\u306E\u65B0\u3057\u3044 SSL \u8A3C\u660E\u66F8\u3092\u9001\u4FE1\u3057\u3066\u304F\u3060\u3055\u3044\: -message.validate.instance.name=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u540D\u306F 63 \u6587\u5B57\u4EE5\u5185\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002ASCII \u6587\u5B57\u306E a\uFF5Ez\u3001A\uFF5EZ\u3001\u6570\u5B57\u306E 0\uFF5E9\u3001\u304A\u3088\u3073\u30CF\u30A4\u30D5\u30F3\u306E\u307F\u3092\u4F7F\u7528\u3067\u304D\u307E\u3059\u3002\u6587\u5B57\u3067\u59CB\u307E\u308A\u3001\u6587\u5B57\u307E\u305F\u306F\u6570\u5B57\u3067\u7D42\u308F\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -message.virtual.network.desc=\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u5C02\u7528\u4EEE\u60F3\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3067\u3059\u3002\u30D6\u30ED\u30FC\u30C9\u30AD\u30E3\u30B9\u30C8 \u30C9\u30E1\u30A4\u30F3\u306F VLAN \u5185\u306B\u914D\u7F6E\u3055\u308C\u3001\u30D1\u30D6\u30EA\u30C3\u30AF \u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3078\u306E\u30A2\u30AF\u30BB\u30B9\u306F\u3059\u3079\u3066\u4EEE\u60F3\u30EB\u30FC\u30BF\u30FC\u306B\u3088\u3063\u3066\u30EB\u30FC\u30C6\u30A3\u30F3\u30B0\u3055\u308C\u307E\u3059\u3002 -message.vm.create.template.confirm=\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3092\u4F5C\u6210\u3059\u308B\u3068 VM \u304C\u81EA\u52D5\u7684\u306B\u518D\u8D77\u52D5\u3055\u308C\u307E\u3059\u3002 -message.vm.review.launch=\u6B21\u306E\u60C5\u5831\u3092\u53C2\u7167\u3057\u3066\u3001\u4EEE\u60F3\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3092\u6B63\u3057\u304F\u8A2D\u5B9A\u3057\u305F\u3053\u3068\u3092\u78BA\u8A8D\u3057\u3066\u304B\u3089\u8D77\u52D5\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.volume.create.template.confirm=\u3053\u306E\u30C7\u30A3\u30B9\u30AF \u30DC\u30EA\u30E5\u30FC\u30E0\u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3092\u4F5C\u6210\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? \u30DC\u30EA\u30E5\u30FC\u30E0 \u30B5\u30A4\u30BA\u306B\u3088\u3063\u3066\u306F\u3001\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u4F5C\u6210\u306B\u306F\u6570\u5206\u4EE5\u4E0A\u304B\u304B\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002 -message.you.must.have.at.least.one.physical.network=\u5C11\u306A\u304F\u3068\u3082 1 \u3064\u7269\u7406\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u304C\u5FC5\u8981\u3067\u3059 -message.Zone.creation.complete=\u30BE\u30FC\u30F3\u304C\u4F5C\u6210\u3055\u308C\u307E\u3057\u305F -message.zone.creation.complete.would.you.like.to.enable.this.zone=\u30BE\u30FC\u30F3\u304C\u4F5C\u6210\u3055\u308C\u307E\u3057\u305F\u3002\u3053\u306E\u30BE\u30FC\u30F3\u3092\u6709\u52B9\u306B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -message.zone.no.network.selection=\u9078\u629E\u3057\u305F\u30BE\u30FC\u30F3\u3067\u306F\u3001\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u3092\u9078\u629E\u3067\u304D\u307E\u305B\u3093\u3002 -message.zone.step.1.desc=\u30BE\u30FC\u30F3\u306E\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF \u30E2\u30C7\u30EB\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -message.zone.step.2.desc=\u00e6\u0096\u00b0\u00e3\u0081\u0097\u00e3\u0081\u0084Zone\u00e3\u0082\u0092\u00e8\u00bf\u00bd\u00e5\u008a\u00a0\u00e3\u0081\u0099\u00e3\u0082\u008b\u00e3\u0081\u009f\u00e3\u0082\u0081\u00e3\u0081\u00ab\u00e3\u0080\u0081\u00e6\u00ac\u00a1\u00e3\u0081\u00ae\u00e6\u0083\u0085\u00e5\u00a0\u00b1\u00e3\u0082\u0092\u00e5\u0085\u00a5\u00e5\u008a\u009b\u00e3\u0081\u0097\u00e3\u0081\u00a6\u00e3\u0081\u008f\u00e3\u0081\u00a0\u00e3\u0081\u0095\u00e3\u0081\u0084\u00e3\u0080\u0082 -message.zone.step.3.desc=\u00e6\u0096\u00b0\u00e3\u0081\u0097\u00e3\u0081\u0084Pod\u00e3\u0082\u0092\u00e8\u00bf\u00bd\u00e5\u008a\u00a0\u00e3\u0081\u0099\u00e3\u0082\u008b\u00e3\u0081\u009f\u00e3\u0082\u0081\u00e3\u0081\u00ab\u00e3\u0080\u0081\u00e6\u00ac\u00a1\u00e3\u0081\u00ae\u00e6\u0083\u0085\u00e5\u00a0\u00b1\u00e3\u0082\u0092\u00e5\u0085\u00a5\u00e5\u008a\u009b\u00e3\u0081\u0097\u00e3\u0081\u00a6\u00e3\u0081\u008f\u00e3\u0081\u00a0\u00e3\u0081\u0095\u00e3\u0081\u0084\u00e3\u0080\u0082 -message.zoneWizard.enable.local.storage=\u8B66\u544A\: \u3053\u306E\u30BE\u30FC\u30F3\u306E\u30ED\u30FC\u30AB\u30EB \u30B9\u30C8\u30EC\u30FC\u30B8\u3092\u6709\u52B9\u306B\u3059\u308B\u5834\u5408\u306F\u3001\u30B7\u30B9\u30C6\u30E0 VM \u306E\u8D77\u52D5\u5834\u6240\u306B\u5FDC\u3058\u3066\u6B21\u306E\u64CD\u4F5C\u304C\u5FC5\u8981\u3067\u3059\u3002

1. \u30B7\u30B9\u30C6\u30E0 VM \u3092\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u3067\u8D77\u52D5\u3059\u308B\u5FC5\u8981\u304C\u3042\u308B\u5834\u5408\u306F\u3001\u30D7\u30E9\u30A4\u30DE\u30EA \u30B9\u30C8\u30EC\u30FC\u30B8\u3092\u4F5C\u6210\u3057\u305F\u5F8C\u3067\u30BE\u30FC\u30F3\u306B\u8FFD\u52A0\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002\u307E\u305F\u3001\u7121\u52B9\u72B6\u614B\u306E\u30BE\u30FC\u30F3\u3092\u8D77\u52D5\u3059\u308B\u5FC5\u8981\u3082\u3042\u308A\u307E\u3059\u3002

2. \u30B7\u30B9\u30C6\u30E0 VM \u3092\u30ED\u30FC\u30AB\u30EB \u30B9\u30C8\u30EC\u30FC\u30B8\u3067\u8D77\u52D5\u3059\u308B\u5FC5\u8981\u304C\u3042\u308B\u5834\u5408\u306F\u3001system.vm.use.local.storage \u3092 true \u306B\u8A2D\u5B9A\u3057\u3066\u304B\u3089\u30BE\u30FC\u30F3\u3092\u6709\u52B9\u306B\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002


\u7D9A\u884C\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B? -mode=\u30E2\u30FC\u30C9 -network.rate=\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF\u901F\u5EA6 -notification.reboot.instance=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u518D\u8D77\u52D5 -notification.start.instance=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u8D77\u52D5 -notification.stop.instance=\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u306E\u505C\u6B62 -side.by.side=\u4E26\u5217 -state.Accepted=\u627F\u8AFE\u6E08\u307F -state.Active=\u30A2\u30AF\u30C6\u30A3\u30D6 -state.Allocated=\u5272\u308A\u5F53\u3066\u6E08\u307F -state.Allocating=\u5272\u308A\u5F53\u3066\u4E2D -state.BackedUp=\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u6E08\u307F -state.BackingUp=\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u4E2D -state.Completed=\u5B8C\u4E86 -state.Creating=\u4F5C\u6210\u4E2D -state.Declined=\u8F9E\u9000 -state.Destroyed=\u7834\u68C4\u6E08\u307F -state.Disabled=\u7121\u52B9 -state.enabled=\u6709\u52B9 -state.Enabled=\u6709\u52B9 -state.Error=\u30A8\u30E9\u30FC -state.Expunging=\u62B9\u6D88\u4E2D -state.Migrating=\u79FB\u884C\u4E2D -state.Pending=\u4FDD\u7559 -state.ready=\u6E96\u5099\u5B8C\u4E86 -state.Ready=\u6E96\u5099\u5B8C\u4E86 -state.Running=\u5B9F\u884C\u4E2D -state.Starting=\u958B\u59CB\u4E2D -state.Stopped=\u505C\u6B62\u6E08\u307F -state.Stopping=\u505C\u6B62\u3057\u3066\u3044\u307E\u3059 -state.Suspended=\u4E00\u6642\u505C\u6B62 +message.step.4.continue=\u7d9a\u884c\u3059\u308b\u306b\u306f\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u5c11\u306a\u304f\u3068\u3082 1 \u3064\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044 +message.step.4.desc=\u4eee\u60f3\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u304c\u63a5\u7d9a\u3059\u308b\u30d7\u30e9\u30a4\u30de\u30ea \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.suspend.project=\u3053\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3092\u4e00\u6642\u505c\u6b62\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.template.desc=VM \u306e\u8d77\u52d5\u306b\u4f7f\u7528\u3067\u304d\u308b OS \u30a4\u30e1\u30fc\u30b8 +message.tooltip.dns.1=\u30be\u30fc\u30f3\u5185\u306e VM \u3067\u4f7f\u7528\u3059\u308b DNS \u30b5\u30fc\u30d0\u30fc\u306e\u540d\u524d\u3067\u3059\u3002\u30be\u30fc\u30f3\u306e\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9\u304b\u3089\u3001\u3053\u306e\u30b5\u30fc\u30d0\u30fc\u306b\u901a\u4fe1\u3067\u304d\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +message.tooltip.dns.2=\u30be\u30fc\u30f3\u5185\u306e VM \u3067\u4f7f\u7528\u3059\u308b 2 \u756a\u76ee\u306e DNS \u30b5\u30fc\u30d0\u30fc\u306e\u540d\u524d\u3067\u3059\u3002\u30be\u30fc\u30f3\u306e\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9\u304b\u3089\u3001\u3053\u306e\u30b5\u30fc\u30d0\u30fc\u306b\u901a\u4fe1\u3067\u304d\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +message.tooltip.internal.dns.1=\u30be\u30fc\u30f3\u5185\u306e CloudStack \u5185\u90e8\u30b7\u30b9\u30c6\u30e0 VM \u3067\u4f7f\u7528\u3059\u308b DNS \u30b5\u30fc\u30d0\u30fc\u306e\u540d\u524d\u3067\u3059\u3002\u30dd\u30c3\u30c9\u306e\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 IP \u30a2\u30c9\u30ec\u30b9\u304b\u3089\u3001\u3053\u306e\u30b5\u30fc\u30d0\u30fc\u306b\u901a\u4fe1\u3067\u304d\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +message.tooltip.internal.dns.2=\u30be\u30fc\u30f3\u5185\u306e CloudStack \u5185\u90e8\u30b7\u30b9\u30c6\u30e0 VM \u3067\u4f7f\u7528\u3059\u308b DNS \u30b5\u30fc\u30d0\u30fc\u306e\u540d\u524d\u3067\u3059\u3002\u30dd\u30c3\u30c9\u306e\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 IP \u30a2\u30c9\u30ec\u30b9\u304b\u3089\u3001\u3053\u306e\u30b5\u30fc\u30d0\u30fc\u306b\u901a\u4fe1\u3067\u304d\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +message.tooltip.network.domain=DNS \u30b5\u30d5\u30a3\u30c3\u30af\u30b9\u3067\u3059\u3002\u3053\u306e\u30b5\u30d5\u30a3\u30c3\u30af\u30b9\u304b\u3089\u30b2\u30b9\u30c8 VM \u3067\u30a2\u30af\u30bb\u30b9\u3059\u308b\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u30ab\u30b9\u30bf\u30e0 \u30c9\u30e1\u30a4\u30f3\u540d\u304c\u4f5c\u6210\u3055\u308c\u307e\u3059\u3002 +message.tooltip.pod.name=\u3053\u306e\u30dd\u30c3\u30c9\u306e\u540d\u524d\u3067\u3059\u3002 +message.tooltip.reserved.system.gateway=\u30dd\u30c3\u30c9\u5185\u306e\u30db\u30b9\u30c8\u306e\u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u3067\u3059\u3002 +message.tooltip.reserved.system.netmask=\u30dd\u30c3\u30c9\u306e\u30b5\u30d6\u30cd\u30c3\u30c8\u3092\u5b9a\u7fa9\u3059\u308b\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30d7\u30ec\u30d5\u30a3\u30c3\u30af\u30b9\u3067\u3059\u3002CIDR \u8868\u8a18\u3092\u4f7f\u7528\u3057\u307e\u3059\u3002 +message.tooltip.zone.name=\u30be\u30fc\u30f3\u306e\u540d\u524d\u3067\u3059\u3002 +message.update.os.preference=\u3053\u306e\u30db\u30b9\u30c8\u306e OS \u57fa\u672c\u8a2d\u5b9a\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u540c\u69d8\u306e\u57fa\u672c\u8a2d\u5b9a\u3092\u6301\u3064\u3059\u3079\u3066\u306e\u4eee\u60f3\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306f\u3001\u5225\u306e\u30db\u30b9\u30c8\u3092\u9078\u629e\u3059\u308b\u524d\u306b\u307e\u305a\u3053\u306e\u30db\u30b9\u30c8\u306b\u5272\u308a\u5f53\u3066\u3089\u308c\u307e\u3059\u3002 +message.update.resource.count=\u3053\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u30ea\u30bd\u30fc\u30b9\u6570\u3092\u66f4\u65b0\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.update.ssl=\u5404\u30b3\u30f3\u30bd\u30fc\u30eb \u30d7\u30ed\u30ad\u30b7\u306e\u4eee\u60f3\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3067\u66f4\u65b0\u3059\u308b\u3001X.509 \u6e96\u62e0\u306e\u65b0\u3057\u3044 SSL \u8a3c\u660e\u66f8\u3092\u9001\u4fe1\u3057\u3066\u304f\u3060\u3055\u3044\: +message.validate.instance.name=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u540d\u306f 63 \u6587\u5b57\u4ee5\u5185\u3067\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002ASCII \u6587\u5b57\u306e a\uff5ez\u3001A\uff5eZ\u3001\u6570\u5b57\u306e 0\uff5e9\u3001\u304a\u3088\u3073\u30cf\u30a4\u30d5\u30f3\u306e\u307f\u3092\u4f7f\u7528\u3067\u304d\u307e\u3059\u3002\u6587\u5b57\u3067\u59cb\u307e\u308a\u3001\u6587\u5b57\u307e\u305f\u306f\u6570\u5b57\u3067\u7d42\u308f\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +message.virtual.network.desc=\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u5c02\u7528\u4eee\u60f3\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3067\u3059\u3002\u30d6\u30ed\u30fc\u30c9\u30ad\u30e3\u30b9\u30c8 \u30c9\u30e1\u30a4\u30f3\u306f VLAN \u5185\u306b\u914d\u7f6e\u3055\u308c\u3001\u30d1\u30d6\u30ea\u30c3\u30af \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3078\u306e\u30a2\u30af\u30bb\u30b9\u306f\u3059\u3079\u3066\u4eee\u60f3\u30eb\u30fc\u30bf\u30fc\u306b\u3088\u3063\u3066\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0\u3055\u308c\u307e\u3059\u3002 +message.vm.create.template.confirm=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u4f5c\u6210\u3059\u308b\u3068 VM \u304c\u81ea\u52d5\u7684\u306b\u518d\u8d77\u52d5\u3055\u308c\u307e\u3059\u3002 +message.vm.review.launch=\u6b21\u306e\u60c5\u5831\u3092\u53c2\u7167\u3057\u3066\u3001\u4eee\u60f3\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u6b63\u3057\u304f\u8a2d\u5b9a\u3057\u305f\u3053\u3068\u3092\u78ba\u8a8d\u3057\u3066\u304b\u3089\u8d77\u52d5\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.volume.create.template.confirm=\u3053\u306e\u30c7\u30a3\u30b9\u30af \u30dc\u30ea\u30e5\u30fc\u30e0\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u4f5c\u6210\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? \u30dc\u30ea\u30e5\u30fc\u30e0 \u30b5\u30a4\u30ba\u306b\u3088\u3063\u3066\u306f\u3001\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u4f5c\u6210\u306b\u306f\u6570\u5206\u4ee5\u4e0a\u304b\u304b\u308b\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059\u3002 +message.you.must.have.at.least.one.physical.network=\u5c11\u306a\u304f\u3068\u3082 1 \u3064\u7269\u7406\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u304c\u5fc5\u8981\u3067\u3059 +message.Zone.creation.complete=\u30be\u30fc\u30f3\u304c\u4f5c\u6210\u3055\u308c\u307e\u3057\u305f +message.zone.creation.complete.would.you.like.to.enable.this.zone=\u30be\u30fc\u30f3\u304c\u4f5c\u6210\u3055\u308c\u307e\u3057\u305f\u3002\u3053\u306e\u30be\u30fc\u30f3\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.zone.no.network.selection=\u9078\u629e\u3057\u305f\u30be\u30fc\u30f3\u3067\u306f\u3001\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3092\u9078\u629e\u3067\u304d\u307e\u305b\u3093\u3002 +message.zone.step.1.desc=\u30be\u30fc\u30f3\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30e2\u30c7\u30eb\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.zone.step.2.desc=\u00e6\u0096\u00b0\u00e3\u0081\u0097\u00e3\u0081\u0084Zone\u00e3\u0082\u0092\u00e8\u00bf\u00bd\u00e5\u008a\u00a0\u00e3\u0081\u0099\u00e3\u0082\u008b\u00e3\u0081\u009f\u00e3\u0082\u0081\u00e3\u0081\u00ab\u00e3\u0080\u0081\u00e6\u00ac\u00a1\u00e3\u0081\u00ae\u00e6\u0083 +message.zone.step.3.desc=\u00e6\u0096\u00b0\u00e3\u0081\u0097\u00e3\u0081\u0084Pod\u00e3\u0082\u0092\u00e8\u00bf\u00bd\u00e5\u008a\u00a0\u00e3\u0081\u0099\u00e3\u0082\u008b\u00e3\u0081\u009f\u00e3\u0082\u0081\u00e3\u0081\u00ab\u00e3\u0080\u0081\u00e6\u00ac\u00a1\u00e3\u0081\u00ae\u00e6\u0083 +message.zoneWizard.enable.local.storage=\u8b66\u544a\: \u3053\u306e\u30be\u30fc\u30f3\u306e\u30ed\u30fc\u30ab\u30eb \u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u6709\u52b9\u306b\u3059\u308b\u5834\u5408\u306f\u3001\u30b7\u30b9\u30c6\u30e0 VM \u306e\u8d77\u52d5\u5834\u6240\u306b\u5fdc\u3058\u3066\u6b21\u306e\u64cd\u4f5c\u304c\u5fc5\u8981\u3067\u3059\u3002

1. \u30b7\u30b9\u30c6\u30e0 VM \u3092\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3067\u8d77\u52d5\u3059\u308b\u5fc5\u8981\u304c\u3042\u308b\u5834\u5408\u306f\u3001\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u4f5c\u6210\u3057\u305f\u5f8c\u3067\u30be\u30fc\u30f3\u306b\u8ffd\u52a0\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002\u307e\u305f\u3001\u7121\u52b9\u72b6\u614b\u306e\u30be\u30fc\u30f3\u3092\u8d77\u52d5\u3059\u308b\u5fc5\u8981\u3082\u3042\u308a\u307e\u3059\u3002

2. \u30b7\u30b9\u30c6\u30e0 VM \u3092\u30ed\u30fc\u30ab\u30eb \u30b9\u30c8\u30ec\u30fc\u30b8\u3067\u8d77\u52d5\u3059\u308b\u5fc5\u8981\u304c\u3042\u308b\u5834\u5408\u306f\u3001system.vm.use.local.storage \u3092 true \u306b\u8a2d\u5b9a\u3057\u3066\u304b\u3089\u30be\u30fc\u30f3\u3092\u6709\u52b9\u306b\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002


\u7d9a\u884c\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +mode=\u30e2\u30fc\u30c9 +network.rate=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u901f\u5ea6 +notification.reboot.instance=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u518d\u8d77\u52d5 +notification.start.instance=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u8d77\u52d5 +notification.stop.instance=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u505c\u6b62 +side.by.side=\u4e26\u5217 +state.Accepted=\u627f\u8afe\u6e08\u307f +state.Active=\u30a2\u30af\u30c6\u30a3\u30d6 +state.Allocated=\u5272\u308a\u5f53\u3066\u6e08\u307f +state.Allocating=\u5272\u308a\u5f53\u3066\u4e2d +state.BackedUp=\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u6e08\u307f +state.BackingUp=\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u4e2d +state.Completed=\u5b8c\u4e86 +state.Creating=\u4f5c\u6210\u4e2d +state.Declined=\u8f9e\u9000 +state.Destroyed=\u7834\u68c4\u6e08\u307f +state.Disabled=\u7121\u52b9 +state.enabled=\u6709\u52b9 +state.Enabled=\u6709\u52b9 +state.Error=\u30a8\u30e9\u30fc +state.Expunging=\u62b9\u6d88\u4e2d +state.Migrating=\u79fb\u884c\u4e2d +state.Pending=\u4fdd\u7559 +state.ready=\u6e96\u5099\u5b8c\u4e86 +state.Ready=\u6e96\u5099\u5b8c\u4e86 +state.Running=\u5b9f\u884c\u4e2d +state.Starting=\u958b\u59cb\u4e2d +state.Stopped=\u505c\u6b62\u6e08\u307f +state.Stopping=\u505c\u6b62\u3057\u3066\u3044\u307e\u3059 +state.Suspended=\u4e00\u6642\u505c\u6b62 ui.listView.filters.all=\u3059\u3079\u3066 -ui.listView.filters.mine=\u81EA\u5206\u306E\u3082\u306E +ui.listView.filters.mine=\u81ea\u5206\u306e\u3082\u306e diff --git a/client/WEB-INF/classes/resources/messages_ko_KR.properties b/client/WEB-INF/classes/resources/messages_ko_KR.properties index 757871acde0..766fc607648 100644 --- a/client/WEB-INF/classes/resources/messages_ko_KR.properties +++ b/client/WEB-INF/classes/resources/messages_ko_KR.properties @@ -15,6 +15,7 @@ # specific language governing permissions and limitations # under the License. + changed.item.properties=\ud56d\ubaa9 \uc18d\uc131 \ubcc0\uacbd confirm.enable.swift=Swift \uae30\uc220 \uc9c0\uc6d0\ub97c \uc0ac\uc6a9 \ud558\ub824\uba74 \ub2e4\uc74c \uc815\ubcf4\ub97c \uc785\ub825\ud574 \uc8fc\uc2ed\uc2dc\uc624. error.could.not.enable.zone=Zone\uc744 \uc0ac\uc6a9 \ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. @@ -1193,7 +1194,6 @@ message.add.load.balancer.under.ip=\ub2e4\uc74c IP \uc8fc\uc18c\uc5d0 \ub300\ud5 message.add.load.balancer=Zone\uc5d0 \ub124\ud2b8\uc6cc\ud06c \ub85c\ub4dc \uacf5\uc720 \uc7a5\uce58\ub97c \ucd94\uac00\ud569\ub2c8\ub2e4. message.add.network=Zone \uc5d0 \uc0c8\ub85c\uc6b4 \ub124\ud2b8\uc6cc\ud06c\ub97c \ucd94\uac00\ud569\ub2c8\ub2e4. message.add.new.gateway.to.vpc=\ud604\uc7ac VPC\uc5d0 \uc0c8\ub85c\uc6b4 \uac8c\uc774\ud2b8\uc6e8\uc774\ub97c \ucd94\uac00\ud558\uae30 \uc704\ud55c \uc815\ubcf4\ub97c \uc9c0\uc815\ud574 \uc8fc\uc2ed\uc2dc\uc624. -message.add.pod.during.zone.creation=\uac01 Zone\uc5d0\ub294 \ud55c \uac1c \uc774\uc0c1 Pod\uac00 \ud544\uc694\ud569\ub2c8\ub2e4. \uc9c0\uae08 \uc5ec\uae30\uc11c \uccab\ubc88\uc9f8 Pod\ub97c \ucd94\uac00\ud569\ub2c8\ub2e4. Pod\ub294 \ud638\uc2a4\ud2b8\uc640 \uae30\ubcf8 \uc2a4\ud1a0\ub9ac\uc9c0 \uc11c\ubc84\uc5d0\uc11c \uad6c\uc131\ud569\ub2c8\ub2e4\ub9cc \uc774\ub294 \ub2e4\uc74c \uc21c\uc11c\ub85c \ucd94\uac00\ud569\ub2c8\ub2e4. \ub9e8 \ucc98\uc74c CloudStack \ub0b4\ubd80 \uad00\ub9ac \ud2b8\ub798\ud53d\uc744 \uc704\ud574\uc11c IP \uc8fc\uc18c \ubc94\uc704\ub97c \uc608\uc57d\ud569\ub2c8\ub2e4. IP \uc8fc\uc18c \ubc94\uc704\ub294 \ud074\ub77c\uc6b0\ub4dc \ub0b4\ubd80 \uac01 Zone\uc5d0\uc11c \uc911\ubcf5 \ud558\uc9c0 \uc54a\uac8c \uc608\uc57d\ud560 \ud544\uc694\uac00 \uc788\uc2b5\ub2c8\ub2e4. message.add.pod=Zone \uc5d0 \uc0c8\ub85c\uc6b4 Pod\ub97c \ucd94\uac00\ud569\ub2c8\ub2e4. message.add.primary.storage=Zone Pod \uc5d0 \uc0c8\ub85c\uc6b4 \uae30\ubcf8 \uc2a4\ud1a0\ub9ac\uc9c0\ub97c \ucd94\uac00\ud569\ub2c8\ub2e4. message.add.primary=\uc0c8\ub85c\uc6b4 \uae30\ubcf8 \uc2a4\ud1a0\ub9ac\uc9c0\ub97c \ucd94\uac00\ud558\uae30 \uc704\ud574 \uc544\ub798 \ud30c\ub77c\ubbf8\ud130\ub97c \uc9c0\uc815\ud574 \uc8fc\uc2ed\uc2dc\uc624. @@ -1253,7 +1253,6 @@ message.delete.VPN.gateway=\ud604\uc7ac VPN \uac8c\uc774\ud2b8\uc6e8\uc774\ub97c message.desc.advanced.zone=\ubcf4\ub2e4 \uc138\ub828\ub41c \ub124\ud2b8\uc6cc\ud06c \uae30\uc220\uc744 \uc9c0\uc6d0\ud569\ub2c8\ub2e4. \uc774 \ub124\ud2b8\uc6cc\ud06c \ubaa8\ub378\uc744 \uc120\ud0dd\ud558\uba74, \ubcf4\ub2e4 \uc720\uc5f0\ud558\uac8c \uac8c\uc2a4\ud2b8 \ub124\ud2b8\uc6cc\ud06c\ub97c \uc815\ud558\uace0 \ubc29\ud654\ubcbd(fire wall), VPN, \ub124\ud2b8\uc6cc\ud06c \ub85c\ub4dc \uacf5\uc720 \uc7a5\uce58 \uae30\uc220 \uc9c0\uc6d0\uc640 \uac19\uc740 \uc0ac\uc6a9\uc790 \uc9c0\uc815 \ud55c \ub124\ud2b8\uc6cc\ud06c \uc81c\uacf5\uc744 \uc81c\uacf5\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. message.desc.basic.zone=\uac01 VM \uc778\uc2a4\ud134\uc2a4\uc5d0 IP \uc8fc\uc18c\uac00 \ub124\ud2b8\uc6cc\ud06c\uc5d0\uc11c \uc9c1\uc811 \ud560\ub2f9\ud560 \uc218 \uc788\ub294 \ub2e8\uc77c \ub124\ud2b8\uc6cc\ud06c\ub97c \uc81c\uacf5\ud569\ub2c8\ub2e4. \ubcf4\uc548 \uadf8\ub8f9 (\uc804\uc1a1\uc6d0 IP \uc8fc\uc18c \ud544\ud130)\uacfc \uac19\uc740 \uce35 \uc138 \uac00\uc9c0 \ub808\ubca8 \ubc29\ubc95\uc73c\ub85c \uac8c\uc2a4\ud2b8\ub97c \ubd84\ub9ac\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. message.desc.cluster=\uac01 Pod\uc5d0\ub294 \ud55c \uac1c \uc774\uc0c1 \ud074\ub7ec\uc2a4\ud130\uac00 \ud544\uc694\ud569\ub2c8\ub2e4. \uc9c0\uae08 \uc5ec\uae30\uc11c \ucd5c\ucd08 \ud074\ub7ec\uc2a4\ud130\ub97c \ucd94\uac00\ud569\ub2c8\ub2e4. \ud074\ub7ec\uc2a4\ud130\ub294 \ud638\uc2a4\ud2b8\ub97c \uadf8\ub8f9\ud654 \ud558\ub294 \ubc29\ubc95\uc785\ub2c8\ub2e4. \ud55c \ud074\ub7ec\uc2a4\ud130 \ub0b4\ubd80 \ud638\uc2a4\ud2b8\ub294 \ubaa8\ub450 \ub3d9\uc77c\ud55c \ud558\ub4dc\uc6e8\uc5b4\uc5d0\uc11c \uad6c\uc131\ub418\uc5b4 \uac19\uc740 \ud558\uc774\ud37c \ubc14\uc774\uc800\ub97c \uc2e4\ud589\ud558\uace0 \uac19\uc740 \uc11c\ube0c \ub124\ud2b8\uc6cc\ud06c\uc0c1\uc5d0 \uc788\uc5b4 \uac19\uc740 \uacf5\uc720 \uc2a4\ud1a0\ub9ac\uc9c0\uc5d0 \uc811\uadfc \ud569\ub2c8\ub2e4. \uac01 \ud074\ub7ec\uc2a4\ud130\ub294 \ud55c \uac1c \uc774\uc0c1 \ud638\uc2a4\ud2b8\uc640 \ud55c \uac1c \uc774\uc0c1 \uae30\ubcf8 \uc2a4\ud1a0\ub9ac\uc9c0 \uc11c\ubc84\uc5d0\uc11c \uad6c\uc131\ub429\ub2c8\ub2e4. -message.desc.host=\uac01 \ud074\ub7ec\uc2a4\ud130\uc5d0\ub294 \uc801\uc5b4\ub3c4 \ud55c \uac1c \uc774\uc0c1 \uac8c\uc2a4\ud2b8 VM\ub97c \uc2e4\ud589\ud558\uae30 \uc704\ud55c \ud638\uc2a4\ud2b8 (\ucef4\ud4e8\ud130)\uac00 \ud544\uc694\ud569\ub2c8\ub2e4. \uc9c0\uae08 \uc5ec\uae30\uc11c \uccab\ubc88\uc9f8 \ud638\uc2a4\ud2b8\ub97c \ucd94\uac00\ud569\ub2c8\ub2e4. CloudStack\uc73c\ub85c \ud638\uc2a4\ud2b8\ub97c \ub3d9\uc791\ud558\ub824\uba74 \ud638\uc2a4\ud2b8\uc5d0\uac8c \ud558\uc774\ud37c \ubc14\uc774\uc800\ub97c \uc124\uce58\ud558\uace0 IP \uc8fc\uc18c\ub97c \ud560\ub2f9\ud574 \ud638\uc2a4\ud2b8\uac00 CloudStack \uad00\ub9ac \uc11c\ubc84\uc5d0 \uc811\uc18d\ud558\ub3c4\ub85d \ud569\ub2c8\ub2e4.

\ud638\uc2a4\ud2b8 DNS \uba85 \ub610\ub294 IP \uc8fc\uc18c, \uc0ac\uc6a9\uc790\uba85(\uc6d0\ub798 root)\uacfc \uc554\ud638 \ubc0f \ud638\uc2a4\ud2b8 \ubd84\ub958\uc5d0 \uc0ac\uc6a9\ud558\ub294 \ub77c\ubca8\uc744 \uc785\ub825\ud574 \uc8fc\uc2ed\uc2dc\uc624. message.desc.primary.storage=\uac01 \ud074\ub7ec\uc2a4\ud130\uc5d0\ub294 \uc801\uc5b4\ub3c4 \ud55c \uac1c \uc774\uc0c1\uc758 \uae30\ubcf8 \uc2a4\ud1a0\ub9ac\uc9c0 \uc11c\ubc84\uac00 \ud544\uc694\ud569\ub2c8\ub2e4. \uc9c0\uae08 \uc5ec\uae30\uc11c \uccab\ubc88\uc9f8 \uc11c\ubc84\ub97c \ucd94\uac00\ud569\ub2c8\ub2e4. \uae30\ubcf8 \uc2a4\ud1a0\ub9ac\uc9c0\ub294 \ud074\ub7ec\uc2a4\ud130 \ub0b4 \ubd80 \ud638\uc2a4\ud2b8\uc0c1\uc5d0\uc11c \ub3d9\uc791\ud558\ub294 \ubaa8\ub4e0 VM \ub514\uc2a4\ud06c \ubcfc\ub968\uc744 \ud3ec\ud568\ud569\ub2c8\ub2e4. \uae30\ubcf8\uc801\uc73c\ub85c \ud558\uc774\ud37c \ubc14\uc774\uc800\uc5d0\uc11c \uae30\uc220 \uc9c0\uc6d0\ub418\ub294 \ud45c\uc900\uc5d0 \uc900\uac70\ud55c \ud504\ub85c\ud1a0\ucf5c\uc744 \uc0ac\uc6a9\ud574 \uc8fc\uc2ed\uc2dc\uc624. message.desc.secondary.storage=\uac01 Zone\uc5d0\ub294 \uc801\uc5b4\ub3c4 \ud55c \uac1c \uc774\uc0c1\uc758 NFS \uc989 2\ucc28 \uc2a4\ud1a0\ub9ac\uc9c0 \uc11c\ubc84\uac00 \ud544\uc694\ud569\ub2c8\ub2e4. \uc9c0\uae08 \uc5ec\uae30\uc11c \uccab\ubc88\uc9f8 \uc11c\ubc84\ub97c \ucd94\uac00\ud569\ub2c8\ub2e4. 2\ucc28 \uc2a4\ud1a0\ub9ac\uc9c0\ub294 VM \ud15c\ud50c\ub9bf, ISO \uc774\ubbf8\uc9c0 \ubc0f VM \ub514\uc2a4\ud06c \ubcfc\ub968 \uc2a4\ub0c5\uc0f7\uc744 \ud3ec\ud568\ud569\ub2c8\ub2e4. \uc774 \uc11c\ubc84\ub294 Zone\ub0b4 \ubaa8\ub4e0 \ud638\uc2a4\ud2b8\uc5d0\uc11c \uc0ac\uc6a9\ud560 \uc218 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4.

IP \uc8fc\uc18c\uc640 \ub0b4\ubcf4\ub0b4\ub0bc \uacbd\ub85c\ub97c \uc785\ub825\ud574 \uc8fc\uc2ed\uc2dc\uc624. message.desc.zone=Zone\uc740 CloudStack \ud658\uacbd\ub0b4 \ucd5c\ub300 \uc870\uc9c1 \ub2e8\uc704\ub85c \uc6d0\ub798 \ub2e8\uc77c \ub370\uc774\ud130 \uc13c\ud130\uc5d0 \ud574\ub2f9\ud569\ub2c8\ub2e4. Zone\uc5d0 \ud574\uc11c \ubb3c\ub9ac\uc801\uc778 \ubd84\ub9ac\uc640 \uc911\ubcf5\uc131\uc774 \uc81c\uacf5\ub429\ub2c8\ub2e4. Zone\uc740 \ud55c \uac1c \uc774\uc0c1 Pod( \uac01 Pod\ub294 \ud638\uc2a4\ud2b8\uc640 \uae30\ubcf8 \uc2a4\ud1a0\ub9ac\uc9c0 \uc11c\ubc84\uc5d0\uc11c \uad6c\uc131)\uc640 Zone\ub0b4 \ubaa8\ub4e0 Pod\ub85c \uacf5\uc720\ub418\ub294 2\ucc28 \uc2a4\ud1a0\ub9ac\uc9c0 \uc11c\ubc84\ub85c \uad6c\uc131\ub429\ub2c8\ub2e4. @@ -1381,7 +1380,6 @@ message.step.3.continue=\uc2e4\ud589\ud558\ub824\uba74 \ub514\uc2a4\ud06c\uc81c\ message.step.3.desc= message.step.4.continue=\uc2e4\ud589\ud558\ub824\uba74 \ub124\ud2b8\uc6cc\ud06c\ub97c \uc801\uc5b4\ub3c4 \ud55c \uac1c \uc774\uc0c1 \uc120\ud0dd\ud574 \uc8fc\uc2ed\uc2dc\uc624. message.step.4.desc=\uac00\uc0c1 \uc778\uc2a4\ud134\uc2a4\uac00 \uc811\uc18d\ud558\ub294 \uae30\ubcf8 \ub124\ud2b8\uc6cc\ud06c\ub97c \uc120\ud0dd\ud574 \uc8fc\uc2ed\uc2dc\uc624. -message.storage.traffic=\ud638\uc2a4\ud2b8\ub098 CloudStack \uc2dc\uc2a4\ud15c VM \ub4f1 \uad00\ub9ac \uc11c\ubc84\uc640 \ud1b5\uc2e0\ud558\ub294 CloudStack \ub0b4\ubd80 \uc790\uc6d0\uac04 \ud2b8\ub798\ud53d\uc785\ub2c8\ub2e4. \uc5ec\uae30\uc11c \uc2a4\ud1a0\ub9ac\uc9c0 \ud2b8\ub798\ud53d\uc744 \uad6c\uc131\ud574 \uc8fc\uc2ed\uc2dc\uc624. message.suspend.project=\ud604\uc7ac \ud504\ub85c\uc81d\ud2b8\ub97c \uc77c\uc2dc\uc815\uc9c0\ud558\uc2dc\uaca0\uc2b5\ub2c8\uae4c? message.template.desc=VM\uc758 \uc2dc\uc791\uc5d0 \uc0ac\uc6a9\ud560 \uc218 \uc788\ub294 OS \uc774\ubbf8\uc9c0 message.tooltip.dns.1=Zone\ub0b4 VM \ub85c \uc0ac\uc6a9\ud558\ub294 DNS \uc11c\ubc84 \uc774\ub984\uc785\ub2c8\ub2e4. Zone \uacf5\uac1c IP \uc8fc\uc18c\uc5d0\uc11c \uc774 \uc11c\ubc84\uc5d0 \ud1b5\uc2e0\ud560 \uc218 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. diff --git a/client/WEB-INF/classes/resources/messages_nb_NO.properties b/client/WEB-INF/classes/resources/messages_nb_NO.properties index be412449398..8fba48ca9c4 100644 --- a/client/WEB-INF/classes/resources/messages_nb_NO.properties +++ b/client/WEB-INF/classes/resources/messages_nb_NO.properties @@ -15,6 +15,7 @@ # specific language governing permissions and limitations # under the License. + changed.item.properties=Endrede egenskaper error.could.not.enable.zone=Kunne ikke aktivere sonen error.installWizard.message=Noe gikk galt. G\u00e5 tilbake og korriger feilene. diff --git a/client/WEB-INF/classes/resources/messages_pt_BR.properties b/client/WEB-INF/classes/resources/messages_pt_BR.properties index fd24f542e8d..23123c16764 100644 --- a/client/WEB-INF/classes/resources/messages_pt_BR.properties +++ b/client/WEB-INF/classes/resources/messages_pt_BR.properties @@ -15,6 +15,7 @@ # specific language governing permissions and limitations # under the License. + changed.item.properties=Alteradas propriedades do item confirm.enable.s3=Por favor preencha as informa\u00e7\u00f5es abaixo para habilitar suporte a storage secund\u00e1ria fornecida por S3 confirm.enable.swift=Por favor preencha as informa\u00e7\u00f5es abaixo para habilitar suporte ao Swift @@ -1112,7 +1113,6 @@ label.zones=Zonas label.zone.type=Tipo de Zona label.zone.wide=Zone-Wide label.zoneWizard.trafficType.guest=H\u00f3spede\: tr\u00e1fego entre m\u00e1quinas virtuais de usu\u00e1rios finais -label.zoneWizard.trafficType.management=Ger\u00eancia\: tr\u00e1fego entre recursos internos do CloudStack, incluindo quaisquer componentes que se comunicam com o servidor de gerenciamento, tais como hosts e m\u00e1quinas virtuais de sistema do CloudStack label.zoneWizard.trafficType.public=P\u00fablico\: tr\u00e1fego entre a internet e m\u00e1quinas virtuais na nuvem. label.zoneWizard.trafficType.storage=Storage\: tr\u00e1fego entre servidores de storage prim\u00e1ria e secund\u00e1ria, tais como templates de m\u00e1quinas virtuais e snapshots label.zone=Zona diff --git a/client/WEB-INF/classes/resources/messages_ru_RU.properties b/client/WEB-INF/classes/resources/messages_ru_RU.properties index b0ffe406ba8..5818abc9199 100644 --- a/client/WEB-INF/classes/resources/messages_ru_RU.properties +++ b/client/WEB-INF/classes/resources/messages_ru_RU.properties @@ -15,6 +15,7 @@ # specific language governing permissions and limitations # under the License. + changed.item.properties=\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u044b confirm.enable.swift=\u0417\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u043d\u0438\u0436\u0435\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438 Swift error.could.not.enable.zone=\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0437\u043e\u043d\u0443 @@ -1052,7 +1053,7 @@ message.acquire.public.ip=\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442 message.action.cancel.maintenance.mode=\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0435, \u0447\u0442\u043e \u0432\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0440\u0435\u0436\u0438\u043c \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f. message.action.cancel.maintenance=\u0423\u0437\u0435\u043b \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0432\u044b\u0448\u0435\u043b \u0438\u0437 \u0440\u0435\u0436\u0438\u043c\u0430 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f. \u042d\u0442\u043b\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043c\u043e\u0436\u0435\u0442 \u0434\u043b\u0438\u0442\u044c\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0438\u043d\u0443\u0442. message.action.change.service.warning.for.instance=\u0414\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u043e\u0433\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u0432\u0430\u0448\u0430 \u043c\u0430\u0448\u0438\u043d\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430. -message.action.change.service.warning.for.router=\n +message.action.change.service.warning.for.router=\u0414\u043b\u044f \u0440\u043e\u0443\u0442\u0435\u0440 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u043e\u0433\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u0432\u0430\u0448\u0430 \u043c\u0430\u0448\u0438\u043d\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430. message.action.delete.cluster=\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0435, \u0447\u0442\u043e \u0432\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0442\u0435\u0440. message.action.delete.disk.offering=\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0435, \u0447\u0442\u043e \u0432\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u0434\u0438\u0441\u043a\u043e\u0432\u044b\u0439 \u0440\u0435\u0441\u0443\u0440\u0441. message.action.delete.domain=\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0435, \u0447\u0442\u043e \u0432\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u0434\u043e\u043c\u0435\u043d. @@ -1130,7 +1131,6 @@ message.additional.networks.desc=\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u044 message.add.load.balancer=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u043a\u0443 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0432 \u0437\u043e\u043d\u0443 message.add.load.balancer.under.ip=\u041f\u0440\u0430\u0432\u0438\u043b\u043e \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u043a\u0438 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0431\u044b\u043b \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d \u0432 IP\: message.add.network=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0441\u0435\u0442\u044c \u0434\u043b\u044f \u0437\u043e\u043d\u044b\: -message.add.pod.during.zone.creation=\u041a\u0430\u0436\u0434\u0430\u044f \u0437\u043e\u043d\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043e\u0434\u0438\u043d \u0438\u043b\u0438 \u0431\u043e\u043b\u0435\u0435 \u0441\u0442\u0435\u043d\u0434\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b \u0441\u0435\u0439\u0447\u0430\u0441 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u0435 \u043f\u0435\u0440\u0432\u044b\u043c. \u0421\u0442\u0435\u043d\u0434 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0443\u0437\u043b\u044b \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u044b \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u043c \u0448\u0430\u0433\u0435. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u044b\u0445 \u0430\u0434\u0440\u0435\u0441\u043e\u0432 IP \u0434\u043b\u044f \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0439 \u0441\u0435\u0442\u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f. \u0414\u0438\u0430\u043f\u0430\u0437\u043e\u043d \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u044b\u0445 IP \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u043c \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0437\u043e\u043d\u044b \u043e\u0431\u043b\u0430\u043a\u0430. message.add.pod=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u0441\u0442\u0435\u043d\u0434 \u0434\u043b\u044f \u0437\u043e\u043d\u044b message.add.primary.storage=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0434\u043b\u044f \u0437\u043e\u043d\u044b , \u0441\u0442\u0435\u043d\u0434\u0430 message.add.primary=\u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 @@ -1185,7 +1185,6 @@ message.delete.user=\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442 message.desc.advanced.zone=\u0414\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0441\u0435\u0442\u0435\u0432\u044b\u0445 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u0439. \u042d\u0442\u0430 \u0441\u0435\u0442\u0435\u0432\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u0443\u044e \u0433\u0438\u0431\u043a\u043e\u0441\u0442\u044c \u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0438 \u0433\u043e\u0441\u0442\u0435\u0432\u043e\u0439 \u0441\u0435\u0442\u0438 \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0443\u0441\u043b\u0443\u0433, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a \u043c\u0435\u0436\u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u044d\u043a\u0440\u0430\u043d, VPN, \u0438\u043b\u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u043a\u0438 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438. message.desc.basic.zone=\u041f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0435\u0434\u0438\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u0441\u0435\u0442\u044c, \u0433\u0434\u0435 \u043a\u0430\u0436\u0434\u0430\u044f \u0412\u041c \u0438\u043c\u0435\u0435\u0442 \u00ab\u0431\u0435\u043b\u044b\u0439\u00bb IP-\u0430\u0434\u0440\u0435\u0441 \u0441\u0435\u0442\u0438. \u0418\u0437\u043e\u043b\u044f\u0446\u0438\u0438 \u0433\u043e\u0441\u0442\u0435\u0439 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0441\u0435\u0442\u0438 3-\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0433\u0440\u0443\u043f\u043f\u044b \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 (\u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044f IP-\u0432\u0434\u0440\u0435\u0441\u043e\u0432) message.desc.cluster=\u041a\u0430\u0436\u0434\u044b\u0439 \u0441\u0442\u0435\u043d\u0434 \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u043e\u0434\u0438\u043d \u0438\u043b\u0438 \u0431\u043e\u043b\u0435\u0435 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u043e\u0432, \u043f\u0435\u0440\u0432\u044b\u0439 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0432\u044b \u0441\u0435\u0439\u0447\u0430\u0441 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u0435. \u041a\u043b\u0430\u0441\u0442\u0435\u0440 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0433\u0440\u0443\u043f\u043f\u0443 \u0443\u0437\u043b\u043e\u0432. \u0423\u0437\u043b\u044b \u0432 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0435 \u0438\u043c\u0435\u044e\u0442 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e\u0435 \u043e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0435, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u043e\u0434\u0438\u043d \u0433\u0438\u043f\u0435\u0440\u0432\u0438\u0437\u043e\u0440, \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u043e\u0434\u043d\u043e\u0439 \u0441\u0435\u0442\u0438 \u0438 \u0438\u043c\u0435\u044e\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043e\u0434\u043d\u043e\u043c\u0443 \u0438 \u0442\u043e\u043c\u0443 \u0436\u0435 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c\u0443 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0443. \u041a\u0430\u0436\u0434\u044b\u0439 \u043a\u043b\u0430\u0441\u0442\u0435\u0440 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043e\u0434\u0438\u043d \u0438\u043b\u0438 \u0431\u043e\u043b\u0435\u0435 \u0443\u0437\u043b\u043e\u0432, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0438\u0435\u0442\u044c \u043e\u0434\u0438\u043d \u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449. -message.desc.host=\u041a\u0430\u0436\u0434\u044b\u0439 \u043a\u043b\u0430\u0441\u0442\u0435\u0440 \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u043e\u0434\u0438\u043d \u0443\u0437\u0435\u043b (\u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440) \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0412\u041c, \u043f\u0435\u0440\u0432\u044b\u0439 \u0438\u0437 \u043a\u043b\u0430\u0441\u0442\u0435\u0440 \u0432\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u0435 \u0441\u0435\u0439\u0447\u0430\u0441. \u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0443\u0437\u043b\u0430 \u0432 CloudStack \u0432\u0430\u0436\u043d\u0430 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0433\u0438\u043f\u0435\u0440\u0432\u0438\u0437\u043e\u0440\u0430 \u043d\u0430 \u0443\u0437\u0435\u043b, \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0430 IP \u043a \u0443\u0437\u043b\u0443 \u0438 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0443\u0437\u043b\u0430 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f CloudStack.

\u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u0438\u043c\u044f DNS \u0438\u043b\u0438 \u0430\u0434\u0440\u0435\u0441 IP, \u0438\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u043a \u041e\u0421 (\u043e\u0431\u044b\u0447\u043d\u043e root), \u0430 \u0442\u0430\u043a\u0436\u0435 \u043c\u0435\u0442\u043a\u0438 \u0434\u043b\u044f \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0443\u0437\u043b\u043e\u0432. message.desc.primary.storage=\u041a\u0430\u0436\u0434\u0430\u044f \u0433\u0440\u0443\u043f\u043f\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043e\u0434\u0438\u043d \u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u044b\u0445 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445, \u0438 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u0435\u0440\u0432\u044b\u0439 \u0441\u0435\u0439\u0447\u0430\u0441. \u041f\u0435\u0440\u0432\u0438\u0447\u043d\u0430\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u044b \u0436\u0435\u0441\u0442\u043a\u043e\u0433\u043e \u0434\u0438\u0441\u043a\u0430 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u043c\u0430\u0448\u0438\u043d, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0445 \u043d\u0430 \u0443\u0437\u043b\u0430\u0445 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u043b\u044e\u0431\u043e\u0439 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0439 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0433\u0438\u043f\u0435\u0440\u0432\u0438\u0437\u043e\u0440\u0430. message.desc.secondary.storage=\u041a\u0430\u0436\u0434\u0430\u044f \u0437\u043e\u043d\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u043e\u0431\u043b\u0430\u0434\u0430\u0442\u044c \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u043d\u0438\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c NFS \u0438\u043b\u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435\u043c \u0438 \u0438\u0445 \u043d\u0430\u0434\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c. \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043e \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432 \u0412\u041c, \u043e\u0431\u0440\u0430\u0437\u043e\u0432 ISO \u0438 \u0441\u043d\u0438\u043c\u043a\u043e\u0432 \u0412\u041c. \u042d\u0442\u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0443\u0437\u043b\u043e\u0432 \u0437\u043e\u043d\u044b.

\u041f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c IP-\u0430\u0434\u0440\u0435\u0441 \u0438 \u043f\u0443\u0442\u044c. message.desc.zone=layer 3 @@ -1310,7 +1309,6 @@ message.step.3.continue=\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0434\ message.step.3.desc= message.step.4.continue=\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u043d\u0443 \u0441\u0435\u0442\u044c \u0434\u043b\u044f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f. message.step.4.desc=\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u0443\u044e \u0441\u0435\u0442\u044c, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0430 \u043c\u0430\u0448\u0438\u043d\u0430. -message.storage.traffic=\u0422\u0440\u0430\u0444\u0438\u043a \u043c\u0435\u0436\u0434\u0443 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u043c\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c\u0438 CloudStack, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0432\u0441\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0442 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0435 \u0445\u043e\u0441\u0442\u044b \u0438 CloudStack \u0441\u0438\u0441\u0442\u0435\u043c\u044b. \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435 \u0442\u0440\u0430\u0444\u0438\u043a \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0437\u0434\u0435\u0441\u044c. message.suspend.project=\u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442? message.template.desc=\u041e\u0431\u0440\u0430\u0437 \u041e\u0421, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043e\u0447\u043d\u043e\u0439 \u0432 \u0412\u041c message.tooltip.dns.1=\u0418\u043c\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u0430 DNS \u0434\u043b\u044f \u0412\u041c \u044d\u0442\u043e\u0439 \u0437\u043e\u043d\u044b. \u041f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0435 IP-\u0430\u0434\u0440\u0435\u0441\u0430 \u044d\u0442\u043e\u0439 \u0437\u043e\u043d\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u043c\u0435\u0442\u044c \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u0434\u043e \u044d\u0442\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430. diff --git a/client/WEB-INF/classes/resources/messages_zh_CN.properties b/client/WEB-INF/classes/resources/messages_zh_CN.properties index f62439d460d..687ef60b3c1 100644 --- a/client/WEB-INF/classes/resources/messages_zh_CN.properties +++ b/client/WEB-INF/classes/resources/messages_zh_CN.properties @@ -15,6 +15,7 @@ # specific language governing permissions and limitations # under the License. + changed.item.properties=\u66f4\u6539\u9879\u76ee\u5c5e\u6027 confirm.enable.s3=\u8bf7\u586b\u5199\u4e0b\u5217\u4fe1\u606f\u4ee5\u542f\u7528\u652f\u6301S3\u7684\u4e8c\u7ea7\u5b58\u50a8 confirm.enable.swift=\u8bf7\u586b\u5199\u4ee5\u4e0b\u4fe1\u606f\u4ee5\u542f\u7528\u5bf9 SWIFT \u7684\u652f\u6301 @@ -1164,7 +1165,6 @@ label.zone.type=\u533a\u57df\u7c7b\u578b label.zone=\u533a\u57df label.zone.wide=\u6574\u4e2a\u533a\u57df label.zoneWizard.trafficType.guest=\u6765\u5bbe\u7f51\u7edc\: \u5ba2\u6237\u865a\u62df\u673a\u4e4b\u95f4\u7684\u7f51\u7edc\u6d41\u91cf -label.zoneWizard.trafficType.management=\u7ba1\u7406\u7f51\: CloudStack\u5185\u90e8\u8d44\u6e90\u4e4b\u95f4\u7684\u7f51\u7edc\u6d41\u91cf, \u5305\u62ec\u4e0e\u7ba1\u7406\u670d\u52a1\u5668\u4ea4\u4e92\u7684\u4efb\u4f55\u7ec4\u4ef6, \u6bd4\u5982\u4e3b\u673a\u548cCloudStack\u7cfb\u7edf\u865a\u62df\u673a label.zoneWizard.trafficType.public=\u516c\u5171\u7f51\u7edc\: \u4e91\u73af\u5883\u4e2d\u865a\u62df\u673a\u4e0e\u56e0\u7279\u7f51\u4e4b\u95f4\u7684\u7f51\u7edc\u6d41\u91cf. label.zoneWizard.trafficType.storage=\u5b58\u50a8\u7f51\: \u4e3b\u5b58\u50a8\u4e0e\u4e8c\u7ea7\u5b58\u50a8\u670d\u52a1\u5668\u4e4b\u95f4\u7684\u6d41\u91cf, \u6bd4\u5982\u865a\u673a\u6a21\u677f\u548c\u5feb\u7167 managed.state=\u6258\u7ba1\u72b6\u6001 @@ -1255,7 +1255,6 @@ message.add.load.balancer=\u5411\u533a\u57df\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u8d1f message.add.load.balancer.under.ip=\u5df2\u5728\u4ee5\u4e0b IP \u4e0b\u6dfb\u52a0\u8d1f\u8f7d\u5e73\u8861\u5668\u89c4\u5219\: message.add.network=\u4e3a\u533a\u57df\u6dfb\u52a0\u4e00\u4e2a\u65b0\u7f51\u7edc\: message.add.new.gateway.to.vpc=\u8bf7\u6307\u5b9a\u5c06\u65b0\u7f51\u5173\u6dfb\u52a0\u5230\u6b64 VPC \u6240\u9700\u7684\u4fe1\u606f\u3002 -message.add.pod.during.zone.creation=\u6bcf\u4e2a\u533a\u57df\u4e2d\u5fc5\u987b\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u63d0\u4f9b\u70b9\uff0c\u73b0\u5728\u6211\u4eec\u5c06\u6dfb\u52a0\u7b2c\u4e00\u4e2a\u63d0\u4f9b\u70b9\u3002\u63d0\u4f9b\u70b9\u4e2d\u5305\u542b\u4e3b\u673a\u548c\u4e3b\u5b58\u50a8\u670d\u52a1\u5668\uff0c\u60a8\u5c06\u5728\u968f\u540e\u7684\u67d0\u4e2a\u6b65\u9aa4\u4e2d\u6dfb\u52a0\u8fd9\u4e9b\u4e3b\u673a\u548c\u670d\u52a1\u5668\u3002\u9996\u5148\uff0c\u8bf7\u4e3a CloudStack \u7684\u5185\u90e8\u7ba1\u7406\u6d41\u91cf\u914d\u7f6e\u4e00\u4e2a\u9884\u7559 IP \u5730\u5740\u8303\u56f4\u3002\u9884\u7559\u7684 IP \u8303\u56f4\u5bf9\u4e91\u4e2d\u7684\u6bcf\u4e2a\u533a\u57df\u6765\u8bf4\u5fc5\u987b\u552f\u4e00\u3002 message.add.pod=\u4e3a\u533a\u57df \u6dfb\u52a0\u4e00\u4e2a\u65b0\u63d0\u4f9b\u70b9 message.add.primary.storage=\u4e3a\u533a\u57df \u3001\u63d0\u4f9b\u70b9 \u6dfb\u52a0\u4e00\u4e2a\u65b0\u7684\u4e3b\u5b58\u50a8 message.add.primary=\u8bf7\u6307\u5b9a\u4ee5\u4e0b\u53c2\u6570\u4ee5\u6dfb\u52a0\u4e00\u4e2a\u65b0\u4e3b\u5b58\u50a8 @@ -1317,7 +1316,6 @@ message.delete.VPN.gateway=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u966 message.desc.advanced.zone=\u9002\u7528\u4e8e\u66f4\u52a0\u590d\u6742\u7684\u7f51\u7edc\u62d3\u6251\u3002\u6b64\u7f51\u7edc\u6a21\u5f0f\u5728\u5b9a\u4e49\u6765\u5bbe\u7f51\u7edc\u5e76\u63d0\u4f9b\u9632\u706b\u5899\u3001VPN \u6216\u8d1f\u8f7d\u5e73\u8861\u5668\u652f\u6301\u7b49\u81ea\u5b9a\u4e49\u7f51\u7edc\u65b9\u6848\u65b9\u9762\u63d0\u4f9b\u4e86\u6700\u5927\u7684\u7075\u6d3b\u6027\u3002 message.desc.basic.zone=\u63d0\u4f9b\u4e00\u4e2a\u7f51\u7edc\uff0c\u5c06\u76f4\u63a5\u4ece\u6b64\u7f51\u7edc\u4e2d\u4e3a\u6bcf\u4e2a VM \u5b9e\u4f8b\u5206\u914d\u4e00\u4e2a IP\u3002\u53ef\u4ee5\u901a\u8fc7\u5b89\u5168\u7ec4\u7b49\u7b2c 3 \u5c42\u65b9\u5f0f\u63d0\u4f9b\u6765\u5bbe\u9694\u79bb(IP \u5730\u5740\u6e90\u8fc7\u6ee4)\u3002 message.desc.cluster=\u6bcf\u4e2a\u63d0\u4f9b\u70b9\u4e2d\u5fc5\u987b\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u7fa4\u96c6\uff0c\u73b0\u5728\u6211\u4eec\u5c06\u6dfb\u52a0\u7b2c\u4e00\u4e2a\u7fa4\u96c6\u3002\u7fa4\u96c6\u63d0\u4f9b\u4e86\u4e00\u79cd\u7f16\u7ec4\u4e3b\u673a\u7684\u65b9\u6cd5\u3002\u7fa4\u96c6\u4e2d\u7684\u6240\u6709\u4e3b\u673a\u90fd\u5177\u6709\u76f8\u540c\u7684\u786c\u4ef6\uff0c\u8fd0\u884c\u76f8\u540c\u7684\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\uff0c\u4f4d\u4e8e\u76f8\u540c\u7684\u5b50\u7f51\u4e2d\uff0c\u5e76\u8bbf\u95ee\u76f8\u540c\u7684\u5171\u4eab\u5b58\u50a8\u3002\u6bcf\u4e2a\u7fa4\u96c6\u7531\u4e00\u4e2a\u6216\u591a\u4e2a\u4e3b\u673a\u4ee5\u53ca\u4e00\u4e2a\u6216\u591a\u4e2a\u4e3b\u5b58\u50a8\u670d\u52a1\u5668\u7ec4\u6210\u3002 -message.desc.host=\u6bcf\u4e2a\u7fa4\u96c6\u4e2d\u5fc5\u987b\u81f3\u5c11\u5305\u542b\u4e00\u4e2a\u4e3b\u673a\u4ee5\u4f9b\u6765\u5bbe VM \u5728\u4e0a\u9762\u8fd0\u884c\uff0c\u73b0\u5728\u6211\u4eec\u5c06\u6dfb\u52a0\u7b2c\u4e00\u4e2a\u4e3b\u673a\u3002\u8981\u4f7f\u4e3b\u673a\u5728 CloudStack \u4e2d\u8fd0\u884c\uff0c\u5fc5\u987b\u5728\u6b64\u4e3b\u673a\u4e0a\u5b89\u88c5\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u8f6f\u4ef6\uff0c\u4e3a\u5176\u5206\u914d\u4e00\u4e2a IP \u5730\u5740\uff0c\u5e76\u786e\u4fdd\u5c06\u5176\u8fde\u63a5\u5230 CloudStack \u7ba1\u7406\u670d\u52a1\u5668\u3002

\u8bf7\u63d0\u4f9b\u4e3b\u673a\u7684 DNS \u6216 IP \u5730\u5740\u3001\u7528\u6237\u540d(\u901a\u5e38\u4e3a root)\u548c\u5bc6\u7801\uff0c\u4ee5\u53ca\u7528\u4e8e\u5bf9\u4e3b\u673a\u8fdb\u884c\u5206\u7c7b\u7684\u4efb\u4f55\u6807\u7b7e\u3002 message.desc.primary.storage=\u6bcf\u4e2a\u7fa4\u96c6\u4e2d\u5fc5\u987b\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u4e3b\u5b58\u50a8\u670d\u52a1\u5668\uff0c\u73b0\u5728\u6211\u4eec\u5c06\u6dfb\u52a0\u7b2c\u4e00\u4e2a\u4e3b\u5b58\u50a8\u670d\u52a1\u5668\u3002\u4e3b\u5b58\u50a8\u4e2d\u5305\u542b\u5728\u7fa4\u96c6\u4e2d\u7684\u4e3b\u673a\u4e0a\u8fd0\u884c\u7684\u6240\u6709 VM \u7684\u78c1\u76d8\u5377\u3002\u8bf7\u4f7f\u7528\u5e95\u5c42\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u652f\u6301\u7684\u7b26\u5408\u6807\u51c6\u7684\u534f\u8bae\u3002 message.desc.secondary.storage=\u6bcf\u4e2a\u533a\u57df\u4e2d\u5fc5\u987b\u81f3\u5c11\u5305\u542b\u4e00\u4e2a NFS \u6216\u8f85\u52a9\u5b58\u50a8\u670d\u52a1\u5668\uff0c\u73b0\u5728\u6211\u4eec\u5c06\u6dfb\u52a0\u7b2c\u4e00\u4e2a NFS \u6216\u8f85\u52a9\u5b58\u50a8\u670d\u52a1\u5668\u3002\u8f85\u52a9\u5b58\u50a8\u7528\u4e8e\u5b58\u50a8 VM \u6a21\u677f\u3001ISO \u6620\u50cf\u548c VM \u78c1\u76d8\u5377\u5feb\u7167\u3002\u6b64\u670d\u52a1\u5668\u5fc5\u987b\u5bf9\u533a\u57df\u4e2d\u7684\u6240\u6709\u670d\u52a1\u5668\u53ef\u7528\u3002

\u8bf7\u63d0\u4f9b IP \u5730\u5740\u548c\u5bfc\u51fa\u8def\u5f84\u3002 message.desc.zone=\u533a\u57df\u662f CloudStack \u4e2d\u6700\u5927\u7684\u7ec4\u7ec7\u5355\u4f4d\uff0c\u4e00\u4e2a\u533a\u57df\u901a\u5e38\u4e0e\u4e00\u4e2a\u6570\u636e\u4e2d\u5fc3\u76f8\u5bf9\u5e94\u3002\u533a\u57df\u53ef\u63d0\u4f9b\u7269\u7406\u9694\u79bb\u548c\u5197\u4f59\u3002\u4e00\u4e2a\u533a\u57df\u7531\u4e00\u4e2a\u6216\u591a\u4e2a\u63d0\u4f9b\u70b9\u4ee5\u53ca\u7531\u533a\u57df\u4e2d\u7684\u6240\u6709\u63d0\u4f9b\u70b9\u5171\u4eab\u7684\u4e00\u4e2a\u8f85\u52a9\u5b58\u50a8\u670d\u52a1\u5668\u7ec4\u6210\uff0c\u5176\u4e2d\u6bcf\u4e2a\u63d0\u4f9b\u70b9\u4e2d\u5305\u542b\u591a\u4e2a\u4e3b\u673a\u548c\u4e3b\u5b58\u50a8\u670d\u52a1\u5668\u3002 @@ -1447,7 +1445,6 @@ message.step.3.continue=\u8bf7\u9009\u62e9\u4e00\u79cd\u78c1\u76d8\u65b9\u6848\u message.step.3.desc= message.step.4.continue=\u8bf7\u81f3\u5c11\u9009\u62e9\u4e00\u4e2a\u7f51\u7edc\u4ee5\u7ee7\u7eed message.step.4.desc=\u8bf7\u9009\u62e9\u865a\u62df\u5b9e\u4f8b\u8981\u8fde\u63a5\u5230\u7684\u4e3b\u7f51\u7edc\u3002 -message.storage.traffic=CloudStack \u5185\u90e8\u8d44\u6e90(\u5305\u62ec\u4e0e\u7ba1\u7406\u670d\u52a1\u5668\u901a\u4fe1\u7684\u4efb\u4f55\u7ec4\u4ef6\uff0c\u4f8b\u5982\u4e3b\u673a\u548c CloudStack \u7cfb\u7edf VM)\u4e4b\u95f4\u7684\u6d41\u91cf\u3002\u8bf7\u5728\u6b64\u5904\u914d\u7f6e\u5b58\u50a8\u6d41\u91cf\u3002 message.suspend.project=\u662f\u5426\u786e\u5b9e\u8981\u6682\u505c\u6b64\u9879\u76ee? message.template.desc=\u53ef\u7528\u4e8e\u542f\u52a8 VM \u7684\u64cd\u4f5c\u7cfb\u7edf\u6620\u50cf message.tooltip.dns.1=\u4f9b\u533a\u57df\u4e2d\u7684 VM \u4f7f\u7528\u7684 DNS \u670d\u52a1\u5668\u540d\u79f0\u3002\u533a\u57df\u7684\u516c\u7528 IP \u5730\u5740\u5fc5\u987b\u8def\u7531\u5230\u6b64\u670d\u52a1\u5668\u3002 diff --git a/client/pom.xml b/client/pom.xml index 743cd363005..197ba27975c 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -85,6 +85,11 @@ cloud-plugin-network-midonet ${project.version} + + org.apache.cloudstack + cloud-plugin-network-internallb + ${project.version} + org.apache.cloudstack cloud-plugin-hypervisor-xen @@ -239,6 +244,11 @@ cloud-plugin-host-anti-affinity ${project.version} + + org.apache.cloudstack + cloud-console-proxy + ${project.version} + install @@ -450,16 +460,15 @@ - test - - - - - + + + + + diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 40c2182666f..222924c2f07 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -82,7 +82,7 @@
- + + + + + @@ -703,7 +711,6 @@ - @@ -790,6 +797,8 @@ + + diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index ccd6adfc6fe..0e6f3a7111c 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -67,7 +67,7 @@ getVMPassword=15 restoreVirtualMachine=15 changeServiceForVirtualMachine=15 scaleVirtualMachine=15 -assignVirtualMachine=1 +assignVirtualMachine=7 migrateVirtualMachine=1 migrateVirtualMachineWithVolume=1 recoverVirtualMachine=7 @@ -127,6 +127,9 @@ deleteVlanIpRange=1 listVlanIpRanges=1 dedicatePublicIpRange=1 releasePublicIpRange=1 +dedicateGuestVlanRange=1 +releaseDedicatedGuestVlanRange=1 +listDedicatedGuestVlanRanges=1 #### address commands associateIpAddress=15 @@ -583,11 +586,22 @@ removeFromGlobalLoadBalancerRule=15 listVMSnapshot=15 createVMSnapshot=15 deleteVMSnapshot=15 -revertToSnapshot=15 +revertToVMSnapshot=15 #### Baremetal commands addBaremetalHost=1 +#### New Load Balancer commands +createLoadBalancer=15 +listLoadBalancers=15 +deleteLoadBalancer=15 + +#Internal Load Balancer Element commands +configureInternalLoadBalancerElement=1 +createInternalLoadBalancerElement=1 +listInternalLoadBalancerElements=1 + + #### Affinity group commands createAffinityGroup=15 deleteAffinityGroup=15 @@ -605,3 +619,10 @@ addCiscoAsa1000vResource=1 deleteCiscoAsa1000vResource=1 listCiscoAsa1000vResources=1 +#### Internal LB VM commands +stopInternalLoadBalancerVM=1 +startInternalLoadBalancerVM=1 +listInternalLoadBalancerVMs=1 + +### Network Isolation methods listing +listNetworkIsolationMethods=1 diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index 7a469816f82..8a45e5fea85 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -198,6 +198,7 @@ + @@ -241,6 +242,7 @@ + - + @@ -294,6 +294,7 @@ + @@ -343,6 +344,7 @@ + + + + + + diff --git a/docs/en-US/MidoNet_Plugin_Guide.xml b/docs/en-US/MidoNet_Plugin_Guide.xml new file mode 100644 index 00000000000..86182e60b71 --- /dev/null +++ b/docs/en-US/MidoNet_Plugin_Guide.xml @@ -0,0 +1,52 @@ + + +%BOOK_ENTITIES; + +%xinclude; +]> + + + + + + &PRODUCT; Plugin Guide for the MidoNet Plugin + Apache CloudStack + 4.2.0 + 1 + + + + Plugin Guide for the MidoNet Plugin. + + + + + + + + + + + + + + + + diff --git a/docs/en-US/Release_Notes.xml b/docs/en-US/Release_Notes.xml index cda8d724e9f..dca95d37c16 100644 --- a/docs/en-US/Release_Notes.xml +++ b/docs/en-US/Release_Notes.xml @@ -5113,7 +5113,7 @@ service cloudstack-agent start Start the first Management Server. Do not start any other Management Server nodes yet. - # service cloud-management start + # service cloudstack-management start Wait until the databases are upgraded. Ensure that the database upgrade is complete. After confirmation, start the other Management Servers one at a time by running the same command on each node. @@ -5126,7 +5126,7 @@ service cloudstack-agent start Start all Usage Servers (if they were running on your previous version). Perform this on each Usage Server host. - # service cloud-usage start + # service cloudstack-usage start @@ -5152,7 +5152,7 @@ service cloudstack-agent start Start the agent. - # service cloud-agent start + # service cloudstack-agent start Edit /etc/cloud/agent/agent.properties to change the @@ -5742,7 +5742,7 @@ service cloudstack-agent start Start the first Management Server. Do not start any other Management Server nodes yet. - # service cloud-management start + # service cloudstack-management start Wait until the databases are upgraded. Ensure that the database upgrade is complete. You should see a message like "Complete! Done." After confirmation, start the other Management Servers one at a time by running the same command on each node. @@ -5750,7 +5750,7 @@ service cloudstack-agent start Start all Usage Servers (if they were running on your previous version). Perform this on each Usage Server host. - # service cloud-usage start + # service cloudstack-usage start (KVM only) Additional steps are required for each KVM host. These steps will not @@ -5776,7 +5776,7 @@ service cloudstack-agent start Start the agent. - # service cloud-agent start + # service cloudstack-agent start Copy the contents of the agent.properties file to the new diff --git a/docs/en-US/added-API-commands-4.2.xml b/docs/en-US/added-API-commands-4.2.xml index 4bec148ba96..3abb780663e 100644 --- a/docs/en-US/added-API-commands-4.2.xml +++ b/docs/en-US/added-API-commands-4.2.xml @@ -39,5 +39,83 @@ The response parameters are: id, ipaddress, secondaryips, gateway, netmask, macaddr, broadcasturi, isolationuri, isdefault, + + deleteAlerts + Deletes the specified alerts. The request parameters are: ids (allowed to pass one or + more IDs separated by comma); type (string); olderthan (yyyy-mm-dd format). + The response parameters are: true, false + + + archiveAlerts + Archives the specified alerts. The request parameters are: ids (allowed to pass one or + more IDs separated by comma); type (string); olderthan (yyyy-mm-dd format). + The response parameters are: true, false + + + deleteEvents + Deletes the specified events. The request parameters are: ids (allowed to pass one or + more IDs separated by comma); type (string); olderthan (yyyy-mm-dd format). + The response parameters are: true, false + + + archiveEvents + Archives the specified events. The request parameters are: ids (allowed to pass one or + more IDs separated by comma); type (string); olderthan (yyyy-mm-dd format). + The response parameters are: true, false + + + createGlobalLoadBalancerRule + Creates a GSLB rule. The request parameters are name (the name of the global load + balancer rule); domain name ( the preferred domain name for the service); lb algorithm (the + algorithm used to load balance the traffic across the zones); session persistence (source IP + and HTTP cookie); account name; and domain Id. + + + assignToGlobalLoadBalancerRule + Assigns a load balancing rule or list of load balancing rules to GSLB. The request + parameters are: id (the UUID of global load balancer rule); loadbalancerrulelist (the list + load balancer rules that will be assigned to global load balancer rule. These are second + tier load balancing rules created with createLoadBalancerRule API. Weight is optional, the + default is 1). + + + removeFromGlobalLoadBalancerRule + Removes a load balancer rule association with global load balancer rule. The request + parameters are id (the UUID of global load balancer rule); loadbalancerrulelist (the list + load balancer rules that will be assigned to global load balancer rule). + + + deleteGlobalLoadBalancerRule + Deletes a global load balancer rule. The request parameters is: id (the unique ID of the + global load balancer rule). + + + listGlobalLoadBalancerRule + Lists load balancer rules. + The request parameters are: account (lists resources by account. Use with the domainid + parameter); domainid (lists only resources belonging to the domain specified); id (the + unique ID of the global load balancer rule); isrecursive (defaults to false; but if true, + lists all the resources from the parent specified by the domainid); keyword (lists by + keyword); listall (if set to false, lists only resources belonging to the command's caller; + if set to true, lists resources that the caller is authorized to see. Default value is + false); page; pagesize; projectid (lists objects by project); regionid ; tags (lists + resources by tags: key/value pairs). + + + updateGlobalLoadBalancerRule + Updates global load balancer rules. + The request parameters are: id (the unique ID of the global load balancer rule); account + (lists resources by account. Use with the domainid parameter); description (the description + of the load balancer rule); domainid (lists only resources belonging to the domain + specified); gslblbmethod (the load balancer algorithm that is used to distributed traffic + across the zones participating in global server load balancing, if not specified defaults to + round robin); gslbstickysessionmethodname (the session sticky method; if not specified + defaults to sourceip); isrecursive (defaults to false, but if true, lists all resources from + the parent specified by the domainid till leaves); keyword (lists by keyword); listall (if + set to false, list only those resources belonging to the command's caller; if set to true, + lists resources that the caller is authorized to see. Default value is false); page; + pagesize; projectid (lists objects by project); regionid; tags (lists resources by tags: + key/value pairs) + diff --git a/docs/en-US/aws-ec2-configuration.xml b/docs/en-US/aws-ec2-configuration.xml index dd7732ebced..d6dd2b5467e 100644 --- a/docs/en-US/aws-ec2-configuration.xml +++ b/docs/en-US/aws-ec2-configuration.xml @@ -35,7 +35,7 @@ Be sure you have included the Amazon default service offering, m1.small. As well as any EC2 instance types that you will use. If you did not already do so when you set the configuration parameter in step , restart the Management Server. - # service cloud-management restart + # service cloudstack-management restart The following sections provides details to perform these steps diff --git a/docs/en-US/change-database-password.xml b/docs/en-US/change-database-password.xml index 0ab52675e3c..b0021a42a13 100644 --- a/docs/en-US/change-database-password.xml +++ b/docs/en-US/change-database-password.xml @@ -29,8 +29,8 @@ Before changing the password, you'll need to stop CloudStack's management server and the usage engine if you've deployed that component. -# service cloud-management stop -# service cloud-usage stop +# service cloudstack-management stop +# service cloudstack-usage stop @@ -68,7 +68,7 @@ db.usage.password=ENC(encrypted_password_from_above) After copying the new password over, you can now start CloudStack (and the usage engine, if necessary). - # service cloud-management start + # service cloudstack-management start # service cloud-usage start diff --git a/docs/en-US/changed-API-commands-4.2.xml b/docs/en-US/changed-API-commands-4.2.xml index 26f10ff6037..2dd5a3b05ea 100644 --- a/docs/en-US/changed-API-commands-4.2.xml +++ b/docs/en-US/changed-API-commands-4.2.xml @@ -29,6 +29,15 @@ + + createVlanIpRange + + No new parameter has been added. However, the current functionality has been + extended to add guest IPs from a different subnet in shared networks in a Basic zone. + Ensure that you provide netmask and gateway if you are adding guest IPs from a + different subnet. + + updateResourceLimit @@ -113,8 +122,10 @@ removelan (removes the specified VLAN range) - The removevlan and vlan parameters can be used together. If the VLAN range that you are trying - to remove is in use, the operation will not succeed. + + The removevlan and vlan parameters can be used together. If the VLAN range that + you are trying to remove is in use, the operation will not succeed. + diff --git a/docs/en-US/citrix-xenserver-installation.xml b/docs/en-US/citrix-xenserver-installation.xml index 2cd39a41368..a5118d751d4 100644 --- a/docs/en-US/citrix-xenserver-installation.xml +++ b/docs/en-US/citrix-xenserver-installation.xml @@ -610,7 +610,7 @@ master-password=[your password] Restart the Management Server and Usage Server. You only need to do this once for all clusters. - # service cloud-management start + # service cloudstack-management start # service cloud-usage start diff --git a/docs/en-US/configure-usage-server.xml b/docs/en-US/configure-usage-server.xml index 173f4a5306d..83bed07b349 100644 --- a/docs/en-US/configure-usage-server.xml +++ b/docs/en-US/configure-usage-server.xml @@ -32,8 +32,8 @@ In Actions, click the Edit icon. Type the desired value and click the Save icon. Restart the Management Server (as usual with any global configuration change) and also the Usage Server: - # service cloud-management restart -# service cloud-usage restart + # service cloudstack-management restart +# service cloudstack-usage restart The following table shows the global configuration settings that control the behavior of the Usage Server. diff --git a/docs/en-US/creating-network-offerings.xml b/docs/en-US/creating-network-offerings.xml index 2b23ca89a1f..260751ea079 100644 --- a/docs/en-US/creating-network-offerings.xml +++ b/docs/en-US/creating-network-offerings.xml @@ -253,7 +253,7 @@ mode. In this mode, network resources are allocated only when the first virtual machine starts in the network. When conservative mode is off, the public IP can only be used for a single service. For example, a public IP used for a port forwarding rule cannot be - used for defining other services, such as SaticNAT or load balancing. When the conserve + used for defining other services, such as StaticNAT or load balancing. When the conserve mode is on, you can define more than one service on the same public IP. If StaticNAT is enabled, irrespective of the status of the conserve mode, no port diff --git a/docs/en-US/database-replication.xml b/docs/en-US/database-replication.xml index 718c34959da..bb144579ddf 100644 --- a/docs/en-US/database-replication.xml +++ b/docs/en-US/database-replication.xml @@ -121,14 +121,14 @@ mysql> start slave; Failover This will provide for a replicated database that can be used to implement manual failover for the Management Servers. &PRODUCT; failover from one MySQL instance to another is performed by the administrator. In the event of a database failure you should: - Stop the Management Servers (via service cloud-management stop). + Stop the Management Servers (via service cloudstack-management stop). Change the replica's configuration to be a master and restart it. Ensure that the replica's port 3306 is open to the Management Servers. - Make a change so that the Management Server uses the new database. The simplest process here is to put the IP address of the new database server into each Management Server's /etc/cloud/management/db.properties. + Make a change so that the Management Server uses the new database. The simplest process here is to put the IP address of the new database server into each Management Server's /etc/cloudstack/management/db.properties. Restart the Management Servers: -# service cloud-management start +# service cloudstack-management start diff --git a/docs/en-US/delete-event-alerts.xml b/docs/en-US/delete-event-alerts.xml index 3eebcb727a0..ef39040c102 100644 --- a/docs/en-US/delete-event-alerts.xml +++ b/docs/en-US/delete-event-alerts.xml @@ -28,6 +28,18 @@ or by using the Details page. If you want to delete multiple alerts or events at the same time, you can use the respective context menu. You can delete alerts or events by category for a time period. + In order to support the delete or archive alerts, the following global parameters have been + added: + + + alert.purge.delay: The alerts older than specified + number of days are purged. Set the value to 0 to never purge alerts automatically. + + + alert.purge.interval: The interval in seconds to wait + before running the alert purge thread. The default is 86400 seconds (one day). + + Archived alerts or events cannot be viewed in the UI, or by using the API. They are maintained in the database for auditing or compliance purposes. diff --git a/docs/en-US/elastic-ip.xml b/docs/en-US/elastic-ip.xml index b09d37d43e1..8ecbd75be70 100644 --- a/docs/en-US/elastic-ip.xml +++ b/docs/en-US/elastic-ip.xml @@ -21,16 +21,31 @@
About Elastic IP Elastic IP (EIP) addresses are the IP addresses that are associated with an account, and act - as static IP addresses. The account owner has complete control over the Elastic IP addresses - that belong to the account. You can allocate an Elastic IP to a VM of your choice from the EIP - pool of your account. Later if required you can reassign the IP address to a different VM. This - feature is extremely helpful during VM failure. Instead of replacing the VM which is down, the - IP address can be reassigned to a new VM in your account. Elastic IP service provides Static NAT - (1:1) service in an EIP-enabled basic zone. The default network offering, + as static IP addresses. The account owner has the complete control over the Elastic IP addresses + that belong to the account. As an account owner, you can allocate an Elastic IP to a VM of your + choice from the EIP pool of your account. Later if required you can reassign the IP address to a + different VM. This feature is extremely helpful during VM failure. Instead of replacing the VM + which is down, the IP address can be reassigned to a new VM in your account. + Similar to the public IP address, Elastic IP addresses are mapped to their associated + private IP addresses by using StaticNAT. The EIP service is equipped with StaticNAT (1:1) + service in an EIP-enabled basic zone. The default network offering, DefaultSharedNetscalerEIPandELBNetworkOffering, provides your network with EIP and ELB network - services if a NetScaler device is deployed in your zone. Similar to the public IP address, - Elastic IP addresses are also mapped to their associated private IP addresses by using Stactic - NAT. + services if a NetScaler device is deployed in your zone. Consider the following illustration for + more details. + + + + + + eip-ns-basiczone.png: Elastic IP in a NetScaler-enabled Basic Zone. + + + In the illustration, a NetScaler appliance is the default entry or exit point for the + &PRODUCT; instances, and firewall is the default entry or exit point for the rest of the data + center. Netscaler provides LB services and staticNAT service to the guest networks. The guest + traffic in the pods and the Management Server are on different subnets / VLANs. The policy-based + routing in the data center core switch sends the public traffic through the NetScaler, whereas + the rest of the data center goes through the firewall. The EIP work flow is as follows: @@ -48,7 +63,6 @@ supported by NetScaler, in which the source IP address is replaced in the packets generated by a VM in the private network with the public IP address. - This default public IP will be released in two cases: @@ -68,12 +82,12 @@ - However, for the deployments where public IPs are limited resources, you have the - flexibility to choose not to allocate a public IP by default. You can use the Associate Public - IP option to turn on or off the automatic public IP assignment in the EIP-enabled Basic zones. - If you turn off the automatic public IP assignment while creating a network offering, only a - private IP is assigned to a VM when the VM is deployed with that network offering. Later, the - user can acquire an IP for the VM and enable static NAT. + For the deployments where public IPs are limited resources, you have the flexibility to + choose not to allocate a public IP by default. You can use the Associate Public IP option to + turn on or off the automatic public IP assignment in the EIP-enabled Basic zones. If you turn + off the automatic public IP assignment while creating a network offering, only a private IP is + assigned to a VM when the VM is deployed with that network offering. Later, the user can acquire + an IP for the VM and enable static NAT. For more information on the Associate Public IP option, see . For more information on the Associate Public IP option, see the @@ -83,7 +97,6 @@ continue to get both public IP and private by default, irrespective of the network offering configuration. - New deployments which use the default shared network offering with EIP and ELB services to create a shared network in the Basic zone will continue allocating public IPs to each user VM. diff --git a/docs/en-US/events.xml b/docs/en-US/events.xml index 4a1445873a4..3b93ee0451e 100644 --- a/docs/en-US/events.xml +++ b/docs/en-US/events.xml @@ -25,7 +25,7 @@ physical resources associated with a cloud environment. Events are used by monitoring systems, usage and billing systems, or any other event-driven workflow systems to discern a pattern and make the right business decision. In &PRODUCT; an event could be a state change of virtual or - psychical resources, an action performed by an user (action events), or policy based events + physical resources, an action performed by an user (action events), or policy based events (alerts). diff --git a/docs/en-US/external-firewalls-and-load-balancers.xml b/docs/en-US/external-firewalls-and-load-balancers.xml index b947daf7361..42ecacf9f75 100644 --- a/docs/en-US/external-firewalls-and-load-balancers.xml +++ b/docs/en-US/external-firewalls-and-load-balancers.xml @@ -29,5 +29,6 @@ xmlns:xi="http://www.w3.org/2001/XInclude"/> +
diff --git a/docs/en-US/gslb.xml b/docs/en-US/gslb.xml new file mode 100644 index 00000000000..23033317381 --- /dev/null +++ b/docs/en-US/gslb.xml @@ -0,0 +1,499 @@ + + +%BOOK_ENTITIES; +]> + + +
+ Global Server Load Balancing Support + &PRODUCT; supports Global Server Load Balancing (GSLB) functionalities to provide business + continuity, and enable seamless resource movement within a &PRODUCT; environment. &PRODUCT; + achieve this by extending its functionality of integrating with NetScaler Application Delivery + Controller (ADC), which also provides various GSLB capabilities, such as disaster recovery and + load balancing. The DNS redirection technique is used to achieve GSLB in &PRODUCT;. + In order to support this functionality, region level services and service provider are + introduced. A new service 'GSLB' is introduced as a region level service. The GSLB service + provider is introduced that will provider the GSLB service. Currently, NetScaler is the + supported GSLB provider in &PRODUCT;. GSLB functionality works in an Active-Active data center + environment. +
+ About Global Server Load Balancing + Global Server Load Balancing (GSLB) is an extension of load balancing functionality, which + is highly efficient in avoiding downtime. Based on the nature of deployment, GSLB represents a + set of technologies that is used for various purposes, such as load sharing, disaster + recovery, performance, and legal obligations. With GSLB, workloads can be distributed across + multiple data centers situated at geographically separated locations. GSLB can also provide an + alternate location for accessing a resource in the event of a failure, or to provide a means + of shifting traffic easily to simplify maintenance, or both. +
+ Components of GSLB + A typical GSLB environment is comprised of the following components: + + + GSLB Site: In &PRODUCT;terminology, GSLB sites are + represented by zones that are mapped to data centers, each of which has various network + appliances. Each GSLB site is managed by a NetScaler appliance that is local to that + site. Each of these appliances treats its own site as the local site and all other + sites, managed by other appliances, as remote sites. It is the central entity in a GSLB + deployment, and is represented by a name and an IP address. + + + GSLB Services: A GSLB service is typically + represented by a load balancing or content switching virtual server. In a GSLB + environment, you can have a local as well as remote GSLB services. A local GSLB service + represents a local load balancing or content switching virtual server. A remote GSLB + service is the one configured at one of the other sites in the GSLB setup. At each site + in the GSLB setup, you can create one local GSLB service and any number of remote GSLB + services. + + + GSLB Virtual Servers: A GSLB virtual server refers + to one or more GSLB services and balances traffic between traffic across the VMs in + multiple zones by using the &PRODUCT; functionality. It evaluates the configured GSLB + methods or algorithms to select a GSLB service to which to send the client requests. One + or more virtual servers from different zones are bound to the GSLB virtual server. GSLB + virtual server does not have a public IP associated with it, instead it will have a FQDN + DNS name. + + + Load Balancing or Content Switching Virtual + Servers: According to Citrix NetScaler terminology, a load balancing or + content switching virtual server represents one or many servers on the local network. + Clients send their requests to the load balancing or content switching virtual server’s + virtual IP (VIP) address, and the virtual server balances the load across the local + servers. After a GSLB virtual server selects a GSLB service representing either a local + or a remote load balancing or content switching virtual server, the client sends the + request to that virtual server’s VIP address. + + + DNS VIPs: DNS virtual IP represents a load + balancing DNS virtual server on the GSLB service provider. The DNS requests for domains + for which the GSLB service provider is authoritative can be sent to a DNS VIP. + + + Authoritative DNS: ADNS (Authoritative Domain Name + Server) is a service that provides actual answer to DNS queries, such as web site IP + address. In a GSLB environment, an ADNS service responds only to DNS requests for + domains for which the GSLB service provider is authoritative. When an ADNS service is + configured, the service provider owns that IP address and advertises it. When you create + an ADNS service, the NetScaler responds to DNS queries on the configured ADNS service IP + and port. + + +
+
+ How Does GSLB Works in &PRODUCT;? + Global server load balancing is used to manage the traffic flow to a web site hosted on + two separate zones that ideally are in different geographic locations. The following is an + illustration of how GLSB functionality is provided in &PRODUCT;: An organization, xyztelco, + has set up a public cloud that spans two zones, Zone-1 and Zone-2, across geographically + separated data centers that are managed by &PRODUCT;. Tenant-A of the cloud launches a + highly available solution by using xyztelco cloud. For that purpose, they launch two + instances each in both the zones: VM1 and VM2 in Zone-1 and VM5 and VM6 in Zone-2. Tenant-A + acquires a public IP, IP-1 in Zone-1, and configures a load balancer rule to load balance + the traffic between VM1 and VM2 instances. &PRODUCT; orchestrates setting up a virtual + server on the LB service provider in Zone-1. Virtual server 1 that is set up on the LB + service provider in Zone-1 represents a publicly accessible virtual server that client + reaches at IP-1. The client traffic to virtual server 1 at IP-1 will be load balanced across + VM1 and VM2 instances. + Tenant-A acquires another public IP, IP-2 in Zone-2 and sets up a load balancer rule to + load balance the traffic between VM5 and VM6 instances. Similarly in Zone-2, &PRODUCT; + orchestrates setting up a virtual server on the LB service provider. Virtual server 2 that + is setup on the LB service provider in Zone-2 represents a publicly accessible virtual + server that client reaches at IP-2. The client traffic that reaches virtual server 2 at IP-2 + is load balanced across VM5 and VM6 instances. At this point Tenant-A has the service + enabled in both the zones, but has no means to set up a disaster recovery plan if one of the + zone fails. Additionally, there is no way for Tenant-A to load balance the traffic + intelligently to one of the zones based on load, proximity and so on. The cloud + administrator of xyztelco provisions a GSLB service provider to both the zones. A GSLB + provider is typically an ADC that has the ability to act as an ADNS (Authoritative Domain + Name Server) and has the mechanism to monitor health of virtual servers both at local and + remote sites. The cloud admin enables GSLB as a service to the tenants that use zones 1 and + 2. + + + + + + gslb.png: GSLB architecture + + + Tenant-A wishes to leverage the GSLB service provided by the xyztelco cloud. Tenant-A + configures a GSLB rule to load balance traffic across virtual server 1 at Zone-1 and virtual + server 2 at Zone-2. The domain name is provided as A.xyztelco.com. &PRODUCT; orchestrates + setting up GSLB virtual server 1 on the GSLB service provider at Zone-1. &PRODUCT; binds + virtual server 1 of Zone-1 and virtual server 2 of Zone-2 to GLSB virtual server 1. GSLB + virtual server 1 is configured to start monitoring the health of virtual server 1 and 2 in + Zone-1. &PRODUCT; will also orchestrate setting up GSLB virtual server 2 on GSLB service + provider at Zone-2. &PRODUCT; will bind virtual server 1 of Zone-1 and virtual server 2 of + Zone-2 to GLSB virtual server 2. GSLB virtual server 2 is configured to start monitoring the + health of virtual server 1 and 2. &PRODUCT; will bind the domain A.xyztelco.com to both the + GSLB virtual server 1 and 2. At this point, Tenant-A service will be globally reachable at + A.xyztelco.com. The private DNS server for the domain xyztelcom.com is configured by the + admin out-of-band to resolve the domain A.xyztelco.com to the GSLB providers at both the + zones, which are configured as ADNS for the domain A.xyztelco.com. A client when sends a DNS + request to resolve A.xyztelcom.com, will eventually get DNS delegation to the address of + GSLB providers at zone 1 and 2. A client DNS request will be received by the GSLB provider. + The GSLB provider, depending on the domain for which it needs to resolve, will pick up the + GSLB virtual server associated with the domain. Depending on the health of the virtual + servers being load balanced, DNS request for the domain will be resolved to the public IP + associated with the selected virtual server. +
+
+
+ Configuring GSLB + A GSLB deployment is the logical collection of GSLB virtual server, GSLB service, LB + virtual server, service, domain, and ADNS service. To create a GSLB site, you must configure + load balancing in the zone. You must create GSLB vservers and GSLB services for each site. You + must bind GSLB services to GSLB vservers. You must then create an ADNS service that provides + the IP address of the best performing site to the client's request. A GSLB vserver is an + entity that performs load balancing for the domains bound to it by returning the IP address of + the best GSLB service. A GSLB service is a representation of the load balancing/content + switching vserver. An LB vserver load balances incoming traffic by identifying the best + server, then directs traffic to the corresponding service. It can also load-balance external + DNS name servers. Services are entities that represent the servers. The domain is the domain + name for which the system is the authoritative DNS server. By creating an ADNS service, the + system can be configured as an authoritative DNS server. + To configure GSLB in your cloud environment, as a cloud administrator you must perform the + following. + To configure such a GSLB setup, you must first configure a standard load balancing setup + for each zone. This enables you to balance load across the different servers in each zone in + the region. Then, configure both NetScaler appliances that you plan to add to each zone as + authoritative DNS (ADNS) servers. Next, create a GSLB site for each zone, configure GSLB + virtual servers for each site, create GLSB services, and bind the GSLB services to the GSLB + virtual servers. Finally, bind the domain to the GSLB virtual servers. The GSLB configurations + on the two appliances at the two different sites are identical, although each sites + load-balancing configuration is specific to that site. + Perform the following as a cloud administrator. As per the above example, the + administrator of xyztelco is the one who sets up GSLB: + + + In the cloud.dns.name global parameter, specify the DNS name of your tenant's cloud + that make use of the GSLB service. + + + On the NetScaler side, configure GSLB as given in Configuring Global Server Load Balancing (GSLB): + + + Configuring a standard load balancing setup. + + + Configure Authoritative DNS, as explained in Configuring an Authoritative DNS Service. + + + Configure a GSLB site with site name formed from the domain name details. + For more information, see Configuring a Basic GSLB Site. + + + Configure a GSLB virtual server. + For more information, see Configuring a GSLB Virtual Server. + + + Configure a GSLB service for each virtual server. + For more information, see Configuring a GSLB Service. + + + Bind the GSLB services to the GSLB virtual server. + For more information, see Binding GSLB Services to a GSLB Virtual Server. + + + Bind domain name to GSLB virtual server. Domain name is obtained from the domain + details. + For more information, see Binding a Domain to a GSLB Virtual Server. + + + + + In each zone that are participating in GSLB, add GSLB-enabled NetScaler device. + For more information, see . + + + As a domain administrator/ user perform the following: + + + Add a GSLB rule on both the sites. + See . + + + Assign load balancer rules. + See . + + +
+ Prerequisites and Guidelines + + + The GSLB functionality is supported both Basic and Advanced zones. + + + GSLB is added as a new network service. + + + GSLB service provider can be added to a physical network in a zone. + + + The admin is allowed to enable or disable GSLB functionality at region level. + + + The admin is allowed to configure a zone as GSLB capable or enabled. + A zone shall be considered as GSLB capable only if a GSLB service provider is + provisioned in the zone. + + + When users have VMs deployed in multiple availability zones which are GSLB enabled, + they can use the GSLB functionality to load balance traffic across the VMs in multiple + zones. + + + The users can use GSLB to load balance across the VMs across zones in a region only + if the admin has enabled GSLB in that region. + + + The users can load balance traffic across the availability zones in the same region + or different regions. + + + The admin can configure DNS name for the entire cloud. + + + The users can specify an unique name across the cloud for a globally load balanced + service. The provided name is used as the domain name under the DNS name associated with + the cloud. + The user-provided name along with the admin-provided DNS name is used to produce a + globally resolvable FQDN for the globally load balanced service of the user. For + example, if the admin has configured xyztelco.com as the DNS name for the cloud, and + user specifies 'foo' for the GSLB virtual service, then the FQDN name of the GSLB + virtual service is foo.xyztelco.com. + + + While setting up GSLB, users can select a load balancing method, such as round + robin, for using across the zones that are part of GSLB. + + + The user shall be able to set weight to zone-level virtual server. Weight shall be + considered by the load balancing method for distributing the traffic. + + + The GSLB functionality shall support session persistence, where series of client + requests for particular domain name is sent to a virtual server on the same zone. + Statistics is collected from each GSLB virtual server. + + +
+
+ Enabling GSLB in NetScaler + In each zone, add GSLB-enabled NetScaler device for load balancing. + + + Log in as administrator to the &PRODUCT; UI. + + + In the left navigation bar, click Infrastructure. + + + In Zones, click View More. + + + Choose the zone you want to work with. + + + Click the Physical Network tab, then click the name of the physical network. + + + In the Network Service Providers node of the diagram, click Configure. + You might have to scroll down to see this. + + + Click NetScaler. + + + Click Add NetScaler device and provide the following: + For NetScaler: + + + IP Address: The IP address of the SRX. + + + Username/Password: The authentication + credentials to access the device. &PRODUCT; uses these credentials to access the + device. + + + Type: The type of device that is being added. + It could be F5 Big Ip Load Balancer, NetScaler VPX, NetScaler MPX, or NetScaler SDX. + For a comparison of the NetScaler types, see the &PRODUCT; Administration + Guide. + + + Public interface: Interface of device that is + configured to be part of the public network. + + + Private interface: Interface of device that is + configured to be part of the private network. + + + GSLB service: Select this option. + + + GSLB service Public IP: The public IP address + of the NAT translator for a GSLB service that is on a private network. + + + GSLB service Private IP: The private IP of the + GSLB service. + + + Number of Retries. Number of times to attempt a + command on the device before considering the operation failed. Default is 2. + + + Capacity: The number of networks the device can + handle. + + + Dedicated: When marked as dedicated, this + device will be dedicated to a single account. When Dedicated is checked, the value + in the Capacity field has no significance implicitly, its value is 1. + + + + + Click OK. + + +
+
+ Adding a GSLB Rule + + + Log in to the &PRODUCT; UI as a domain administrator or user. + + + In the left navigation pane, click Region. + + + Select the region for which you want to create a GSLB rule. + + + In the Details tab, click View GSLB. + + + Click Add GSLB. + The Add GSLB page is displayed as follows: + + + + + + gslb-add.png: adding a gslb rule + + + + + Specify the following: + + + Name: Name for the GSLB rule. + + + Description: (Optional) A short description of + the GSLB rule that can be displayed to users. + + + GSLB Domain Name: A preferred domain name for + the service. + + + Algorithm: (Optional) The algorithm to use to + load balance the traffic across the zones. The options are Round Robin, Least + Connection, and Proximity. + + + Service Type: The transport protocol to use for + GSLB. The options are TCP and UDP. + + + Domain: (Optional) The domain for which you + want to create the GSLB rule. + + + Account: (Optional) The account on which you + want to apply the GSLB rule. + + + + + Click OK to confirm. + + +
+
+ Assigning Load Balancing Rules to GSLB + + + + Log in to the &PRODUCT; UI as a domain administrator or user. + + + In the left navigation pane, click Region. + + + Select the region for which you want to create a GSLB rule. + + + In the Details tab, click View GSLB. + + + Select the desired GSLB. + + + Click view assigned load balancing. + + + Click assign more load balancing. + + + Select the load balancing rule you have created for the zone. + + + Click OK to confirm. + + +
+
+
+ Known Limitation + Currently, &PRODUCT; does not support orchestration of services across the zones. The + notion of services and service providers in region are to be introduced. +
+
diff --git a/docs/en-US/guest-ip-ranges.xml b/docs/en-US/guest-ip-ranges.xml index 1f8c8a1a4b1..b3ebd761394 100644 --- a/docs/en-US/guest-ip-ranges.xml +++ b/docs/en-US/guest-ip-ranges.xml @@ -21,8 +21,12 @@ specific language governing permissions and limitations under the License. --> -
- Guest IP Ranges - The IP ranges for guest network traffic are set on a per-account basis by the user. This allows the users to configure their network in a fashion that will enable VPN linking between their guest network and their clients. + Guest IP Ranges + The IP ranges for guest network traffic are set on a per-account basis by the user. This + allows the users to configure their network in a fashion that will enable VPN linking between + their guest network and their clients. + In shared networks in Basic zone and Security Group-enabled Advanced networks, you will have + the flexibility to add multiple guest IP ranges from different subnets. You can add or remove + one IP range at a time.
diff --git a/docs/en-US/hypervisor-host-install-agent.xml b/docs/en-US/hypervisor-host-install-agent.xml index e5bfa37fb6d..41b6719bbaf 100644 --- a/docs/en-US/hypervisor-host-install-agent.xml +++ b/docs/en-US/hypervisor-host-install-agent.xml @@ -27,8 +27,8 @@ To manage KVM instances on the host &PRODUCT; uses a Agent. This Agent communicates with the Management server and controls all the instances on the host. First we start by installing the agent: In RHEL or CentOS: - $ yum install cloud-agent + $ yum install cloudstack-agent In Ubuntu: - $ apt-get install cloud-agent + $ apt-get install cloudstack-agent The host is now ready to be added to a cluster. This is covered in a later section, see . It is recommended that you continue to read the documentation before adding the host! - \ No newline at end of file + diff --git a/docs/en-US/hypervisor-host-install-libvirt.xml b/docs/en-US/hypervisor-host-install-libvirt.xml index f3ff090463c..d3d6b9b4e80 100644 --- a/docs/en-US/hypervisor-host-install-libvirt.xml +++ b/docs/en-US/hypervisor-host-install-libvirt.xml @@ -24,7 +24,7 @@
Install and Configure libvirt - &PRODUCT; uses libvirt for managing virtual machines. Therefore it is vital that libvirt is configured correctly. Libvirt is a dependency of cloud-agent and should already be installed. + &PRODUCT; uses libvirt for managing virtual machines. Therefore it is vital that libvirt is configured correctly. Libvirt is a dependency of cloudstack-agent and should already be installed. In order to have live migration working libvirt has to listen for unsecured TCP connections. We also need to turn off libvirts attempt to use Multicast DNS advertising. Both of these settings are in /etc/libvirt/libvirtd.conf diff --git a/docs/en-US/images/add-gslb.png b/docs/en-US/images/add-gslb.png new file mode 100644 index 0000000000000000000000000000000000000000..827a913093b5e68a6afbd74fd172a28d82815aff GIT binary patch literal 17665 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 literal 0 HcmV?d00001 diff --git a/docs/en-US/images/eip-ns-basiczone.png b/docs/en-US/images/eip-ns-basiczone.png new file mode 100644 index 0000000000000000000000000000000000000000..bc88570531ab5117cc8b128714872506b8b826d0 GIT binary patch literal 63227 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 z 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 b;{QMp-xzl+SAb=O0{kh+yq2z%Gzs`Whq0Rt literal 0 HcmV?d00001 diff --git a/docs/en-US/images/gslb.png b/docs/en-US/images/gslb.png new file mode 100644 index 0000000000000000000000000000000000000000..9f13580c56095985891f09e9c33bc363567eb57e GIT binary patch literal 60354 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
    ;&pSt)P4zsY0Tm3{`Ktu zr=ozz#9T&5@1^yZfd(%h4Y%w8OPt{QwT=}qhU)3L@Fa_y{5NOD&rMi}dK;^JD_qmW zX1vJfO?CORUK%|Smtf!1>XSp4dulRS1&XV}c{Op=!T9!K1Z_Dv*kRsX zFup9IDYs+N?M26Ik!otMZ)2^7f`+Lr?%8}&0r@-ok?)Vl;x}jXZVEakYf6~CE(&n{ zicI{eyf{7kt_JkoR43MHO7lLEI;eo|>WzRkUSeW7x@TK1Nr#4RGtvB~&f>Y}D@au* zS3SW$D_ZXxORnDf;`9twRHfhk^XN*kxWvof1L^_N->olpuixl&v_17a*{`D_5wod>Gy5?otoMetd5ez%zf=>y5{Gcg$8@1eHkp@00!c*ef!fRK z5*8lpBHEhQR}|4j9Wl_){Eccads$_Fl@)iK_9RzFQvEsibI*kpRihY|rlP*9;lI#T zKOi_sW@7nrbY9PT0I4?B`}tLWMZ3Qwr=Zbl`FOnbTieh&LpBE;0jQy!Vzjf5aA%to zA_9d%^(1hC20&yj9I}4&Wp^~(F(75Z03ioPNzK};_`-D_{Yw6x%jy{drg{~PhRKyo z1;gErEWdbd`cfYDtR%JO5Y>CQs`;L1{0QDWlRo@5je(bAmd5vZk^Q?@&iBtCgXeME zk=FkD7Do4hOJN|}<1`ug)$2BuLt-96>2o`gS`Z7D&ERjGS(c#`*~Zf3a}T8O|yywJrb`h zjlI?wyc#)RE4ZeJ*<1D&%Cr@ZQZ!)Hc^XGb<_sHrckLyH`J)q>&-XQDGGrt9HR=blI``&76 zSYN8^ydD!UC1&PmY;tNRw9QoSrdd@UK5to7JI}w#Eqvg)-kk2#CadD?G|ISjPte)31bA~ljj<8@Ox@8HzO}U#lw08^GGW77vPy!RKd0m2YEDC^FLDK?h9EPyu z1vyq-p-)6RjX3&u8VMszR8>jC>wxDu2ZUD48;!Pp|Ka<`G!-Y#@z0T1en{IN+_6Td ziomJjpfwg?%Xxg|gf3PwIyoY2s10x=Wo(=gM~sm!Vqsq_;fI|0aY}WVy+Pr?&pqx0 z$sjIh;yu?^)J9K0Gf>m~d{BIO9Lz$)hBd?BKcI|R1*~AwWVw4r^Zi#N+ma|9}TR?s@G&B@v$2~}h61@(w>K_@Q4sQ_lW}-sI$W=NW zQCbpT?1++N$@;$P9e)4RyqZZAD%?Zi=}5e=N^l8LQ}HJ7LgM=R`qtLg65@S|3JZnE z9cK=+9VEhE(Y#f_(>rpL)6Y-0q9M%!#|poWMYbT3$mZte21g;OUos$_*payO0X!N~ z1;E{?XcX#@5r@0ejX^pD>1ISFQE^2_`X@bog_J_E%xb`FJiI1Zf2omCZ;w-c+9Rz8v$I!Kqz6)xl#&(n8qhDe3 zViHr(sNVdnf5r{)jfP;2t(eC{JrtQKx4Cljt|4K9lohFie31H=WbBbXm8pr(XLH`- zY>a;rfDLE)Sm%}Gdc62UW{`z$l>?Xe?B5)zr9p}axlDF0{A|LHJmkiSPnB;-t>%Z}Uk1A3NQKe`Z^8Wy&<08)h literal 0 HcmV?d00001 diff --git a/docs/en-US/increase-management-server-max-memory.xml b/docs/en-US/increase-management-server-max-memory.xml index 16d18e75830..51c8724a020 100644 --- a/docs/en-US/increase-management-server-max-memory.xml +++ b/docs/en-US/increase-management-server-max-memory.xml @@ -28,7 +28,7 @@ Edit the Tomcat configuration file:/etc/cloud/management/tomcat6.conf Change the command-line parameter -XmxNNNm to a higher value of N.For example, if the current value is -Xmx128m, change it to -Xmx1024m or higher. - To put the new setting into effect, restart the Management Server.# service cloud-management restart + To put the new setting into effect, restart the Management Server.# service cloudstack-management restart For more information about memory issues, see "FAQ: Memory" at Tomcat Wiki.
diff --git a/docs/en-US/install-usage-server.xml b/docs/en-US/install-usage-server.xml index 9dde5523f5e..ffd748d758e 100644 --- a/docs/en-US/install-usage-server.xml +++ b/docs/en-US/install-usage-server.xml @@ -52,7 +52,7 @@ Once installed, start the Usage Server with the following command. -# service cloud-usage start +# service cloudstack-usage start diff --git a/docs/en-US/libcloud-examples.xml b/docs/en-US/libcloud-examples.xml new file mode 100644 index 00000000000..d2db5269eb9 --- /dev/null +++ b/docs/en-US/libcloud-examples.xml @@ -0,0 +1,75 @@ + + +%BOOK_ENTITIES; +]> + + + +
+ Apache Libcloud + There are many tools available to interface with the &PRODUCT; API. Apache Libcloud is one of those. In this section + we provide a basic example of how to use Libcloud with &PRODUCT;. It assumes that you have access to a &PRODUCT; endpoint and that you have the API access key and secret key of a user. + To install Libcloud refer to the libcloud website. If you are familiar with Pypi simply do: + pip install apache-libcloud + You should see the following output: + +pip install apache-libcloud +Downloading/unpacking apache-libcloud + Downloading apache-libcloud-0.12.4.tar.bz2 (376kB): 376kB downloaded + Running setup.py egg_info for package apache-libcloud + +Installing collected packages: apache-libcloud + Running setup.py install for apache-libcloud + +Successfully installed apache-libcloud +Cleaning up... + + + You can then open a Python interactive shell, create an instance of a &PRODUCT; driver and call the available methods via the libcloud API. + + + >> from libcloud.compute.types import Provider +>>> from libcloud.compute.providers import get_driver +>>> Driver = get_driver(Provider.CLOUDSTACK) +>>> apikey='plgWJfZK4gyS3mOMTVmjUVg-X-jlWlnfaUJ9GAbBbf9EdM-kAYMmAiLqzzq1ElZLYq_u38zCm0bewzGUdP66mg' +>>> secretkey='VDaACYb0LV9eNjTetIOElcVQkvJck_J_QljX_FcHRj87ZKiy0z0ty0ZsYBkoXkY9b7eq1EhwJaw7FF3akA3KBQ' +>>> host='http://localhost:8080' +>>> path='/client/api' +>>> conn=Driver(apikey,secretkey,secure='False',host='localhost:8080',path=path) +>>> conn=Driver(key=apikey,secret=secretkey,secure=False,host='localhost',port='8080',path=path) +>>> conn.list_images() +[] +>>> conn.list_sizes() +[, , ] +>>> images=conn.list_images() +>>> offerings=conn.list_sizes() +>>> node=conn.create_node(name='toto',image=images[0],size=offerings[0]) +>>> help(node) +>>> node.get_uuid() +'b1aa381ba1de7f2d5048e248848993d5a900984f' +>>> node.name +u'toto' +]]> + + + One of the interesting use cases of Libcloud is that you can use multiple Cloud Providers, such as AWS, Rackspace, OpenNebula, vCloud and so on. You can then create Driver instances to each of these clouds and create your own multi cloud application. + +
diff --git a/docs/en-US/lxc-install.xml b/docs/en-US/lxc-install.xml index a80c18afdd6..40f6a0aaa69 100644 --- a/docs/en-US/lxc-install.xml +++ b/docs/en-US/lxc-install.xml @@ -74,9 +74,9 @@ To manage LXC instances on the host &PRODUCT; uses a Agent. This Agent communicates with the Management server and controls all the instances on the host. First we start by installing the agent: In RHEL or CentOS: - $ yum install cloud-agent + $ yum install cloudstack-agent In Ubuntu: - $ apt-get install cloud-agent + $ apt-get install cloudstack-agent Next step is to update the Agent configuration setttings. The settings are in /etc/cloudstack/agent/agent.properties diff --git a/docs/en-US/networks.xml b/docs/en-US/networks.xml index c2090d2b1b4..8a7405a63ac 100644 --- a/docs/en-US/networks.xml +++ b/docs/en-US/networks.xml @@ -36,7 +36,8 @@ - + diff --git a/docs/en-US/plugin-midonet-about.xml b/docs/en-US/plugin-midonet-about.xml new file mode 100644 index 00000000000..dd9b3ad08e0 --- /dev/null +++ b/docs/en-US/plugin-midonet-about.xml @@ -0,0 +1,27 @@ + + +%BOOK_ENTITIES; + +%xinclude; +]> + + + The MidoNet Plugin + + + diff --git a/docs/en-US/plugin-midonet-features.xml b/docs/en-US/plugin-midonet-features.xml new file mode 100644 index 00000000000..f242d63d0ee --- /dev/null +++ b/docs/en-US/plugin-midonet-features.xml @@ -0,0 +1,57 @@ + + +%BOOK_ENTITIES; + +%xinclude; +]> + +
+ Features of the MidoNet Plugin + + + + In &PRODUCT; 4.2.0 only the KVM hypervisor is supported for use in combination with MidoNet. + + + + In &PRODUCT; release 4.2.0 this plugin supports several services in the Advanced Isolated network mode. + + + + When tenants create new isolated layer 3 networks, instead of spinning up extra Virtual Router VMs, the relevant L3 elements (routers etc) are created in the MidoNet virtual topology by making the appropriate calls to the MidoNet API. Instead of using VLANs, isolation is provided by MidoNet. + + + + Aside from the above service (Connectivity), several extra features are supported in the 4.2.0 release: + + + + DHCP + Firewall (ingress) + Source NAT + Static NAT + Port Forwarding + + + + The plugin has been tested with MidoNet version 12.12. (Caddo). + + + + +
diff --git a/docs/en-US/plugin-midonet-introduction.xml b/docs/en-US/plugin-midonet-introduction.xml new file mode 100644 index 00000000000..7793ecbc884 --- /dev/null +++ b/docs/en-US/plugin-midonet-introduction.xml @@ -0,0 +1,26 @@ + + +%BOOK_ENTITIES; + +%xinclude; +]> + +
+ Introduction to the MidoNet Plugin + The MidoNet plugin allows &PRODUCT; to use the MidoNet virtualized networking solution as a provider for &PRODUCT; networks and services. For more information on MidoNet and how it works, see http://www.midokura.com/midonet/. +
diff --git a/docs/en-US/plugin-midonet-preparations.xml b/docs/en-US/plugin-midonet-preparations.xml new file mode 100644 index 00000000000..cf78774ec2b --- /dev/null +++ b/docs/en-US/plugin-midonet-preparations.xml @@ -0,0 +1,90 @@ + + +%BOOK_ENTITIES; + +%xinclude; +]> + +
+ Prerequisites + + In order to use the MidoNet plugin, the compute hosts must be running the MidoNet Agent, and the MidoNet API server must be available. Please consult the MidoNet User Guide for more information. The following section describes the &PRODUCT; side setup. + + + + &PRODUCT; needs to have at least one physical network with the isolation method set to "MIDO". This network should be enabled for the Guest and Public traffic types. + + + + Next, we need to set the following &PRODUCT; settings under "Global Settings" in the UI: + +&PRODUCT; settings + + + + Setting Name + Description + Example + + + + + midonet.apiserver.address + Specify the address at which the Midonet API server can be contacted + http://192.168.1.144:8081/midolmanj-mgmt + + + midonet.providerrouter.id + Specifies the UUID of the Midonet provider router + d7c5e6a3-e2f4-426b-b728-b7ce6a0448e5 + + + +
+
+ + + + We also want MidoNet to take care of public traffic, so in componentContext.xml we need to replace this line: + + ]]> + + + With this: + + ]]> + + + +
+ + + + On the compute host, MidoNet takes advantage of per-traffic type VIF driver support in &PRODUCT; KVM. + + + In agent.properties, we set the following to make MidoNet take care of Guest and Public traffic: + +libvirt.vif.driver.Guest=com.cloud.network.resource.MidoNetVifDriver +libvirt.vif.driver.Public=com.cloud.network.resource.MidoNetVifDriver + + This is explained further in MidoNet User Guide. + + + +
diff --git a/docs/en-US/plugin-midonet-provider.xml b/docs/en-US/plugin-midonet-provider.xml new file mode 100644 index 00000000000..904828caecd --- /dev/null +++ b/docs/en-US/plugin-midonet-provider.xml @@ -0,0 +1,39 @@ + + +%BOOK_ENTITIES; + +%xinclude; +]> + +
+ Enabling the MidoNet service provider via the API + + To enable via the API, use the following API calls: + addNetworkServiceProvider + + name = "MidoNet" + physicalnetworkid = <the uuid of the physical network> + + updateNetworkServiceProvider + + id = <the provider uuid returned by the previous call> + state = "Enabled" + + + +
\ No newline at end of file diff --git a/docs/en-US/plugin-midonet-revisions.xml b/docs/en-US/plugin-midonet-revisions.xml new file mode 100644 index 00000000000..73def2325b5 --- /dev/null +++ b/docs/en-US/plugin-midonet-revisions.xml @@ -0,0 +1,45 @@ + + +%BOOK_ENTITIES; +]> + + + + + Revision History + + + + 0-0 + Wed Mar 13 2013 + + Dave + Cahill + dcahill@midokura.com + + + + Documentation created for 4.2.0 version of the MidoNet Plugin + + + + + + diff --git a/docs/en-US/plugin-midonet-ui.xml b/docs/en-US/plugin-midonet-ui.xml new file mode 100644 index 00000000000..8ee9850e5a7 --- /dev/null +++ b/docs/en-US/plugin-midonet-ui.xml @@ -0,0 +1,65 @@ + + +%BOOK_ENTITIES; + +%xinclude; +]> + +
+ Enabling the MidoNet service provider via the UI + To allow &PRODUCT; to use the MidoNet Plugin the network service provider needs to be enabled on the physical network. + + + + The steps to enable via the UI are as follows: + + + In the left navbar, click Infrastructure + + + + In Zones, click View All + + + + Click the name of the Zone on which you are setting up MidoNet + + + + Click the Physical Network tab + + + + Click the Name of the Network on which you are setting up MidoNet + + + + Click Configure on the Network Service Providers box + + + + Click on the name MidoNet + + + + Click the Enable Provider button in the Network tab + + + + +
diff --git a/docs/en-US/plugin-midonet-usage.xml b/docs/en-US/plugin-midonet-usage.xml new file mode 100644 index 00000000000..a314581dcda --- /dev/null +++ b/docs/en-US/plugin-midonet-usage.xml @@ -0,0 +1,29 @@ + + +%BOOK_ENTITIES; + +%xinclude; +]> + + + Using the MidoNet Plugin + + + + + diff --git a/docs/en-US/set-database-buffer-pool-size.xml b/docs/en-US/set-database-buffer-pool-size.xml index 1c7503101ca..8265ae544f2 100644 --- a/docs/en-US/set-database-buffer-pool-size.xml +++ b/docs/en-US/set-database-buffer-pool-size.xml @@ -26,7 +26,7 @@ Set Database Buffer Pool Size It is important to provide enough memory space for the MySQL database to cache data and indexes: - Edit the Tomcat configuration file:/etc/my.cnf + Edit the MySQL configuration file:/etc/my.cnf Insert the following line in the [mysqld] section, below the datadir line. Use a value that is appropriate for your situation. We recommend setting the buffer pool at 40% of RAM if MySQL is on the same server as the management server or 70% of RAM if MySQL has a dedicated server. The following example assumes a dedicated server with 1024M of RAM. innodb_buffer_pool_size=700M Restart the MySQL service.# service mysqld restart diff --git a/docs/en-US/set-global-project-resource-limits.xml b/docs/en-US/set-global-project-resource-limits.xml index d91942ad8db..8ec13259051 100644 --- a/docs/en-US/set-global-project-resource-limits.xml +++ b/docs/en-US/set-global-project-resource-limits.xml @@ -76,7 +76,7 @@
Restart the Management Server. - # service cloud-management restart + # service cloudstack-management restart
diff --git a/docs/en-US/set-projects-creator-permissions.xml b/docs/en-US/set-projects-creator-permissions.xml index 9b272f6bc7e..dd9cfe95d56 100644 --- a/docs/en-US/set-projects-creator-permissions.xml +++ b/docs/en-US/set-projects-creator-permissions.xml @@ -56,7 +56,7 @@
Restart the Management Server. - # service cloud-management restart + # service cloudstack-management restart diff --git a/docs/en-US/set-up-invitations.xml b/docs/en-US/set-up-invitations.xml index c1303cf5e92..180c041e87e 100644 --- a/docs/en-US/set-up-invitations.xml +++ b/docs/en-US/set-up-invitations.xml @@ -89,7 +89,7 @@
Restart the Management Server: - service cloud-management restart + service cloudstack-management restart diff --git a/docs/en-US/signing-api-calls-python.xml b/docs/en-US/signing-api-calls-python.xml new file mode 100644 index 00000000000..a2f897f6df1 --- /dev/null +++ b/docs/en-US/signing-api-calls-python.xml @@ -0,0 +1,101 @@ + + +%BOOK_ENTITIES; +]> + + + +
+ How to sign an API call with Python + To illustrate the procedure used to sign API calls we present a step by step interactive session + using Python. + + First import the required modules: + + + >> import urllib2 +>>> import urllib +>>> import hashlib +>>> import hmac +>>> import base64 + ]]> + + + Define the endpoint of the Cloud, the command that you want to execute and the keys of the user. + + >> baseurl='http://localhost:8080/client/api?' +>>> request={} +>>> request['command']='listUsers' +>>> request['response']='json' +>>> request['apikey']='plgWJfZK4gyS3mOMTVmjUVg-X-jlWlnfaUJ9GAbBbf9EdM-kAYMmAiLqzzq1ElZLYq_u38zCm0bewzGUdP66mg' +>>> secretkey='VDaACYb0LV9eNjTetIOElcVQkvJck_J_QljX_FcHRj87ZKiy0z0ty0ZsYBkoXkY9b7eq1EhwJaw7FF3akA3KBQ' + ]]> + + Build the request string: + + >> request_str='&'.join(['='.join([k,urllib.quote_plus(request[k])]) for k in request.keys()]) +>>> request_str +'apikey=plgWJfZK4gyS3mOMTVmjUVg-X-jlWlnfaUJ9GAbBbf9EdM-kAYMmAiLqzzq1ElZLYq_u38zCm0bewzGUdP66mg&command=listUsers&response=json' + ]]> + + + Compute the signature with hmac, do a 64 bit encoding and a url encoding: + + >> sig_str='&'.join(['='.join([k.lower(),urllib.quote_plus(request[k].lower().replace('+','%20'))])for k in sorted(request.iterkeys())]) +>>> sig_str +'apikey=plgwjfzk4gys3momtvmjuvg-x-jlwlnfauj9gabbbf9edm-kaymmailqzzq1elzlyq_u38zcm0bewzgudp66mg&command=listusers&response=json' +>>> sig=hmac.new(secretkey,sig_str,hashlib.sha1) +>>> sig + +>>> sig=hmac.new(secretkey,sig_str,hashlib.sha1).digest() +>>> sig +'M:]\x0e\xaf\xfb\x8f\xf2y\xf1p\x91\x1e\x89\x8a\xa1\x05\xc4A\xdb' +>>> sig=base64.encodestring(hmac.new(secretkey,sig_str,hashlib.sha1).digest()) +>>> sig +'TTpdDq/7j/J58XCRHomKoQXEQds=\n' +>>> sig=base64.encodestring(hmac.new(secretkey,sig_str,hashlib.sha1).digest()).strip() +>>> sig +'TTpdDq/7j/J58XCRHomKoQXEQds=' +>>> sig=urllib.quote_plus(base64.encodestring(hmac.new(secretkey,sig_str,hashlib.sha1).digest()).strip()) + ]]> + + + Finally, build the entire string and do an http GET: + + >> req=baseurl+request_str+'&signature='+sig +>>> req +'http://localhost:8080/client/api?apikey=plgWJfZK4gyS3mOMTVmjUVg-X-jlWlnfaUJ9GAbBbf9EdM-kAYMmAiLqzzq1ElZLYq_u38zCm0bewzGUdP66mg&command=listUsers&response=json&signature=TTpdDq%2F7j%2FJ58XCRHomKoQXEQds%3D' +>>> res=urllib2.urlopen(req) +>>> res.read() +'{ "listusersresponse" : { "count":3 ,"user" : [ {"id":"7ed6d5da-93b2-4545-a502-23d20b48ef2a","username":"admin","firstname":"admin","lastname":"cloud","created":"2012-07-05T12:18:27-0700","state":"enabled","account":"admin","accounttype":1,"domainid":"8a111e58-e155-4482-93ce-84efff3c7c77","domain":"ROOT","apikey":"plgWJfZK4gyS3mOMTVmjUVg-X-jlWlnfaUJ9GAbBbf9EdM-kAYMmAiLqzzq1ElZLYq_u38zCm0bewzGUdP66mg","secretkey":"VDaACYb0LV9eNjTetIOElcVQkvJck_J_QljX_FcHRj87ZKiy0z0ty0ZsYBkoXkY9b7eq1EhwJaw7FF3akA3KBQ","accountid":"7548ac03-af1d-4c1c-9064-2f3e2c0eda0d"}, {"id":"1fea6418-5576-4989-a21e-4790787bbee3","username":"runseb","firstname":"foobar","lastname":"goa","email":"joe@smith.com","created":"2013-04-10T16:52:06-0700","state":"enabled","account":"admin","accounttype":1,"domainid":"8a111e58-e155-4482-93ce-84efff3c7c77","domain":"ROOT","apikey":"Xhsb3MewjJQaXXMszRcLvQI9_NPy_UcbDj1QXikkVbDC9MDSPwWdtZ1bUY1H7JBEYTtDDLY3yuchCeW778GkBA","secretkey":"gIsgmi8C5YwxMHjX5o51pSe0kqs6JnKriw0jJBLceY5bgnfzKjL4aM6ctJX-i1ddQIHJLbLJDK9MRzsKk6xZ_w","accountid":"7548ac03-af1d-4c1c-9064-2f3e2c0eda0d"}, {"id":"52f65396-183c-4473-883f-a37e7bb93967","username":"toto","firstname":"john","lastname":"smith","email":"john@smith.com","created":"2013-04-23T04:27:22-0700","state":"enabled","account":"admin","accounttype":1,"domainid":"8a111e58-e155-4482-93ce-84efff3c7c77","domain":"ROOT","apikey":"THaA6fFWS_OmvU8od201omxFC8yKNL_Hc5ZCS77LFCJsRzSx48JyZucbUul6XYbEg-ZyXMl_wuEpECzK-wKnow","secretkey":"O5ywpqJorAsEBKR_5jEvrtGHfWL1Y_j1E4Z_iCr8OKCYcsPIOdVcfzjJQ8YqK0a5EzSpoRrjOFiLsG0hQrYnDA","accountid":"7548ac03-af1d-4c1c-9064-2f3e2c0eda0d"} ] } }' + ]]> + + +
diff --git a/docs/en-US/signing-api-requests.xml b/docs/en-US/signing-api-requests.xml index 581b32a41ba..fc8773b92c8 100644 --- a/docs/en-US/signing-api-requests.xml +++ b/docs/en-US/signing-api-requests.xml @@ -57,4 +57,7 @@ http://localhost:8080/client/api?command=deployVirtualMachine&serviceOfferingId=1&diskOfferingId=1&templateId=2&zoneId=4&apiKey=miVr6X7u6bN_sdahOBpjNejPgEsT35eXq-jB8CG20YI3yaxXcgpyuaIRmFI_EJTVwZ0nUkkJbPmY3y2bciKwFQ&signature=Lxx1DM40AjcXU%2FcaiK8RAP0O1hU%3D + + + diff --git a/docs/en-US/stop-restart-management-server.xml b/docs/en-US/stop-restart-management-server.xml index 5c1bcecbc00..74a687c23a1 100644 --- a/docs/en-US/stop-restart-management-server.xml +++ b/docs/en-US/stop-restart-management-server.xml @@ -26,9 +26,9 @@ The root administrator will need to stop and restart the Management Server from time to time. For example, after changing a global configuration parameter, a restart is required. If you have multiple Management Server nodes, restart all of them to put the new parameter value into effect consistently throughout the cloud.. To stop the Management Server, issue the following command at the operating system prompt on the Management Server node: - # service cloud-management stop + # service cloudstack-management stop To start the Management Server: - # service cloud-management start + # service cloudstack-management start To stop the Management Server: - # service cloud-management stop + # service cloudstack-management stop diff --git a/docs/en-US/sys-offering-sysvm.xml b/docs/en-US/sys-offering-sysvm.xml index cccf3e04796..563dd6f5ebf 100644 --- a/docs/en-US/sys-offering-sysvm.xml +++ b/docs/en-US/sys-offering-sysvm.xml @@ -65,7 +65,7 @@ Restart &PRODUCT; Management Server. Restarting is required because the default offerings are loaded into the memory at startup. - service cloud-management restart + service cloudstack-management restart Destroy the existing CPVM or SSVM offerings and wait for them to be recreated. The new diff --git a/docs/en-US/tools.xml b/docs/en-US/tools.xml index db6a510d593..8cddf28014f 100644 --- a/docs/en-US/tools.xml +++ b/docs/en-US/tools.xml @@ -27,4 +27,5 @@ + diff --git a/docs/en-US/zone-add.xml b/docs/en-US/zone-add.xml index 4f6606fce03..3ca5789cd99 100644 --- a/docs/en-US/zone-add.xml +++ b/docs/en-US/zone-add.xml @@ -42,7 +42,7 @@ Restart the Management Server. - # service cloud-management restart + # service cloudstack-management restart Refresh the &PRODUCT; UI browser tab and log back in. diff --git a/docs/publican-plugin-midonet.cfg b/docs/publican-plugin-midonet.cfg new file mode 100644 index 00000000000..6558d99e897 --- /dev/null +++ b/docs/publican-plugin-midonet.cfg @@ -0,0 +1,28 @@ +# Publican configuration file for CloudStack Complete Documentation Set +# Contains all technical docs except release notes +# Config::Simple 4.58 +# Tue May 29 00:57:27 2012 +# +# 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. + +xml_lang: en-US +type: Book +docname: MidoNet_Plugin_Guide +brand: cloudstack +chunk_first: 1 +chunk_section_depth: 1 +condition: install diff --git a/engine/api/pom.xml b/engine/api/pom.xml index 1e8e8c3eb38..1b8f26c2320 100644 --- a/engine/api/pom.xml +++ b/engine/api/pom.xml @@ -30,11 +30,6 @@ cloud-api ${project.version} - - org.apache.cloudstack - cloud-framework-api - ${project.version} - org.apache.cxf cxf-bundle-jaxrs @@ -55,6 +50,11 @@ cloud-framework-rest ${project.version} + + org.apache.cloudstack + cloud-framework-ipc + ${project.version} + install diff --git a/engine/pom.xml b/engine/pom.xml index 1a3d896d50d..169425ae14e 100644 --- a/engine/pom.xml +++ b/engine/pom.xml @@ -29,8 +29,6 @@ install - src - test api diff --git a/core/src/com/cloud/alert/AlertVO.java b/engine/schema/src/com/cloud/alert/AlertVO.java similarity index 100% rename from core/src/com/cloud/alert/AlertVO.java rename to engine/schema/src/com/cloud/alert/AlertVO.java diff --git a/server/src/com/cloud/alert/dao/AlertDao.java b/engine/schema/src/com/cloud/alert/dao/AlertDao.java similarity index 100% rename from server/src/com/cloud/alert/dao/AlertDao.java rename to engine/schema/src/com/cloud/alert/dao/AlertDao.java diff --git a/server/src/com/cloud/alert/dao/AlertDaoImpl.java b/engine/schema/src/com/cloud/alert/dao/AlertDaoImpl.java similarity index 100% rename from server/src/com/cloud/alert/dao/AlertDaoImpl.java rename to engine/schema/src/com/cloud/alert/dao/AlertDaoImpl.java diff --git a/core/src/com/cloud/capacity/CapacityVO.java b/engine/schema/src/com/cloud/capacity/CapacityVO.java similarity index 100% rename from core/src/com/cloud/capacity/CapacityVO.java rename to engine/schema/src/com/cloud/capacity/CapacityVO.java diff --git a/server/src/com/cloud/capacity/dao/CapacityDao.java b/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java similarity index 97% rename from server/src/com/cloud/capacity/dao/CapacityDao.java rename to engine/schema/src/com/cloud/capacity/dao/CapacityDao.java index 0132f69cd50..04466f4adb2 100755 --- a/server/src/com/cloud/capacity/dao/CapacityDao.java +++ b/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java @@ -41,5 +41,5 @@ public interface CapacityDao extends GenericDao { List listCapacitiesGroupedByLevelAndType(Integer capacityType, Long zoneId, Long podId, Long clusterId, int level, Long limit); void updateCapacityState(Long dcId, Long podId, Long clusterId, Long hostId, String capacityState); - List listClustersCrossingThreshold(short capacityType, Long zoneId, Float disableThreshold, long computeRequested); + List listClustersCrossingThreshold(short capacityType, Long zoneId, String ConfigName, long computeRequested); } diff --git a/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java b/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java similarity index 95% rename from server/src/com/cloud/capacity/dao/CapacityDaoImpl.java rename to engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java index c3d98173a5c..0b9ff1a5ece 100755 --- a/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java +++ b/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java @@ -115,12 +115,20 @@ public class CapacityDaoImpl extends GenericDaoBase implements private static final String LIST_CAPACITY_GROUP_BY_CLUSTER_TYPE_PART2 = " GROUP BY cluster_id, capacity_type order by percent desc limit "; private static final String UPDATE_CAPACITY_STATE = "UPDATE `cloud`.`op_host_capacity` SET capacity_state = ? WHERE "; - private static final String LIST_CLUSTERS_CROSSING_THRESHOLD = "SELECT cluster_id " + - "FROM (SELECT cluster_id, ( (sum(capacity.used_capacity) + sum(capacity.reserved_capacity) + ?)/sum(total_capacity) ) ratio "+ - "FROM `cloud`.`op_host_capacity` capacity "+ - "WHERE capacity.data_center_id = ? AND capacity.capacity_type = ? AND capacity.total_capacity > 0 "+ - "GROUP BY cluster_id) tmp " + - "WHERE tmp.ratio > ? "; + + private static final String LIST_CLUSTERS_CROSSING_THRESHOLD = "SELECT clusterList.cluster_id " + + "FROM ( SELECT cluster.cluster_id cluster_id, ( (sum(cluster.used) + sum(cluster.reserved) + ?)/sum(cluster.total) ) ratio, cluster.configValue value " + + "FROM ( SELECT capacity.cluster_id cluster_id, capacity.used_capacity used, capacity.reserved_capacity reserved, capacity.total_capacity total, " + + "CASE (SELECT count(*) FROM `cloud`.`cluster_details` details WHERE details.cluster_id = capacity.cluster_id AND details.name = ? ) " + + "WHEN 1 THEN ( SELECT details.value FROM `cloud`.`cluster_details` details WHERE details.cluster_id = capacity.cluster_id AND details.name = ? ) " + + "ELSE ( SELECT config.value FROM `cloud`.`configuration` config WHERE config.name = ?) " + + "END configValue " + + "FROM `cloud`.`op_host_capacity` capacity " + + "WHERE capacity.data_center_id = ? AND capacity.capacity_type = ? AND capacity.total_capacity > 0) cluster " + + + "GROUP BY cluster.cluster_id) clusterList " + + "WHERE clusterList.ratio > clusterList.value; "; + public CapacityDaoImpl() { @@ -146,20 +154,22 @@ public class CapacityDaoImpl extends GenericDaoBase implements } @Override - public List listClustersCrossingThreshold(short capacityType, Long zoneId, Float disableThreshold, long compute_requested){ + public List listClustersCrossingThreshold(short capacityType, Long zoneId, String configName, long compute_requested){ Transaction txn = Transaction.currentTxn(); PreparedStatement pstmt = null; List result = new ArrayList(); StringBuilder sql = new StringBuilder(LIST_CLUSTERS_CROSSING_THRESHOLD); - - + // during listing the clusters that cross the threshold + // we need to check with disabled thresholds of each cluster if not defined at cluster consider the global value try { pstmt = txn.prepareAutoCloseStatement(sql.toString()); pstmt.setLong(1,compute_requested); - pstmt.setShort(2,capacityType); - pstmt.setFloat(3,disableThreshold); - pstmt.setLong(4,zoneId); + pstmt.setString(2, configName); + pstmt.setString(3, configName); + pstmt.setString(4, configName); + pstmt.setLong(5,zoneId); + pstmt.setShort(6,capacityType); ResultSet rs = pstmt.executeQuery(); while (rs.next()) { diff --git a/core/src/com/cloud/certificate/CertificateVO.java b/engine/schema/src/com/cloud/certificate/CertificateVO.java similarity index 100% rename from core/src/com/cloud/certificate/CertificateVO.java rename to engine/schema/src/com/cloud/certificate/CertificateVO.java diff --git a/server/src/com/cloud/certificate/dao/CertificateDao.java b/engine/schema/src/com/cloud/certificate/dao/CertificateDao.java similarity index 100% rename from server/src/com/cloud/certificate/dao/CertificateDao.java rename to engine/schema/src/com/cloud/certificate/dao/CertificateDao.java diff --git a/server/src/com/cloud/certificate/dao/CertificateDaoImpl.java b/engine/schema/src/com/cloud/certificate/dao/CertificateDaoImpl.java similarity index 100% rename from server/src/com/cloud/certificate/dao/CertificateDaoImpl.java rename to engine/schema/src/com/cloud/certificate/dao/CertificateDaoImpl.java diff --git a/server/src/com/cloud/cluster/ClusterInvalidSessionException.java b/engine/schema/src/com/cloud/cluster/ClusterInvalidSessionException.java similarity index 100% rename from server/src/com/cloud/cluster/ClusterInvalidSessionException.java rename to engine/schema/src/com/cloud/cluster/ClusterInvalidSessionException.java diff --git a/server/src/com/cloud/cluster/ManagementServerHostPeerVO.java b/engine/schema/src/com/cloud/cluster/ManagementServerHostPeerVO.java similarity index 100% rename from server/src/com/cloud/cluster/ManagementServerHostPeerVO.java rename to engine/schema/src/com/cloud/cluster/ManagementServerHostPeerVO.java diff --git a/server/src/com/cloud/cluster/ManagementServerHostVO.java b/engine/schema/src/com/cloud/cluster/ManagementServerHostVO.java similarity index 100% rename from server/src/com/cloud/cluster/ManagementServerHostVO.java rename to engine/schema/src/com/cloud/cluster/ManagementServerHostVO.java diff --git a/server/src/com/cloud/cluster/agentlb/HostTransferMapVO.java b/engine/schema/src/com/cloud/cluster/agentlb/HostTransferMapVO.java similarity index 100% rename from server/src/com/cloud/cluster/agentlb/HostTransferMapVO.java rename to engine/schema/src/com/cloud/cluster/agentlb/HostTransferMapVO.java diff --git a/server/src/com/cloud/cluster/agentlb/dao/HostTransferMapDao.java b/engine/schema/src/com/cloud/cluster/agentlb/dao/HostTransferMapDao.java similarity index 100% rename from server/src/com/cloud/cluster/agentlb/dao/HostTransferMapDao.java rename to engine/schema/src/com/cloud/cluster/agentlb/dao/HostTransferMapDao.java diff --git a/server/src/com/cloud/cluster/agentlb/dao/HostTransferMapDaoImpl.java b/engine/schema/src/com/cloud/cluster/agentlb/dao/HostTransferMapDaoImpl.java similarity index 100% rename from server/src/com/cloud/cluster/agentlb/dao/HostTransferMapDaoImpl.java rename to engine/schema/src/com/cloud/cluster/agentlb/dao/HostTransferMapDaoImpl.java diff --git a/server/src/com/cloud/cluster/dao/ManagementServerHostDao.java b/engine/schema/src/com/cloud/cluster/dao/ManagementServerHostDao.java similarity index 100% rename from server/src/com/cloud/cluster/dao/ManagementServerHostDao.java rename to engine/schema/src/com/cloud/cluster/dao/ManagementServerHostDao.java diff --git a/server/src/com/cloud/cluster/dao/ManagementServerHostDaoImpl.java b/engine/schema/src/com/cloud/cluster/dao/ManagementServerHostDaoImpl.java similarity index 100% rename from server/src/com/cloud/cluster/dao/ManagementServerHostDaoImpl.java rename to engine/schema/src/com/cloud/cluster/dao/ManagementServerHostDaoImpl.java diff --git a/server/src/com/cloud/cluster/dao/ManagementServerHostPeerDao.java b/engine/schema/src/com/cloud/cluster/dao/ManagementServerHostPeerDao.java similarity index 100% rename from server/src/com/cloud/cluster/dao/ManagementServerHostPeerDao.java rename to engine/schema/src/com/cloud/cluster/dao/ManagementServerHostPeerDao.java diff --git a/server/src/com/cloud/cluster/dao/ManagementServerHostPeerDaoImpl.java b/engine/schema/src/com/cloud/cluster/dao/ManagementServerHostPeerDaoImpl.java similarity index 100% rename from server/src/com/cloud/cluster/dao/ManagementServerHostPeerDaoImpl.java rename to engine/schema/src/com/cloud/cluster/dao/ManagementServerHostPeerDaoImpl.java diff --git a/core/src/com/cloud/configuration/ConfigurationVO.java b/engine/schema/src/com/cloud/configuration/ConfigurationVO.java similarity index 100% rename from core/src/com/cloud/configuration/ConfigurationVO.java rename to engine/schema/src/com/cloud/configuration/ConfigurationVO.java diff --git a/core/src/com/cloud/configuration/ResourceCountVO.java b/engine/schema/src/com/cloud/configuration/ResourceCountVO.java similarity index 100% rename from core/src/com/cloud/configuration/ResourceCountVO.java rename to engine/schema/src/com/cloud/configuration/ResourceCountVO.java diff --git a/core/src/com/cloud/configuration/ResourceLimitVO.java b/engine/schema/src/com/cloud/configuration/ResourceLimitVO.java similarity index 100% rename from core/src/com/cloud/configuration/ResourceLimitVO.java rename to engine/schema/src/com/cloud/configuration/ResourceLimitVO.java diff --git a/server/src/com/cloud/configuration/dao/ConfigurationDao.java b/engine/schema/src/com/cloud/configuration/dao/ConfigurationDao.java similarity index 100% rename from server/src/com/cloud/configuration/dao/ConfigurationDao.java rename to engine/schema/src/com/cloud/configuration/dao/ConfigurationDao.java diff --git a/server/src/com/cloud/configuration/dao/ConfigurationDaoImpl.java b/engine/schema/src/com/cloud/configuration/dao/ConfigurationDaoImpl.java similarity index 100% rename from server/src/com/cloud/configuration/dao/ConfigurationDaoImpl.java rename to engine/schema/src/com/cloud/configuration/dao/ConfigurationDaoImpl.java diff --git a/server/src/com/cloud/configuration/dao/ResourceCountDao.java b/engine/schema/src/com/cloud/configuration/dao/ResourceCountDao.java similarity index 100% rename from server/src/com/cloud/configuration/dao/ResourceCountDao.java rename to engine/schema/src/com/cloud/configuration/dao/ResourceCountDao.java diff --git a/server/src/com/cloud/configuration/dao/ResourceCountDaoImpl.java b/engine/schema/src/com/cloud/configuration/dao/ResourceCountDaoImpl.java similarity index 100% rename from server/src/com/cloud/configuration/dao/ResourceCountDaoImpl.java rename to engine/schema/src/com/cloud/configuration/dao/ResourceCountDaoImpl.java diff --git a/server/src/com/cloud/configuration/dao/ResourceLimitDao.java b/engine/schema/src/com/cloud/configuration/dao/ResourceLimitDao.java similarity index 100% rename from server/src/com/cloud/configuration/dao/ResourceLimitDao.java rename to engine/schema/src/com/cloud/configuration/dao/ResourceLimitDao.java diff --git a/server/src/com/cloud/configuration/dao/ResourceLimitDaoImpl.java b/engine/schema/src/com/cloud/configuration/dao/ResourceLimitDaoImpl.java similarity index 100% rename from server/src/com/cloud/configuration/dao/ResourceLimitDaoImpl.java rename to engine/schema/src/com/cloud/configuration/dao/ResourceLimitDaoImpl.java diff --git a/server/src/com/cloud/dc/AccountVlanMapVO.java b/engine/schema/src/com/cloud/dc/AccountVlanMapVO.java similarity index 100% rename from server/src/com/cloud/dc/AccountVlanMapVO.java rename to engine/schema/src/com/cloud/dc/AccountVlanMapVO.java diff --git a/server/src/com/cloud/dc/ClusterDetailsDao.java b/engine/schema/src/com/cloud/dc/ClusterDetailsDao.java similarity index 100% rename from server/src/com/cloud/dc/ClusterDetailsDao.java rename to engine/schema/src/com/cloud/dc/ClusterDetailsDao.java diff --git a/server/src/com/cloud/dc/ClusterDetailsDaoImpl.java b/engine/schema/src/com/cloud/dc/ClusterDetailsDaoImpl.java similarity index 92% rename from server/src/com/cloud/dc/ClusterDetailsDaoImpl.java rename to engine/schema/src/com/cloud/dc/ClusterDetailsDaoImpl.java index 4c8591870bd..d14e0e42af2 100755 --- a/server/src/com/cloud/dc/ClusterDetailsDaoImpl.java +++ b/engine/schema/src/com/cloud/dc/ClusterDetailsDaoImpl.java @@ -50,9 +50,17 @@ public class ClusterDetailsDaoImpl extends GenericDaoBase sc = DetailSearch.create(); + // This is temporary fix to support list/update configuration api for cpu and memory overprovisioning ratios + if(name.equalsIgnoreCase("cpu.overprovisioning.factor")) { + name = "cpuOvercommitRatio"; + } + if (name.equalsIgnoreCase("mem.overprovisioning.factor")) { + name = "memoryOvercommitRatio"; + } sc.setParameters("clusterId", clusterId); sc.setParameters("name", name); + ClusterDetailsVO detail = findOneIncludingRemovedBy(sc); if("password".equals(name) && detail != null){ detail.setValue(DBEncryptionUtil.decrypt(detail.getValue())); diff --git a/server/src/com/cloud/dc/ClusterDetailsVO.java b/engine/schema/src/com/cloud/dc/ClusterDetailsVO.java similarity index 100% rename from server/src/com/cloud/dc/ClusterDetailsVO.java rename to engine/schema/src/com/cloud/dc/ClusterDetailsVO.java diff --git a/server/src/com/cloud/dc/ClusterVO.java b/engine/schema/src/com/cloud/dc/ClusterVO.java similarity index 100% rename from server/src/com/cloud/dc/ClusterVO.java rename to engine/schema/src/com/cloud/dc/ClusterVO.java diff --git a/server/src/com/cloud/dc/ClusterVSMMapVO.java b/engine/schema/src/com/cloud/dc/ClusterVSMMapVO.java similarity index 100% rename from server/src/com/cloud/dc/ClusterVSMMapVO.java rename to engine/schema/src/com/cloud/dc/ClusterVSMMapVO.java diff --git a/server/src/com/cloud/dc/DataCenterIpAddressVO.java b/engine/schema/src/com/cloud/dc/DataCenterIpAddressVO.java similarity index 100% rename from server/src/com/cloud/dc/DataCenterIpAddressVO.java rename to engine/schema/src/com/cloud/dc/DataCenterIpAddressVO.java diff --git a/server/src/com/cloud/dc/DataCenterLinkLocalIpAddressVO.java b/engine/schema/src/com/cloud/dc/DataCenterLinkLocalIpAddressVO.java similarity index 100% rename from server/src/com/cloud/dc/DataCenterLinkLocalIpAddressVO.java rename to engine/schema/src/com/cloud/dc/DataCenterLinkLocalIpAddressVO.java diff --git a/server/src/com/cloud/dc/DataCenterVO.java b/engine/schema/src/com/cloud/dc/DataCenterVO.java similarity index 100% rename from server/src/com/cloud/dc/DataCenterVO.java rename to engine/schema/src/com/cloud/dc/DataCenterVO.java diff --git a/server/src/com/cloud/dc/DataCenterVnetVO.java b/engine/schema/src/com/cloud/dc/DataCenterVnetVO.java similarity index 90% rename from server/src/com/cloud/dc/DataCenterVnetVO.java rename to engine/schema/src/com/cloud/dc/DataCenterVnetVO.java index 52d7ad2067b..9bae132fb16 100755 --- a/server/src/com/cloud/dc/DataCenterVnetVO.java +++ b/engine/schema/src/com/cloud/dc/DataCenterVnetVO.java @@ -56,6 +56,9 @@ public class DataCenterVnetVO implements InternalIdentity { @Column(name="reservation_id") protected String reservationId; + + @Column(name="account_vnet_map_id") + protected Long accountGuestVlanMapId; public Date getTakenAt() { return takenAt; @@ -103,6 +106,14 @@ public class DataCenterVnetVO implements InternalIdentity { public long getPhysicalNetworkId() { return physicalNetworkId; } + + public void setAccountGuestVlanMapId(Long accountGuestVlanMapId) { + this.accountGuestVlanMapId = accountGuestVlanMapId; + } + + public Long getAccountGuestVlanMapId() { + return accountGuestVlanMapId; + } protected DataCenterVnetVO() { } diff --git a/server/src/com/cloud/dc/DcDetailVO.java b/engine/schema/src/com/cloud/dc/DcDetailVO.java similarity index 100% rename from server/src/com/cloud/dc/DcDetailVO.java rename to engine/schema/src/com/cloud/dc/DcDetailVO.java diff --git a/server/src/com/cloud/dc/HostPodVO.java b/engine/schema/src/com/cloud/dc/HostPodVO.java similarity index 100% rename from server/src/com/cloud/dc/HostPodVO.java rename to engine/schema/src/com/cloud/dc/HostPodVO.java diff --git a/server/src/com/cloud/dc/PodCluster.java b/engine/schema/src/com/cloud/dc/PodCluster.java similarity index 100% rename from server/src/com/cloud/dc/PodCluster.java rename to engine/schema/src/com/cloud/dc/PodCluster.java diff --git a/server/src/com/cloud/dc/PodVlanMapVO.java b/engine/schema/src/com/cloud/dc/PodVlanMapVO.java similarity index 100% rename from server/src/com/cloud/dc/PodVlanMapVO.java rename to engine/schema/src/com/cloud/dc/PodVlanMapVO.java diff --git a/server/src/com/cloud/dc/PodVlanVO.java b/engine/schema/src/com/cloud/dc/PodVlanVO.java similarity index 100% rename from server/src/com/cloud/dc/PodVlanVO.java rename to engine/schema/src/com/cloud/dc/PodVlanVO.java diff --git a/server/src/com/cloud/dc/StorageNetworkIpAddressVO.java b/engine/schema/src/com/cloud/dc/StorageNetworkIpAddressVO.java similarity index 100% rename from server/src/com/cloud/dc/StorageNetworkIpAddressVO.java rename to engine/schema/src/com/cloud/dc/StorageNetworkIpAddressVO.java diff --git a/server/src/com/cloud/dc/StorageNetworkIpRangeVO.java b/engine/schema/src/com/cloud/dc/StorageNetworkIpRangeVO.java similarity index 100% rename from server/src/com/cloud/dc/StorageNetworkIpRangeVO.java rename to engine/schema/src/com/cloud/dc/StorageNetworkIpRangeVO.java diff --git a/server/src/com/cloud/dc/VlanVO.java b/engine/schema/src/com/cloud/dc/VlanVO.java similarity index 100% rename from server/src/com/cloud/dc/VlanVO.java rename to engine/schema/src/com/cloud/dc/VlanVO.java diff --git a/server/src/com/cloud/dc/dao/AccountVlanMapDao.java b/engine/schema/src/com/cloud/dc/dao/AccountVlanMapDao.java similarity index 100% rename from server/src/com/cloud/dc/dao/AccountVlanMapDao.java rename to engine/schema/src/com/cloud/dc/dao/AccountVlanMapDao.java diff --git a/server/src/com/cloud/dc/dao/AccountVlanMapDaoImpl.java b/engine/schema/src/com/cloud/dc/dao/AccountVlanMapDaoImpl.java similarity index 100% rename from server/src/com/cloud/dc/dao/AccountVlanMapDaoImpl.java rename to engine/schema/src/com/cloud/dc/dao/AccountVlanMapDaoImpl.java diff --git a/server/src/com/cloud/dc/dao/ClusterDao.java b/engine/schema/src/com/cloud/dc/dao/ClusterDao.java similarity index 100% rename from server/src/com/cloud/dc/dao/ClusterDao.java rename to engine/schema/src/com/cloud/dc/dao/ClusterDao.java diff --git a/server/src/com/cloud/dc/dao/ClusterDaoImpl.java b/engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java similarity index 100% rename from server/src/com/cloud/dc/dao/ClusterDaoImpl.java rename to engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java diff --git a/server/src/com/cloud/dc/dao/ClusterVSMMapDao.java b/engine/schema/src/com/cloud/dc/dao/ClusterVSMMapDao.java similarity index 100% rename from server/src/com/cloud/dc/dao/ClusterVSMMapDao.java rename to engine/schema/src/com/cloud/dc/dao/ClusterVSMMapDao.java diff --git a/server/src/com/cloud/dc/dao/ClusterVSMMapDaoImpl.java b/engine/schema/src/com/cloud/dc/dao/ClusterVSMMapDaoImpl.java similarity index 100% rename from server/src/com/cloud/dc/dao/ClusterVSMMapDaoImpl.java rename to engine/schema/src/com/cloud/dc/dao/ClusterVSMMapDaoImpl.java diff --git a/server/src/com/cloud/dc/dao/DataCenterDao.java b/engine/schema/src/com/cloud/dc/dao/DataCenterDao.java similarity index 100% rename from server/src/com/cloud/dc/dao/DataCenterDao.java rename to engine/schema/src/com/cloud/dc/dao/DataCenterDao.java diff --git a/server/src/com/cloud/dc/dao/DataCenterDaoImpl.java b/engine/schema/src/com/cloud/dc/dao/DataCenterDaoImpl.java similarity index 94% rename from server/src/com/cloud/dc/dao/DataCenterDaoImpl.java rename to engine/schema/src/com/cloud/dc/dao/DataCenterDaoImpl.java index 4afd640d314..4d9d01065ca 100755 --- a/server/src/com/cloud/dc/dao/DataCenterDaoImpl.java +++ b/engine/schema/src/com/cloud/dc/dao/DataCenterDaoImpl.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.dc.dao; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Random; @@ -33,6 +34,8 @@ import com.cloud.dc.DataCenterLinkLocalIpAddressVO; import com.cloud.dc.DataCenterVO; import com.cloud.dc.DataCenterVnetVO; import com.cloud.dc.PodVlanVO; +import com.cloud.network.dao.AccountGuestVlanMapDao; +import com.cloud.network.dao.AccountGuestVlanMapVO; import com.cloud.org.Grouping; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; @@ -68,6 +71,7 @@ public class DataCenterDaoImpl extends GenericDaoBase implem @Inject protected DataCenterVnetDao _vnetAllocDao = null; @Inject protected PodVlanDao _podVlanAllocDao = null; @Inject protected DcDetailsDao _detailsDao = null; + @Inject protected AccountGuestVlanMapDao _accountGuestVlanMapDao = null; protected long _prefix; protected Random _rand = new Random(System.currentTimeMillis()); @@ -189,11 +193,20 @@ public class DataCenterDaoImpl extends GenericDaoBase implem @Override public String allocateVnet(long dataCenterId, long physicalNetworkId, long accountId, String reservationId) { - DataCenterVnetVO vo = _vnetAllocDao.take(physicalNetworkId, accountId, reservationId); + ArrayList dedicatedVlanDbIds = new ArrayList(); + List maps = _accountGuestVlanMapDao.listAccountGuestVlanMapsByAccount(accountId); + for (AccountGuestVlanMapVO map : maps) { + dedicatedVlanDbIds.add(map.getId()); + } + if (dedicatedVlanDbIds != null && !dedicatedVlanDbIds.isEmpty()) { + DataCenterVnetVO vo = _vnetAllocDao.take(physicalNetworkId, accountId, reservationId, dedicatedVlanDbIds); + if (vo != null) + return vo.getVnet(); + } + DataCenterVnetVO vo = _vnetAllocDao.take(physicalNetworkId, accountId, reservationId, null); if (vo == null) { return null; } - return vo.getVnet(); } diff --git a/server/src/com/cloud/dc/dao/DataCenterIpAddressDao.java b/engine/schema/src/com/cloud/dc/dao/DataCenterIpAddressDao.java similarity index 100% rename from server/src/com/cloud/dc/dao/DataCenterIpAddressDao.java rename to engine/schema/src/com/cloud/dc/dao/DataCenterIpAddressDao.java diff --git a/server/src/com/cloud/dc/dao/DataCenterIpAddressDaoImpl.java b/engine/schema/src/com/cloud/dc/dao/DataCenterIpAddressDaoImpl.java similarity index 100% rename from server/src/com/cloud/dc/dao/DataCenterIpAddressDaoImpl.java rename to engine/schema/src/com/cloud/dc/dao/DataCenterIpAddressDaoImpl.java diff --git a/server/src/com/cloud/dc/dao/DataCenterLinkLocalIpAddressDao.java b/engine/schema/src/com/cloud/dc/dao/DataCenterLinkLocalIpAddressDao.java similarity index 100% rename from server/src/com/cloud/dc/dao/DataCenterLinkLocalIpAddressDao.java rename to engine/schema/src/com/cloud/dc/dao/DataCenterLinkLocalIpAddressDao.java diff --git a/server/src/com/cloud/dc/dao/DataCenterLinkLocalIpAddressDaoImpl.java b/engine/schema/src/com/cloud/dc/dao/DataCenterLinkLocalIpAddressDaoImpl.java similarity index 100% rename from server/src/com/cloud/dc/dao/DataCenterLinkLocalIpAddressDaoImpl.java rename to engine/schema/src/com/cloud/dc/dao/DataCenterLinkLocalIpAddressDaoImpl.java diff --git a/server/src/com/cloud/dc/dao/DataCenterVnetDao.java b/engine/schema/src/com/cloud/dc/dao/DataCenterVnetDao.java similarity index 87% rename from server/src/com/cloud/dc/dao/DataCenterVnetDao.java rename to engine/schema/src/com/cloud/dc/dao/DataCenterVnetDao.java index 7fb68dcd7ac..778498d8898 100644 --- a/server/src/com/cloud/dc/dao/DataCenterVnetDao.java +++ b/engine/schema/src/com/cloud/dc/dao/DataCenterVnetDao.java @@ -37,8 +37,13 @@ public interface DataCenterVnetDao extends GenericDao { public void lockRange(long dcId, long physicalNetworkId, Integer start, Integer end); - public DataCenterVnetVO take(long physicalNetworkId, long accountId, String reservationId); + public DataCenterVnetVO take(long physicalNetworkId, long accountId, String reservationId, List vlanDbIds); public void release(String vnet, long physicalNetworkId, long accountId, String reservationId); + public void releaseDedicatedGuestVlans(Long dedicatedGuestVlanRangeId); + + public int countVnetsAllocatedToAccount(long dcId, long accountId); + + public int countVnetsDedicatedToAccount(long dcId, long accountId); } diff --git a/server/src/com/cloud/dc/dao/DataCenterVnetDaoImpl.java b/engine/schema/src/com/cloud/dc/dao/DataCenterVnetDaoImpl.java similarity index 69% rename from server/src/com/cloud/dc/dao/DataCenterVnetDaoImpl.java rename to engine/schema/src/com/cloud/dc/dao/DataCenterVnetDaoImpl.java index 2e044394ddc..e97f2c62ee3 100755 --- a/server/src/com/cloud/dc/dao/DataCenterVnetDaoImpl.java +++ b/engine/schema/src/com/cloud/dc/dao/DataCenterVnetDaoImpl.java @@ -20,15 +20,22 @@ import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.Date; import java.util.List; +import java.util.Map; + +import javax.inject.Inject; +import javax.naming.ConfigurationException; import com.cloud.exception.InvalidParameterValueException; import org.springframework.stereotype.Component; import com.cloud.dc.DataCenterVnetVO; +import com.cloud.network.dao.AccountGuestVlanMapDao; +import com.cloud.network.dao.AccountGuestVlanMapVO; import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDao; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Func; @@ -43,7 +50,9 @@ import com.cloud.utils.exception.CloudRuntimeException; @Component @DB(txn=false) public class DataCenterVnetDaoImpl extends GenericDaoBase implements DataCenterVnetDao { + private final SearchBuilder FreeVnetSearch; + private final SearchBuilder FreeDedicatedVnetSearch; private final SearchBuilder VnetDcSearch; private final SearchBuilder VnetDcSearchAllocated; private final SearchBuilder DcSearchAllocated; @@ -51,6 +60,12 @@ public class DataCenterVnetDaoImpl extends GenericDaoBase countZoneVlans; private final GenericSearchBuilder countAllocatedZoneVlans; private final SearchBuilder SearchRange; + private final SearchBuilder DedicatedGuestVlanRangeSearch; + private final GenericSearchBuilder countVnetsAllocatedToAccount; + protected GenericSearchBuilder countVnetsDedicatedToAccount; + protected SearchBuilder AccountGuestVlanMapSearch; + + @Inject protected AccountGuestVlanMapDao _accountGuestVlanMapDao; public List listAllocatedVnets(long physicalNetworkId) { SearchCriteria sc = DcSearchAllocated.create(); @@ -141,9 +156,15 @@ public class DataCenterVnetDaoImpl extends GenericDaoBase sc = FreeVnetSearch.create(); - sc.setParameters("physicalNetworkId", physicalNetworkId); + public DataCenterVnetVO take(long physicalNetworkId, long accountId, String reservationId, List vlanDbIds) { + SearchCriteria sc; + if (vlanDbIds != null) { + sc = FreeDedicatedVnetSearch.create(); + sc.setParameters("accountGuestVlanMapId", vlanDbIds.toArray()); + } else { + sc = FreeVnetSearch.create(); + } + sc.setParameters("physicalNetworkId", physicalNetworkId); Date now = new Date(); Transaction txn = Transaction.currentTxn(); txn.start(); @@ -160,6 +181,7 @@ public class DataCenterVnetDaoImpl extends GenericDaoBase sc = VnetDcSearchAllocated.create(); sc.setParameters("vnet", vnet); @@ -178,6 +200,51 @@ public class DataCenterVnetDaoImpl extends GenericDaoBase sc = DedicatedGuestVlanRangeSearch.create(); + sc.setParameters("dedicatedGuestVlanRangeId", dedicatedGuestVlanRangeId); + List vnets = listBy(sc); + for(DataCenterVnetVO vnet : vnets) { + vnet.setAccountGuestVlanMapId(null); + update(vnet.getId(), vnet); + } + } + + @Override + public int countVnetsAllocatedToAccount(long dcId, long accountId) { + SearchCriteria sc = countVnetsAllocatedToAccount.create(); + sc.setParameters("dc", dcId); + sc.setParameters("accountId", accountId); + return customSearch(sc, null).get(0); + } + + @Override + public int countVnetsDedicatedToAccount(long dcId, long accountId) { + SearchCriteria sc = countVnetsDedicatedToAccount.create(); + sc.setParameters("dc", dcId); + sc.setParameters("accountId", accountId); + return customSearch(sc, null).get(0); + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + boolean result = super.configure(name, params); + + countVnetsDedicatedToAccount = createSearchBuilder(Integer.class); + countVnetsDedicatedToAccount.and("dc", countVnetsDedicatedToAccount.entity().getDataCenterId(), SearchCriteria.Op.EQ); + countVnetsDedicatedToAccount.and("accountGuestVlanMapId", countVnetsDedicatedToAccount.entity().getAccountGuestVlanMapId(), Op.NNULL); + AccountGuestVlanMapSearch = _accountGuestVlanMapDao.createSearchBuilder(); + AccountGuestVlanMapSearch.and("accountId", AccountGuestVlanMapSearch.entity().getAccountId(), SearchCriteria.Op.EQ); + countVnetsDedicatedToAccount.join("AccountGuestVlanMapSearch", AccountGuestVlanMapSearch, countVnetsDedicatedToAccount.entity().getAccountGuestVlanMapId(), + AccountGuestVlanMapSearch.entity().getId(), JoinBuilder.JoinType.INNER); + countVnetsDedicatedToAccount.select(null, Func.COUNT, countVnetsDedicatedToAccount.entity().getId()); + countVnetsDedicatedToAccount.done(); + AccountGuestVlanMapSearch.done(); + + return result; + } + public DataCenterVnetDaoImpl() { super(); DcSearchAllocated = createSearchBuilder(); @@ -202,7 +269,15 @@ public class DataCenterVnetDaoImpl extends GenericDaoBase { - + public List listLatestEvents(Date endDate); public List getLatestEvent(); - - List getRecentEvents(Date endDate) throws UsageServerException; + + List getRecentEvents(Date endDate); List listDirectIpEvents(Date startDate, Date endDate, long zoneId); diff --git a/core/src/com/cloud/event/dao/UsageEventDaoImpl.java b/engine/schema/src/com/cloud/event/dao/UsageEventDaoImpl.java similarity index 92% rename from core/src/com/cloud/event/dao/UsageEventDaoImpl.java rename to engine/schema/src/com/cloud/event/dao/UsageEventDaoImpl.java index dafc8d4d5ec..004ab7c381f 100644 --- a/core/src/com/cloud/event/dao/UsageEventDaoImpl.java +++ b/engine/schema/src/com/cloud/event/dao/UsageEventDaoImpl.java @@ -30,7 +30,6 @@ import org.springframework.stereotype.Component; import com.cloud.dc.Vlan; import com.cloud.event.EventTypes; import com.cloud.event.UsageEventVO; -import com.cloud.exception.UsageServerException; import com.cloud.utils.DateUtil; import com.cloud.utils.db.DB; import com.cloud.utils.db.Filter; @@ -38,6 +37,7 @@ import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; @Component @Local(value={UsageEventDao.class}) @@ -58,8 +58,8 @@ public class UsageEventDaoImpl extends GenericDaoBase implem latestEventsSearch.and("processed", latestEventsSearch.entity().isProcessed(), SearchCriteria.Op.EQ); latestEventsSearch.and("enddate", latestEventsSearch.entity().getCreateDate(), SearchCriteria.Op.LTEQ); latestEventsSearch.done(); - - IpeventsSearch = createSearchBuilder(); + + IpeventsSearch = createSearchBuilder(); IpeventsSearch.and("startdate", IpeventsSearch.entity().getCreateDate(), SearchCriteria.Op.GTEQ); IpeventsSearch.and("enddate", IpeventsSearch.entity().getCreateDate(), SearchCriteria.Op.LTEQ); IpeventsSearch.and("zoneid", IpeventsSearch.entity().getZoneId(), SearchCriteria.Op.EQ); @@ -84,10 +84,10 @@ public class UsageEventDaoImpl extends GenericDaoBase implem Filter filter = new Filter(UsageEventVO.class, "id", Boolean.FALSE, Long.valueOf(0), Long.valueOf(1)); return listAll(filter); } - + @Override @DB - public synchronized List getRecentEvents(Date endDate) throws UsageServerException { + public synchronized List getRecentEvents(Date endDate) { long recentEventId = getMostRecentEventId(); long maxEventId = getMaxEventId(endDate); Transaction txn = Transaction.open(Transaction.USAGE_DB); @@ -114,12 +114,12 @@ public class UsageEventDaoImpl extends GenericDaoBase implem } catch (Exception ex) { txn.rollback(); s_logger.error("error copying events from cloud db to usage db", ex); - throw new UsageServerException(ex.getMessage()); + throw new CloudRuntimeException(ex.getMessage()); } } @DB - private long getMostRecentEventId() throws UsageServerException { + private long getMostRecentEventId() { Transaction txn = Transaction.open(Transaction.USAGE_DB); try { List latestEvents = getLatestEvent(); @@ -133,25 +133,25 @@ public class UsageEventDaoImpl extends GenericDaoBase implem return 0; } catch (Exception ex) { s_logger.error("error getting most recent event id", ex); - throw new UsageServerException(ex.getMessage()); + throw new CloudRuntimeException(ex.getMessage()); } finally { txn.close(); } } - private List findRecentEvents(Date endDate) throws UsageServerException { + private List findRecentEvents(Date endDate) { Transaction txn = Transaction.open(Transaction.USAGE_DB); try { return listLatestEvents(endDate); } catch (Exception ex) { s_logger.error("error getting most recent event date", ex); - throw new UsageServerException(ex.getMessage()); + throw new CloudRuntimeException(ex.getMessage()); } finally { txn.close(); } } - - private long getMaxEventId(Date endDate) throws UsageServerException { + + private long getMaxEventId(Date endDate) { Transaction txn = Transaction.currentTxn(); PreparedStatement pstmt = null; try { @@ -165,7 +165,7 @@ public class UsageEventDaoImpl extends GenericDaoBase implem return 0; } catch (Exception ex) { s_logger.error("error getting max event id", ex); - throw new UsageServerException(ex.getMessage()); + throw new CloudRuntimeException(ex.getMessage()); } finally { txn.close(); } diff --git a/core/src/com/cloud/host/DetailVO.java b/engine/schema/src/com/cloud/host/DetailVO.java similarity index 100% rename from core/src/com/cloud/host/DetailVO.java rename to engine/schema/src/com/cloud/host/DetailVO.java diff --git a/core/src/com/cloud/host/HostTagVO.java b/engine/schema/src/com/cloud/host/HostTagVO.java similarity index 100% rename from core/src/com/cloud/host/HostTagVO.java rename to engine/schema/src/com/cloud/host/HostTagVO.java diff --git a/core/src/com/cloud/host/HostVO.java b/engine/schema/src/com/cloud/host/HostVO.java similarity index 100% rename from core/src/com/cloud/host/HostVO.java rename to engine/schema/src/com/cloud/host/HostVO.java diff --git a/server/src/com/cloud/host/dao/HostDao.java b/engine/schema/src/com/cloud/host/dao/HostDao.java similarity index 100% rename from server/src/com/cloud/host/dao/HostDao.java rename to engine/schema/src/com/cloud/host/dao/HostDao.java diff --git a/server/src/com/cloud/host/dao/HostDaoImpl.java b/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java similarity index 100% rename from server/src/com/cloud/host/dao/HostDaoImpl.java rename to engine/schema/src/com/cloud/host/dao/HostDaoImpl.java diff --git a/server/src/com/cloud/host/dao/HostDetailsDao.java b/engine/schema/src/com/cloud/host/dao/HostDetailsDao.java similarity index 100% rename from server/src/com/cloud/host/dao/HostDetailsDao.java rename to engine/schema/src/com/cloud/host/dao/HostDetailsDao.java diff --git a/server/src/com/cloud/host/dao/HostDetailsDaoImpl.java b/engine/schema/src/com/cloud/host/dao/HostDetailsDaoImpl.java similarity index 100% rename from server/src/com/cloud/host/dao/HostDetailsDaoImpl.java rename to engine/schema/src/com/cloud/host/dao/HostDetailsDaoImpl.java diff --git a/server/src/com/cloud/host/dao/HostTagsDao.java b/engine/schema/src/com/cloud/host/dao/HostTagsDao.java similarity index 100% rename from server/src/com/cloud/host/dao/HostTagsDao.java rename to engine/schema/src/com/cloud/host/dao/HostTagsDao.java diff --git a/server/src/com/cloud/host/dao/HostTagsDaoImpl.java b/engine/schema/src/com/cloud/host/dao/HostTagsDaoImpl.java similarity index 100% rename from server/src/com/cloud/host/dao/HostTagsDaoImpl.java rename to engine/schema/src/com/cloud/host/dao/HostTagsDaoImpl.java diff --git a/core/src/com/cloud/hypervisor/HypervisorCapabilitiesVO.java b/engine/schema/src/com/cloud/hypervisor/HypervisorCapabilitiesVO.java similarity index 100% rename from core/src/com/cloud/hypervisor/HypervisorCapabilitiesVO.java rename to engine/schema/src/com/cloud/hypervisor/HypervisorCapabilitiesVO.java diff --git a/server/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDao.java b/engine/schema/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDao.java similarity index 100% rename from server/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDao.java rename to engine/schema/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDao.java diff --git a/server/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java b/engine/schema/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java similarity index 100% rename from server/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java rename to engine/schema/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java diff --git a/server/src/com/cloud/keystore/KeystoreDao.java b/engine/schema/src/com/cloud/keystore/KeystoreDao.java similarity index 100% rename from server/src/com/cloud/keystore/KeystoreDao.java rename to engine/schema/src/com/cloud/keystore/KeystoreDao.java diff --git a/server/src/com/cloud/keystore/KeystoreDaoImpl.java b/engine/schema/src/com/cloud/keystore/KeystoreDaoImpl.java similarity index 100% rename from server/src/com/cloud/keystore/KeystoreDaoImpl.java rename to engine/schema/src/com/cloud/keystore/KeystoreDaoImpl.java diff --git a/server/src/com/cloud/keystore/KeystoreVO.java b/engine/schema/src/com/cloud/keystore/KeystoreVO.java similarity index 100% rename from server/src/com/cloud/keystore/KeystoreVO.java rename to engine/schema/src/com/cloud/keystore/KeystoreVO.java diff --git a/server/src/com/cloud/migration/DiskOffering20Dao.java b/engine/schema/src/com/cloud/migration/DiskOffering20Dao.java similarity index 100% rename from server/src/com/cloud/migration/DiskOffering20Dao.java rename to engine/schema/src/com/cloud/migration/DiskOffering20Dao.java diff --git a/server/src/com/cloud/migration/DiskOffering20DaoImpl.java b/engine/schema/src/com/cloud/migration/DiskOffering20DaoImpl.java similarity index 100% rename from server/src/com/cloud/migration/DiskOffering20DaoImpl.java rename to engine/schema/src/com/cloud/migration/DiskOffering20DaoImpl.java diff --git a/server/src/com/cloud/migration/DiskOffering20VO.java b/engine/schema/src/com/cloud/migration/DiskOffering20VO.java similarity index 100% rename from server/src/com/cloud/migration/DiskOffering20VO.java rename to engine/schema/src/com/cloud/migration/DiskOffering20VO.java diff --git a/server/src/com/cloud/migration/DiskOffering21Dao.java b/engine/schema/src/com/cloud/migration/DiskOffering21Dao.java similarity index 100% rename from server/src/com/cloud/migration/DiskOffering21Dao.java rename to engine/schema/src/com/cloud/migration/DiskOffering21Dao.java diff --git a/server/src/com/cloud/migration/DiskOffering21DaoImpl.java b/engine/schema/src/com/cloud/migration/DiskOffering21DaoImpl.java similarity index 100% rename from server/src/com/cloud/migration/DiskOffering21DaoImpl.java rename to engine/schema/src/com/cloud/migration/DiskOffering21DaoImpl.java diff --git a/server/src/com/cloud/migration/DiskOffering21VO.java b/engine/schema/src/com/cloud/migration/DiskOffering21VO.java similarity index 100% rename from server/src/com/cloud/migration/DiskOffering21VO.java rename to engine/schema/src/com/cloud/migration/DiskOffering21VO.java diff --git a/server/src/com/cloud/migration/ServiceOffering20Dao.java b/engine/schema/src/com/cloud/migration/ServiceOffering20Dao.java similarity index 100% rename from server/src/com/cloud/migration/ServiceOffering20Dao.java rename to engine/schema/src/com/cloud/migration/ServiceOffering20Dao.java diff --git a/server/src/com/cloud/migration/ServiceOffering20DaoImpl.java b/engine/schema/src/com/cloud/migration/ServiceOffering20DaoImpl.java similarity index 100% rename from server/src/com/cloud/migration/ServiceOffering20DaoImpl.java rename to engine/schema/src/com/cloud/migration/ServiceOffering20DaoImpl.java diff --git a/server/src/com/cloud/migration/ServiceOffering20VO.java b/engine/schema/src/com/cloud/migration/ServiceOffering20VO.java similarity index 100% rename from server/src/com/cloud/migration/ServiceOffering20VO.java rename to engine/schema/src/com/cloud/migration/ServiceOffering20VO.java diff --git a/server/src/com/cloud/migration/ServiceOffering21Dao.java b/engine/schema/src/com/cloud/migration/ServiceOffering21Dao.java similarity index 100% rename from server/src/com/cloud/migration/ServiceOffering21Dao.java rename to engine/schema/src/com/cloud/migration/ServiceOffering21Dao.java diff --git a/server/src/com/cloud/migration/ServiceOffering21DaoImpl.java b/engine/schema/src/com/cloud/migration/ServiceOffering21DaoImpl.java similarity index 100% rename from server/src/com/cloud/migration/ServiceOffering21DaoImpl.java rename to engine/schema/src/com/cloud/migration/ServiceOffering21DaoImpl.java diff --git a/server/src/com/cloud/migration/ServiceOffering21VO.java b/engine/schema/src/com/cloud/migration/ServiceOffering21VO.java similarity index 100% rename from server/src/com/cloud/migration/ServiceOffering21VO.java rename to engine/schema/src/com/cloud/migration/ServiceOffering21VO.java diff --git a/server/src/com/cloud/network/LBHealthCheckPolicyVO.java b/engine/schema/src/com/cloud/network/LBHealthCheckPolicyVO.java similarity index 100% rename from server/src/com/cloud/network/LBHealthCheckPolicyVO.java rename to engine/schema/src/com/cloud/network/LBHealthCheckPolicyVO.java diff --git a/server/src/com/cloud/network/UserIpv6AddressVO.java b/engine/schema/src/com/cloud/network/UserIpv6AddressVO.java similarity index 100% rename from server/src/com/cloud/network/UserIpv6AddressVO.java rename to engine/schema/src/com/cloud/network/UserIpv6AddressVO.java diff --git a/core/src/com/cloud/network/VpnUserVO.java b/engine/schema/src/com/cloud/network/VpnUserVO.java similarity index 100% rename from core/src/com/cloud/network/VpnUserVO.java rename to engine/schema/src/com/cloud/network/VpnUserVO.java diff --git a/server/src/com/cloud/network/as/AutoScalePolicyConditionMapVO.java b/engine/schema/src/com/cloud/network/as/AutoScalePolicyConditionMapVO.java similarity index 100% rename from server/src/com/cloud/network/as/AutoScalePolicyConditionMapVO.java rename to engine/schema/src/com/cloud/network/as/AutoScalePolicyConditionMapVO.java diff --git a/server/src/com/cloud/network/as/AutoScalePolicyVO.java b/engine/schema/src/com/cloud/network/as/AutoScalePolicyVO.java similarity index 100% rename from server/src/com/cloud/network/as/AutoScalePolicyVO.java rename to engine/schema/src/com/cloud/network/as/AutoScalePolicyVO.java diff --git a/server/src/com/cloud/network/as/AutoScaleVmGroupPolicyMapVO.java b/engine/schema/src/com/cloud/network/as/AutoScaleVmGroupPolicyMapVO.java similarity index 100% rename from server/src/com/cloud/network/as/AutoScaleVmGroupPolicyMapVO.java rename to engine/schema/src/com/cloud/network/as/AutoScaleVmGroupPolicyMapVO.java diff --git a/server/src/com/cloud/network/as/AutoScaleVmGroupVO.java b/engine/schema/src/com/cloud/network/as/AutoScaleVmGroupVO.java similarity index 100% rename from server/src/com/cloud/network/as/AutoScaleVmGroupVO.java rename to engine/schema/src/com/cloud/network/as/AutoScaleVmGroupVO.java diff --git a/server/src/com/cloud/network/as/AutoScaleVmProfileVO.java b/engine/schema/src/com/cloud/network/as/AutoScaleVmProfileVO.java similarity index 100% rename from server/src/com/cloud/network/as/AutoScaleVmProfileVO.java rename to engine/schema/src/com/cloud/network/as/AutoScaleVmProfileVO.java diff --git a/server/src/com/cloud/network/as/ConditionVO.java b/engine/schema/src/com/cloud/network/as/ConditionVO.java similarity index 100% rename from server/src/com/cloud/network/as/ConditionVO.java rename to engine/schema/src/com/cloud/network/as/ConditionVO.java diff --git a/server/src/com/cloud/network/as/CounterVO.java b/engine/schema/src/com/cloud/network/as/CounterVO.java similarity index 100% rename from server/src/com/cloud/network/as/CounterVO.java rename to engine/schema/src/com/cloud/network/as/CounterVO.java diff --git a/server/src/com/cloud/network/as/dao/AutoScalePolicyConditionMapDao.java b/engine/schema/src/com/cloud/network/as/dao/AutoScalePolicyConditionMapDao.java similarity index 100% rename from server/src/com/cloud/network/as/dao/AutoScalePolicyConditionMapDao.java rename to engine/schema/src/com/cloud/network/as/dao/AutoScalePolicyConditionMapDao.java diff --git a/server/src/com/cloud/network/as/dao/AutoScalePolicyConditionMapDaoImpl.java b/engine/schema/src/com/cloud/network/as/dao/AutoScalePolicyConditionMapDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/as/dao/AutoScalePolicyConditionMapDaoImpl.java rename to engine/schema/src/com/cloud/network/as/dao/AutoScalePolicyConditionMapDaoImpl.java diff --git a/server/src/com/cloud/network/as/dao/AutoScalePolicyDao.java b/engine/schema/src/com/cloud/network/as/dao/AutoScalePolicyDao.java similarity index 100% rename from server/src/com/cloud/network/as/dao/AutoScalePolicyDao.java rename to engine/schema/src/com/cloud/network/as/dao/AutoScalePolicyDao.java diff --git a/server/src/com/cloud/network/as/dao/AutoScalePolicyDaoImpl.java b/engine/schema/src/com/cloud/network/as/dao/AutoScalePolicyDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/as/dao/AutoScalePolicyDaoImpl.java rename to engine/schema/src/com/cloud/network/as/dao/AutoScalePolicyDaoImpl.java diff --git a/server/src/com/cloud/network/as/dao/AutoScaleVmGroupDao.java b/engine/schema/src/com/cloud/network/as/dao/AutoScaleVmGroupDao.java similarity index 100% rename from server/src/com/cloud/network/as/dao/AutoScaleVmGroupDao.java rename to engine/schema/src/com/cloud/network/as/dao/AutoScaleVmGroupDao.java diff --git a/server/src/com/cloud/network/as/dao/AutoScaleVmGroupDaoImpl.java b/engine/schema/src/com/cloud/network/as/dao/AutoScaleVmGroupDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/as/dao/AutoScaleVmGroupDaoImpl.java rename to engine/schema/src/com/cloud/network/as/dao/AutoScaleVmGroupDaoImpl.java diff --git a/server/src/com/cloud/network/as/dao/AutoScaleVmGroupPolicyMapDao.java b/engine/schema/src/com/cloud/network/as/dao/AutoScaleVmGroupPolicyMapDao.java similarity index 100% rename from server/src/com/cloud/network/as/dao/AutoScaleVmGroupPolicyMapDao.java rename to engine/schema/src/com/cloud/network/as/dao/AutoScaleVmGroupPolicyMapDao.java diff --git a/server/src/com/cloud/network/as/dao/AutoScaleVmGroupPolicyMapDaoImpl.java b/engine/schema/src/com/cloud/network/as/dao/AutoScaleVmGroupPolicyMapDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/as/dao/AutoScaleVmGroupPolicyMapDaoImpl.java rename to engine/schema/src/com/cloud/network/as/dao/AutoScaleVmGroupPolicyMapDaoImpl.java diff --git a/server/src/com/cloud/network/as/dao/AutoScaleVmProfileDao.java b/engine/schema/src/com/cloud/network/as/dao/AutoScaleVmProfileDao.java similarity index 100% rename from server/src/com/cloud/network/as/dao/AutoScaleVmProfileDao.java rename to engine/schema/src/com/cloud/network/as/dao/AutoScaleVmProfileDao.java diff --git a/server/src/com/cloud/network/as/dao/AutoScaleVmProfileDaoImpl.java b/engine/schema/src/com/cloud/network/as/dao/AutoScaleVmProfileDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/as/dao/AutoScaleVmProfileDaoImpl.java rename to engine/schema/src/com/cloud/network/as/dao/AutoScaleVmProfileDaoImpl.java diff --git a/server/src/com/cloud/network/as/dao/ConditionDao.java b/engine/schema/src/com/cloud/network/as/dao/ConditionDao.java similarity index 100% rename from server/src/com/cloud/network/as/dao/ConditionDao.java rename to engine/schema/src/com/cloud/network/as/dao/ConditionDao.java diff --git a/server/src/com/cloud/network/as/dao/ConditionDaoImpl.java b/engine/schema/src/com/cloud/network/as/dao/ConditionDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/as/dao/ConditionDaoImpl.java rename to engine/schema/src/com/cloud/network/as/dao/ConditionDaoImpl.java diff --git a/server/src/com/cloud/network/as/dao/CounterDao.java b/engine/schema/src/com/cloud/network/as/dao/CounterDao.java similarity index 100% rename from server/src/com/cloud/network/as/dao/CounterDao.java rename to engine/schema/src/com/cloud/network/as/dao/CounterDao.java diff --git a/server/src/com/cloud/network/as/dao/CounterDaoImpl.java b/engine/schema/src/com/cloud/network/as/dao/CounterDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/as/dao/CounterDaoImpl.java rename to engine/schema/src/com/cloud/network/as/dao/CounterDaoImpl.java diff --git a/engine/schema/src/com/cloud/network/dao/AccountGuestVlanMapDao.java b/engine/schema/src/com/cloud/network/dao/AccountGuestVlanMapDao.java new file mode 100644 index 00000000000..dc1ec895d80 --- /dev/null +++ b/engine/schema/src/com/cloud/network/dao/AccountGuestVlanMapDao.java @@ -0,0 +1,34 @@ +// 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. +package com.cloud.network.dao; + +import com.cloud.network.dao.AccountGuestVlanMapVO; +import com.cloud.utils.db.GenericDao; + +import java.util.List; + +public interface AccountGuestVlanMapDao extends GenericDao { + + public List listAccountGuestVlanMapsByAccount(long accountId); + + public List listAccountGuestVlanMapsByVlan(long guestVlanId); + + public List listAccountGuestVlanMapsByPhysicalNetwork(long physicalNetworkId); + + public int removeByAccountId(long accountId); + +} diff --git a/engine/schema/src/com/cloud/network/dao/AccountGuestVlanMapDaoImpl.java b/engine/schema/src/com/cloud/network/dao/AccountGuestVlanMapDaoImpl.java new file mode 100644 index 00000000000..e7a7b34d9bd --- /dev/null +++ b/engine/schema/src/com/cloud/network/dao/AccountGuestVlanMapDaoImpl.java @@ -0,0 +1,83 @@ +// 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. +package com.cloud.network.dao; + +import com.cloud.network.dao.AccountGuestVlanMapVO; +import com.cloud.network.dao.AccountGuestVlanMapDao; + +import java.util.List; +import javax.ejb.Local; +import org.springframework.stereotype.Component; + +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +@Component +@Local(value={AccountGuestVlanMapDao.class}) +@DB(txn=false) +public class AccountGuestVlanMapDaoImpl extends GenericDaoBase implements AccountGuestVlanMapDao { + + protected SearchBuilder AccountSearch; + protected SearchBuilder GuestVlanSearch; + protected SearchBuilder PhysicalNetworkSearch; + + @Override + public List listAccountGuestVlanMapsByAccount(long accountId) { + SearchCriteria sc = AccountSearch.create(); + sc.setParameters("accountId", accountId); + return listIncludingRemovedBy(sc); + } + + @Override + public List listAccountGuestVlanMapsByVlan(long guestVlanId) { + SearchCriteria sc = GuestVlanSearch.create(); + sc.setParameters("guestVlanId", guestVlanId); + return listIncludingRemovedBy(sc); + } + + @Override + public List listAccountGuestVlanMapsByPhysicalNetwork(long physicalNetworkId) { + SearchCriteria sc = GuestVlanSearch.create(); + sc.setParameters("physicalNetworkId", physicalNetworkId); + return listIncludingRemovedBy(sc); + } + + @Override + public int removeByAccountId(long accountId) { + SearchCriteria sc = AccountSearch.create(); + sc.setParameters("accountId", accountId); + return expunge(sc); + } + + public AccountGuestVlanMapDaoImpl() { + super(); + AccountSearch = createSearchBuilder(); + AccountSearch.and("accountId", AccountSearch.entity().getAccountId(), SearchCriteria.Op.EQ); + AccountSearch.done(); + + GuestVlanSearch = createSearchBuilder(); + GuestVlanSearch.and("guestVlanId", GuestVlanSearch.entity().getId(), SearchCriteria.Op.EQ); + GuestVlanSearch.done(); + + PhysicalNetworkSearch = createSearchBuilder(); + PhysicalNetworkSearch.and("physicalNetworkId", PhysicalNetworkSearch.entity().getId(), SearchCriteria.Op.EQ); + PhysicalNetworkSearch.done(); + } + +} diff --git a/engine/schema/src/com/cloud/network/dao/AccountGuestVlanMapVO.java b/engine/schema/src/com/cloud/network/dao/AccountGuestVlanMapVO.java new file mode 100644 index 00000000000..17c941a7e36 --- /dev/null +++ b/engine/schema/src/com/cloud/network/dao/AccountGuestVlanMapVO.java @@ -0,0 +1,94 @@ +// 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. +package com.cloud.network.dao; + +import com.cloud.network.GuestVlan; + +import javax.persistence.*; +import java.util.UUID; + +@Entity +@Table(name="account_vnet_map") +public class AccountGuestVlanMapVO implements GuestVlan { + + @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) + @Column(name="id") + private long id; + + @Column(name="account_id") + private long accountId; + + @Column(name="uuid") + private String uuid; + + @Column(name="vnet_range") + private String guestVlanRange; + + @Column(name="physical_network_id") + private long physicalNetworkId; + + public AccountGuestVlanMapVO(long accountId,long physicalNetworkId) { + this.accountId = accountId; + this.physicalNetworkId = physicalNetworkId; + this.guestVlanRange = null; + this.uuid = UUID.randomUUID().toString(); + } + + public AccountGuestVlanMapVO() { + + } + + @Override + public long getId() { + return id; + } + + @Override + public long getAccountId() { + return accountId; + } + + @Override + public String getGuestVlanRange() { + return guestVlanRange; + } + + + public void setGuestVlanRange(String guestVlanRange) { + this.guestVlanRange = guestVlanRange; + } + + @Override + public String getUuid() { + return this.uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + @Override + public long getPhysicalNetworkId() { + return this.physicalNetworkId; + } + + public void setPhysicalNetworkId(long physicalNetworkId) { + this.physicalNetworkId = physicalNetworkId; + } + +} diff --git a/server/src/com/cloud/network/dao/ExternalFirewallDeviceDao.java b/engine/schema/src/com/cloud/network/dao/ExternalFirewallDeviceDao.java similarity index 100% rename from server/src/com/cloud/network/dao/ExternalFirewallDeviceDao.java rename to engine/schema/src/com/cloud/network/dao/ExternalFirewallDeviceDao.java diff --git a/server/src/com/cloud/network/dao/ExternalFirewallDeviceDaoImpl.java b/engine/schema/src/com/cloud/network/dao/ExternalFirewallDeviceDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/ExternalFirewallDeviceDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/ExternalFirewallDeviceDaoImpl.java diff --git a/server/src/com/cloud/network/dao/ExternalFirewallDeviceVO.java b/engine/schema/src/com/cloud/network/dao/ExternalFirewallDeviceVO.java similarity index 100% rename from server/src/com/cloud/network/dao/ExternalFirewallDeviceVO.java rename to engine/schema/src/com/cloud/network/dao/ExternalFirewallDeviceVO.java diff --git a/server/src/com/cloud/network/dao/ExternalLoadBalancerDeviceDao.java b/engine/schema/src/com/cloud/network/dao/ExternalLoadBalancerDeviceDao.java similarity index 100% rename from server/src/com/cloud/network/dao/ExternalLoadBalancerDeviceDao.java rename to engine/schema/src/com/cloud/network/dao/ExternalLoadBalancerDeviceDao.java diff --git a/server/src/com/cloud/network/dao/ExternalLoadBalancerDeviceDaoImpl.java b/engine/schema/src/com/cloud/network/dao/ExternalLoadBalancerDeviceDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/ExternalLoadBalancerDeviceDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/ExternalLoadBalancerDeviceDaoImpl.java diff --git a/server/src/com/cloud/network/dao/ExternalLoadBalancerDeviceVO.java b/engine/schema/src/com/cloud/network/dao/ExternalLoadBalancerDeviceVO.java similarity index 100% rename from server/src/com/cloud/network/dao/ExternalLoadBalancerDeviceVO.java rename to engine/schema/src/com/cloud/network/dao/ExternalLoadBalancerDeviceVO.java diff --git a/server/src/com/cloud/network/dao/FirewallRulesCidrsDao.java b/engine/schema/src/com/cloud/network/dao/FirewallRulesCidrsDao.java similarity index 100% rename from server/src/com/cloud/network/dao/FirewallRulesCidrsDao.java rename to engine/schema/src/com/cloud/network/dao/FirewallRulesCidrsDao.java diff --git a/server/src/com/cloud/network/dao/FirewallRulesCidrsDaoImpl.java b/engine/schema/src/com/cloud/network/dao/FirewallRulesCidrsDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/FirewallRulesCidrsDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/FirewallRulesCidrsDaoImpl.java diff --git a/server/src/com/cloud/network/dao/FirewallRulesCidrsVO.java b/engine/schema/src/com/cloud/network/dao/FirewallRulesCidrsVO.java similarity index 100% rename from server/src/com/cloud/network/dao/FirewallRulesCidrsVO.java rename to engine/schema/src/com/cloud/network/dao/FirewallRulesCidrsVO.java diff --git a/server/src/com/cloud/network/dao/FirewallRulesDao.java b/engine/schema/src/com/cloud/network/dao/FirewallRulesDao.java similarity index 98% rename from server/src/com/cloud/network/dao/FirewallRulesDao.java rename to engine/schema/src/com/cloud/network/dao/FirewallRulesDao.java index 0bbaa93363d..6b9b3bb83e5 100644 --- a/server/src/com/cloud/network/dao/FirewallRulesDao.java +++ b/engine/schema/src/com/cloud/network/dao/FirewallRulesDao.java @@ -18,7 +18,6 @@ package com.cloud.network.dao; import java.util.List; -import com.cloud.host.HostVO; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRuleVO; import com.cloud.utils.db.GenericDao; diff --git a/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java b/engine/schema/src/com/cloud/network/dao/FirewallRulesDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/FirewallRulesDaoImpl.java diff --git a/server/src/com/cloud/network/dao/IPAddressDao.java b/engine/schema/src/com/cloud/network/dao/IPAddressDao.java similarity index 100% rename from server/src/com/cloud/network/dao/IPAddressDao.java rename to engine/schema/src/com/cloud/network/dao/IPAddressDao.java diff --git a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java b/engine/schema/src/com/cloud/network/dao/IPAddressDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/IPAddressDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/IPAddressDaoImpl.java diff --git a/server/src/com/cloud/network/dao/IPAddressVO.java b/engine/schema/src/com/cloud/network/dao/IPAddressVO.java similarity index 98% rename from server/src/com/cloud/network/dao/IPAddressVO.java rename to engine/schema/src/com/cloud/network/dao/IPAddressVO.java index c5c78e557ae..ae27e95ce4b 100644 --- a/server/src/com/cloud/network/dao/IPAddressVO.java +++ b/engine/schema/src/com/cloud/network/dao/IPAddressVO.java @@ -31,12 +31,8 @@ import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.persistence.Transient; -import org.apache.cloudstack.api.Identity; - import com.cloud.network.IpAddress; -import com.cloud.network.IpAddress.State; import com.cloud.utils.net.Ip; -import org.apache.cloudstack.api.InternalIdentity; /** * A bean representing a public IP Address @@ -304,4 +300,9 @@ public class IPAddressVO implements IpAddress { public void setVmIp(String vmIp) { this.vmIp = vmIp; } + + @Override + public Long getNetworkId() { + return sourceNetworkId; + } } diff --git a/server/src/com/cloud/network/dao/InlineLoadBalancerNicMapDao.java b/engine/schema/src/com/cloud/network/dao/InlineLoadBalancerNicMapDao.java similarity index 100% rename from server/src/com/cloud/network/dao/InlineLoadBalancerNicMapDao.java rename to engine/schema/src/com/cloud/network/dao/InlineLoadBalancerNicMapDao.java diff --git a/server/src/com/cloud/network/dao/InlineLoadBalancerNicMapDaoImpl.java b/engine/schema/src/com/cloud/network/dao/InlineLoadBalancerNicMapDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/InlineLoadBalancerNicMapDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/InlineLoadBalancerNicMapDaoImpl.java diff --git a/server/src/com/cloud/network/dao/InlineLoadBalancerNicMapVO.java b/engine/schema/src/com/cloud/network/dao/InlineLoadBalancerNicMapVO.java similarity index 100% rename from server/src/com/cloud/network/dao/InlineLoadBalancerNicMapVO.java rename to engine/schema/src/com/cloud/network/dao/InlineLoadBalancerNicMapVO.java diff --git a/server/src/com/cloud/network/dao/LBHealthCheckPolicyDao.java b/engine/schema/src/com/cloud/network/dao/LBHealthCheckPolicyDao.java similarity index 100% rename from server/src/com/cloud/network/dao/LBHealthCheckPolicyDao.java rename to engine/schema/src/com/cloud/network/dao/LBHealthCheckPolicyDao.java diff --git a/server/src/com/cloud/network/dao/LBHealthCheckPolicyDaoImpl.java b/engine/schema/src/com/cloud/network/dao/LBHealthCheckPolicyDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/LBHealthCheckPolicyDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/LBHealthCheckPolicyDaoImpl.java diff --git a/server/src/com/cloud/network/dao/LBStickinessPolicyDao.java b/engine/schema/src/com/cloud/network/dao/LBStickinessPolicyDao.java similarity index 100% rename from server/src/com/cloud/network/dao/LBStickinessPolicyDao.java rename to engine/schema/src/com/cloud/network/dao/LBStickinessPolicyDao.java diff --git a/server/src/com/cloud/network/dao/LBStickinessPolicyDaoImpl.java b/engine/schema/src/com/cloud/network/dao/LBStickinessPolicyDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/LBStickinessPolicyDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/LBStickinessPolicyDaoImpl.java diff --git a/server/src/com/cloud/network/dao/LBStickinessPolicyVO.java b/engine/schema/src/com/cloud/network/dao/LBStickinessPolicyVO.java similarity index 100% rename from server/src/com/cloud/network/dao/LBStickinessPolicyVO.java rename to engine/schema/src/com/cloud/network/dao/LBStickinessPolicyVO.java diff --git a/server/src/com/cloud/network/dao/LoadBalancerDao.java b/engine/schema/src/com/cloud/network/dao/LoadBalancerDao.java similarity index 74% rename from server/src/com/cloud/network/dao/LoadBalancerDao.java rename to engine/schema/src/com/cloud/network/dao/LoadBalancerDao.java index 611282e5693..331f7555d81 100644 --- a/server/src/com/cloud/network/dao/LoadBalancerDao.java +++ b/engine/schema/src/com/cloud/network/dao/LoadBalancerDao.java @@ -18,19 +18,15 @@ package com.cloud.network.dao; import java.util.List; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.utils.db.GenericDao; public interface LoadBalancerDao extends GenericDao { - List listInstancesByLoadBalancer(long loadBalancerId); List listByIpAddress(long ipAddressId); - LoadBalancerVO findByIpAddressAndPublicPort(long ipAddressId, String publicPort); + List listByNetworkIdAndScheme(long networkId, Scheme scheme); - LoadBalancerVO findByAccountAndName(Long accountId, String name); - - List listByNetworkId(long networkId); - - List listInTransitionStateByNetworkId(long networkId); + List listInTransitionStateByNetworkIdAndScheme(long networkId, Scheme scheme); } diff --git a/engine/schema/src/com/cloud/network/dao/LoadBalancerDaoImpl.java b/engine/schema/src/com/cloud/network/dao/LoadBalancerDaoImpl.java new file mode 100644 index 00000000000..c20d8b23d6a --- /dev/null +++ b/engine/schema/src/com/cloud/network/dao/LoadBalancerDaoImpl.java @@ -0,0 +1,79 @@ +// 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. +package com.cloud.network.dao; + +import java.util.List; + +import javax.ejb.Local; +import javax.inject.Inject; + +import org.springframework.stereotype.Component; + +import com.cloud.network.rules.FirewallRule.State; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; + +@Component +@Local(value = { LoadBalancerDao.class }) +public class LoadBalancerDaoImpl extends GenericDaoBase implements LoadBalancerDao { + private final SearchBuilder ListByIp; + protected final SearchBuilder TransitionStateSearch; + + @Inject protected FirewallRulesCidrsDao _portForwardingRulesCidrsDao; + + protected LoadBalancerDaoImpl() { + ListByIp = createSearchBuilder(); + ListByIp.and("ipAddressId", ListByIp.entity().getSourceIpAddressId(), SearchCriteria.Op.EQ); + ListByIp.and("networkId", ListByIp.entity().getNetworkId(), SearchCriteria.Op.EQ); + ListByIp.and("scheme", ListByIp.entity().getScheme(), SearchCriteria.Op.EQ); + ListByIp.done(); + + TransitionStateSearch = createSearchBuilder(); + TransitionStateSearch.and("networkId", TransitionStateSearch.entity().getNetworkId(), Op.EQ); + TransitionStateSearch.and("state", TransitionStateSearch.entity().getState(), Op.IN); + TransitionStateSearch.and("scheme", TransitionStateSearch.entity().getScheme(), Op.EQ); + TransitionStateSearch.done(); + } + + @Override + public List listByIpAddress(long ipAddressId) { + SearchCriteria sc = ListByIp.create(); + sc.setParameters("ipAddressId", ipAddressId); + return listBy(sc); + } + + @Override + public List listByNetworkIdAndScheme(long networkId, Scheme scheme) { + SearchCriteria sc = ListByIp.create(); + sc.setParameters("networkId", networkId); + sc.setParameters("scheme", scheme); + return listBy(sc); + } + + @Override + public List listInTransitionStateByNetworkIdAndScheme(long networkId, Scheme scheme) { + SearchCriteria sc = TransitionStateSearch.create(); + sc.setParameters("networkId", networkId); + sc.setParameters("state", State.Add.toString(), State.Revoke.toString()); + sc.setParameters("scheme", scheme); + return listBy(sc); + } + +} diff --git a/server/src/com/cloud/network/dao/LoadBalancerVMMapDao.java b/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapDao.java similarity index 100% rename from server/src/com/cloud/network/dao/LoadBalancerVMMapDao.java rename to engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapDao.java diff --git a/server/src/com/cloud/network/dao/LoadBalancerVMMapDaoImpl.java b/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/LoadBalancerVMMapDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapDaoImpl.java diff --git a/server/src/com/cloud/network/dao/LoadBalancerVMMapVO.java b/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapVO.java similarity index 100% rename from server/src/com/cloud/network/dao/LoadBalancerVMMapVO.java rename to engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapVO.java diff --git a/server/src/com/cloud/network/dao/LoadBalancerVO.java b/engine/schema/src/com/cloud/network/dao/LoadBalancerVO.java similarity index 86% rename from server/src/com/cloud/network/dao/LoadBalancerVO.java rename to engine/schema/src/com/cloud/network/dao/LoadBalancerVO.java index 5422f41774b..fee88cf7b0a 100644 --- a/server/src/com/cloud/network/dao/LoadBalancerVO.java +++ b/engine/schema/src/com/cloud/network/dao/LoadBalancerVO.java @@ -19,6 +19,8 @@ package com.cloud.network.dao; import javax.persistence.Column; import javax.persistence.DiscriminatorValue; import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.Table; @@ -26,6 +28,12 @@ import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.LoadBalancer; import com.cloud.utils.net.NetUtils; +/** + * This VO represent Public Load Balancer + * It references source ip address by its Id. + * To get the VO for Internal Load Balancer rule, please refer to LoadBalancerRuleVO + * + */ @Entity @Table(name=("load_balancing_rules")) @DiscriminatorValue(value="LoadBalancing") @@ -46,6 +54,10 @@ public class LoadBalancerVO extends FirewallRuleVO implements LoadBalancer { @Column(name="default_port_end") private int defaultPortEnd; + + @Enumerated(value=EnumType.STRING) + @Column(name="scheme") + Scheme scheme = Scheme.Public; public LoadBalancerVO() { } @@ -57,6 +69,7 @@ public class LoadBalancerVO extends FirewallRuleVO implements LoadBalancer { this.algorithm = algorithm; this.defaultPortStart = dstPort; this.defaultPortEnd = dstPort; + this.scheme = Scheme.Public; } @Override @@ -94,5 +107,10 @@ public class LoadBalancerVO extends FirewallRuleVO implements LoadBalancer { public void setDescription(String description) { this.description = description; + } + + @Override + public Scheme getScheme() { + return scheme; } } diff --git a/server/src/com/cloud/network/dao/NetworkAccountDao.java b/engine/schema/src/com/cloud/network/dao/NetworkAccountDao.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkAccountDao.java rename to engine/schema/src/com/cloud/network/dao/NetworkAccountDao.java diff --git a/server/src/com/cloud/network/dao/NetworkAccountDaoImpl.java b/engine/schema/src/com/cloud/network/dao/NetworkAccountDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkAccountDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/NetworkAccountDaoImpl.java diff --git a/server/src/com/cloud/network/dao/NetworkAccountVO.java b/engine/schema/src/com/cloud/network/dao/NetworkAccountVO.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkAccountVO.java rename to engine/schema/src/com/cloud/network/dao/NetworkAccountVO.java diff --git a/server/src/com/cloud/network/dao/NetworkDao.java b/engine/schema/src/com/cloud/network/dao/NetworkDao.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkDao.java rename to engine/schema/src/com/cloud/network/dao/NetworkDao.java diff --git a/server/src/com/cloud/network/dao/NetworkDaoImpl.java b/engine/schema/src/com/cloud/network/dao/NetworkDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/NetworkDaoImpl.java diff --git a/server/src/com/cloud/network/dao/NetworkDomainDao.java b/engine/schema/src/com/cloud/network/dao/NetworkDomainDao.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkDomainDao.java rename to engine/schema/src/com/cloud/network/dao/NetworkDomainDao.java diff --git a/server/src/com/cloud/network/dao/NetworkDomainDaoImpl.java b/engine/schema/src/com/cloud/network/dao/NetworkDomainDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkDomainDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/NetworkDomainDaoImpl.java diff --git a/server/src/com/cloud/network/dao/NetworkDomainVO.java b/engine/schema/src/com/cloud/network/dao/NetworkDomainVO.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkDomainVO.java rename to engine/schema/src/com/cloud/network/dao/NetworkDomainVO.java diff --git a/server/src/com/cloud/network/dao/NetworkExternalFirewallDao.java b/engine/schema/src/com/cloud/network/dao/NetworkExternalFirewallDao.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkExternalFirewallDao.java rename to engine/schema/src/com/cloud/network/dao/NetworkExternalFirewallDao.java diff --git a/server/src/com/cloud/network/dao/NetworkExternalFirewallDaoImpl.java b/engine/schema/src/com/cloud/network/dao/NetworkExternalFirewallDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkExternalFirewallDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/NetworkExternalFirewallDaoImpl.java diff --git a/server/src/com/cloud/network/dao/NetworkExternalFirewallVO.java b/engine/schema/src/com/cloud/network/dao/NetworkExternalFirewallVO.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkExternalFirewallVO.java rename to engine/schema/src/com/cloud/network/dao/NetworkExternalFirewallVO.java diff --git a/server/src/com/cloud/network/dao/NetworkExternalLoadBalancerDao.java b/engine/schema/src/com/cloud/network/dao/NetworkExternalLoadBalancerDao.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkExternalLoadBalancerDao.java rename to engine/schema/src/com/cloud/network/dao/NetworkExternalLoadBalancerDao.java diff --git a/server/src/com/cloud/network/dao/NetworkExternalLoadBalancerDaoImpl.java b/engine/schema/src/com/cloud/network/dao/NetworkExternalLoadBalancerDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkExternalLoadBalancerDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/NetworkExternalLoadBalancerDaoImpl.java diff --git a/server/src/com/cloud/network/dao/NetworkExternalLoadBalancerVO.java b/engine/schema/src/com/cloud/network/dao/NetworkExternalLoadBalancerVO.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkExternalLoadBalancerVO.java rename to engine/schema/src/com/cloud/network/dao/NetworkExternalLoadBalancerVO.java diff --git a/server/src/com/cloud/network/dao/NetworkOpDao.java b/engine/schema/src/com/cloud/network/dao/NetworkOpDao.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkOpDao.java rename to engine/schema/src/com/cloud/network/dao/NetworkOpDao.java diff --git a/server/src/com/cloud/network/dao/NetworkOpDaoImpl.java b/engine/schema/src/com/cloud/network/dao/NetworkOpDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkOpDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/NetworkOpDaoImpl.java diff --git a/server/src/com/cloud/network/dao/NetworkOpVO.java b/engine/schema/src/com/cloud/network/dao/NetworkOpVO.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkOpVO.java rename to engine/schema/src/com/cloud/network/dao/NetworkOpVO.java diff --git a/server/src/com/cloud/network/dao/NetworkRuleConfigDao.java b/engine/schema/src/com/cloud/network/dao/NetworkRuleConfigDao.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkRuleConfigDao.java rename to engine/schema/src/com/cloud/network/dao/NetworkRuleConfigDao.java diff --git a/server/src/com/cloud/network/dao/NetworkRuleConfigDaoImpl.java b/engine/schema/src/com/cloud/network/dao/NetworkRuleConfigDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkRuleConfigDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/NetworkRuleConfigDaoImpl.java diff --git a/server/src/com/cloud/network/dao/NetworkRuleConfigVO.java b/engine/schema/src/com/cloud/network/dao/NetworkRuleConfigVO.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkRuleConfigVO.java rename to engine/schema/src/com/cloud/network/dao/NetworkRuleConfigVO.java diff --git a/server/src/com/cloud/network/dao/NetworkServiceMapDao.java b/engine/schema/src/com/cloud/network/dao/NetworkServiceMapDao.java similarity index 95% rename from server/src/com/cloud/network/dao/NetworkServiceMapDao.java rename to engine/schema/src/com/cloud/network/dao/NetworkServiceMapDao.java index 79b97bec0f1..6d401c40d8b 100644 --- a/server/src/com/cloud/network/dao/NetworkServiceMapDao.java +++ b/engine/schema/src/com/cloud/network/dao/NetworkServiceMapDao.java @@ -35,4 +35,5 @@ public interface NetworkServiceMapDao extends GenericDao getDistinctProviders(long networkId); String isProviderForNetwork(long networkId, Provider provider); + List getProvidersForServiceInNetwork(long networkId, Service service); } diff --git a/server/src/com/cloud/network/dao/NetworkServiceMapDaoImpl.java b/engine/schema/src/com/cloud/network/dao/NetworkServiceMapDaoImpl.java similarity index 93% rename from server/src/com/cloud/network/dao/NetworkServiceMapDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/NetworkServiceMapDaoImpl.java index 13fbfbc401f..3cdd73885c8 100644 --- a/server/src/com/cloud/network/dao/NetworkServiceMapDaoImpl.java +++ b/engine/schema/src/com/cloud/network/dao/NetworkServiceMapDaoImpl.java @@ -56,6 +56,7 @@ public class NetworkServiceMapDaoImpl extends GenericDaoBase getProvidersForServiceInNetwork(long networkId, Service service) { + SearchCriteria sc = DistinctProvidersSearch.create(); + sc.setParameters("networkId", networkId); + sc.setParameters("service", service.getName()); + return customSearch(sc, null); + } } diff --git a/server/src/com/cloud/network/dao/NetworkServiceMapVO.java b/engine/schema/src/com/cloud/network/dao/NetworkServiceMapVO.java similarity index 100% rename from server/src/com/cloud/network/dao/NetworkServiceMapVO.java rename to engine/schema/src/com/cloud/network/dao/NetworkServiceMapVO.java diff --git a/server/src/com/cloud/network/dao/NetworkVO.java b/engine/schema/src/com/cloud/network/dao/NetworkVO.java similarity index 99% rename from server/src/com/cloud/network/dao/NetworkVO.java rename to engine/schema/src/com/cloud/network/dao/NetworkVO.java index 7e4c6bcaa6b..9b0eec53020 100644 --- a/server/src/com/cloud/network/dao/NetworkVO.java +++ b/engine/schema/src/com/cloud/network/dao/NetworkVO.java @@ -32,9 +32,6 @@ import javax.persistence.Transient; import org.apache.cloudstack.acl.ControlledEntity; import com.cloud.network.Network; -import com.cloud.network.Networks; -import com.cloud.network.Network.GuestType; -import com.cloud.network.Network.State; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.Mode; import com.cloud.network.Networks.TrafficType; diff --git a/server/src/com/cloud/network/dao/PhysicalNetworkDao.java b/engine/schema/src/com/cloud/network/dao/PhysicalNetworkDao.java similarity index 100% rename from server/src/com/cloud/network/dao/PhysicalNetworkDao.java rename to engine/schema/src/com/cloud/network/dao/PhysicalNetworkDao.java diff --git a/server/src/com/cloud/network/dao/PhysicalNetworkDaoImpl.java b/engine/schema/src/com/cloud/network/dao/PhysicalNetworkDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/PhysicalNetworkDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/PhysicalNetworkDaoImpl.java diff --git a/server/src/com/cloud/network/dao/PhysicalNetworkIsolationMethodDaoImpl.java b/engine/schema/src/com/cloud/network/dao/PhysicalNetworkIsolationMethodDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/PhysicalNetworkIsolationMethodDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/PhysicalNetworkIsolationMethodDaoImpl.java diff --git a/server/src/com/cloud/network/dao/PhysicalNetworkIsolationMethodVO.java b/engine/schema/src/com/cloud/network/dao/PhysicalNetworkIsolationMethodVO.java similarity index 100% rename from server/src/com/cloud/network/dao/PhysicalNetworkIsolationMethodVO.java rename to engine/schema/src/com/cloud/network/dao/PhysicalNetworkIsolationMethodVO.java diff --git a/server/src/com/cloud/network/dao/PhysicalNetworkServiceProviderDao.java b/engine/schema/src/com/cloud/network/dao/PhysicalNetworkServiceProviderDao.java similarity index 100% rename from server/src/com/cloud/network/dao/PhysicalNetworkServiceProviderDao.java rename to engine/schema/src/com/cloud/network/dao/PhysicalNetworkServiceProviderDao.java diff --git a/server/src/com/cloud/network/dao/PhysicalNetworkServiceProviderDaoImpl.java b/engine/schema/src/com/cloud/network/dao/PhysicalNetworkServiceProviderDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/PhysicalNetworkServiceProviderDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/PhysicalNetworkServiceProviderDaoImpl.java diff --git a/server/src/com/cloud/network/dao/PhysicalNetworkServiceProviderVO.java b/engine/schema/src/com/cloud/network/dao/PhysicalNetworkServiceProviderVO.java similarity index 100% rename from server/src/com/cloud/network/dao/PhysicalNetworkServiceProviderVO.java rename to engine/schema/src/com/cloud/network/dao/PhysicalNetworkServiceProviderVO.java diff --git a/server/src/com/cloud/network/dao/PhysicalNetworkTagDaoImpl.java b/engine/schema/src/com/cloud/network/dao/PhysicalNetworkTagDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/PhysicalNetworkTagDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/PhysicalNetworkTagDaoImpl.java diff --git a/server/src/com/cloud/network/dao/PhysicalNetworkTagVO.java b/engine/schema/src/com/cloud/network/dao/PhysicalNetworkTagVO.java similarity index 100% rename from server/src/com/cloud/network/dao/PhysicalNetworkTagVO.java rename to engine/schema/src/com/cloud/network/dao/PhysicalNetworkTagVO.java diff --git a/server/src/com/cloud/network/dao/PhysicalNetworkTrafficTypeDao.java b/engine/schema/src/com/cloud/network/dao/PhysicalNetworkTrafficTypeDao.java similarity index 100% rename from server/src/com/cloud/network/dao/PhysicalNetworkTrafficTypeDao.java rename to engine/schema/src/com/cloud/network/dao/PhysicalNetworkTrafficTypeDao.java diff --git a/server/src/com/cloud/network/dao/PhysicalNetworkTrafficTypeDaoImpl.java b/engine/schema/src/com/cloud/network/dao/PhysicalNetworkTrafficTypeDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/PhysicalNetworkTrafficTypeDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/PhysicalNetworkTrafficTypeDaoImpl.java diff --git a/server/src/com/cloud/network/dao/PhysicalNetworkTrafficTypeVO.java b/engine/schema/src/com/cloud/network/dao/PhysicalNetworkTrafficTypeVO.java similarity index 100% rename from server/src/com/cloud/network/dao/PhysicalNetworkTrafficTypeVO.java rename to engine/schema/src/com/cloud/network/dao/PhysicalNetworkTrafficTypeVO.java diff --git a/server/src/com/cloud/network/dao/PhysicalNetworkVO.java b/engine/schema/src/com/cloud/network/dao/PhysicalNetworkVO.java similarity index 100% rename from server/src/com/cloud/network/dao/PhysicalNetworkVO.java rename to engine/schema/src/com/cloud/network/dao/PhysicalNetworkVO.java diff --git a/server/src/com/cloud/network/dao/PortProfileDao.java b/engine/schema/src/com/cloud/network/dao/PortProfileDao.java similarity index 100% rename from server/src/com/cloud/network/dao/PortProfileDao.java rename to engine/schema/src/com/cloud/network/dao/PortProfileDao.java diff --git a/server/src/com/cloud/network/dao/PortProfileDaoImpl.java b/engine/schema/src/com/cloud/network/dao/PortProfileDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/PortProfileDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/PortProfileDaoImpl.java diff --git a/server/src/com/cloud/network/dao/PortProfileVO.java b/engine/schema/src/com/cloud/network/dao/PortProfileVO.java similarity index 100% rename from server/src/com/cloud/network/dao/PortProfileVO.java rename to engine/schema/src/com/cloud/network/dao/PortProfileVO.java diff --git a/server/src/com/cloud/network/dao/RemoteAccessVpnDao.java b/engine/schema/src/com/cloud/network/dao/RemoteAccessVpnDao.java similarity index 100% rename from server/src/com/cloud/network/dao/RemoteAccessVpnDao.java rename to engine/schema/src/com/cloud/network/dao/RemoteAccessVpnDao.java diff --git a/server/src/com/cloud/network/dao/RemoteAccessVpnDaoImpl.java b/engine/schema/src/com/cloud/network/dao/RemoteAccessVpnDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/RemoteAccessVpnDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/RemoteAccessVpnDaoImpl.java diff --git a/server/src/com/cloud/network/dao/RemoteAccessVpnVO.java b/engine/schema/src/com/cloud/network/dao/RemoteAccessVpnVO.java similarity index 100% rename from server/src/com/cloud/network/dao/RemoteAccessVpnVO.java rename to engine/schema/src/com/cloud/network/dao/RemoteAccessVpnVO.java diff --git a/server/src/com/cloud/network/dao/RouterNetworkDao.java b/engine/schema/src/com/cloud/network/dao/RouterNetworkDao.java similarity index 100% rename from server/src/com/cloud/network/dao/RouterNetworkDao.java rename to engine/schema/src/com/cloud/network/dao/RouterNetworkDao.java diff --git a/server/src/com/cloud/network/dao/RouterNetworkDaoImpl.java b/engine/schema/src/com/cloud/network/dao/RouterNetworkDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/RouterNetworkDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/RouterNetworkDaoImpl.java diff --git a/server/src/com/cloud/network/dao/RouterNetworkVO.java b/engine/schema/src/com/cloud/network/dao/RouterNetworkVO.java similarity index 100% rename from server/src/com/cloud/network/dao/RouterNetworkVO.java rename to engine/schema/src/com/cloud/network/dao/RouterNetworkVO.java diff --git a/server/src/com/cloud/network/dao/Site2SiteCustomerGatewayDao.java b/engine/schema/src/com/cloud/network/dao/Site2SiteCustomerGatewayDao.java similarity index 100% rename from server/src/com/cloud/network/dao/Site2SiteCustomerGatewayDao.java rename to engine/schema/src/com/cloud/network/dao/Site2SiteCustomerGatewayDao.java diff --git a/server/src/com/cloud/network/dao/Site2SiteCustomerGatewayDaoImpl.java b/engine/schema/src/com/cloud/network/dao/Site2SiteCustomerGatewayDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/Site2SiteCustomerGatewayDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/Site2SiteCustomerGatewayDaoImpl.java diff --git a/server/src/com/cloud/network/dao/Site2SiteCustomerGatewayVO.java b/engine/schema/src/com/cloud/network/dao/Site2SiteCustomerGatewayVO.java similarity index 100% rename from server/src/com/cloud/network/dao/Site2SiteCustomerGatewayVO.java rename to engine/schema/src/com/cloud/network/dao/Site2SiteCustomerGatewayVO.java diff --git a/server/src/com/cloud/network/dao/Site2SiteVpnConnectionDao.java b/engine/schema/src/com/cloud/network/dao/Site2SiteVpnConnectionDao.java similarity index 100% rename from server/src/com/cloud/network/dao/Site2SiteVpnConnectionDao.java rename to engine/schema/src/com/cloud/network/dao/Site2SiteVpnConnectionDao.java diff --git a/server/src/com/cloud/network/dao/Site2SiteVpnConnectionDaoImpl.java b/engine/schema/src/com/cloud/network/dao/Site2SiteVpnConnectionDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/Site2SiteVpnConnectionDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/Site2SiteVpnConnectionDaoImpl.java diff --git a/server/src/com/cloud/network/dao/Site2SiteVpnConnectionVO.java b/engine/schema/src/com/cloud/network/dao/Site2SiteVpnConnectionVO.java similarity index 100% rename from server/src/com/cloud/network/dao/Site2SiteVpnConnectionVO.java rename to engine/schema/src/com/cloud/network/dao/Site2SiteVpnConnectionVO.java diff --git a/server/src/com/cloud/network/dao/Site2SiteVpnGatewayDao.java b/engine/schema/src/com/cloud/network/dao/Site2SiteVpnGatewayDao.java similarity index 100% rename from server/src/com/cloud/network/dao/Site2SiteVpnGatewayDao.java rename to engine/schema/src/com/cloud/network/dao/Site2SiteVpnGatewayDao.java diff --git a/server/src/com/cloud/network/dao/Site2SiteVpnGatewayDaoImpl.java b/engine/schema/src/com/cloud/network/dao/Site2SiteVpnGatewayDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/Site2SiteVpnGatewayDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/Site2SiteVpnGatewayDaoImpl.java diff --git a/server/src/com/cloud/network/dao/Site2SiteVpnGatewayVO.java b/engine/schema/src/com/cloud/network/dao/Site2SiteVpnGatewayVO.java similarity index 100% rename from server/src/com/cloud/network/dao/Site2SiteVpnGatewayVO.java rename to engine/schema/src/com/cloud/network/dao/Site2SiteVpnGatewayVO.java diff --git a/server/src/com/cloud/network/dao/UserIpv6AddressDao.java b/engine/schema/src/com/cloud/network/dao/UserIpv6AddressDao.java similarity index 100% rename from server/src/com/cloud/network/dao/UserIpv6AddressDao.java rename to engine/schema/src/com/cloud/network/dao/UserIpv6AddressDao.java diff --git a/server/src/com/cloud/network/dao/UserIpv6AddressDaoImpl.java b/engine/schema/src/com/cloud/network/dao/UserIpv6AddressDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/UserIpv6AddressDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/UserIpv6AddressDaoImpl.java diff --git a/server/src/com/cloud/network/dao/VirtualRouterProviderDao.java b/engine/schema/src/com/cloud/network/dao/VirtualRouterProviderDao.java similarity index 100% rename from server/src/com/cloud/network/dao/VirtualRouterProviderDao.java rename to engine/schema/src/com/cloud/network/dao/VirtualRouterProviderDao.java diff --git a/server/src/com/cloud/network/dao/VirtualRouterProviderDaoImpl.java b/engine/schema/src/com/cloud/network/dao/VirtualRouterProviderDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/VirtualRouterProviderDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/VirtualRouterProviderDaoImpl.java diff --git a/server/src/com/cloud/network/dao/VpnUserDao.java b/engine/schema/src/com/cloud/network/dao/VpnUserDao.java similarity index 100% rename from server/src/com/cloud/network/dao/VpnUserDao.java rename to engine/schema/src/com/cloud/network/dao/VpnUserDao.java diff --git a/server/src/com/cloud/network/dao/VpnUserDaoImpl.java b/engine/schema/src/com/cloud/network/dao/VpnUserDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/dao/VpnUserDaoImpl.java rename to engine/schema/src/com/cloud/network/dao/VpnUserDaoImpl.java diff --git a/server/src/com/cloud/network/element/VirtualRouterProviderVO.java b/engine/schema/src/com/cloud/network/element/VirtualRouterProviderVO.java similarity index 100% rename from server/src/com/cloud/network/element/VirtualRouterProviderVO.java rename to engine/schema/src/com/cloud/network/element/VirtualRouterProviderVO.java diff --git a/server/src/com/cloud/network/rules/FirewallRuleVO.java b/engine/schema/src/com/cloud/network/rules/FirewallRuleVO.java similarity index 98% rename from server/src/com/cloud/network/rules/FirewallRuleVO.java rename to engine/schema/src/com/cloud/network/rules/FirewallRuleVO.java index a761520ccfe..9f73029349f 100644 --- a/server/src/com/cloud/network/rules/FirewallRuleVO.java +++ b/engine/schema/src/com/cloud/network/rules/FirewallRuleVO.java @@ -20,7 +20,6 @@ import java.util.Date; import java.util.List; import java.util.UUID; -import javax.inject.Inject; import javax.persistence.Column; import javax.persistence.DiscriminatorColumn; import javax.persistence.DiscriminatorType; @@ -35,7 +34,6 @@ import javax.persistence.InheritanceType; import javax.persistence.Table; import javax.persistence.Transient; -import com.cloud.network.dao.FirewallRulesCidrsDao; import com.cloud.utils.db.GenericDao; import com.cloud.utils.net.NetUtils; diff --git a/server/src/com/cloud/network/rules/PortForwardingRuleVO.java b/engine/schema/src/com/cloud/network/rules/PortForwardingRuleVO.java similarity index 100% rename from server/src/com/cloud/network/rules/PortForwardingRuleVO.java rename to engine/schema/src/com/cloud/network/rules/PortForwardingRuleVO.java diff --git a/server/src/com/cloud/network/rules/dao/PortForwardingRulesDao.java b/engine/schema/src/com/cloud/network/rules/dao/PortForwardingRulesDao.java similarity index 100% rename from server/src/com/cloud/network/rules/dao/PortForwardingRulesDao.java rename to engine/schema/src/com/cloud/network/rules/dao/PortForwardingRulesDao.java diff --git a/server/src/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java b/engine/schema/src/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java rename to engine/schema/src/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java diff --git a/core/src/com/cloud/network/security/SecurityGroupRuleVO.java b/engine/schema/src/com/cloud/network/security/SecurityGroupRuleVO.java similarity index 100% rename from core/src/com/cloud/network/security/SecurityGroupRuleVO.java rename to engine/schema/src/com/cloud/network/security/SecurityGroupRuleVO.java diff --git a/core/src/com/cloud/network/security/SecurityGroupRulesVO.java b/engine/schema/src/com/cloud/network/security/SecurityGroupRulesVO.java similarity index 91% rename from core/src/com/cloud/network/security/SecurityGroupRulesVO.java rename to engine/schema/src/com/cloud/network/security/SecurityGroupRulesVO.java index 82060efce12..c74152e453c 100644 --- a/core/src/com/cloud/network/security/SecurityGroupRulesVO.java +++ b/engine/schema/src/com/cloud/network/security/SecurityGroupRulesVO.java @@ -54,6 +54,9 @@ public class SecurityGroupRulesVO implements SecurityGroupRules { @Column(name = "id", table = "security_group_rule", insertable = false, updatable = false) private Long ruleId; + @Column(name = "uuid", table = "security_group_rule", insertable = false, updatable = false) + private String ruleUuid; + @Column(name = "start_port", table = "security_group_rule", insertable = false, updatable = false) private int startPort; @@ -75,7 +78,11 @@ public class SecurityGroupRulesVO implements SecurityGroupRules { public SecurityGroupRulesVO() { } - public SecurityGroupRulesVO(long id, String name, String description, Long domainId, Long accountId, Long ruleId, int startPort, int endPort, String protocol, Long allowedNetworkId, + public SecurityGroupRulesVO(long id) { + this.id = id; + } + + public SecurityGroupRulesVO(long id, String name, String description, Long domainId, Long accountId, Long ruleId, String ruleUuid, int startPort, int endPort, String protocol, Long allowedNetworkId, String allowedSourceIpCidr) { this.id = id; this.name = name; @@ -83,6 +90,7 @@ public class SecurityGroupRulesVO implements SecurityGroupRules { this.domainId = domainId; this.accountId = accountId; this.ruleId = ruleId; + this.ruleUuid = ruleUuid; this.startPort = startPort; this.endPort = endPort; this.protocol = protocol; @@ -120,6 +128,11 @@ public class SecurityGroupRulesVO implements SecurityGroupRules { return ruleId; } + @Override + public String getRuleUuid() { + return ruleUuid; + } + @Override public int getStartPort() { return startPort; diff --git a/core/src/com/cloud/network/security/SecurityGroupVMMapVO.java b/engine/schema/src/com/cloud/network/security/SecurityGroupVMMapVO.java similarity index 100% rename from core/src/com/cloud/network/security/SecurityGroupVMMapVO.java rename to engine/schema/src/com/cloud/network/security/SecurityGroupVMMapVO.java diff --git a/core/src/com/cloud/network/security/SecurityGroupVO.java b/engine/schema/src/com/cloud/network/security/SecurityGroupVO.java similarity index 100% rename from core/src/com/cloud/network/security/SecurityGroupVO.java rename to engine/schema/src/com/cloud/network/security/SecurityGroupVO.java diff --git a/core/src/com/cloud/network/security/SecurityGroupWork.java b/engine/schema/src/com/cloud/network/security/SecurityGroupWork.java similarity index 100% rename from core/src/com/cloud/network/security/SecurityGroupWork.java rename to engine/schema/src/com/cloud/network/security/SecurityGroupWork.java diff --git a/core/src/com/cloud/network/security/SecurityGroupWorkVO.java b/engine/schema/src/com/cloud/network/security/SecurityGroupWorkVO.java similarity index 100% rename from core/src/com/cloud/network/security/SecurityGroupWorkVO.java rename to engine/schema/src/com/cloud/network/security/SecurityGroupWorkVO.java diff --git a/core/src/com/cloud/network/security/VmRulesetLogVO.java b/engine/schema/src/com/cloud/network/security/VmRulesetLogVO.java similarity index 100% rename from core/src/com/cloud/network/security/VmRulesetLogVO.java rename to engine/schema/src/com/cloud/network/security/VmRulesetLogVO.java diff --git a/server/src/com/cloud/network/security/dao/SecurityGroupDao.java b/engine/schema/src/com/cloud/network/security/dao/SecurityGroupDao.java similarity index 100% rename from server/src/com/cloud/network/security/dao/SecurityGroupDao.java rename to engine/schema/src/com/cloud/network/security/dao/SecurityGroupDao.java diff --git a/server/src/com/cloud/network/security/dao/SecurityGroupDaoImpl.java b/engine/schema/src/com/cloud/network/security/dao/SecurityGroupDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/security/dao/SecurityGroupDaoImpl.java rename to engine/schema/src/com/cloud/network/security/dao/SecurityGroupDaoImpl.java diff --git a/server/src/com/cloud/network/security/dao/SecurityGroupRuleDao.java b/engine/schema/src/com/cloud/network/security/dao/SecurityGroupRuleDao.java similarity index 100% rename from server/src/com/cloud/network/security/dao/SecurityGroupRuleDao.java rename to engine/schema/src/com/cloud/network/security/dao/SecurityGroupRuleDao.java diff --git a/server/src/com/cloud/network/security/dao/SecurityGroupRuleDaoImpl.java b/engine/schema/src/com/cloud/network/security/dao/SecurityGroupRuleDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/security/dao/SecurityGroupRuleDaoImpl.java rename to engine/schema/src/com/cloud/network/security/dao/SecurityGroupRuleDaoImpl.java diff --git a/server/src/com/cloud/network/security/dao/SecurityGroupRulesDao.java b/engine/schema/src/com/cloud/network/security/dao/SecurityGroupRulesDao.java similarity index 100% rename from server/src/com/cloud/network/security/dao/SecurityGroupRulesDao.java rename to engine/schema/src/com/cloud/network/security/dao/SecurityGroupRulesDao.java diff --git a/server/src/com/cloud/network/security/dao/SecurityGroupRulesDaoImpl.java b/engine/schema/src/com/cloud/network/security/dao/SecurityGroupRulesDaoImpl.java similarity index 89% rename from server/src/com/cloud/network/security/dao/SecurityGroupRulesDaoImpl.java rename to engine/schema/src/com/cloud/network/security/dao/SecurityGroupRulesDaoImpl.java index f08ca05cd7a..18ef57fbcd8 100644 --- a/server/src/com/cloud/network/security/dao/SecurityGroupRulesDaoImpl.java +++ b/engine/schema/src/com/cloud/network/security/dao/SecurityGroupRulesDaoImpl.java @@ -84,4 +84,13 @@ public class SecurityGroupRulesDaoImpl extends GenericDaoBase sc = createSearchCriteria(); + sc.addAnd("ruleUuid", SearchCriteria.Op.EQ, uuid); + SecurityGroupRulesVO rule = findOneIncludingRemovedBy(sc); + SecurityGroupRulesVO newRule = new SecurityGroupRulesVO(rule.getRuleId()); + return newRule; + } } diff --git a/server/src/com/cloud/network/security/dao/SecurityGroupVMMapDao.java b/engine/schema/src/com/cloud/network/security/dao/SecurityGroupVMMapDao.java similarity index 100% rename from server/src/com/cloud/network/security/dao/SecurityGroupVMMapDao.java rename to engine/schema/src/com/cloud/network/security/dao/SecurityGroupVMMapDao.java diff --git a/server/src/com/cloud/network/security/dao/SecurityGroupVMMapDaoImpl.java b/engine/schema/src/com/cloud/network/security/dao/SecurityGroupVMMapDaoImpl.java similarity index 100% rename from server/src/com/cloud/network/security/dao/SecurityGroupVMMapDaoImpl.java rename to engine/schema/src/com/cloud/network/security/dao/SecurityGroupVMMapDaoImpl.java diff --git a/server/src/com/cloud/network/security/dao/SecurityGroupWorkDao.java b/engine/schema/src/com/cloud/network/security/dao/SecurityGroupWorkDao.java similarity index 100% rename from server/src/com/cloud/network/security/dao/SecurityGroupWorkDao.java rename to engine/schema/src/com/cloud/network/security/dao/SecurityGroupWorkDao.java diff --git a/server/src/com/cloud/network/security/dao/SecurityGroupWorkDaoImpl.java b/engine/schema/src/com/cloud/network/security/dao/SecurityGroupWorkDaoImpl.java similarity index 93% rename from server/src/com/cloud/network/security/dao/SecurityGroupWorkDaoImpl.java rename to engine/schema/src/com/cloud/network/security/dao/SecurityGroupWorkDaoImpl.java index dcd1238186e..3154ffeb873 100644 --- a/server/src/com/cloud/network/security/dao/SecurityGroupWorkDaoImpl.java +++ b/engine/schema/src/com/cloud/network/security/dao/SecurityGroupWorkDaoImpl.java @@ -24,17 +24,16 @@ import javax.ejb.Local; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import com.cloud.ha.HaWorkVO; import com.cloud.network.security.SecurityGroupWork; -import com.cloud.network.security.SecurityGroupWorkVO; import com.cloud.network.security.SecurityGroupWork.Step; +import com.cloud.network.security.SecurityGroupWorkVO; import com.cloud.utils.db.DB; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.Transaction; import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; @Component @@ -42,12 +41,12 @@ import com.cloud.utils.exception.CloudRuntimeException; public class SecurityGroupWorkDaoImpl extends GenericDaoBase implements SecurityGroupWorkDao { private static final Logger s_logger = Logger.getLogger(SecurityGroupWorkDaoImpl.class); - private SearchBuilder VmIdTakenSearch; - private SearchBuilder VmIdSeqNumSearch; - private SearchBuilder VmIdUnTakenSearch; - private SearchBuilder UntakenWorkSearch; - private SearchBuilder VmIdStepSearch; - private SearchBuilder CleanupSearch; + private final SearchBuilder VmIdTakenSearch; + private final SearchBuilder VmIdSeqNumSearch; + private final SearchBuilder VmIdUnTakenSearch; + private final SearchBuilder UntakenWorkSearch; + private final SearchBuilder VmIdStepSearch; + private final SearchBuilder CleanupSearch; protected SecurityGroupWorkDaoImpl() { @@ -56,38 +55,38 @@ public class SecurityGroupWorkDaoImpl extends GenericDaoBase sc = VmIdSeqNumSearch.create(); sc.setParameters("vmId", vmId); sc.setParameters("seqno", logSequenceNumber); - - final Filter filter = new Filter(HaWorkVO.class, null, true, 0l, 1l); + + final Filter filter = new Filter(SecurityGroupWorkVO.class, null, true, 0l, 1l); final List vos = lockRows(sc, filter, true); if (vos.size() == 0) { @@ -183,7 +182,7 @@ public class SecurityGroupWorkDaoImpl extends GenericDaoBase result = listIncludingRemovedBy(sc); - + return result; } - + @Override public List findAndCleanupUnfinishedWork(Date timeBefore) { final SearchCriteria sc = CleanupSearch.create(); @@ -230,7 +229,7 @@ public class SecurityGroupWorkDaoImpl extends GenericDaoBase findScheduledWork() { final SearchCriteria sc = UntakenWorkSearch.create(); @@ -238,5 +237,5 @@ public class SecurityGroupWorkDaoImpl extends GenericDaoBase List listByTrafficTypeGuestTypeAndState(NetworkOffering.State state, TrafficType trafficType, Network.GuestType type); + NetworkOfferingVO persist(NetworkOfferingVO off, Map details); + } diff --git a/server/src/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java b/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java similarity index 89% rename from server/src/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java rename to engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java index d1e44242d2a..ef8237a48f5 100644 --- a/server/src/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java +++ b/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java @@ -17,8 +17,10 @@ package com.cloud.offerings.dao; import java.util.List; +import java.util.Map; import javax.ejb.Local; +import javax.inject.Inject; import javax.persistence.EntityExistsException; import org.springframework.stereotype.Component; @@ -27,6 +29,8 @@ import com.cloud.network.Network; import com.cloud.network.Networks.TrafficType; import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.Availability; +import com.cloud.offering.NetworkOffering.Detail; +import com.cloud.offerings.NetworkOfferingDetailsVO; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; @@ -45,6 +49,7 @@ public class NetworkOfferingDaoImpl extends GenericDaoBase AvailabilitySearch; final SearchBuilder AllFieldsSearch; private final GenericSearchBuilder UpgradeSearch; + @Inject NetworkOfferingDetailsDao _detailsDao; protected NetworkOfferingDaoImpl() { super(); @@ -165,5 +170,24 @@ public class NetworkOfferingDaoImpl extends GenericDaoBase details) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + //1) persist the offering + NetworkOfferingVO vo = super.persist(off); + + //2) persist the details + if (details != null && !details.isEmpty()) { + for (NetworkOffering.Detail detail : details.keySet()) { + _detailsDao.persist(new NetworkOfferingDetailsVO(off.getId(), detail, details.get(detail))); + } + } + + txn.commit(); + return vo; + } } diff --git a/server/src/com/cloud/maint/dao/AgentUpgradeDaoImpl.java b/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDao.java similarity index 63% rename from server/src/com/cloud/maint/dao/AgentUpgradeDaoImpl.java rename to engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDao.java index 80c6d851aef..ce209e04694 100644 --- a/server/src/com/cloud/maint/dao/AgentUpgradeDaoImpl.java +++ b/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDao.java @@ -14,16 +14,18 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.maint.dao; +package com.cloud.offerings.dao; -import javax.ejb.Local; -import org.springframework.stereotype.Component; +import java.util.Map; -import com.cloud.maint.AgentUpgradeVO; -import com.cloud.utils.db.GenericDaoBase; +import com.cloud.offering.NetworkOffering; +import com.cloud.offering.NetworkOffering.Detail; +import com.cloud.offerings.NetworkOfferingDetailsVO; +import com.cloud.utils.db.GenericDao; -@Component -@Local(AgentUpgradeDao.class) -public class AgentUpgradeDaoImpl extends GenericDaoBase implements AgentUpgradeDao { +public interface NetworkOfferingDetailsDao extends GenericDao{ + + Map getNtwkOffDetails(long offeringId); + String getDetail(long offeringId, Detail detailName); } diff --git a/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDaoImpl.java b/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDaoImpl.java new file mode 100644 index 00000000000..068f3908b8d --- /dev/null +++ b/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDaoImpl.java @@ -0,0 +1,79 @@ +// 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. +package com.cloud.offerings.dao; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.cloud.offering.NetworkOffering; +import com.cloud.offering.NetworkOffering.Detail; +import com.cloud.offerings.NetworkOfferingDetailsVO; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Func; +import com.cloud.utils.db.SearchCriteria.Op; + +public class NetworkOfferingDetailsDaoImpl extends GenericDaoBase implements NetworkOfferingDetailsDao{ + protected final SearchBuilder DetailSearch; + private final GenericSearchBuilder ValueSearch; + + + public NetworkOfferingDetailsDaoImpl() { + + DetailSearch = createSearchBuilder(); + DetailSearch.and("offeringId", DetailSearch.entity().getOfferingId(), SearchCriteria.Op.EQ); + DetailSearch.and("name", DetailSearch.entity().getName(), SearchCriteria.Op.EQ); + DetailSearch.done(); + + ValueSearch = createSearchBuilder(String.class); + ValueSearch.select(null, Func.DISTINCT, ValueSearch.entity().getValue()); + ValueSearch.and("offeringId", ValueSearch.entity().getOfferingId(), SearchCriteria.Op.EQ); + ValueSearch.and("name", ValueSearch.entity().getName(), Op.EQ); + ValueSearch.done(); + } + + @Override + public Map getNtwkOffDetails(long offeringId) { + SearchCriteria sc = DetailSearch.create(); + sc.setParameters("offeringId", offeringId); + + List results = search(sc, null); + Map details = new HashMap(results.size()); + for (NetworkOfferingDetailsVO result : results) { + details.put(result.getName(), result.getValue()); + } + + return details; + } + + @Override + public String getDetail(long offeringId, Detail detailName) { + SearchCriteria sc = ValueSearch.create(); + sc.setParameters("name", detailName); + sc.setParameters("offeringId", offeringId); + List results = customSearch(sc, null); + if (results.isEmpty()) { + return null; + } else { + return results.get(0); + } + } + +} diff --git a/server/src/com/cloud/offerings/dao/NetworkOfferingServiceMapDao.java b/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingServiceMapDao.java similarity index 100% rename from server/src/com/cloud/offerings/dao/NetworkOfferingServiceMapDao.java rename to engine/schema/src/com/cloud/offerings/dao/NetworkOfferingServiceMapDao.java diff --git a/server/src/com/cloud/offerings/dao/NetworkOfferingServiceMapDaoImpl.java b/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingServiceMapDaoImpl.java similarity index 100% rename from server/src/com/cloud/offerings/dao/NetworkOfferingServiceMapDaoImpl.java rename to engine/schema/src/com/cloud/offerings/dao/NetworkOfferingServiceMapDaoImpl.java diff --git a/server/src/com/cloud/projects/ProjectAccountVO.java b/engine/schema/src/com/cloud/projects/ProjectAccountVO.java similarity index 100% rename from server/src/com/cloud/projects/ProjectAccountVO.java rename to engine/schema/src/com/cloud/projects/ProjectAccountVO.java diff --git a/server/src/com/cloud/projects/ProjectInvitationVO.java b/engine/schema/src/com/cloud/projects/ProjectInvitationVO.java similarity index 100% rename from server/src/com/cloud/projects/ProjectInvitationVO.java rename to engine/schema/src/com/cloud/projects/ProjectInvitationVO.java diff --git a/server/src/com/cloud/projects/ProjectVO.java b/engine/schema/src/com/cloud/projects/ProjectVO.java similarity index 100% rename from server/src/com/cloud/projects/ProjectVO.java rename to engine/schema/src/com/cloud/projects/ProjectVO.java diff --git a/server/src/com/cloud/projects/dao/ProjectAccountDao.java b/engine/schema/src/com/cloud/projects/dao/ProjectAccountDao.java similarity index 100% rename from server/src/com/cloud/projects/dao/ProjectAccountDao.java rename to engine/schema/src/com/cloud/projects/dao/ProjectAccountDao.java diff --git a/server/src/com/cloud/projects/dao/ProjectAccountDaoImpl.java b/engine/schema/src/com/cloud/projects/dao/ProjectAccountDaoImpl.java similarity index 100% rename from server/src/com/cloud/projects/dao/ProjectAccountDaoImpl.java rename to engine/schema/src/com/cloud/projects/dao/ProjectAccountDaoImpl.java diff --git a/server/src/com/cloud/projects/dao/ProjectDao.java b/engine/schema/src/com/cloud/projects/dao/ProjectDao.java similarity index 100% rename from server/src/com/cloud/projects/dao/ProjectDao.java rename to engine/schema/src/com/cloud/projects/dao/ProjectDao.java diff --git a/server/src/com/cloud/projects/dao/ProjectDaoImpl.java b/engine/schema/src/com/cloud/projects/dao/ProjectDaoImpl.java similarity index 100% rename from server/src/com/cloud/projects/dao/ProjectDaoImpl.java rename to engine/schema/src/com/cloud/projects/dao/ProjectDaoImpl.java diff --git a/server/src/com/cloud/projects/dao/ProjectInvitationDao.java b/engine/schema/src/com/cloud/projects/dao/ProjectInvitationDao.java similarity index 100% rename from server/src/com/cloud/projects/dao/ProjectInvitationDao.java rename to engine/schema/src/com/cloud/projects/dao/ProjectInvitationDao.java diff --git a/server/src/com/cloud/projects/dao/ProjectInvitationDaoImpl.java b/engine/schema/src/com/cloud/projects/dao/ProjectInvitationDaoImpl.java similarity index 100% rename from server/src/com/cloud/projects/dao/ProjectInvitationDaoImpl.java rename to engine/schema/src/com/cloud/projects/dao/ProjectInvitationDaoImpl.java diff --git a/server/src/com/cloud/secstorage/CommandExecLogDao.java b/engine/schema/src/com/cloud/secstorage/CommandExecLogDao.java similarity index 100% rename from server/src/com/cloud/secstorage/CommandExecLogDao.java rename to engine/schema/src/com/cloud/secstorage/CommandExecLogDao.java diff --git a/server/src/com/cloud/secstorage/CommandExecLogDaoImpl.java b/engine/schema/src/com/cloud/secstorage/CommandExecLogDaoImpl.java similarity index 100% rename from server/src/com/cloud/secstorage/CommandExecLogDaoImpl.java rename to engine/schema/src/com/cloud/secstorage/CommandExecLogDaoImpl.java diff --git a/server/src/com/cloud/secstorage/CommandExecLogVO.java b/engine/schema/src/com/cloud/secstorage/CommandExecLogVO.java similarity index 100% rename from server/src/com/cloud/secstorage/CommandExecLogVO.java rename to engine/schema/src/com/cloud/secstorage/CommandExecLogVO.java diff --git a/server/src/com/cloud/service/ServiceOfferingVO.java b/engine/schema/src/com/cloud/service/ServiceOfferingVO.java similarity index 100% rename from server/src/com/cloud/service/ServiceOfferingVO.java rename to engine/schema/src/com/cloud/service/ServiceOfferingVO.java diff --git a/server/src/com/cloud/service/dao/ServiceOfferingDao.java b/engine/schema/src/com/cloud/service/dao/ServiceOfferingDao.java similarity index 100% rename from server/src/com/cloud/service/dao/ServiceOfferingDao.java rename to engine/schema/src/com/cloud/service/dao/ServiceOfferingDao.java diff --git a/server/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java b/engine/schema/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java similarity index 100% rename from server/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java rename to engine/schema/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java diff --git a/core/src/com/cloud/storage/DiskOfferingVO.java b/engine/schema/src/com/cloud/storage/DiskOfferingVO.java similarity index 100% rename from core/src/com/cloud/storage/DiskOfferingVO.java rename to engine/schema/src/com/cloud/storage/DiskOfferingVO.java diff --git a/core/src/com/cloud/storage/GuestOSCategoryVO.java b/engine/schema/src/com/cloud/storage/GuestOSCategoryVO.java similarity index 100% rename from core/src/com/cloud/storage/GuestOSCategoryVO.java rename to engine/schema/src/com/cloud/storage/GuestOSCategoryVO.java diff --git a/core/src/com/cloud/storage/GuestOSVO.java b/engine/schema/src/com/cloud/storage/GuestOSVO.java similarity index 100% rename from core/src/com/cloud/storage/GuestOSVO.java rename to engine/schema/src/com/cloud/storage/GuestOSVO.java diff --git a/core/src/com/cloud/storage/LaunchPermissionVO.java b/engine/schema/src/com/cloud/storage/LaunchPermissionVO.java similarity index 100% rename from core/src/com/cloud/storage/LaunchPermissionVO.java rename to engine/schema/src/com/cloud/storage/LaunchPermissionVO.java diff --git a/core/src/com/cloud/storage/S3VO.java b/engine/schema/src/com/cloud/storage/S3VO.java similarity index 100% rename from core/src/com/cloud/storage/S3VO.java rename to engine/schema/src/com/cloud/storage/S3VO.java diff --git a/core/src/com/cloud/storage/SnapshotPolicyVO.java b/engine/schema/src/com/cloud/storage/SnapshotPolicyVO.java similarity index 100% rename from core/src/com/cloud/storage/SnapshotPolicyVO.java rename to engine/schema/src/com/cloud/storage/SnapshotPolicyVO.java diff --git a/core/src/com/cloud/storage/SnapshotScheduleVO.java b/engine/schema/src/com/cloud/storage/SnapshotScheduleVO.java similarity index 100% rename from core/src/com/cloud/storage/SnapshotScheduleVO.java rename to engine/schema/src/com/cloud/storage/SnapshotScheduleVO.java diff --git a/core/src/com/cloud/storage/SnapshotVO.java b/engine/schema/src/com/cloud/storage/SnapshotVO.java similarity index 100% rename from core/src/com/cloud/storage/SnapshotVO.java rename to engine/schema/src/com/cloud/storage/SnapshotVO.java diff --git a/core/src/com/cloud/storage/StoragePoolHostAssoc.java b/engine/schema/src/com/cloud/storage/StoragePoolHostAssoc.java similarity index 100% rename from core/src/com/cloud/storage/StoragePoolHostAssoc.java rename to engine/schema/src/com/cloud/storage/StoragePoolHostAssoc.java diff --git a/core/src/com/cloud/storage/StoragePoolHostVO.java b/engine/schema/src/com/cloud/storage/StoragePoolHostVO.java similarity index 94% rename from core/src/com/cloud/storage/StoragePoolHostVO.java rename to engine/schema/src/com/cloud/storage/StoragePoolHostVO.java index a8a2bac4886..1b02f6d9754 100644 --- a/core/src/com/cloud/storage/StoragePoolHostVO.java +++ b/engine/schema/src/com/cloud/storage/StoragePoolHostVO.java @@ -28,7 +28,6 @@ import javax.persistence.Temporal; import javax.persistence.TemporalType; import com.cloud.utils.db.GenericDaoBase; -import org.apache.cloudstack.api.InternalIdentity; /** * Join table for storage pools and hosts @@ -40,24 +39,24 @@ public class StoragePoolHostVO implements StoragePoolHostAssoc { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; - + @Column(name="pool_id") private long poolId; - + @Column(name="host_id") private long hostId; - + @Column(name="local_path") private String localPath; - + @Column(name=GenericDaoBase.CREATED_COLUMN) - private Date created = null; - + private Date created = null; + @Column(name="last_updated") @Temporal(value=TemporalType.TIMESTAMP) - private Date lastUpdated = null; - - + private Date lastUpdated = null; + + public StoragePoolHostVO() { super(); } @@ -76,6 +75,7 @@ public class StoragePoolHostVO implements StoragePoolHostAssoc { } + @Override public long getId() { return id; } diff --git a/core/src/com/cloud/storage/StoragePoolWorkVO.java b/engine/schema/src/com/cloud/storage/StoragePoolWorkVO.java similarity index 100% rename from core/src/com/cloud/storage/StoragePoolWorkVO.java rename to engine/schema/src/com/cloud/storage/StoragePoolWorkVO.java diff --git a/core/src/com/cloud/storage/SwiftVO.java b/engine/schema/src/com/cloud/storage/SwiftVO.java similarity index 100% rename from core/src/com/cloud/storage/SwiftVO.java rename to engine/schema/src/com/cloud/storage/SwiftVO.java diff --git a/core/src/com/cloud/storage/UploadVO.java b/engine/schema/src/com/cloud/storage/UploadVO.java similarity index 100% rename from core/src/com/cloud/storage/UploadVO.java rename to engine/schema/src/com/cloud/storage/UploadVO.java diff --git a/core/src/com/cloud/storage/VMTemplateDetailVO.java b/engine/schema/src/com/cloud/storage/VMTemplateDetailVO.java similarity index 100% rename from core/src/com/cloud/storage/VMTemplateDetailVO.java rename to engine/schema/src/com/cloud/storage/VMTemplateDetailVO.java diff --git a/core/src/com/cloud/storage/VMTemplateHostVO.java b/engine/schema/src/com/cloud/storage/VMTemplateHostVO.java similarity index 100% rename from core/src/com/cloud/storage/VMTemplateHostVO.java rename to engine/schema/src/com/cloud/storage/VMTemplateHostVO.java diff --git a/core/src/com/cloud/storage/VMTemplateS3VO.java b/engine/schema/src/com/cloud/storage/VMTemplateS3VO.java similarity index 100% rename from core/src/com/cloud/storage/VMTemplateS3VO.java rename to engine/schema/src/com/cloud/storage/VMTemplateS3VO.java diff --git a/core/src/com/cloud/storage/VMTemplateStoragePoolVO.java b/engine/schema/src/com/cloud/storage/VMTemplateStoragePoolVO.java similarity index 100% rename from core/src/com/cloud/storage/VMTemplateStoragePoolVO.java rename to engine/schema/src/com/cloud/storage/VMTemplateStoragePoolVO.java diff --git a/core/src/com/cloud/storage/VMTemplateSwiftVO.java b/engine/schema/src/com/cloud/storage/VMTemplateSwiftVO.java similarity index 100% rename from core/src/com/cloud/storage/VMTemplateSwiftVO.java rename to engine/schema/src/com/cloud/storage/VMTemplateSwiftVO.java diff --git a/core/src/com/cloud/storage/VMTemplateVO.java b/engine/schema/src/com/cloud/storage/VMTemplateVO.java similarity index 100% rename from core/src/com/cloud/storage/VMTemplateVO.java rename to engine/schema/src/com/cloud/storage/VMTemplateVO.java diff --git a/core/src/com/cloud/storage/VMTemplateZoneVO.java b/engine/schema/src/com/cloud/storage/VMTemplateZoneVO.java similarity index 100% rename from core/src/com/cloud/storage/VMTemplateZoneVO.java rename to engine/schema/src/com/cloud/storage/VMTemplateZoneVO.java diff --git a/core/src/com/cloud/storage/VolumeHostVO.java b/engine/schema/src/com/cloud/storage/VolumeHostVO.java similarity index 100% rename from core/src/com/cloud/storage/VolumeHostVO.java rename to engine/schema/src/com/cloud/storage/VolumeHostVO.java diff --git a/core/src/com/cloud/storage/VolumeVO.java b/engine/schema/src/com/cloud/storage/VolumeVO.java similarity index 100% rename from core/src/com/cloud/storage/VolumeVO.java rename to engine/schema/src/com/cloud/storage/VolumeVO.java diff --git a/server/src/com/cloud/storage/dao/DiskOfferingDao.java b/engine/schema/src/com/cloud/storage/dao/DiskOfferingDao.java similarity index 100% rename from server/src/com/cloud/storage/dao/DiskOfferingDao.java rename to engine/schema/src/com/cloud/storage/dao/DiskOfferingDao.java diff --git a/server/src/com/cloud/storage/dao/DiskOfferingDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/DiskOfferingDaoImpl.java similarity index 100% rename from server/src/com/cloud/storage/dao/DiskOfferingDaoImpl.java rename to engine/schema/src/com/cloud/storage/dao/DiskOfferingDaoImpl.java diff --git a/server/src/com/cloud/storage/dao/GuestOSCategoryDao.java b/engine/schema/src/com/cloud/storage/dao/GuestOSCategoryDao.java similarity index 100% rename from server/src/com/cloud/storage/dao/GuestOSCategoryDao.java rename to engine/schema/src/com/cloud/storage/dao/GuestOSCategoryDao.java diff --git a/server/src/com/cloud/storage/dao/GuestOSCategoryDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/GuestOSCategoryDaoImpl.java similarity index 100% rename from server/src/com/cloud/storage/dao/GuestOSCategoryDaoImpl.java rename to engine/schema/src/com/cloud/storage/dao/GuestOSCategoryDaoImpl.java diff --git a/server/src/com/cloud/storage/dao/GuestOSDao.java b/engine/schema/src/com/cloud/storage/dao/GuestOSDao.java similarity index 100% rename from server/src/com/cloud/storage/dao/GuestOSDao.java rename to engine/schema/src/com/cloud/storage/dao/GuestOSDao.java diff --git a/server/src/com/cloud/storage/dao/GuestOSDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/GuestOSDaoImpl.java similarity index 100% rename from server/src/com/cloud/storage/dao/GuestOSDaoImpl.java rename to engine/schema/src/com/cloud/storage/dao/GuestOSDaoImpl.java diff --git a/server/src/com/cloud/storage/dao/LaunchPermissionDao.java b/engine/schema/src/com/cloud/storage/dao/LaunchPermissionDao.java similarity index 100% rename from server/src/com/cloud/storage/dao/LaunchPermissionDao.java rename to engine/schema/src/com/cloud/storage/dao/LaunchPermissionDao.java diff --git a/server/src/com/cloud/storage/dao/LaunchPermissionDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/LaunchPermissionDaoImpl.java similarity index 100% rename from server/src/com/cloud/storage/dao/LaunchPermissionDaoImpl.java rename to engine/schema/src/com/cloud/storage/dao/LaunchPermissionDaoImpl.java diff --git a/server/src/com/cloud/storage/dao/S3Dao.java b/engine/schema/src/com/cloud/storage/dao/S3Dao.java similarity index 100% rename from server/src/com/cloud/storage/dao/S3Dao.java rename to engine/schema/src/com/cloud/storage/dao/S3Dao.java diff --git a/server/src/com/cloud/storage/dao/S3DaoImpl.java b/engine/schema/src/com/cloud/storage/dao/S3DaoImpl.java similarity index 100% rename from server/src/com/cloud/storage/dao/S3DaoImpl.java rename to engine/schema/src/com/cloud/storage/dao/S3DaoImpl.java diff --git a/server/src/com/cloud/storage/dao/SnapshotDao.java b/engine/schema/src/com/cloud/storage/dao/SnapshotDao.java similarity index 100% rename from server/src/com/cloud/storage/dao/SnapshotDao.java rename to engine/schema/src/com/cloud/storage/dao/SnapshotDao.java diff --git a/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/SnapshotDaoImpl.java similarity index 100% rename from server/src/com/cloud/storage/dao/SnapshotDaoImpl.java rename to engine/schema/src/com/cloud/storage/dao/SnapshotDaoImpl.java diff --git a/server/src/com/cloud/storage/dao/SnapshotPolicyDao.java b/engine/schema/src/com/cloud/storage/dao/SnapshotPolicyDao.java similarity index 100% rename from server/src/com/cloud/storage/dao/SnapshotPolicyDao.java rename to engine/schema/src/com/cloud/storage/dao/SnapshotPolicyDao.java diff --git a/server/src/com/cloud/storage/dao/SnapshotPolicyDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/SnapshotPolicyDaoImpl.java similarity index 100% rename from server/src/com/cloud/storage/dao/SnapshotPolicyDaoImpl.java rename to engine/schema/src/com/cloud/storage/dao/SnapshotPolicyDaoImpl.java diff --git a/server/src/com/cloud/storage/dao/SnapshotScheduleDao.java b/engine/schema/src/com/cloud/storage/dao/SnapshotScheduleDao.java similarity index 100% rename from server/src/com/cloud/storage/dao/SnapshotScheduleDao.java rename to engine/schema/src/com/cloud/storage/dao/SnapshotScheduleDao.java diff --git a/server/src/com/cloud/storage/dao/SnapshotScheduleDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/SnapshotScheduleDaoImpl.java similarity index 100% rename from server/src/com/cloud/storage/dao/SnapshotScheduleDaoImpl.java rename to engine/schema/src/com/cloud/storage/dao/SnapshotScheduleDaoImpl.java diff --git a/server/src/com/cloud/storage/dao/StoragePoolDetailsDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/StoragePoolDetailsDaoImpl.java similarity index 97% rename from server/src/com/cloud/storage/dao/StoragePoolDetailsDaoImpl.java rename to engine/schema/src/com/cloud/storage/dao/StoragePoolDetailsDaoImpl.java index a0d5d0e6e97..38b525330f2 100644 --- a/server/src/com/cloud/storage/dao/StoragePoolDetailsDaoImpl.java +++ b/engine/schema/src/com/cloud/storage/dao/StoragePoolDetailsDaoImpl.java @@ -41,6 +41,7 @@ public class StoragePoolDetailsDaoImpl extends GenericDaoBase, StateDao< public Set> searchTemplates(String name, String keyword, TemplateFilter templateFilter, boolean isIso, List hypers, Boolean bootable, DomainVO domain, Long pageSize, Long startIndex, Long zoneId, HypervisorType hyperType, boolean onlyReady, boolean showDomr, List permittedAccounts, Account caller, - ListProjectResourcesCriteria listProjectResourcesCriteria, Map tags); + ListProjectResourcesCriteria listProjectResourcesCriteria, Map tags, String zoneType); public Set> searchSwiftTemplates(String name, String keyword, TemplateFilter templateFilter, boolean isIso, List hypers, Boolean bootable, DomainVO domain, Long pageSize, Long startIndex, @@ -75,7 +75,7 @@ public interface VMTemplateDao extends GenericDao, StateDao< VMTemplateVO findSystemVMTemplate(long zoneId); VMTemplateVO findSystemVMTemplate(long zoneId, HypervisorType hType); - VMTemplateVO findRoutingTemplate(HypervisorType type); + VMTemplateVO findRoutingTemplate(HypervisorType type, String templateName); List listPrivateTemplatesByHost(Long hostId); public Long countTemplatesForAccount(long accountId); diff --git a/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/VMTemplateDaoImpl.java similarity index 98% rename from server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java rename to engine/schema/src/com/cloud/storage/dao/VMTemplateDaoImpl.java index d9a26d3ca66..25ae933740d 100755 --- a/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java +++ b/engine/schema/src/com/cloud/storage/dao/VMTemplateDaoImpl.java @@ -353,6 +353,7 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem tmpltTypeHyperSearch2 = createSearchBuilder(); tmpltTypeHyperSearch2.and("templateType", tmpltTypeHyperSearch2.entity().getTemplateType(), SearchCriteria.Op.EQ); tmpltTypeHyperSearch2.and("hypervisorType", tmpltTypeHyperSearch2.entity().getHypervisorType(), SearchCriteria.Op.EQ); + tmpltTypeHyperSearch2.and("templateName", tmpltTypeHyperSearch2.entity().getName(), SearchCriteria.Op.EQ); tmpltTypeSearch = createSearchBuilder(); @@ -520,7 +521,7 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem public Set> searchTemplates(String name, String keyword, TemplateFilter templateFilter, boolean isIso, List hypers, Boolean bootable, DomainVO domain, Long pageSize, Long startIndex, Long zoneId, HypervisorType hyperType, boolean onlyReady, boolean showDomr,List permittedAccounts, - Account caller, ListProjectResourcesCriteria listProjectResourcesCriteria, Map tags) { + Account caller, ListProjectResourcesCriteria listProjectResourcesCriteria, Map tags, String zoneType) { StringBuilder builder = new StringBuilder(); if (!permittedAccounts.isEmpty()) { for (Account permittedAccount : permittedAccounts) { @@ -564,7 +565,12 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem if ((templateFilter == TemplateFilter.featured) || (templateFilter == TemplateFilter.community)) { dataCenterJoin = " INNER JOIN data_center dc on (h.data_center_id = dc.id)"; } - + + if (zoneType != null) { + dataCenterJoin = " INNER JOIN template_host_ref thr on (t.id = thr.template_id) INNER JOIN host h on (thr.host_id = h.id)"; + dataCenterJoin += " INNER JOIN data_center dc on (h.data_center_id = dc.id)"; + } + if (templateFilter == TemplateFilter.sharedexecutable || templateFilter == TemplateFilter.shared ){ lpjoin = " INNER JOIN launch_permission lp ON t.id = lp.template_id "; } @@ -691,7 +697,7 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem } sql += whereClause + getExtrasWhere(templateFilter, name, keyword, isIso, bootable, hyperType, zoneId, - onlyReady, showDomr) + groupByClause + getOrderByLimit(pageSize, startIndex); + onlyReady, showDomr, zoneType) + groupByClause + getOrderByLimit(pageSize, startIndex); pstmt = txn.prepareStatement(sql); rs = pstmt.executeQuery(); @@ -752,7 +758,7 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem return templateZonePairList; } - private String getExtrasWhere(TemplateFilter templateFilter, String name, String keyword, boolean isIso, Boolean bootable, HypervisorType hyperType, Long zoneId, boolean onlyReady, boolean showDomr) { + private String getExtrasWhere(TemplateFilter templateFilter, String name, String keyword, boolean isIso, Boolean bootable, HypervisorType hyperType, Long zoneId, boolean onlyReady, boolean showDomr, String zoneType) { String sql = ""; if (keyword != null) { sql += " t.name LIKE \"%" + keyword + "%\" AND"; @@ -782,10 +788,15 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem sql += " AND h.data_center_id = " +zoneId; } }else if (zoneId != null){ - sql += " AND tzr.zone_id = " +zoneId+ " AND tzr.removed is null" ; + sql += " AND tzr.zone_id = " +zoneId+ " AND tzr.removed is null" ; }else{ sql += " AND tzr.removed is null "; } + + if (zoneType != null){ + sql += " AND dc.networktype = '" + zoneType + "'"; + } + if (!showDomr){ sql += " AND t.type != '" +Storage.TemplateType.SYSTEM.toString() + "'"; } @@ -894,10 +905,13 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem } @Override - public VMTemplateVO findRoutingTemplate(HypervisorType hType) { + public VMTemplateVO findRoutingTemplate(HypervisorType hType, String templateName) { SearchCriteria sc = tmpltTypeHyperSearch2.create(); sc.setParameters("templateType", Storage.TemplateType.SYSTEM); sc.setParameters("hypervisorType", hType); + if (templateName != null) { + sc.setParameters("templateName", templateName); + } //order by descending order of id and select the first (this is going to be the latest) List tmplts = listBy(sc, new Filter(VMTemplateVO.class, "id", false, null, 1l)); diff --git a/server/src/com/cloud/storage/dao/VMTemplateDetailsDao.java b/engine/schema/src/com/cloud/storage/dao/VMTemplateDetailsDao.java similarity index 100% rename from server/src/com/cloud/storage/dao/VMTemplateDetailsDao.java rename to engine/schema/src/com/cloud/storage/dao/VMTemplateDetailsDao.java diff --git a/server/src/com/cloud/storage/dao/VMTemplateDetailsDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/VMTemplateDetailsDaoImpl.java similarity index 100% rename from server/src/com/cloud/storage/dao/VMTemplateDetailsDaoImpl.java rename to engine/schema/src/com/cloud/storage/dao/VMTemplateDetailsDaoImpl.java diff --git a/server/src/com/cloud/storage/dao/VMTemplateHostDao.java b/engine/schema/src/com/cloud/storage/dao/VMTemplateHostDao.java similarity index 100% rename from server/src/com/cloud/storage/dao/VMTemplateHostDao.java rename to engine/schema/src/com/cloud/storage/dao/VMTemplateHostDao.java diff --git a/server/src/com/cloud/storage/dao/VMTemplateHostDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/VMTemplateHostDaoImpl.java similarity index 100% rename from server/src/com/cloud/storage/dao/VMTemplateHostDaoImpl.java rename to engine/schema/src/com/cloud/storage/dao/VMTemplateHostDaoImpl.java diff --git a/server/src/com/cloud/storage/dao/VMTemplatePoolDao.java b/engine/schema/src/com/cloud/storage/dao/VMTemplatePoolDao.java similarity index 100% rename from server/src/com/cloud/storage/dao/VMTemplatePoolDao.java rename to engine/schema/src/com/cloud/storage/dao/VMTemplatePoolDao.java diff --git a/server/src/com/cloud/storage/dao/VMTemplatePoolDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/VMTemplatePoolDaoImpl.java similarity index 100% rename from server/src/com/cloud/storage/dao/VMTemplatePoolDaoImpl.java rename to engine/schema/src/com/cloud/storage/dao/VMTemplatePoolDaoImpl.java diff --git a/server/src/com/cloud/storage/dao/VMTemplateS3Dao.java b/engine/schema/src/com/cloud/storage/dao/VMTemplateS3Dao.java similarity index 100% rename from server/src/com/cloud/storage/dao/VMTemplateS3Dao.java rename to engine/schema/src/com/cloud/storage/dao/VMTemplateS3Dao.java diff --git a/server/src/com/cloud/storage/dao/VMTemplateS3DaoImpl.java b/engine/schema/src/com/cloud/storage/dao/VMTemplateS3DaoImpl.java similarity index 100% rename from server/src/com/cloud/storage/dao/VMTemplateS3DaoImpl.java rename to engine/schema/src/com/cloud/storage/dao/VMTemplateS3DaoImpl.java diff --git a/server/src/com/cloud/storage/dao/VMTemplateSwiftDao.java b/engine/schema/src/com/cloud/storage/dao/VMTemplateSwiftDao.java similarity index 100% rename from server/src/com/cloud/storage/dao/VMTemplateSwiftDao.java rename to engine/schema/src/com/cloud/storage/dao/VMTemplateSwiftDao.java diff --git a/server/src/com/cloud/storage/dao/VMTemplateSwiftDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/VMTemplateSwiftDaoImpl.java similarity index 100% rename from server/src/com/cloud/storage/dao/VMTemplateSwiftDaoImpl.java rename to engine/schema/src/com/cloud/storage/dao/VMTemplateSwiftDaoImpl.java diff --git a/server/src/com/cloud/storage/dao/VMTemplateZoneDao.java b/engine/schema/src/com/cloud/storage/dao/VMTemplateZoneDao.java similarity index 100% rename from server/src/com/cloud/storage/dao/VMTemplateZoneDao.java rename to engine/schema/src/com/cloud/storage/dao/VMTemplateZoneDao.java diff --git a/server/src/com/cloud/storage/dao/VMTemplateZoneDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/VMTemplateZoneDaoImpl.java similarity index 100% rename from server/src/com/cloud/storage/dao/VMTemplateZoneDaoImpl.java rename to engine/schema/src/com/cloud/storage/dao/VMTemplateZoneDaoImpl.java diff --git a/server/src/com/cloud/storage/dao/VolumeDao.java b/engine/schema/src/com/cloud/storage/dao/VolumeDao.java similarity index 100% rename from server/src/com/cloud/storage/dao/VolumeDao.java rename to engine/schema/src/com/cloud/storage/dao/VolumeDao.java diff --git a/server/src/com/cloud/storage/dao/VolumeDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/VolumeDaoImpl.java similarity index 100% rename from server/src/com/cloud/storage/dao/VolumeDaoImpl.java rename to engine/schema/src/com/cloud/storage/dao/VolumeDaoImpl.java diff --git a/server/src/com/cloud/storage/dao/VolumeHostDao.java b/engine/schema/src/com/cloud/storage/dao/VolumeHostDao.java similarity index 100% rename from server/src/com/cloud/storage/dao/VolumeHostDao.java rename to engine/schema/src/com/cloud/storage/dao/VolumeHostDao.java diff --git a/server/src/com/cloud/storage/dao/VolumeHostDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/VolumeHostDaoImpl.java similarity index 100% rename from server/src/com/cloud/storage/dao/VolumeHostDaoImpl.java rename to engine/schema/src/com/cloud/storage/dao/VolumeHostDaoImpl.java diff --git a/server/src/com/cloud/tags/ResourceTagVO.java b/engine/schema/src/com/cloud/tags/ResourceTagVO.java similarity index 100% rename from server/src/com/cloud/tags/ResourceTagVO.java rename to engine/schema/src/com/cloud/tags/ResourceTagVO.java diff --git a/server/src/com/cloud/tags/dao/ResourceTagDao.java b/engine/schema/src/com/cloud/tags/dao/ResourceTagDao.java similarity index 100% rename from server/src/com/cloud/tags/dao/ResourceTagDao.java rename to engine/schema/src/com/cloud/tags/dao/ResourceTagDao.java diff --git a/server/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java b/engine/schema/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java similarity index 100% rename from server/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java rename to engine/schema/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java diff --git a/server/src/com/cloud/upgrade/DatabaseCreator.java b/engine/schema/src/com/cloud/upgrade/DatabaseCreator.java similarity index 100% rename from server/src/com/cloud/upgrade/DatabaseCreator.java rename to engine/schema/src/com/cloud/upgrade/DatabaseCreator.java diff --git a/server/src/com/cloud/upgrade/DatabaseIntegrityChecker.java b/engine/schema/src/com/cloud/upgrade/DatabaseIntegrityChecker.java similarity index 100% rename from server/src/com/cloud/upgrade/DatabaseIntegrityChecker.java rename to engine/schema/src/com/cloud/upgrade/DatabaseIntegrityChecker.java diff --git a/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java b/engine/schema/src/com/cloud/upgrade/DatabaseUpgradeChecker.java similarity index 98% rename from server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java rename to engine/schema/src/com/cloud/upgrade/DatabaseUpgradeChecker.java index 8f9be0f5d57..9bc0ba599c2 100755 --- a/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java +++ b/engine/schema/src/com/cloud/upgrade/DatabaseUpgradeChecker.java @@ -34,7 +34,6 @@ import javax.ejb.Local; import org.apache.log4j.Logger; -import com.cloud.cluster.ClusterManagerImpl; import com.cloud.maint.Version; import com.cloud.upgrade.dao.DbUpgrade; import com.cloud.upgrade.dao.Upgrade217to218; @@ -63,7 +62,6 @@ import com.cloud.upgrade.dao.VersionDao; import com.cloud.upgrade.dao.VersionDaoImpl; import com.cloud.upgrade.dao.VersionVO; import com.cloud.upgrade.dao.VersionVO.Step; - import com.cloud.utils.component.SystemIntegrityChecker; import com.cloud.utils.db.GlobalLock; import com.cloud.utils.db.ScriptRunner; @@ -212,7 +210,8 @@ public class DatabaseUpgradeChecker implements SystemIntegrityChecker { } } - if (!supportsRollingUpgrade && ClusterManagerImpl.arePeersRunning(null)) { + if (!supportsRollingUpgrade && false) { // FIXME: Needs to detect if there are management servers running + // ClusterManagerImpl.arePeersRunning(null)) { s_logger.error("Unable to run upgrade because the upgrade sequence does not support rolling update and there are other management server nodes running"); throw new CloudRuntimeException("Unable to run upgrade because the upgrade sequence does not support rolling update and there are other management server nodes running"); } @@ -267,7 +266,8 @@ public class DatabaseUpgradeChecker implements SystemIntegrityChecker { } } - if (!ClusterManagerImpl.arePeersRunning(trimmedCurrentVersion)) { + if (true) { // FIXME Needs to detect if management servers are running + // !ClusterManagerImpl.arePeersRunning(trimmedCurrentVersion)) { s_logger.info("Cleaning upgrades because all management server are now at the same version"); TreeMap> upgradedVersions = new TreeMap>(); diff --git a/server/src/com/cloud/upgrade/PremiumDatabaseUpgradeChecker.java b/engine/schema/src/com/cloud/upgrade/PremiumDatabaseUpgradeChecker.java similarity index 77% rename from server/src/com/cloud/upgrade/PremiumDatabaseUpgradeChecker.java rename to engine/schema/src/com/cloud/upgrade/PremiumDatabaseUpgradeChecker.java index 14a81439670..bad32536955 100755 --- a/server/src/com/cloud/upgrade/PremiumDatabaseUpgradeChecker.java +++ b/engine/schema/src/com/cloud/upgrade/PremiumDatabaseUpgradeChecker.java @@ -40,6 +40,7 @@ import com.cloud.upgrade.dao.Upgrade229to2210; import com.cloud.upgrade.dao.Upgrade301to302; import com.cloud.upgrade.dao.Upgrade302to40; import com.cloud.upgrade.dao.Upgrade30to301; +import com.cloud.upgrade.dao.Upgrade40to41; import com.cloud.upgrade.dao.UpgradeSnapshot217to224; import com.cloud.upgrade.dao.UpgradeSnapshot223to224; import com.cloud.upgrade.dao.VersionDaoImpl; @@ -53,87 +54,95 @@ public class PremiumDatabaseUpgradeChecker extends DatabaseUpgradeChecker { new Upgrade221to222Premium(), new UpgradeSnapshot217to224(), new Upgrade222to224Premium(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228Premium(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212Premium(), - new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), - new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), + new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41() }); _upgradeMap.put("2.1.8", new DbUpgrade[] { new Upgrade218to22Premium(), new Upgrade221to222Premium(), new UpgradeSnapshot217to224(), new Upgrade222to224Premium(), new Upgrade218to224DomainVlans(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228Premium(), new Upgrade228to229(), - new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212Premium(), new Upgrade2212to2213() - , new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), - new Upgrade302to40() }); + new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212Premium(), new Upgrade2212to2213(), + new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), + new Upgrade302to40(), new Upgrade40to41() }); _upgradeMap.put("2.1.9", new DbUpgrade[] { new Upgrade218to22Premium(), new Upgrade221to222Premium(), new UpgradeSnapshot217to224(), new Upgrade222to224Premium(), new Upgrade218to224DomainVlans(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228Premium(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212Premium(), new Upgrade2212to2213(), - new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), - new Upgrade302to40() }); + new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), + new Upgrade302to40(), new Upgrade40to41() }); _upgradeMap.put("2.2.1", new DbUpgrade[] { new Upgrade221to222Premium(), new Upgrade222to224Premium(), new UpgradeSnapshot223to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228Premium(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212Premium(), - new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), - new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), + new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41() }); _upgradeMap.put("2.2.2", new DbUpgrade[] { new Upgrade222to224Premium(), new UpgradeSnapshot223to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228Premium(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212Premium(), new Upgrade2212to2213(), - new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), - new Upgrade302to40() }); + new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), + new Upgrade302to40(), new Upgrade40to41() }); _upgradeMap.put("2.2.3", new DbUpgrade[] { new Upgrade222to224Premium(), new UpgradeSnapshot223to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228Premium(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212Premium(), new Upgrade2212to2213(), - new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), + new Upgrade302to40(), new Upgrade40to41() }); _upgradeMap.put("2.2.4", new DbUpgrade[] { new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228Premium(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212Premium(), - new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), - new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), + new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41() }); _upgradeMap.put("2.2.5", new DbUpgrade[] { new Upgrade225to226(), new Upgrade227to228Premium(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212Premium(), - new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), - new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), + new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41() }); _upgradeMap.put("2.2.6", new DbUpgrade[] { new Upgrade227to228Premium(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212Premium(), new Upgrade2212to2213(), - new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), + new Upgrade302to40(), new Upgrade40to41() }); _upgradeMap.put("2.2.7", new DbUpgrade[] { new Upgrade227to228Premium(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212Premium(), new Upgrade2212to2213(), - new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), + new Upgrade302to40(), new Upgrade40to41() }); _upgradeMap.put("2.2.8", new DbUpgrade[] { new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212Premium(), new Upgrade2212to2213(), new Upgrade2213to2214(), - new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41() }); _upgradeMap.put("2.2.9", new DbUpgrade[] { new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212Premium(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), - new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41() }); _upgradeMap.put("2.2.10", new DbUpgrade[] { new Upgrade2210to2211(), new Upgrade2211to2212Premium(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), - new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41() }); _upgradeMap.put("2.2.11", new DbUpgrade[] { new Upgrade2211to2212Premium(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), - new Upgrade302to40() }); + new Upgrade302to40(), new Upgrade40to41() }); _upgradeMap.put("2.2.12", new DbUpgrade[] { new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), - new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40() }); + new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41() }); - _upgradeMap.put("2.2.13", new DbUpgrade[] { new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), - new Upgrade301to302(), new Upgrade302to40() }); + _upgradeMap.put("2.2.13", new DbUpgrade[] { new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), + new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41() }); _upgradeMap.put("2.2.14", new DbUpgrade[] { new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), - new Upgrade302to40() }); + new Upgrade302to40(), new Upgrade40to41() }); - _upgradeMap.put("3.0.0", new DbUpgrade[] { new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40() }); - - _upgradeMap.put("3.0.1", new DbUpgrade[] { new Upgrade301to302(), new Upgrade302to40() }); - - _upgradeMap.put("3.0.2", new DbUpgrade[] { new Upgrade302to40() }); - } + _upgradeMap.put("3.0.0", new DbUpgrade[] { new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41() }); + + _upgradeMap.put("3.0.1", new DbUpgrade[] { new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41() }); + + _upgradeMap.put("3.0.2", new DbUpgrade[] { new Upgrade302to40(), new Upgrade40to41() }); + + _upgradeMap.put("4.0.0", new DbUpgrade[] { new Upgrade40to41() }); + + _upgradeMap.put("4.0.1", new DbUpgrade[] { new Upgrade40to41() }); + + _upgradeMap.put("4.0.2", new DbUpgrade[] { new Upgrade40to41() }); } } diff --git a/server/src/com/cloud/upgrade/dao/DbUpgrade.java b/engine/schema/src/com/cloud/upgrade/dao/DbUpgrade.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/DbUpgrade.java rename to engine/schema/src/com/cloud/upgrade/dao/DbUpgrade.java diff --git a/server/src/com/cloud/upgrade/dao/DbUpgradeUtils.java b/engine/schema/src/com/cloud/upgrade/dao/DbUpgradeUtils.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/DbUpgradeUtils.java rename to engine/schema/src/com/cloud/upgrade/dao/DbUpgradeUtils.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade217to218.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade217to218.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade217to218.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade217to218.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade218to22.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade218to22.java similarity index 99% rename from server/src/com/cloud/upgrade/dao/Upgrade218to22.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade218to22.java index 01fa2cc9cfa..2ef842ac6d2 100644 --- a/server/src/com/cloud/upgrade/dao/Upgrade218to22.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade218to22.java @@ -37,12 +37,9 @@ import java.util.UUID; import org.apache.log4j.Logger; import com.cloud.configuration.Resource.ResourceType; -import com.cloud.consoleproxy.ConsoleProxyManager; import com.cloud.event.EventTypes; import com.cloud.event.EventVO; import com.cloud.event.UsageEventVO; -import com.cloud.network.router.VpcVirtualNetworkApplianceManager; -import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.utils.DateUtil; import com.cloud.utils.NumbersUtil; import com.cloud.utils.exception.CloudRuntimeException; @@ -1146,7 +1143,7 @@ public class Upgrade218to22 implements DbUpgrade { if (!userVmSet.next()) { s_logger.warn("Skipping user_statistics upgrade for account id=" + accountId + " in datacenter id=" + dataCenterId); continue; - } + } deviceId = userVmSet.getLong(1); } else { s_logger.debug("Account id=" + accountId + " doesn't own any user vms and domRs, so skipping user_statistics update"); @@ -1407,9 +1404,9 @@ public class Upgrade218to22 implements DbUpgrade { rs.close(); pstmt.close(); - int proxyRamSize = NumbersUtil.parseInt(getConfigValue(conn, "consoleproxy.ram.size"), ConsoleProxyManager.DEFAULT_PROXY_VM_RAMSIZE); - int domrRamSize = NumbersUtil.parseInt(getConfigValue(conn, "router.ram.size"), VpcVirtualNetworkApplianceManager.DEFAULT_ROUTER_VM_RAMSIZE); - int ssvmRamSize = NumbersUtil.parseInt(getConfigValue(conn, "secstorage.vm.ram.size"), SecondaryStorageVmManager.DEFAULT_SS_VM_RAMSIZE); + int proxyRamSize = NumbersUtil.parseInt(getConfigValue(conn, "consoleproxy.ram.size"), 1024); // ConsoleProxyManager.DEFAULT_PROXY_VM_RAMSIZE); + int domrRamSize = NumbersUtil.parseInt(getConfigValue(conn, "router.ram.size"), 128); // VpcVirtualNetworkApplianceManager.DEFAULT_ROUTER_VM_RAMSIZE); + int ssvmRamSize = NumbersUtil.parseInt(getConfigValue(conn, "secstorage.vm.ram.size"), 256); // SecondaryStorageVmManager.DEFAULT_SS_VM_RAMSIZE); pstmt = conn .prepareStatement("select h.id, count(v.id) from host h, vm_instance v where h.type='Routing' and v.state='Running' and v.`type`='ConsoleProxy' and v.host_id=h.id group by h.id"); @@ -1566,9 +1563,9 @@ public class Upgrade218to22 implements DbUpgrade { rs.close(); pstmt.close(); - int proxyCpuMhz = NumbersUtil.parseInt(getConfigValue(conn, "consoleproxy.cpu.mhz"), ConsoleProxyManager.DEFAULT_PROXY_VM_CPUMHZ); - int domrCpuMhz = NumbersUtil.parseInt(getConfigValue(conn, "router.cpu.mhz"), VpcVirtualNetworkApplianceManager.DEFAULT_ROUTER_CPU_MHZ); - int ssvmCpuMhz = NumbersUtil.parseInt(getConfigValue(conn, "secstorage.vm.cpu.mhz"), SecondaryStorageVmManager.DEFAULT_SS_VM_CPUMHZ); + int proxyCpuMhz = NumbersUtil.parseInt(getConfigValue(conn, "consoleproxy.cpu.mhz"), 500); // ConsoleProxyManager.DEFAULT_PROXY_VM_CPUMHZ); + int domrCpuMhz = NumbersUtil.parseInt(getConfigValue(conn, "router.cpu.mhz"), 500); // VpcVirtualNetworkApplianceManager.DEFAULT_ROUTER_CPU_MHZ); + int ssvmCpuMhz = NumbersUtil.parseInt(getConfigValue(conn, "secstorage.vm.cpu.mhz"), 500); // SecondaryStorageVmManager.DEFAULT_SS_VM_CPUMHZ); pstmt = conn .prepareStatement("select h.id, count(v.id) from host h, vm_instance v where h.type='Routing' and v.state='Running' and v.`type`='ConsoleProxy' and v.host_id=h.id group by h.id"); diff --git a/server/src/com/cloud/upgrade/dao/Upgrade218to224DomainVlans.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade218to224DomainVlans.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade218to224DomainVlans.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade218to224DomainVlans.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade218to22Premium.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade218to22Premium.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade218to22Premium.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade218to22Premium.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade2210to2211.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade2210to2211.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade2210to2211.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade2210to2211.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade2211to2212.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade2211to2212.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade2211to2212.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade2211to2212.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade2211to2212Premium.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade2211to2212Premium.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade2211to2212Premium.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade2211to2212Premium.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade2212to2213.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade2212to2213.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade2212to2213.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade2212to2213.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade2213to2214.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade2213to2214.java similarity index 96% rename from server/src/com/cloud/upgrade/dao/Upgrade2213to2214.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade2213to2214.java index 48b08e41e0a..d3528e3335f 100644 --- a/server/src/com/cloud/upgrade/dao/Upgrade2213to2214.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade2213to2214.java @@ -26,9 +26,9 @@ import java.util.List; import org.apache.log4j.Logger; -import com.cloud.consoleproxy.ConsoleProxyManagerImpl; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; +import com.cloud.vm.ConsoleProxyVO; public class Upgrade2213to2214 implements DbUpgrade { final static Logger s_logger = Logger.getLogger(Upgrade2213to2214.class); @@ -70,13 +70,13 @@ public class Upgrade2213to2214 implements DbUpgrade { if (privateKeyMd5.equalsIgnoreCase("432ea1370f57ccd774f4f36052c5fd73")) { s_logger.debug("Need to upgrade cloudstack provided certificate"); pstmt = conn.prepareStatement("update `cloud`.`keystore` set `cloud`.`keystore`.key = ?, certificate = ? where name = 'CPVMCertificate'"); - pstmt.setString(1, ConsoleProxyManagerImpl.keyContent); - pstmt.setString(2, ConsoleProxyManagerImpl.certContent); + pstmt.setString(1, ConsoleProxyVO.keyContent); + pstmt.setString(2, ConsoleProxyVO.certContent); pstmt.executeUpdate(); - + pstmt = conn.prepareStatement("insert into `cloud`.`keystore` (name, certificate, seq, domain_suffix) VALUES (?,?,?,?)"); pstmt.setString(1, "root"); - pstmt.setString(2, ConsoleProxyManagerImpl.rootCa); + pstmt.setString(2, ConsoleProxyVO.rootCa); pstmt.setInt(3, 0); pstmt.setString(4, "realhostip.com"); pstmt.executeUpdate(); @@ -87,7 +87,7 @@ public class Upgrade2213to2214 implements DbUpgrade { } catch (SQLException e) { s_logger.debug("Failed to upgrade keystore: " + e.toString()); } - + } @Override @@ -162,10 +162,10 @@ public class Upgrade2213to2214 implements DbUpgrade { pstmt.close(); } catch (SQLException e) { throw new CloudRuntimeException("Unable to execute changes for op_vm_ruleset_log", e); - } + } - //Drop i_async__removed, i_async_job__removed (if exists) and add i_async_job__removed + //Drop i_async__removed, i_async_job__removed (if exists) and add i_async_job__removed keys = new ArrayList(); keys.add("i_async__removed"); keys.add("i_async_job__removed"); @@ -177,21 +177,21 @@ public class Upgrade2213to2214 implements DbUpgrade { } catch (SQLException e) { throw new CloudRuntimeException("Unable to insert index for removed column in async_job", e); } - + keys = new ArrayList(); keys.add("fk_ssh_keypair__account_id"); keys.add("fk_ssh_keypair__domain_id"); keys.add("fk_ssh_keypairs__account_id"); keys.add("fk_ssh_keypairs__domain_id"); DbUpgradeUtils.dropKeysIfExist(conn, "ssh_keypairs", keys, true); - + keys = new ArrayList(); keys.add("fk_ssh_keypair__account_id"); keys.add("fk_ssh_keypair__domain_id"); keys.add("fk_ssh_keypairs__account_id"); keys.add("fk_ssh_keypairs__domain_id"); DbUpgradeUtils.dropKeysIfExist(conn, "ssh_keypairs", keys, false); - + try { PreparedStatement pstmt; pstmt = conn.prepareStatement("ALTER TABLE `cloud`.`ssh_keypairs` ADD CONSTRAINT `fk_ssh_keypairs__account_id` FOREIGN KEY `fk_ssh_keypairs__account_id` (`account_id`) REFERENCES `account` (`id`) ON DELETE CASCADE"); pstmt.executeUpdate(); @@ -199,7 +199,7 @@ public class Upgrade2213to2214 implements DbUpgrade { } catch (SQLException e) { throw new CloudRuntimeException("Unable to execute ssh_keypairs table update for adding account_id foreign key", e); } - + try { PreparedStatement pstmt; pstmt = conn.prepareStatement("ALTER TABLE `cloud`.`ssh_keypairs` ADD CONSTRAINT `fk_ssh_keypairs__domain_id` FOREIGN KEY `fk_ssh_keypairs__domain_id` (`domain_id`) REFERENCES `domain` (`id`) ON DELETE CASCADE"); pstmt.executeUpdate(); @@ -208,7 +208,7 @@ public class Upgrade2213to2214 implements DbUpgrade { throw new CloudRuntimeException("Unable to execute ssh_keypairs table update for adding domain_id foreign key", e); } - //Drop i_async__removed, i_async_job__removed (if exists) and add i_async_job__removed + //Drop i_async__removed, i_async_job__removed (if exists) and add i_async_job__removed keys = new ArrayList(); keys.add("i_async__removed"); keys.add("i_async_job__removed"); @@ -220,7 +220,7 @@ public class Upgrade2213to2214 implements DbUpgrade { } catch (SQLException e) { throw new CloudRuntimeException("Unable to insert index for removed column in async_job", e); } - + //Drop storage pool details keys (if exists) and insert one with correct name keys = new ArrayList(); keys.add("fk_storage_pool__pool_id"); @@ -234,7 +234,7 @@ public class Upgrade2213to2214 implements DbUpgrade { } catch (SQLException e) { throw new CloudRuntimeException("Unable to insert foreign key in storage_pool_details ", e); } - + //Drop securityGroup keys (if exists) and insert one with correct name keys = new ArrayList(); keys.add("fk_security_group___account_id"); @@ -248,21 +248,21 @@ public class Upgrade2213to2214 implements DbUpgrade { } catch (SQLException e) { throw new CloudRuntimeException("Unable to insert foreign key in security_group table ", e); } - + //Drop vmInstance keys (if exists) and insert one with correct name keys = new ArrayList(); keys.add("i_vm_instance__host_id"); keys.add("fk_vm_instance__host_id"); - + keys.add("fk_vm_instance__last_host_id"); keys.add("i_vm_instance__last_host_id"); - + keys.add("fk_vm_instance__service_offering_id"); keys.add("i_vm_instance__service_offering_id"); - + keys.add("fk_vm_instance__account_id"); keys.add("i_vm_instance__account_id"); - + DbUpgradeUtils.dropKeysIfExist(conn, "cloud.vm_instance", keys, true); DbUpgradeUtils.dropKeysIfExist(conn, "cloud.vm_instance", keys, false); try { @@ -278,18 +278,18 @@ public class Upgrade2213to2214 implements DbUpgrade { } catch (SQLException e) { throw new CloudRuntimeException("Unable to insert foreign key in vm_instance table ", e); } - + //Drop user_ip_address keys (if exists) and insert one with correct name keys = new ArrayList(); keys.add("fk_user_ip_address__account_id"); keys.add("i_user_ip_address__account_id"); - + keys.add("fk_user_ip_address__vlan_db_id"); keys.add("i_user_ip_address__vlan_db_id"); - + keys.add("fk_user_ip_address__data_center_id"); keys.add("i_user_ip_address__data_center_id"); - + DbUpgradeUtils.dropKeysIfExist(conn, "cloud.user_ip_address", keys, true); DbUpgradeUtils.dropKeysIfExist(conn, "cloud.user_ip_address", keys, false); try { diff --git a/server/src/com/cloud/upgrade/dao/Upgrade2214to30.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade2214to30.java old mode 100755 new mode 100644 similarity index 97% rename from server/src/com/cloud/upgrade/dao/Upgrade2214to30.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade2214to30.java index c0f827e655e..2d77429367a --- a/server/src/com/cloud/upgrade/dao/Upgrade2214to30.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade2214to30.java @@ -629,8 +629,8 @@ public class Upgrade2214to30 extends Upgrade30xBase implements DbUpgrade { s_logger.debug("Updating XenSever System Vms"); //XenServer try { - //Get 3.0.0 xenserer system Vm template Id - pstmt = conn.prepareStatement("select id from `cloud`.`vm_template` where name = 'systemvm-xenserver-3.0.0' and removed is null"); + //Get 3.0.0 or later xenserer system Vm template Id + pstmt = conn.prepareStatement("select max(id) from `cloud`.`vm_template` where name like 'systemvm-xenserver-%' and removed is null"); rs = pstmt.executeQuery(); if(rs.next()){ long templateId = rs.getLong(1); @@ -648,9 +648,9 @@ public class Upgrade2214to30 extends Upgrade30xBase implements DbUpgrade { pstmt.close(); } else { if (xenserver){ - throw new CloudRuntimeException("3.0.0 XenServer SystemVm template not found. Cannot upgrade system Vms"); + throw new CloudRuntimeException("3.0.0 or later XenServer SystemVm template not found. Cannot upgrade system Vms"); } else { - s_logger.warn("3.0.0 XenServer SystemVm template not found. XenServer hypervisor is not used, so not failing upgrade"); + s_logger.warn("3.0.0 or later XenServer SystemVm template not found. XenServer hypervisor is not used, so not failing upgrade"); } } } catch (SQLException e) { @@ -660,8 +660,8 @@ public class Upgrade2214to30 extends Upgrade30xBase implements DbUpgrade { //KVM s_logger.debug("Updating KVM System Vms"); try { - //Get 3.0.0 KVM system Vm template Id - pstmt = conn.prepareStatement("select id from `cloud`.`vm_template` where name = 'systemvm-kvm-3.0.0' and removed is null"); + //Get 3.0.0 or later KVM system Vm template Id + pstmt = conn.prepareStatement("select max(id) from `cloud`.`vm_template` where name like 'systemvm-kvm-%' and removed is null"); rs = pstmt.executeQuery(); if(rs.next()){ long templateId = rs.getLong(1); @@ -679,9 +679,9 @@ public class Upgrade2214to30 extends Upgrade30xBase implements DbUpgrade { pstmt.close(); } else { if (kvm){ - throw new CloudRuntimeException("3.0.0 KVM SystemVm template not found. Cannot upgrade system Vms"); + throw new CloudRuntimeException("3.0.0 or later KVM SystemVm template not found. Cannot upgrade system Vms"); } else { - s_logger.warn("3.0.0 KVM SystemVm template not found. KVM hypervisor is not used, so not failing upgrade"); + s_logger.warn("3.0.0 or later KVM SystemVm template not found. KVM hypervisor is not used, so not failing upgrade"); } } } catch (SQLException e) { @@ -691,8 +691,8 @@ public class Upgrade2214to30 extends Upgrade30xBase implements DbUpgrade { //VMware s_logger.debug("Updating VMware System Vms"); try { - //Get 3.0.0 VMware system Vm template Id - pstmt = conn.prepareStatement("select id from `cloud`.`vm_template` where name = 'systemvm-vmware-3.0.0' and removed is null"); + //Get 3.0.0 or later VMware system Vm template Id + pstmt = conn.prepareStatement("select max(id) from `cloud`.`vm_template` where name like 'systemvm-vmware-%' and removed is null"); rs = pstmt.executeQuery(); if(rs.next()){ long templateId = rs.getLong(1); @@ -710,9 +710,9 @@ public class Upgrade2214to30 extends Upgrade30xBase implements DbUpgrade { pstmt.close(); } else { if (VMware){ - throw new CloudRuntimeException("3.0.0 VMware SystemVm template not found. Cannot upgrade system Vms"); + throw new CloudRuntimeException("3.0.0 or later VMware SystemVm template not found. Cannot upgrade system Vms"); } else { - s_logger.warn("3.0.0 VMware SystemVm template not found. VMware hypervisor is not used, so not failing upgrade"); + s_logger.warn("3.0.0 or later VMware SystemVm template not found. VMware hypervisor is not used, so not failing upgrade"); } } } catch (SQLException e) { diff --git a/server/src/com/cloud/upgrade/dao/Upgrade221to222.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade221to222.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade221to222.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade221to222.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade221to222Premium.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade221to222Premium.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade221to222Premium.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade221to222Premium.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade222to224.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade222to224.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade222to224.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade222to224.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade222to224Premium.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade222to224Premium.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade222to224Premium.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade222to224Premium.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade224to225.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade224to225.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade224to225.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade224to225.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade225to226.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade225to226.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade225to226.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade225to226.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade227to228.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade227to228.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade227to228.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade227to228.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade227to228Premium.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade227to228Premium.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade227to228Premium.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade227to228Premium.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade228to229.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade228to229.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade228to229.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade228to229.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade229to2210.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade229to2210.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade229to2210.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade229to2210.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade301to302.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade301to302.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade301to302.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade301to302.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade302to40.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade302to40.java similarity index 95% rename from server/src/com/cloud/upgrade/dao/Upgrade302to40.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade302to40.java index 753f64ec682..ecda872dfa4 100644 --- a/server/src/com/cloud/upgrade/dao/Upgrade302to40.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade302to40.java @@ -63,6 +63,7 @@ public class Upgrade302to40 extends Upgrade30xBase implements DbUpgrade { @Override public void performDataMigration(Connection conn) { + updateVmWareSystemVms(conn); correctVRProviders(conn); correctMultiplePhysicaNetworkSetups(conn); addHostDetailsUniqueKey(conn); @@ -82,7 +83,55 @@ public class Upgrade302to40 extends Upgrade30xBase implements DbUpgrade { return new File[] { new File(script) }; } - + + private void updateVmWareSystemVms(Connection conn){ + PreparedStatement pstmt = null; + ResultSet rs = null; + boolean VMware = false; + try { + pstmt = conn.prepareStatement("select distinct(hypervisor_type) from `cloud`.`cluster` where removed is null"); + rs = pstmt.executeQuery(); + while(rs.next()){ + if("VMware".equals(rs.getString(1))){ + VMware = true; + } + } + } catch (SQLException e) { + throw new CloudRuntimeException("Error while iterating through list of hypervisors in use", e); + } + // Just update the VMware system template. Other hypervisor templates are unchanged from previous 3.0.x versions. + s_logger.debug("Updating VMware System Vms"); + try { + //Get 4.0 VMware system Vm template Id + pstmt = conn.prepareStatement("select id from `cloud`.`vm_template` where name = 'systemvm-vmware-4.0' and removed is null"); + rs = pstmt.executeQuery(); + if(rs.next()){ + long templateId = rs.getLong(1); + rs.close(); + pstmt.close(); + // change template type to SYSTEM + pstmt = conn.prepareStatement("update `cloud`.`vm_template` set type='SYSTEM' where id = ?"); + pstmt.setLong(1, templateId); + pstmt.executeUpdate(); + pstmt.close(); + // update templete ID of system Vms + pstmt = conn.prepareStatement("update `cloud`.`vm_instance` set vm_template_id = ? where type <> 'User' and hypervisor_type = 'VMware'"); + pstmt.setLong(1, templateId); + pstmt.executeUpdate(); + pstmt.close(); + } else { + if (VMware){ + throw new CloudRuntimeException("4.0 VMware SystemVm template not found. Cannot upgrade system Vms"); + } else { + s_logger.warn("4.0 VMware SystemVm template not found. VMware hypervisor is not used, so not failing upgrade"); + } + } + } catch (SQLException e) { + throw new CloudRuntimeException("Error while updating VMware systemVm template", e); + } + s_logger.debug("Updating System Vm Template IDs Complete"); + } + private void correctVRProviders(Connection conn) { PreparedStatement pstmtVR = null; ResultSet rsVR = null; diff --git a/server/src/com/cloud/upgrade/dao/Upgrade30to301.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade30to301.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade30to301.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade30to301.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade30xBase.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade30xBase.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade30xBase.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade30xBase.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade40to41.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade40to41.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/Upgrade40to41.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade40to41.java diff --git a/server/src/com/cloud/upgrade/dao/Upgrade410to420.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java similarity index 81% rename from server/src/com/cloud/upgrade/dao/Upgrade410to420.java rename to engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java index 05e2b49ffe4..3a164c413bb 100644 --- a/server/src/com/cloud/upgrade/dao/Upgrade410to420.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java @@ -17,10 +17,6 @@ package com.cloud.upgrade.dao; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.script.Script; -import org.apache.log4j.Logger; - import java.io.File; import java.sql.Connection; import java.sql.PreparedStatement; @@ -28,6 +24,11 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.UUID; +import org.apache.log4j.Logger; + +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.script.Script; + public class Upgrade410to420 implements DbUpgrade { final static Logger s_logger = Logger.getLogger(Upgrade410to420.class); @@ -66,6 +67,8 @@ public class Upgrade410to420 implements DbUpgrade { updatePrimaryStore(conn); addEgressFwRulesForSRXGuestNw(conn); upgradeEIPNetworkOfferings(conn); + upgradeDefaultVpcOffering(conn); + upgradePhysicalNtwksWithInternalLbProvider(conn); } private void updateSystemVmTemplates(Connection conn) { @@ -399,4 +402,88 @@ public class Upgrade410to420 implements DbUpgrade { } } } + + + private void upgradeDefaultVpcOffering(Connection conn) { + + PreparedStatement pstmt = null; + ResultSet rs = null; + + try { + pstmt = conn.prepareStatement("select distinct map.vpc_offering_id from `cloud`.`vpc_offering_service_map` map, `cloud`.`vpc_offerings` off where off.id=map.vpc_offering_id AND service='Lb'"); + rs = pstmt.executeQuery(); + while (rs.next()) { + long id = rs.getLong(1); + //Add internal LB vm as a supported provider for the load balancer service + pstmt = conn.prepareStatement("INSERT INTO `cloud`.`vpc_offering_service_map` (vpc_offering_id, service, provider) VALUES (?,?,?)"); + pstmt.setLong(1, id); + pstmt.setString(2, "Lb"); + pstmt.setString(3, "InternalLbVm"); + pstmt.executeUpdate(); + } + + } catch (SQLException e) { + throw new CloudRuntimeException("Unable update the default VPC offering with the internal lb service", e); + } finally { + try { + if (rs != null) { + rs.close(); + } + if (pstmt != null) { + pstmt.close(); + } + } catch (SQLException e) { + } + } + } + + + private void upgradePhysicalNtwksWithInternalLbProvider(Connection conn) { + + PreparedStatement pstmt = null; + ResultSet rs = null; + + try { + pstmt = conn.prepareStatement("SELECT id FROM `cloud`.`physical_network` where removed is null"); + rs = pstmt.executeQuery(); + while (rs.next()) { + long pNtwkId = rs.getLong(1); + String uuid = UUID.randomUUID().toString(); + //Add internal LB VM to the list of physical network service providers + pstmt = conn.prepareStatement("INSERT INTO `cloud`.`physical_network_service_providers` " + + "(uuid, physical_network_id, provider_name, state, load_balance_service_provided, destination_physical_network_id)" + + " VALUES (?, ?, 'InternalLbVm', 'Enabled', 1, 0)"); + pstmt.setString(1, uuid); + pstmt.setLong(2, pNtwkId); + pstmt.executeUpdate(); + + //Add internal lb vm to the list of physical network elements + PreparedStatement pstmt1 = conn.prepareStatement("SELECT id FROM `cloud`.`physical_network_service_providers`" + + " WHERE physical_network_id=? AND provider_name='InternalLbVm'"); + ResultSet rs1 = pstmt1.executeQuery(); + while (rs1.next()) { + long providerId = rs1.getLong(1); + uuid = UUID.randomUUID().toString(); + pstmt1 = conn.prepareStatement("INSERT INTO `cloud`.`virtual_router_providers` (nsp_id, uuid, type, enabled) VALUES (?, ?, 'InternalLbVm', 1)"); + pstmt1.setLong(1, providerId); + pstmt1.setString(2, uuid); + pstmt1.executeUpdate(); + } + } + + } catch (SQLException e) { + throw new CloudRuntimeException("Unable existing physical networks with internal lb provider", e); + } finally { + try { + if (rs != null) { + rs.close(); + } + if (pstmt != null) { + pstmt.close(); + } + } catch (SQLException e) { + } + } + + } } diff --git a/server/src/com/cloud/upgrade/dao/UpgradeSnapshot217to224.java b/engine/schema/src/com/cloud/upgrade/dao/UpgradeSnapshot217to224.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/UpgradeSnapshot217to224.java rename to engine/schema/src/com/cloud/upgrade/dao/UpgradeSnapshot217to224.java diff --git a/server/src/com/cloud/upgrade/dao/UpgradeSnapshot223to224.java b/engine/schema/src/com/cloud/upgrade/dao/UpgradeSnapshot223to224.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/UpgradeSnapshot223to224.java rename to engine/schema/src/com/cloud/upgrade/dao/UpgradeSnapshot223to224.java diff --git a/server/src/com/cloud/upgrade/dao/VersionDao.java b/engine/schema/src/com/cloud/upgrade/dao/VersionDao.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/VersionDao.java rename to engine/schema/src/com/cloud/upgrade/dao/VersionDao.java diff --git a/server/src/com/cloud/upgrade/dao/VersionDaoImpl.java b/engine/schema/src/com/cloud/upgrade/dao/VersionDaoImpl.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/VersionDaoImpl.java rename to engine/schema/src/com/cloud/upgrade/dao/VersionDaoImpl.java diff --git a/server/src/com/cloud/upgrade/dao/VersionVO.java b/engine/schema/src/com/cloud/upgrade/dao/VersionVO.java similarity index 100% rename from server/src/com/cloud/upgrade/dao/VersionVO.java rename to engine/schema/src/com/cloud/upgrade/dao/VersionVO.java diff --git a/server/src/com/cloud/usage/ExternalPublicIpStatisticsVO.java b/engine/schema/src/com/cloud/usage/ExternalPublicIpStatisticsVO.java similarity index 100% rename from server/src/com/cloud/usage/ExternalPublicIpStatisticsVO.java rename to engine/schema/src/com/cloud/usage/ExternalPublicIpStatisticsVO.java diff --git a/server/src/com/cloud/usage/UsageIPAddressVO.java b/engine/schema/src/com/cloud/usage/UsageIPAddressVO.java similarity index 100% rename from server/src/com/cloud/usage/UsageIPAddressVO.java rename to engine/schema/src/com/cloud/usage/UsageIPAddressVO.java diff --git a/server/src/com/cloud/usage/UsageJobVO.java b/engine/schema/src/com/cloud/usage/UsageJobVO.java similarity index 100% rename from server/src/com/cloud/usage/UsageJobVO.java rename to engine/schema/src/com/cloud/usage/UsageJobVO.java diff --git a/server/src/com/cloud/usage/UsageLoadBalancerPolicyVO.java b/engine/schema/src/com/cloud/usage/UsageLoadBalancerPolicyVO.java similarity index 100% rename from server/src/com/cloud/usage/UsageLoadBalancerPolicyVO.java rename to engine/schema/src/com/cloud/usage/UsageLoadBalancerPolicyVO.java diff --git a/server/src/com/cloud/usage/UsageNetworkOfferingVO.java b/engine/schema/src/com/cloud/usage/UsageNetworkOfferingVO.java similarity index 100% rename from server/src/com/cloud/usage/UsageNetworkOfferingVO.java rename to engine/schema/src/com/cloud/usage/UsageNetworkOfferingVO.java diff --git a/server/src/com/cloud/usage/UsageNetworkVO.java b/engine/schema/src/com/cloud/usage/UsageNetworkVO.java similarity index 100% rename from server/src/com/cloud/usage/UsageNetworkVO.java rename to engine/schema/src/com/cloud/usage/UsageNetworkVO.java diff --git a/server/src/com/cloud/usage/UsagePortForwardingRuleVO.java b/engine/schema/src/com/cloud/usage/UsagePortForwardingRuleVO.java similarity index 100% rename from server/src/com/cloud/usage/UsagePortForwardingRuleVO.java rename to engine/schema/src/com/cloud/usage/UsagePortForwardingRuleVO.java diff --git a/server/src/com/cloud/usage/UsageSecurityGroupVO.java b/engine/schema/src/com/cloud/usage/UsageSecurityGroupVO.java similarity index 100% rename from server/src/com/cloud/usage/UsageSecurityGroupVO.java rename to engine/schema/src/com/cloud/usage/UsageSecurityGroupVO.java diff --git a/server/src/com/cloud/usage/UsageStorageVO.java b/engine/schema/src/com/cloud/usage/UsageStorageVO.java similarity index 100% rename from server/src/com/cloud/usage/UsageStorageVO.java rename to engine/schema/src/com/cloud/usage/UsageStorageVO.java diff --git a/server/src/com/cloud/usage/UsageVMInstanceVO.java b/engine/schema/src/com/cloud/usage/UsageVMInstanceVO.java similarity index 100% rename from server/src/com/cloud/usage/UsageVMInstanceVO.java rename to engine/schema/src/com/cloud/usage/UsageVMInstanceVO.java diff --git a/server/src/com/cloud/usage/UsageVO.java b/engine/schema/src/com/cloud/usage/UsageVO.java similarity index 100% rename from server/src/com/cloud/usage/UsageVO.java rename to engine/schema/src/com/cloud/usage/UsageVO.java diff --git a/server/src/com/cloud/usage/UsageVPNUserVO.java b/engine/schema/src/com/cloud/usage/UsageVPNUserVO.java similarity index 100% rename from server/src/com/cloud/usage/UsageVPNUserVO.java rename to engine/schema/src/com/cloud/usage/UsageVPNUserVO.java diff --git a/server/src/com/cloud/usage/UsageVolumeVO.java b/engine/schema/src/com/cloud/usage/UsageVolumeVO.java similarity index 100% rename from server/src/com/cloud/usage/UsageVolumeVO.java rename to engine/schema/src/com/cloud/usage/UsageVolumeVO.java diff --git a/server/src/com/cloud/usage/dao/ExternalPublicIpStatisticsDao.java b/engine/schema/src/com/cloud/usage/dao/ExternalPublicIpStatisticsDao.java similarity index 100% rename from server/src/com/cloud/usage/dao/ExternalPublicIpStatisticsDao.java rename to engine/schema/src/com/cloud/usage/dao/ExternalPublicIpStatisticsDao.java diff --git a/server/src/com/cloud/usage/dao/ExternalPublicIpStatisticsDaoImpl.java b/engine/schema/src/com/cloud/usage/dao/ExternalPublicIpStatisticsDaoImpl.java similarity index 100% rename from server/src/com/cloud/usage/dao/ExternalPublicIpStatisticsDaoImpl.java rename to engine/schema/src/com/cloud/usage/dao/ExternalPublicIpStatisticsDaoImpl.java diff --git a/server/src/com/cloud/usage/dao/UsageDao.java b/engine/schema/src/com/cloud/usage/dao/UsageDao.java similarity index 70% rename from server/src/com/cloud/usage/dao/UsageDao.java rename to engine/schema/src/com/cloud/usage/dao/UsageDao.java index a25b0dc78ef..6d0c162b52b 100644 --- a/server/src/com/cloud/usage/dao/UsageDao.java +++ b/engine/schema/src/com/cloud/usage/dao/UsageDao.java @@ -16,11 +16,8 @@ // under the License. package com.cloud.usage.dao; -import java.util.Date; import java.util.List; -import com.cloud.event.UsageEventVO; -import com.cloud.exception.UsageServerException; import com.cloud.usage.UsageVO; import com.cloud.user.AccountVO; import com.cloud.user.UserStatisticsVO; @@ -31,11 +28,12 @@ import com.cloud.utils.db.SearchCriteria; public interface UsageDao extends GenericDao { void deleteRecordsForAccount(Long accountId); List searchAllRecords(SearchCriteria sc, Filter filter); - void saveAccounts(List accounts) throws UsageServerException; - void updateAccounts(List accounts) throws UsageServerException; - void saveUserStats(List userStats) throws UsageServerException; - void updateUserStats(List userStats) throws UsageServerException; - Long getLastAccountId() throws UsageServerException; - Long getLastUserStatsId() throws UsageServerException; + + void saveAccounts(List accounts); + void updateAccounts(List accounts); + void saveUserStats(List userStats); + void updateUserStats(List userStats); + Long getLastAccountId(); + Long getLastUserStatsId(); List listPublicTemplatesByAccount(long accountId); } diff --git a/server/src/com/cloud/usage/dao/UsageDaoImpl.java b/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java similarity index 94% rename from server/src/com/cloud/usage/dao/UsageDaoImpl.java rename to engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java index f9ae70c1f20..a5867f0656e 100644 --- a/server/src/com/cloud/usage/dao/UsageDaoImpl.java +++ b/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java @@ -29,7 +29,6 @@ import javax.ejb.Local; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import com.cloud.exception.UsageServerException; import com.cloud.usage.UsageVO; import com.cloud.user.AccountVO; import com.cloud.user.UserStatisticsVO; @@ -38,6 +37,7 @@ import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; @Component @Local(value={UsageDao.class}) @@ -60,7 +60,8 @@ public class UsageDaoImpl extends GenericDaoBase implements Usage public UsageDaoImpl () {} - public void deleteRecordsForAccount(Long accountId) { + @Override + public void deleteRecordsForAccount(Long accountId) { String sql = ((accountId == null) ? DELETE_ALL : DELETE_ALL_BY_ACCOUNTID); Transaction txn = Transaction.open(Transaction.USAGE_DB); PreparedStatement pstmt = null; @@ -86,7 +87,7 @@ public class UsageDaoImpl extends GenericDaoBase implements Usage } @Override - public void saveAccounts(List accounts) throws UsageServerException { + public void saveAccounts(List accounts) { Transaction txn = Transaction.currentTxn(); try { txn.start(); @@ -115,12 +116,12 @@ public class UsageDaoImpl extends GenericDaoBase implements Usage } catch (Exception ex) { txn.rollback(); s_logger.error("error saving account to cloud_usage db", ex); - throw new UsageServerException(ex.getMessage()); + throw new CloudRuntimeException(ex.getMessage()); } } @Override - public void updateAccounts(List accounts) throws UsageServerException { + public void updateAccounts(List accounts) { Transaction txn = Transaction.currentTxn(); try { txn.start(); @@ -145,12 +146,12 @@ public class UsageDaoImpl extends GenericDaoBase implements Usage } catch (Exception ex) { txn.rollback(); s_logger.error("error saving account to cloud_usage db", ex); - throw new UsageServerException(ex.getMessage()); + throw new CloudRuntimeException(ex.getMessage()); } } @Override - public void saveUserStats(List userStats) throws UsageServerException { + public void saveUserStats(List userStats) { Transaction txn = Transaction.currentTxn(); try { txn.start(); @@ -186,12 +187,12 @@ public class UsageDaoImpl extends GenericDaoBase implements Usage } catch (Exception ex) { txn.rollback(); s_logger.error("error saving user stats to cloud_usage db", ex); - throw new UsageServerException(ex.getMessage()); + throw new CloudRuntimeException(ex.getMessage()); } } @Override - public void updateUserStats(List userStats) throws UsageServerException { + public void updateUserStats(List userStats) { Transaction txn = Transaction.currentTxn(); try { txn.start(); @@ -213,7 +214,7 @@ public class UsageDaoImpl extends GenericDaoBase implements Usage } catch (Exception ex) { txn.rollback(); s_logger.error("error saving user stats to cloud_usage db", ex); - throw new UsageServerException(ex.getMessage()); + throw new CloudRuntimeException(ex.getMessage()); } } @@ -250,7 +251,7 @@ public class UsageDaoImpl extends GenericDaoBase implements Usage } return null; } - + @Override public List listPublicTemplatesByAccount(long accountId) { Transaction txn = Transaction.currentTxn(); diff --git a/server/src/com/cloud/usage/dao/UsageIPAddressDao.java b/engine/schema/src/com/cloud/usage/dao/UsageIPAddressDao.java similarity index 100% rename from server/src/com/cloud/usage/dao/UsageIPAddressDao.java rename to engine/schema/src/com/cloud/usage/dao/UsageIPAddressDao.java diff --git a/server/src/com/cloud/usage/dao/UsageIPAddressDaoImpl.java b/engine/schema/src/com/cloud/usage/dao/UsageIPAddressDaoImpl.java similarity index 100% rename from server/src/com/cloud/usage/dao/UsageIPAddressDaoImpl.java rename to engine/schema/src/com/cloud/usage/dao/UsageIPAddressDaoImpl.java diff --git a/server/src/com/cloud/usage/dao/UsageJobDao.java b/engine/schema/src/com/cloud/usage/dao/UsageJobDao.java similarity index 92% rename from server/src/com/cloud/usage/dao/UsageJobDao.java rename to engine/schema/src/com/cloud/usage/dao/UsageJobDao.java index 6921046610b..9ec391804f2 100644 --- a/server/src/com/cloud/usage/dao/UsageJobDao.java +++ b/engine/schema/src/com/cloud/usage/dao/UsageJobDao.java @@ -18,7 +18,6 @@ package com.cloud.usage.dao; import java.util.Date; -import com.cloud.exception.UsageServerException; import com.cloud.usage.UsageJobVO; import com.cloud.utils.db.GenericDao; @@ -30,5 +29,6 @@ public interface UsageJobDao extends GenericDao { long getLastJobSuccessDateMillis(); Date getLastHeartbeat(); UsageJobVO isOwner(String hostname, int pid); - void updateJobSuccess(Long jobId, long startMillis, long endMillis, long execTime, boolean success) throws UsageServerException; + + void updateJobSuccess(Long jobId, long startMillis, long endMillis, long execTime, boolean success); } diff --git a/server/src/com/cloud/usage/dao/UsageJobDaoImpl.java b/engine/schema/src/com/cloud/usage/dao/UsageJobDaoImpl.java similarity index 97% rename from server/src/com/cloud/usage/dao/UsageJobDaoImpl.java rename to engine/schema/src/com/cloud/usage/dao/UsageJobDaoImpl.java index 3c7a3dc110d..783300faeed 100644 --- a/server/src/com/cloud/usage/dao/UsageJobDaoImpl.java +++ b/engine/schema/src/com/cloud/usage/dao/UsageJobDaoImpl.java @@ -26,12 +26,12 @@ import javax.ejb.Local; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import com.cloud.exception.UsageServerException; import com.cloud.usage.UsageJobVO; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; @Component @Local(value={UsageJobDao.class}) @@ -60,7 +60,7 @@ public class UsageJobDaoImpl extends GenericDaoBase implements } @Override - public void updateJobSuccess(Long jobId, long startMillis, long endMillis, long execTime, boolean success) throws UsageServerException { + public void updateJobSuccess(Long jobId, long startMillis, long endMillis, long execTime, boolean success) { Transaction txn = Transaction.open(Transaction.USAGE_DB); try { txn.start(); @@ -79,7 +79,7 @@ public class UsageJobDaoImpl extends GenericDaoBase implements } catch (Exception ex) { txn.rollback(); s_logger.error("error updating job success date", ex); - throw new UsageServerException(ex.getMessage()); + throw new CloudRuntimeException(ex.getMessage()); } finally { txn.close(); } diff --git a/server/src/com/cloud/usage/dao/UsageLoadBalancerPolicyDao.java b/engine/schema/src/com/cloud/usage/dao/UsageLoadBalancerPolicyDao.java similarity index 100% rename from server/src/com/cloud/usage/dao/UsageLoadBalancerPolicyDao.java rename to engine/schema/src/com/cloud/usage/dao/UsageLoadBalancerPolicyDao.java diff --git a/server/src/com/cloud/usage/dao/UsageLoadBalancerPolicyDaoImpl.java b/engine/schema/src/com/cloud/usage/dao/UsageLoadBalancerPolicyDaoImpl.java similarity index 100% rename from server/src/com/cloud/usage/dao/UsageLoadBalancerPolicyDaoImpl.java rename to engine/schema/src/com/cloud/usage/dao/UsageLoadBalancerPolicyDaoImpl.java diff --git a/server/src/com/cloud/usage/dao/UsageNetworkDao.java b/engine/schema/src/com/cloud/usage/dao/UsageNetworkDao.java similarity index 100% rename from server/src/com/cloud/usage/dao/UsageNetworkDao.java rename to engine/schema/src/com/cloud/usage/dao/UsageNetworkDao.java diff --git a/server/src/com/cloud/usage/dao/UsageNetworkDaoImpl.java b/engine/schema/src/com/cloud/usage/dao/UsageNetworkDaoImpl.java similarity index 100% rename from server/src/com/cloud/usage/dao/UsageNetworkDaoImpl.java rename to engine/schema/src/com/cloud/usage/dao/UsageNetworkDaoImpl.java diff --git a/server/src/com/cloud/usage/dao/UsageNetworkOfferingDao.java b/engine/schema/src/com/cloud/usage/dao/UsageNetworkOfferingDao.java similarity index 100% rename from server/src/com/cloud/usage/dao/UsageNetworkOfferingDao.java rename to engine/schema/src/com/cloud/usage/dao/UsageNetworkOfferingDao.java diff --git a/server/src/com/cloud/usage/dao/UsageNetworkOfferingDaoImpl.java b/engine/schema/src/com/cloud/usage/dao/UsageNetworkOfferingDaoImpl.java similarity index 100% rename from server/src/com/cloud/usage/dao/UsageNetworkOfferingDaoImpl.java rename to engine/schema/src/com/cloud/usage/dao/UsageNetworkOfferingDaoImpl.java diff --git a/server/src/com/cloud/usage/dao/UsagePortForwardingRuleDao.java b/engine/schema/src/com/cloud/usage/dao/UsagePortForwardingRuleDao.java similarity index 100% rename from server/src/com/cloud/usage/dao/UsagePortForwardingRuleDao.java rename to engine/schema/src/com/cloud/usage/dao/UsagePortForwardingRuleDao.java diff --git a/server/src/com/cloud/usage/dao/UsagePortForwardingRuleDaoImpl.java b/engine/schema/src/com/cloud/usage/dao/UsagePortForwardingRuleDaoImpl.java similarity index 100% rename from server/src/com/cloud/usage/dao/UsagePortForwardingRuleDaoImpl.java rename to engine/schema/src/com/cloud/usage/dao/UsagePortForwardingRuleDaoImpl.java diff --git a/server/src/com/cloud/usage/dao/UsageSecurityGroupDao.java b/engine/schema/src/com/cloud/usage/dao/UsageSecurityGroupDao.java similarity index 100% rename from server/src/com/cloud/usage/dao/UsageSecurityGroupDao.java rename to engine/schema/src/com/cloud/usage/dao/UsageSecurityGroupDao.java diff --git a/server/src/com/cloud/usage/dao/UsageSecurityGroupDaoImpl.java b/engine/schema/src/com/cloud/usage/dao/UsageSecurityGroupDaoImpl.java similarity index 100% rename from server/src/com/cloud/usage/dao/UsageSecurityGroupDaoImpl.java rename to engine/schema/src/com/cloud/usage/dao/UsageSecurityGroupDaoImpl.java diff --git a/server/src/com/cloud/usage/dao/UsageStorageDao.java b/engine/schema/src/com/cloud/usage/dao/UsageStorageDao.java similarity index 100% rename from server/src/com/cloud/usage/dao/UsageStorageDao.java rename to engine/schema/src/com/cloud/usage/dao/UsageStorageDao.java diff --git a/server/src/com/cloud/usage/dao/UsageStorageDaoImpl.java b/engine/schema/src/com/cloud/usage/dao/UsageStorageDaoImpl.java similarity index 100% rename from server/src/com/cloud/usage/dao/UsageStorageDaoImpl.java rename to engine/schema/src/com/cloud/usage/dao/UsageStorageDaoImpl.java diff --git a/server/src/com/cloud/usage/dao/UsageVMInstanceDao.java b/engine/schema/src/com/cloud/usage/dao/UsageVMInstanceDao.java similarity index 100% rename from server/src/com/cloud/usage/dao/UsageVMInstanceDao.java rename to engine/schema/src/com/cloud/usage/dao/UsageVMInstanceDao.java diff --git a/server/src/com/cloud/usage/dao/UsageVMInstanceDaoImpl.java b/engine/schema/src/com/cloud/usage/dao/UsageVMInstanceDaoImpl.java similarity index 100% rename from server/src/com/cloud/usage/dao/UsageVMInstanceDaoImpl.java rename to engine/schema/src/com/cloud/usage/dao/UsageVMInstanceDaoImpl.java diff --git a/server/src/com/cloud/usage/dao/UsageVPNUserDao.java b/engine/schema/src/com/cloud/usage/dao/UsageVPNUserDao.java similarity index 100% rename from server/src/com/cloud/usage/dao/UsageVPNUserDao.java rename to engine/schema/src/com/cloud/usage/dao/UsageVPNUserDao.java diff --git a/server/src/com/cloud/usage/dao/UsageVPNUserDaoImpl.java b/engine/schema/src/com/cloud/usage/dao/UsageVPNUserDaoImpl.java similarity index 100% rename from server/src/com/cloud/usage/dao/UsageVPNUserDaoImpl.java rename to engine/schema/src/com/cloud/usage/dao/UsageVPNUserDaoImpl.java diff --git a/server/src/com/cloud/usage/dao/UsageVolumeDao.java b/engine/schema/src/com/cloud/usage/dao/UsageVolumeDao.java similarity index 100% rename from server/src/com/cloud/usage/dao/UsageVolumeDao.java rename to engine/schema/src/com/cloud/usage/dao/UsageVolumeDao.java diff --git a/server/src/com/cloud/usage/dao/UsageVolumeDaoImpl.java b/engine/schema/src/com/cloud/usage/dao/UsageVolumeDaoImpl.java similarity index 100% rename from server/src/com/cloud/usage/dao/UsageVolumeDaoImpl.java rename to engine/schema/src/com/cloud/usage/dao/UsageVolumeDaoImpl.java diff --git a/server/src/com/cloud/user/AccountDetailVO.java b/engine/schema/src/com/cloud/user/AccountDetailVO.java similarity index 100% rename from server/src/com/cloud/user/AccountDetailVO.java rename to engine/schema/src/com/cloud/user/AccountDetailVO.java diff --git a/server/src/com/cloud/user/AccountDetailsDao.java b/engine/schema/src/com/cloud/user/AccountDetailsDao.java similarity index 100% rename from server/src/com/cloud/user/AccountDetailsDao.java rename to engine/schema/src/com/cloud/user/AccountDetailsDao.java diff --git a/server/src/com/cloud/user/AccountDetailsDaoImpl.java b/engine/schema/src/com/cloud/user/AccountDetailsDaoImpl.java similarity index 100% rename from server/src/com/cloud/user/AccountDetailsDaoImpl.java rename to engine/schema/src/com/cloud/user/AccountDetailsDaoImpl.java diff --git a/core/src/com/cloud/user/AccountVO.java b/engine/schema/src/com/cloud/user/AccountVO.java similarity index 100% rename from core/src/com/cloud/user/AccountVO.java rename to engine/schema/src/com/cloud/user/AccountVO.java diff --git a/core/src/com/cloud/user/SSHKeyPairVO.java b/engine/schema/src/com/cloud/user/SSHKeyPairVO.java similarity index 100% rename from core/src/com/cloud/user/SSHKeyPairVO.java rename to engine/schema/src/com/cloud/user/SSHKeyPairVO.java diff --git a/core/src/com/cloud/user/UserAccountVO.java b/engine/schema/src/com/cloud/user/UserAccountVO.java similarity index 100% rename from core/src/com/cloud/user/UserAccountVO.java rename to engine/schema/src/com/cloud/user/UserAccountVO.java diff --git a/core/src/com/cloud/user/UserStatisticsVO.java b/engine/schema/src/com/cloud/user/UserStatisticsVO.java similarity index 100% rename from core/src/com/cloud/user/UserStatisticsVO.java rename to engine/schema/src/com/cloud/user/UserStatisticsVO.java diff --git a/core/src/com/cloud/user/UserStatsLogVO.java b/engine/schema/src/com/cloud/user/UserStatsLogVO.java similarity index 100% rename from core/src/com/cloud/user/UserStatsLogVO.java rename to engine/schema/src/com/cloud/user/UserStatsLogVO.java diff --git a/core/src/com/cloud/user/UserVO.java b/engine/schema/src/com/cloud/user/UserVO.java similarity index 100% rename from core/src/com/cloud/user/UserVO.java rename to engine/schema/src/com/cloud/user/UserVO.java diff --git a/server/src/com/cloud/user/dao/AccountDao.java b/engine/schema/src/com/cloud/user/dao/AccountDao.java similarity index 100% rename from server/src/com/cloud/user/dao/AccountDao.java rename to engine/schema/src/com/cloud/user/dao/AccountDao.java diff --git a/server/src/com/cloud/user/dao/AccountDaoImpl.java b/engine/schema/src/com/cloud/user/dao/AccountDaoImpl.java similarity index 100% rename from server/src/com/cloud/user/dao/AccountDaoImpl.java rename to engine/schema/src/com/cloud/user/dao/AccountDaoImpl.java diff --git a/server/src/com/cloud/user/dao/SSHKeyPairDao.java b/engine/schema/src/com/cloud/user/dao/SSHKeyPairDao.java similarity index 100% rename from server/src/com/cloud/user/dao/SSHKeyPairDao.java rename to engine/schema/src/com/cloud/user/dao/SSHKeyPairDao.java diff --git a/server/src/com/cloud/user/dao/SSHKeyPairDaoImpl.java b/engine/schema/src/com/cloud/user/dao/SSHKeyPairDaoImpl.java similarity index 100% rename from server/src/com/cloud/user/dao/SSHKeyPairDaoImpl.java rename to engine/schema/src/com/cloud/user/dao/SSHKeyPairDaoImpl.java diff --git a/server/src/com/cloud/user/dao/UserAccountDao.java b/engine/schema/src/com/cloud/user/dao/UserAccountDao.java similarity index 100% rename from server/src/com/cloud/user/dao/UserAccountDao.java rename to engine/schema/src/com/cloud/user/dao/UserAccountDao.java diff --git a/server/src/com/cloud/user/dao/UserAccountDaoImpl.java b/engine/schema/src/com/cloud/user/dao/UserAccountDaoImpl.java similarity index 100% rename from server/src/com/cloud/user/dao/UserAccountDaoImpl.java rename to engine/schema/src/com/cloud/user/dao/UserAccountDaoImpl.java diff --git a/server/src/com/cloud/user/dao/UserDao.java b/engine/schema/src/com/cloud/user/dao/UserDao.java similarity index 100% rename from server/src/com/cloud/user/dao/UserDao.java rename to engine/schema/src/com/cloud/user/dao/UserDao.java diff --git a/server/src/com/cloud/user/dao/UserDaoImpl.java b/engine/schema/src/com/cloud/user/dao/UserDaoImpl.java similarity index 100% rename from server/src/com/cloud/user/dao/UserDaoImpl.java rename to engine/schema/src/com/cloud/user/dao/UserDaoImpl.java diff --git a/server/src/com/cloud/user/dao/UserStatisticsDao.java b/engine/schema/src/com/cloud/user/dao/UserStatisticsDao.java similarity index 100% rename from server/src/com/cloud/user/dao/UserStatisticsDao.java rename to engine/schema/src/com/cloud/user/dao/UserStatisticsDao.java diff --git a/server/src/com/cloud/user/dao/UserStatisticsDaoImpl.java b/engine/schema/src/com/cloud/user/dao/UserStatisticsDaoImpl.java similarity index 100% rename from server/src/com/cloud/user/dao/UserStatisticsDaoImpl.java rename to engine/schema/src/com/cloud/user/dao/UserStatisticsDaoImpl.java diff --git a/server/src/com/cloud/user/dao/UserStatsLogDao.java b/engine/schema/src/com/cloud/user/dao/UserStatsLogDao.java similarity index 100% rename from server/src/com/cloud/user/dao/UserStatsLogDao.java rename to engine/schema/src/com/cloud/user/dao/UserStatsLogDao.java diff --git a/server/src/com/cloud/user/dao/UserStatsLogDaoImpl.java b/engine/schema/src/com/cloud/user/dao/UserStatsLogDaoImpl.java similarity index 100% rename from server/src/com/cloud/user/dao/UserStatsLogDaoImpl.java rename to engine/schema/src/com/cloud/user/dao/UserStatsLogDaoImpl.java diff --git a/engine/schema/src/com/cloud/vm/ConsoleProxyVO.java b/engine/schema/src/com/cloud/vm/ConsoleProxyVO.java new file mode 100644 index 00000000000..5c1da4855cd --- /dev/null +++ b/engine/schema/src/com/cloud/vm/ConsoleProxyVO.java @@ -0,0 +1,287 @@ +// 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. +package com.cloud.vm; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import javax.persistence.PrimaryKeyJoinColumn; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.Transient; + +import com.cloud.hypervisor.Hypervisor.HypervisorType; + +/** + * ConsoleProxyVO domain object + */ + +@Entity +@Table(name = "console_proxy") +@PrimaryKeyJoinColumn(name = "id") +@DiscriminatorValue(value = "ConsoleProxy") +public class ConsoleProxyVO extends VMInstanceVO implements ConsoleProxy { + public static final String keyContent = + "-----BEGIN PRIVATE KEY-----\n" + + "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCDT9AtEfs+s/I8QXp6rrCw0iNJ\n" + + "0+GgsybNHheU+JpL39LMTZykCrZhZnyDvwdxCoOfE38Sa32baHKNds+y2SHnMNsOkw8OcNucHEBX\n" + + "1FIpOBGph9D6xC+umx9od6xMWETUv7j6h2u+WC3OhBM8fHCBqIiAol31/IkcqDxxsHlQ8S/oCfTl\n" + + "XJUY6Yn628OA1XijKdRnadV0hZ829cv/PZKljjwQUTyrd0KHQeksBH+YAYSo2JUl8ekNLsOi8/cP\n" + + "tfojnltzRI1GXi0ZONs8VnDzJ0a2gqZY+uxlz+CGbLnGnlN4j9cBpE+MfUE+35Dq121sTpsSgF85\n" + + "Mz+pVhn2S633AgMBAAECggEAH/Szd9RxbVADenCA6wxKSa3KErRyq1YN8ksJeCKMAj0FIt0caruE\n" + + "qO11DebWW8cwQu1Otl/cYI6pmg24/BBldMrp9IELX/tNJo+lhPpRyGAxxC0eSXinFfoASb8d+jJd\n" + + "Bd1mmemM6fSxqRlxSP4LrzIhjhR1g2CiyYuTsiM9UtoVKGyHwe7KfFwirUOJo3Mr18zUVNm7YqY4\n" + + "IVhOSq59zkH3ULBlYq4bG50jpxa5mNSCZ7IpafPY/kE/CbR+FWNt30+rk69T+qb5abg6+XGm+OAm\n" + + "bnQ18yZEqX6nJLk7Ch0cfA5orGgrTMOrM71wK7tBBDQ308kOxDGebx6j0qD36QKBgQDTRDr8kuhA\n" + + "9sUyKr9vk2DQCMpNvEeiwI3JRMqmmxpNAtg01aJ3Ya57vX5Fc+zcuV87kP6FM1xgpHQvnw5LWo2J\n" + + "s7ANwQcP8ricEW5zkZhSjI4ssMeAubmsHOloGxmLFYZqwx0JI7CWViGTLMcUlqKblmHcjeQDeDfP\n" + + "P1TaCItFmwKBgQCfHZwVvIcaDs5vxVpZ4ftvflIrW8qq0uOVK6QIf9A/YTGhCXl2qxxTg2A6+0rg\n" + + "ZqI7zKzUDxIbVv0KlgCbpHDC9d5+sdtDB3wW2pimuJ3p1z4/RHb4n/lDwXCACZl1S5l24yXX2pFZ\n" + + "wdPCXmy5PYkHMssFLNhI24pprUIQs66M1QKBgQDQwjAjWisD3pRXESSfZRsaFkWJcM28hdbVFhPF\n" + + "c6gWhwQLmTp0CuL2RPXcPUPFi6sN2iWWi3zxxi9Eyz+9uBn6AsOpo56N5MME/LiOnETO9TKb+Ib6\n" + + "rQtKhjshcv3XkIqFPo2XdVvOAgglPO7vajX91iiXXuH7h7RmJud6l0y/lwKBgE+bi90gLuPtpoEr\n" + + "VzIDKz40ED5bNYHT80NNy0rpT7J2GVN9nwStRYXPBBVeZq7xCpgqpgmO5LtDAWULeZBlbHlOdBwl\n" + + "NhNKKl5wzdEUKwW0yBL1WSS5PQgWPwgARYP25/ggW22sj+49WIo1neXsEKPGWObk8e050f1fTt92\n" + + "Vo1lAoGAb1gCoyBCzvi7sqFxm4V5oapnJeiQQJFjhoYWqGa26rQ+AvXXNuBcigIeDXNJPctSF0Uc\n" + + "p11KbbCgiruBbckvM1vGsk6Sx4leRk+IFHRpJktFUek4o0eUg0shOsyyvyet48Dfg0a8FvcxROs0\n" + + "gD+IYds5doiob/hcm1hnNB/3vk4=\n" + + "-----END PRIVATE KEY-----\n"; + + public static final String certContent = + "-----BEGIN CERTIFICATE-----\n" + + "MIIFZTCCBE2gAwIBAgIHKBCduBUoKDANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE\n" + + "BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY\n" + + "BgNVBAoTEUdvRGFkZHkuY29tLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydGlm\n" + + "aWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkxMDAuBgNVBAMTJ0dvIERhZGR5\n" + + "IFNlY3VyZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTERMA8GA1UEBRMIMDc5Njky\n" + + "ODcwHhcNMTIwMjAzMDMzMDQwWhcNMTcwMjA3MDUxMTIzWjBZMRkwFwYDVQQKDBAq\n" + + "LnJlYWxob3N0aXAuY29tMSEwHwYDVQQLDBhEb21haW4gQ29udHJvbCBWYWxpZGF0\n" + + "ZWQxGTAXBgNVBAMMECoucmVhbGhvc3RpcC5jb20wggEiMA0GCSqGSIb3DQEBAQUA\n" + + "A4IBDwAwggEKAoIBAQCDT9AtEfs+s/I8QXp6rrCw0iNJ0+GgsybNHheU+JpL39LM\n" + + "TZykCrZhZnyDvwdxCoOfE38Sa32baHKNds+y2SHnMNsOkw8OcNucHEBX1FIpOBGp\n" + + "h9D6xC+umx9od6xMWETUv7j6h2u+WC3OhBM8fHCBqIiAol31/IkcqDxxsHlQ8S/o\n" + + "CfTlXJUY6Yn628OA1XijKdRnadV0hZ829cv/PZKljjwQUTyrd0KHQeksBH+YAYSo\n" + + "2JUl8ekNLsOi8/cPtfojnltzRI1GXi0ZONs8VnDzJ0a2gqZY+uxlz+CGbLnGnlN4\n" + + "j9cBpE+MfUE+35Dq121sTpsSgF85Mz+pVhn2S633AgMBAAGjggG+MIIBujAPBgNV\n" + + "HRMBAf8EBTADAQEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAOBgNV\n" + + "HQ8BAf8EBAMCBaAwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5nb2RhZGR5\n" + + "LmNvbS9nZHMxLTY0LmNybDBTBgNVHSAETDBKMEgGC2CGSAGG/W0BBxcBMDkwNwYI\n" + + "KwYBBQUHAgEWK2h0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3Np\n" + + "dG9yeS8wgYAGCCsGAQUFBwEBBHQwcjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au\n" + + "Z29kYWRkeS5jb20vMEoGCCsGAQUFBzAChj5odHRwOi8vY2VydGlmaWNhdGVzLmdv\n" + + "ZGFkZHkuY29tL3JlcG9zaXRvcnkvZ2RfaW50ZXJtZWRpYXRlLmNydDAfBgNVHSME\n" + + "GDAWgBT9rGEyk2xF1uLuhV+auud2mWjM5zArBgNVHREEJDAighAqLnJlYWxob3N0\n" + + "aXAuY29tgg5yZWFsaG9zdGlwLmNvbTAdBgNVHQ4EFgQUZyJz9/QLy5TWIIscTXID\n" + + "E8Xk47YwDQYJKoZIhvcNAQEFBQADggEBAKiUV3KK16mP0NpS92fmQkCLqm+qUWyN\n" + + "BfBVgf9/M5pcT8EiTZlS5nAtzAE/eRpBeR3ubLlaAogj4rdH7YYVJcDDLLoB2qM3\n" + + "qeCHu8LFoblkb93UuFDWqRaVPmMlJRnhsRkL1oa2gM2hwQTkBDkP7w5FG1BELCgl\n" + + "gZI2ij2yxjge6pOEwSyZCzzbCcg9pN+dNrYyGEtB4k+BBnPA3N4r14CWbk+uxjrQ\n" + + "6j2Ip+b7wOc5IuMEMl8xwTyjuX3lsLbAZyFI9RCyofwA9NqIZ1GeB6Zd196rubQp\n" + + "93cmBqGGjZUs3wMrGlm7xdjlX6GQ9UvmvkMub9+lL99A5W50QgCmFeI=\n" + + "-----END CERTIFICATE-----\n"; + + public static final String rootCa = + "-----BEGIN CERTIFICATE-----\n" + + "MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMx\n" + + "ITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g\n" + + "RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYw\n" + + "MTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH\n" + + "QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j\n" + + "b20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j\n" + + "b20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmlj\n" + + "YXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcN\n" + + "AQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3H\n" + + "KrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQm\n" + + "VZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpR\n" + + "SgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRT\n" + + "cDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ\n" + + "6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEu\n" + + "MB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDS\n" + + "kdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEB\n" + + "BCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0f\n" + + "BD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBv\n" + + "c2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUH\n" + + "AgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAO\n" + + "BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IG\n" + + "OgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMU\n" + + "A2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o\n" + + "0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTX\n" + + "RE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuH\n" + + "qDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWV\n" + + "U+4=\n" + + "-----END CERTIFICATE-----\n" + + "-----BEGIN CERTIFICATE-----\n" + + "MIIE+zCCBGSgAwIBAgICAQ0wDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1Zh\n" + + "bGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu\n" + + "Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g\n" + + "QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAe\n" + + "BgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MDYyMFoX\n" + + "DTI0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBE\n" + + "YWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0\n" + + "aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgC\n" + + "ggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv\n" + + "2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+q\n" + + "N1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiO\n" + + "r18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lN\n" + + "f4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+YihfukEH\n" + + "U1jPEX44dMX4/7VpkI+EdOqXG68CAQOjggHhMIIB3TAdBgNVHQ4EFgQU0sSw0pHU\n" + + "TBFxs2HLPaH+3ahq1OMwgdIGA1UdIwSByjCBx6GBwaSBvjCBuzEkMCIGA1UEBxMb\n" + + "VmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwg\n" + + "SW5jLjE1MDMGA1UECxMsVmFsaUNlcnQgQ2xhc3MgMiBQb2xpY3kgVmFsaWRhdGlv\n" + + "biBBdXRob3JpdHkxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQuY29tLzEg\n" + + "MB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb22CAQEwDwYDVR0TAQH/BAUw\n" + + "AwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmdv\n" + + "ZGFkZHkuY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jZXJ0aWZpY2F0ZXMu\n" + + "Z29kYWRkeS5jb20vcmVwb3NpdG9yeS9yb290LmNybDBLBgNVHSAERDBCMEAGBFUd\n" + + "IAAwODA2BggrBgEFBQcCARYqaHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNv\n" + + "bS9yZXBvc2l0b3J5MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQC1\n" + + "QPmnHfbq/qQaQlpE9xXUhUaJwL6e4+PrxeNYiY+Sn1eocSxI0YGyeR+sBjUZsE4O\n" + + "WBsUs5iB0QQeyAfJg594RAoYC5jcdnplDQ1tgMQLARzLrUc+cb53S8wGd9D0Vmsf\n" + + "SxOaFIqII6hR8INMqzW/Rn453HWkrugp++85j09VZw==\n" + + "-----END CERTIFICATE-----\n" + + "-----BEGIN CERTIFICATE-----\n" + + "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n" + + "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz\n" + + "BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y\n" + + "aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG\n" + + "9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy\n" + + "NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y\n" + + "azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs\n" + + "YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw\n" + + "Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl\n" + + "cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY\n" + + "dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9\n" + + "WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS\n" + + "v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v\n" + + "UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu\n" + + "IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC\n" + + "W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd\n" + + "-----END CERTIFICATE-----\n"; + + @Column(name = "public_ip_address", nullable = false) + private String publicIpAddress; + + @Column(name = "public_mac_address", nullable = false) + private String publicMacAddress; + + @Column(name = "public_netmask", nullable = false) + private String publicNetmask; + + @Column(name = "active_session", updatable = true, nullable = false) + private int activeSession; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "last_update", updatable = true, nullable = true) + private Date lastUpdateTime; + + @Column(name = "session_details", updatable = true, nullable = true) + private byte[] sessionDetails; + + @Transient + private boolean sslEnabled = false; + + @Transient + private int port; + + /** + * Correct constructor to use. + * + */ + public ConsoleProxyVO(long id, long serviceOfferingId, String name, long templateId, HypervisorType hypervisorType, long guestOSId, long dataCenterId, long domainId, long accountId, + int activeSession, boolean haEnabled) { + super(id, serviceOfferingId, name, name, Type.ConsoleProxy, templateId, hypervisorType, guestOSId, domainId, accountId, haEnabled); + this.activeSession = activeSession; + } + + protected ConsoleProxyVO() { + super(); + } + + public void setPublicIpAddress(String publicIpAddress) { + this.publicIpAddress = publicIpAddress; + } + + public void setPublicNetmask(String publicNetmask) { + this.publicNetmask = publicNetmask; + } + + public void setPublicMacAddress(String publicMacAddress) { + this.publicMacAddress = publicMacAddress; + } + + public void setActiveSession(int activeSession) { + this.activeSession = activeSession; + } + + public void setLastUpdateTime(Date time) { + this.lastUpdateTime = time; + } + + public void setSessionDetails(byte[] details) { + this.sessionDetails = details; + } + + @Override + public String getPublicIpAddress() { + return this.publicIpAddress; + } + + @Override + public String getPublicNetmask() { + return this.publicNetmask; + } + + @Override + public String getPublicMacAddress() { + return this.publicMacAddress; + } + + @Override + public int getActiveSession() { + return this.activeSession; + } + + @Override + public Date getLastUpdateTime() { + return this.lastUpdateTime; + } + + @Override + public byte[] getSessionDetails() { + return this.sessionDetails; + } + + public boolean isSslEnabled() { + return sslEnabled; + } + + public void setSslEnabled(boolean sslEnabled) { + this.sslEnabled = sslEnabled; + } + + public void setPort(int port) { + this.port = port; + } + + public int getPort() { + return port; + } + +} diff --git a/core/src/com/cloud/vm/DomainRouterVO.java b/engine/schema/src/com/cloud/vm/DomainRouterVO.java similarity index 100% rename from core/src/com/cloud/vm/DomainRouterVO.java rename to engine/schema/src/com/cloud/vm/DomainRouterVO.java diff --git a/core/src/com/cloud/vm/InstanceGroupVMMapVO.java b/engine/schema/src/com/cloud/vm/InstanceGroupVMMapVO.java similarity index 100% rename from core/src/com/cloud/vm/InstanceGroupVMMapVO.java rename to engine/schema/src/com/cloud/vm/InstanceGroupVMMapVO.java diff --git a/core/src/com/cloud/vm/InstanceGroupVO.java b/engine/schema/src/com/cloud/vm/InstanceGroupVO.java similarity index 100% rename from core/src/com/cloud/vm/InstanceGroupVO.java rename to engine/schema/src/com/cloud/vm/InstanceGroupVO.java diff --git a/server/src/com/cloud/vm/ItWorkDao.java b/engine/schema/src/com/cloud/vm/ItWorkDao.java similarity index 100% rename from server/src/com/cloud/vm/ItWorkDao.java rename to engine/schema/src/com/cloud/vm/ItWorkDao.java diff --git a/server/src/com/cloud/vm/ItWorkDaoImpl.java b/engine/schema/src/com/cloud/vm/ItWorkDaoImpl.java similarity index 100% rename from server/src/com/cloud/vm/ItWorkDaoImpl.java rename to engine/schema/src/com/cloud/vm/ItWorkDaoImpl.java diff --git a/server/src/com/cloud/vm/ItWorkVO.java b/engine/schema/src/com/cloud/vm/ItWorkVO.java similarity index 100% rename from server/src/com/cloud/vm/ItWorkVO.java rename to engine/schema/src/com/cloud/vm/ItWorkVO.java diff --git a/server/src/com/cloud/vm/NicVO.java b/engine/schema/src/com/cloud/vm/NicVO.java similarity index 100% rename from server/src/com/cloud/vm/NicVO.java rename to engine/schema/src/com/cloud/vm/NicVO.java diff --git a/core/src/com/cloud/vm/SecondaryStorageVmVO.java b/engine/schema/src/com/cloud/vm/SecondaryStorageVmVO.java similarity index 100% rename from core/src/com/cloud/vm/SecondaryStorageVmVO.java rename to engine/schema/src/com/cloud/vm/SecondaryStorageVmVO.java diff --git a/core/src/com/cloud/vm/UserVmCloneSettingVO.java b/engine/schema/src/com/cloud/vm/UserVmCloneSettingVO.java similarity index 100% rename from core/src/com/cloud/vm/UserVmCloneSettingVO.java rename to engine/schema/src/com/cloud/vm/UserVmCloneSettingVO.java diff --git a/core/src/com/cloud/vm/UserVmDetailVO.java b/engine/schema/src/com/cloud/vm/UserVmDetailVO.java similarity index 100% rename from core/src/com/cloud/vm/UserVmDetailVO.java rename to engine/schema/src/com/cloud/vm/UserVmDetailVO.java diff --git a/core/src/com/cloud/vm/UserVmVO.java b/engine/schema/src/com/cloud/vm/UserVmVO.java similarity index 100% rename from core/src/com/cloud/vm/UserVmVO.java rename to engine/schema/src/com/cloud/vm/UserVmVO.java diff --git a/core/src/com/cloud/vm/VMInstanceVO.java b/engine/schema/src/com/cloud/vm/VMInstanceVO.java similarity index 99% rename from core/src/com/cloud/vm/VMInstanceVO.java rename to engine/schema/src/com/cloud/vm/VMInstanceVO.java index 5f930199548..fbe03dca8a2 100644 --- a/core/src/com/cloud/vm/VMInstanceVO.java +++ b/engine/schema/src/com/cloud/vm/VMInstanceVO.java @@ -156,7 +156,6 @@ public class VMInstanceVO implements VirtualMachine, FiniteStateObject { List listByNetworkId(long networkId); - NicVO findByInstanceIdAndNetworkId(long networkId, long instanceId); + NicVO findByNtwkIdAndInstanceId(long networkId, long instanceId); NicVO findByInstanceIdAndNetworkIdIncludingRemoved(long networkId, long instanceId); diff --git a/server/src/com/cloud/vm/dao/NicDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/NicDaoImpl.java similarity index 99% rename from server/src/com/cloud/vm/dao/NicDaoImpl.java rename to engine/schema/src/com/cloud/vm/dao/NicDaoImpl.java index c70d19432ef..fa30168bf86 100644 --- a/server/src/com/cloud/vm/dao/NicDaoImpl.java +++ b/engine/schema/src/com/cloud/vm/dao/NicDaoImpl.java @@ -113,7 +113,7 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao { } @Override - public NicVO findByInstanceIdAndNetworkId(long networkId, long instanceId) { + public NicVO findByNtwkIdAndInstanceId(long networkId, long instanceId) { SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("network", networkId); sc.setParameters("instance", instanceId); diff --git a/server/src/com/cloud/vm/dao/NicSecondaryIpDao.java b/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpDao.java similarity index 100% rename from server/src/com/cloud/vm/dao/NicSecondaryIpDao.java rename to engine/schema/src/com/cloud/vm/dao/NicSecondaryIpDao.java diff --git a/server/src/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java similarity index 100% rename from server/src/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java rename to engine/schema/src/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java diff --git a/server/src/com/cloud/vm/dao/NicSecondaryIpVO.java b/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpVO.java similarity index 100% rename from server/src/com/cloud/vm/dao/NicSecondaryIpVO.java rename to engine/schema/src/com/cloud/vm/dao/NicSecondaryIpVO.java diff --git a/server/src/com/cloud/vm/dao/SecondaryStorageVmDao.java b/engine/schema/src/com/cloud/vm/dao/SecondaryStorageVmDao.java similarity index 100% rename from server/src/com/cloud/vm/dao/SecondaryStorageVmDao.java rename to engine/schema/src/com/cloud/vm/dao/SecondaryStorageVmDao.java diff --git a/server/src/com/cloud/vm/dao/SecondaryStorageVmDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/SecondaryStorageVmDaoImpl.java similarity index 100% rename from server/src/com/cloud/vm/dao/SecondaryStorageVmDaoImpl.java rename to engine/schema/src/com/cloud/vm/dao/SecondaryStorageVmDaoImpl.java diff --git a/server/src/com/cloud/vm/dao/UserVmCloneSettingDao.java b/engine/schema/src/com/cloud/vm/dao/UserVmCloneSettingDao.java similarity index 100% rename from server/src/com/cloud/vm/dao/UserVmCloneSettingDao.java rename to engine/schema/src/com/cloud/vm/dao/UserVmCloneSettingDao.java diff --git a/server/src/com/cloud/vm/dao/UserVmCloneSettingDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/UserVmCloneSettingDaoImpl.java similarity index 100% rename from server/src/com/cloud/vm/dao/UserVmCloneSettingDaoImpl.java rename to engine/schema/src/com/cloud/vm/dao/UserVmCloneSettingDaoImpl.java diff --git a/server/src/com/cloud/vm/dao/UserVmDao.java b/engine/schema/src/com/cloud/vm/dao/UserVmDao.java similarity index 100% rename from server/src/com/cloud/vm/dao/UserVmDao.java rename to engine/schema/src/com/cloud/vm/dao/UserVmDao.java diff --git a/server/src/com/cloud/vm/dao/UserVmDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/UserVmDaoImpl.java similarity index 100% rename from server/src/com/cloud/vm/dao/UserVmDaoImpl.java rename to engine/schema/src/com/cloud/vm/dao/UserVmDaoImpl.java diff --git a/server/src/com/cloud/vm/dao/UserVmData.java b/engine/schema/src/com/cloud/vm/dao/UserVmData.java similarity index 100% rename from server/src/com/cloud/vm/dao/UserVmData.java rename to engine/schema/src/com/cloud/vm/dao/UserVmData.java diff --git a/server/src/com/cloud/vm/dao/UserVmDetailsDao.java b/engine/schema/src/com/cloud/vm/dao/UserVmDetailsDao.java similarity index 100% rename from server/src/com/cloud/vm/dao/UserVmDetailsDao.java rename to engine/schema/src/com/cloud/vm/dao/UserVmDetailsDao.java diff --git a/server/src/com/cloud/vm/dao/UserVmDetailsDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/UserVmDetailsDaoImpl.java similarity index 100% rename from server/src/com/cloud/vm/dao/UserVmDetailsDaoImpl.java rename to engine/schema/src/com/cloud/vm/dao/UserVmDetailsDaoImpl.java diff --git a/server/src/com/cloud/vm/dao/VMInstanceDao.java b/engine/schema/src/com/cloud/vm/dao/VMInstanceDao.java similarity index 100% rename from server/src/com/cloud/vm/dao/VMInstanceDao.java rename to engine/schema/src/com/cloud/vm/dao/VMInstanceDao.java diff --git a/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/VMInstanceDaoImpl.java similarity index 100% rename from server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java rename to engine/schema/src/com/cloud/vm/dao/VMInstanceDaoImpl.java diff --git a/core/src/com/cloud/vm/snapshot/VMSnapshotVO.java b/engine/schema/src/com/cloud/vm/snapshot/VMSnapshotVO.java similarity index 100% rename from core/src/com/cloud/vm/snapshot/VMSnapshotVO.java rename to engine/schema/src/com/cloud/vm/snapshot/VMSnapshotVO.java diff --git a/server/src/com/cloud/vm/snapshot/dao/VMSnapshotDao.java b/engine/schema/src/com/cloud/vm/snapshot/dao/VMSnapshotDao.java similarity index 100% rename from server/src/com/cloud/vm/snapshot/dao/VMSnapshotDao.java rename to engine/schema/src/com/cloud/vm/snapshot/dao/VMSnapshotDao.java diff --git a/server/src/com/cloud/vm/snapshot/dao/VMSnapshotDaoImpl.java b/engine/schema/src/com/cloud/vm/snapshot/dao/VMSnapshotDaoImpl.java similarity index 100% rename from server/src/com/cloud/vm/snapshot/dao/VMSnapshotDaoImpl.java rename to engine/schema/src/com/cloud/vm/snapshot/dao/VMSnapshotDaoImpl.java diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupVMMapVO.java b/engine/schema/src/org/apache/cloudstack/affinity/AffinityGroupVMMapVO.java similarity index 100% rename from server/src/org/apache/cloudstack/affinity/AffinityGroupVMMapVO.java rename to engine/schema/src/org/apache/cloudstack/affinity/AffinityGroupVMMapVO.java diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupVO.java b/engine/schema/src/org/apache/cloudstack/affinity/AffinityGroupVO.java similarity index 100% rename from server/src/org/apache/cloudstack/affinity/AffinityGroupVO.java rename to engine/schema/src/org/apache/cloudstack/affinity/AffinityGroupVO.java diff --git a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDao.java b/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupDao.java similarity index 100% rename from server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDao.java rename to engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupDao.java diff --git a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java b/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java similarity index 100% rename from server/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java rename to engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java diff --git a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java b/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java similarity index 100% rename from server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java rename to engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java diff --git a/server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java b/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java similarity index 100% rename from server/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java rename to engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java diff --git a/engine/schema/src/org/apache/cloudstack/lb/ApplicationLoadBalancerRuleVO.java b/engine/schema/src/org/apache/cloudstack/lb/ApplicationLoadBalancerRuleVO.java new file mode 100644 index 00000000000..37a747e4272 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/lb/ApplicationLoadBalancerRuleVO.java @@ -0,0 +1,133 @@ +// 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. + +package org.apache.cloudstack.lb; + +import javax.persistence.Column; +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.PrimaryKeyJoinColumn; +import javax.persistence.Table; + +import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule; + +import com.cloud.network.rules.FirewallRuleVO; +import com.cloud.utils.net.Ip; +import com.cloud.utils.net.NetUtils; + +/** + * This VO represent Internal Load Balancer rule. + * Instead of pointing to the public ip address id directly as External Load Balancer rule does, it refers to the ip address by its value/sourceNetworkid + * + */ +@Entity +@Table(name=("load_balancing_rules")) +@DiscriminatorValue(value="LoadBalancing") +@PrimaryKeyJoinColumn(name="id") +public class ApplicationLoadBalancerRuleVO extends FirewallRuleVO implements ApplicationLoadBalancerRule{ + @Column(name="name") + private String name; + + @Column(name="description", length=4096) + private String description; + + @Column(name="algorithm") + private String algorithm; + + @Column(name="default_port_start") + private int defaultPortStart; + + @Column(name="default_port_end") + private int defaultPortEnd; + + @Column(name="source_ip_address_network_id") + Long sourceIpNetworkId; + + @Column(name="source_ip_address") + @Enumerated(value=EnumType.STRING) + private Ip sourceIp = null; + + @Enumerated(value=EnumType.STRING) + @Column(name="scheme") + Scheme scheme; + + + public ApplicationLoadBalancerRuleVO() { + } + + public ApplicationLoadBalancerRuleVO(String name, String description, int srcPort, int instancePort, String algorithm, + long networkId, long accountId, long domainId, Ip sourceIp, long sourceIpNtwkId, Scheme scheme) { + super(null, null, srcPort, srcPort, NetUtils.TCP_PROTO, networkId, accountId, domainId, Purpose.LoadBalancing, null, null,null, null, null); + + this.name = name; + this.description = description; + this.algorithm = algorithm; + this.defaultPortStart = instancePort; + this.defaultPortEnd = instancePort; + this.sourceIp = sourceIp; + this.sourceIpNetworkId = sourceIpNtwkId; + this.scheme = scheme; + } + + + @Override + public Long getSourceIpNetworkId() { + return sourceIpNetworkId; + } + + @Override + public Ip getSourceIp() { + return sourceIp; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public String getAlgorithm() { + return algorithm; + } + + @Override + public int getDefaultPortStart() { + return defaultPortStart; + } + + @Override + public int getDefaultPortEnd() { + return defaultPortEnd; + } + + @Override + public Scheme getScheme() { + return scheme; + } + + @Override + public int getInstancePort() { + return defaultPortStart; + } +} diff --git a/engine/schema/src/org/apache/cloudstack/lb/dao/ApplicationLoadBalancerRuleDao.java b/engine/schema/src/org/apache/cloudstack/lb/dao/ApplicationLoadBalancerRuleDao.java new file mode 100644 index 00000000000..c385e62f6ab --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/lb/dao/ApplicationLoadBalancerRuleDao.java @@ -0,0 +1,35 @@ +// 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. + +package org.apache.cloudstack.lb.dao; + +import java.util.List; + +import org.apache.cloudstack.lb.ApplicationLoadBalancerRuleVO; + +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.utils.db.GenericDao; +import com.cloud.utils.net.Ip; + +public interface ApplicationLoadBalancerRuleDao extends GenericDao{ + List listBySrcIpSrcNtwkId(Ip sourceIp, long sourceNetworkId); + List listLbIpsBySourceIpNetworkId(long sourceIpNetworkId); + long countBySourceIp(Ip sourceIp, long sourceIpNetworkId); + List listBySourceIpAndNotRevoked(Ip sourceIp, long sourceNetworkId); + List listLbIpsBySourceIpNetworkIdAndScheme(long sourceIpNetworkId, Scheme scheme); + +} diff --git a/engine/schema/src/org/apache/cloudstack/lb/dao/ApplicationLoadBalancerRuleDaoImpl.java b/engine/schema/src/org/apache/cloudstack/lb/dao/ApplicationLoadBalancerRuleDaoImpl.java new file mode 100644 index 00000000000..880c67e732c --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/lb/dao/ApplicationLoadBalancerRuleDaoImpl.java @@ -0,0 +1,115 @@ +// 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. + +package org.apache.cloudstack.lb.dao; + +import java.util.List; + +import javax.ejb.Local; + +import org.apache.cloudstack.lb.ApplicationLoadBalancerRuleVO; +import org.springframework.stereotype.Component; + +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Func; +import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.utils.net.Ip; + +@Component +@Local(value = { ApplicationLoadBalancerRuleDao.class }) +public class ApplicationLoadBalancerRuleDaoImpl extends GenericDaoBase implements ApplicationLoadBalancerRuleDao{ + protected final SearchBuilder AllFieldsSearch; + final GenericSearchBuilder listIps; + final GenericSearchBuilder CountBy; + protected final SearchBuilder NotRevokedSearch; + + + + protected ApplicationLoadBalancerRuleDaoImpl() { + AllFieldsSearch = createSearchBuilder(); + AllFieldsSearch.and("sourceIp", AllFieldsSearch.entity().getSourceIp(), SearchCriteria.Op.EQ); + AllFieldsSearch.and("sourceIpNetworkId", AllFieldsSearch.entity().getSourceIpNetworkId(), SearchCriteria.Op.EQ); + AllFieldsSearch.and("networkId", AllFieldsSearch.entity().getNetworkId(), SearchCriteria.Op.EQ); + AllFieldsSearch.and("scheme", AllFieldsSearch.entity().getScheme(), SearchCriteria.Op.EQ); + AllFieldsSearch.done(); + + listIps = createSearchBuilder(String.class); + listIps.select(null, Func.DISTINCT, listIps.entity().getSourceIp()); + listIps.and("sourceIpNetworkId", listIps.entity().getSourceIpNetworkId(), Op.EQ); + listIps.and("scheme", listIps.entity().getScheme(), Op.EQ); + listIps.done(); + + CountBy = createSearchBuilder(Long.class); + CountBy.select(null, Func.COUNT, CountBy.entity().getId()); + CountBy.and("sourceIp", CountBy.entity().getSourceIp(), Op.EQ); + CountBy.and("sourceIpNetworkId", CountBy.entity().getSourceIpNetworkId(), Op.EQ); + CountBy.done(); + + NotRevokedSearch = createSearchBuilder(); + NotRevokedSearch.and("sourceIp", NotRevokedSearch.entity().getSourceIp(), SearchCriteria.Op.EQ); + NotRevokedSearch.and("sourceIpNetworkId", NotRevokedSearch.entity().getSourceIpNetworkId(), SearchCriteria.Op.EQ); + NotRevokedSearch.and("state", NotRevokedSearch.entity().getState(), SearchCriteria.Op.NEQ); + NotRevokedSearch.done(); + } + + @Override + public List listBySrcIpSrcNtwkId(Ip sourceIp, long sourceNetworkId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("sourceIp", sourceIp); + sc.setParameters("sourceIpNetworkId", sourceNetworkId); + return listBy(sc); + } + + @Override + public List listLbIpsBySourceIpNetworkId(long sourceIpNetworkId) { + SearchCriteria sc = listIps.create(); + sc.setParameters("sourceIpNetworkId", sourceIpNetworkId); + return customSearch(sc, null); + } + + @Override + public long countBySourceIp(Ip sourceIp, long sourceIpNetworkId) { + SearchCriteria sc = CountBy.create(); + sc.setParameters("sourceIp", sourceIp); + sc.setParameters("sourceIpNetworkId", sourceIpNetworkId); + List results = customSearch(sc, null); + return results.get(0); + } + + @Override + public List listBySourceIpAndNotRevoked(Ip sourceIp, long sourceNetworkId) { + SearchCriteria sc = NotRevokedSearch.create(); + sc.setParameters("sourceIp", sourceIp); + sc.setParameters("sourceIpNetworkId", sourceNetworkId); + sc.setParameters("state", FirewallRule.State.Revoke); + return listBy(sc); + } + + @Override + public List listLbIpsBySourceIpNetworkIdAndScheme(long sourceIpNetworkId, Scheme scheme) { + SearchCriteria sc = listIps.create(); + sc.setParameters("sourceIpNetworkId", sourceIpNetworkId); + sc.setParameters("scheme", scheme); + return customSearch(sc, null); + } + +} diff --git a/server/src/org/apache/cloudstack/region/RegionSyncVO.java b/engine/schema/src/org/apache/cloudstack/region/RegionSyncVO.java similarity index 100% rename from server/src/org/apache/cloudstack/region/RegionSyncVO.java rename to engine/schema/src/org/apache/cloudstack/region/RegionSyncVO.java diff --git a/server/src/org/apache/cloudstack/region/RegionVO.java b/engine/schema/src/org/apache/cloudstack/region/RegionVO.java similarity index 100% rename from server/src/org/apache/cloudstack/region/RegionVO.java rename to engine/schema/src/org/apache/cloudstack/region/RegionVO.java diff --git a/server/src/org/apache/cloudstack/region/dao/RegionDao.java b/engine/schema/src/org/apache/cloudstack/region/dao/RegionDao.java similarity index 100% rename from server/src/org/apache/cloudstack/region/dao/RegionDao.java rename to engine/schema/src/org/apache/cloudstack/region/dao/RegionDao.java diff --git a/server/src/org/apache/cloudstack/region/dao/RegionDaoImpl.java b/engine/schema/src/org/apache/cloudstack/region/dao/RegionDaoImpl.java similarity index 100% rename from server/src/org/apache/cloudstack/region/dao/RegionDaoImpl.java rename to engine/schema/src/org/apache/cloudstack/region/dao/RegionDaoImpl.java diff --git a/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerDaoImpl.java b/engine/schema/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerDaoImpl.java similarity index 100% rename from server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerDaoImpl.java rename to engine/schema/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerDaoImpl.java diff --git a/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerLbRuleMapDao.java b/engine/schema/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerLbRuleMapDao.java similarity index 100% rename from server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerLbRuleMapDao.java rename to engine/schema/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerLbRuleMapDao.java diff --git a/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerLbRuleMapDaoImpl.java b/engine/schema/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerLbRuleMapDaoImpl.java similarity index 100% rename from server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerLbRuleMapDaoImpl.java rename to engine/schema/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerLbRuleMapDaoImpl.java diff --git a/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerLbRuleMapVO.java b/engine/schema/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerLbRuleMapVO.java similarity index 100% rename from server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerLbRuleMapVO.java rename to engine/schema/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerLbRuleMapVO.java diff --git a/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerRuleDao.java b/engine/schema/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerRuleDao.java similarity index 100% rename from server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerRuleDao.java rename to engine/schema/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerRuleDao.java diff --git a/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerRuleVO.java b/engine/schema/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerRuleVO.java similarity index 100% rename from server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerRuleVO.java rename to engine/schema/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancerRuleVO.java diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/allocator/StorageAllocatorTestConfiguration.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/allocator/StorageAllocatorTestConfiguration.java index b815fc13446..4790086b2e1 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/allocator/StorageAllocatorTestConfiguration.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/allocator/StorageAllocatorTestConfiguration.java @@ -20,6 +20,7 @@ import java.io.IOException; import org.apache.cloudstack.storage.allocator.StorageAllocatorTestConfiguration.Library; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl; +import org.apache.cloudstack.test.utils.SpringUtils; import org.mockito.Mockito; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; @@ -36,7 +37,6 @@ import com.cloud.host.dao.HostDaoImpl; import com.cloud.storage.StorageManager; import com.cloud.storage.dao.StoragePoolDetailsDaoImpl; import com.cloud.storage.dao.VMTemplateDaoImpl; -import com.cloud.utils.component.SpringComponentScanUtils; import com.cloud.vm.UserVmManager; @@ -67,7 +67,7 @@ public class StorageAllocatorTestConfiguration { public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { mdr.getClassMetadata().getClassName(); ComponentScan cs = StorageAllocatorTestConfiguration.class.getAnnotation(ComponentScan.class); - return SpringComponentScanUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); } } } diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/ChildTestConfiguration.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/ChildTestConfiguration.java index a063bdda8ad..0dcdebd6553 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/ChildTestConfiguration.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/ChildTestConfiguration.java @@ -24,6 +24,7 @@ import org.apache.cloudstack.framework.rpc.RpcProvider; import org.apache.cloudstack.storage.HostEndpointRpcServer; import org.apache.cloudstack.storage.endpoint.EndPointSelector; import org.apache.cloudstack.storage.test.ChildTestConfiguration.Library; +import org.apache.cloudstack.test.utils.SpringUtils; import org.mockito.Mockito; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; @@ -75,7 +76,6 @@ import com.cloud.storage.swift.SwiftManager; import com.cloud.tags.dao.ResourceTagsDaoImpl; import com.cloud.template.TemplateManager; import com.cloud.user.dao.UserDaoImpl; -import com.cloud.utils.component.SpringComponentScanUtils; import com.cloud.vm.VirtualMachineManager; import com.cloud.vm.dao.ConsoleProxyDaoImpl; import com.cloud.vm.dao.DomainRouterDao; @@ -222,7 +222,7 @@ public class ChildTestConfiguration extends TestConfiguration { public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { mdr.getClassMetadata().getClassName(); ComponentScan cs = ChildTestConfiguration.class.getAnnotation(ComponentScan.class); - return SpringComponentScanUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); } } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java index f2cb1c45c82..2f0b43ad9f6 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java @@ -56,7 +56,7 @@ public class DefaultHostListener implements HypervisorHostListener { } if (!answer.getResult()) { - String msg = "Add host failed due to ModifyStoragePoolCommand failed" + answer.getDetails(); + String msg = "Unable to attach storage pool" + poolId + " to the host" + hostId; alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, pool.getDataCenterId(), pool.getPodId(), msg, msg); throw new CloudRuntimeException("Unable establish connection from storage head to storage pool " + pool.getId() + " due to " + answer.getDetails() + pool.getId()); } diff --git a/framework/api/pom.xml b/framework/api/pom.xml deleted file mode 100644 index 5260ebc4bf6..00000000000 --- a/framework/api/pom.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - 4.0.0 - cloud-framework-api - - org.apache.cloudstack - cloudstack-framework - 4.2.0-SNAPSHOT - ../pom.xml - - - - - org.apache.cloudstack - cloud-utils - 4.2.0-SNAPSHOT - - - - - - install - src - ${project.basedir}/test - - - ${project.basedir}/test/resources - - - - diff --git a/framework/events/pom.xml b/framework/events/pom.xml index 7c788c35bbd..747c5a1a667 100644 --- a/framework/events/pom.xml +++ b/framework/events/pom.xml @@ -1,23 +1,14 @@ - + + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 cloud-framework-events Apache CloudStack Framework - Event Notification @@ -30,18 +21,18 @@ org.apache.cloudstack - cloud-utils - ${project.version} - + cloud-utils + ${project.version} + - com.google.code.gson - gson - ${cs.gson.version} + com.google.code.gson + gson + ${cs.gson.version} + + + com.google.guava + guava + ${cs.guava.version} - - install - src - test - diff --git a/framework/ipc/pom.xml b/framework/ipc/pom.xml index b7f4fcc78ce..2c2131f01c1 100644 --- a/framework/ipc/pom.xml +++ b/framework/ipc/pom.xml @@ -20,26 +20,24 @@ ../pom.xml - - org.apache.cloudstack - cloud-core - 4.2.0-SNAPSHOT + cglib + cglib-nodep + ${cs.cglib.version} + + + com.google.code.gson + gson + ${cs.gson.version} - org.apache.cloudstack cloud-utils - 4.2.0-SNAPSHOT + ${project.version} - - install - src - ${project.basedir}/test ${project.basedir}/test/resources diff --git a/framework/api/src/org/apache/cloudstack/framework/async/AsyncCallFuture.java b/framework/ipc/src/org/apache/cloudstack/framework/async/AsyncCallFuture.java similarity index 100% rename from framework/api/src/org/apache/cloudstack/framework/async/AsyncCallFuture.java rename to framework/ipc/src/org/apache/cloudstack/framework/async/AsyncCallFuture.java diff --git a/framework/api/src/org/apache/cloudstack/framework/async/AsyncCompletionCallback.java b/framework/ipc/src/org/apache/cloudstack/framework/async/AsyncCompletionCallback.java similarity index 100% rename from framework/api/src/org/apache/cloudstack/framework/async/AsyncCompletionCallback.java rename to framework/ipc/src/org/apache/cloudstack/framework/async/AsyncCompletionCallback.java diff --git a/framework/ipc/src/org/apache/cloudstack/framework/client/ClientEventBus.java b/framework/ipc/src/org/apache/cloudstack/framework/client/ClientEventBus.java index 7930bf2fea0..d876b01981a 100644 --- a/framework/ipc/src/org/apache/cloudstack/framework/client/ClientEventBus.java +++ b/framework/ipc/src/org/apache/cloudstack/framework/client/ClientEventBus.java @@ -18,10 +18,10 @@ */ package org.apache.cloudstack.framework.client; -import org.apache.cloudstack.framework.eventbus.EventBusBase; +import org.apache.cloudstack.framework.messagebus.MessageBusBase; import org.apache.cloudstack.framework.transport.TransportMultiplexier; -public class ClientEventBus extends EventBusBase implements TransportMultiplexier { +public class ClientEventBus extends MessageBusBase implements TransportMultiplexier { @Override public void onTransportMessage(String senderEndpointAddress, diff --git a/framework/ipc/src/org/apache/cloudstack/framework/client/ClientTransportProvider.java b/framework/ipc/src/org/apache/cloudstack/framework/client/ClientTransportProvider.java index bd93824ea85..023b3181b20 100644 --- a/framework/ipc/src/org/apache/cloudstack/framework/client/ClientTransportProvider.java +++ b/framework/ipc/src/org/apache/cloudstack/framework/client/ClientTransportProvider.java @@ -28,7 +28,7 @@ import org.apache.cloudstack.framework.transport.TransportEndpoint; import org.apache.cloudstack.framework.transport.TransportEndpointSite; import org.apache.cloudstack.framework.transport.TransportProvider; -import com.cloud.utils.concurrency.NamedThreadFactory; +import com.cloud.utils.concurrency.NamedThreadFactory; public class ClientTransportProvider implements TransportProvider { public static final int DEFAULT_WORKER_POOL_SIZE = 5; diff --git a/framework/ipc/src/org/apache/cloudstack/framework/eventbus/EventBus.java b/framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageBus.java similarity index 81% rename from framework/ipc/src/org/apache/cloudstack/framework/eventbus/EventBus.java rename to framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageBus.java index 200715c396f..a15dd442937 100644 --- a/framework/ipc/src/org/apache/cloudstack/framework/eventbus/EventBus.java +++ b/framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageBus.java @@ -17,16 +17,18 @@ * under the License. */ -package org.apache.cloudstack.framework.eventbus; +package org.apache.cloudstack.framework.messagebus; import org.apache.cloudstack.framework.serializer.MessageSerializer; -public interface EventBus { +public interface MessageBus { void setMessageSerializer(MessageSerializer messageSerializer); MessageSerializer getMessageSerializer(); - void subscribe(String subject, Subscriber subscriber); - void unsubscribe(String subject, Subscriber subscriber); + void subscribe(String subject, MessageSubscriber subscriber); + void unsubscribe(String subject, MessageSubscriber subscriber); + void clearAll(); + void prune(); void publish(String senderAddress, String subject, PublishScope scope, Object args); } diff --git a/framework/ipc/src/org/apache/cloudstack/framework/eventbus/EventBusBase.java b/framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageBusBase.java similarity index 63% rename from framework/ipc/src/org/apache/cloudstack/framework/eventbus/EventBusBase.java rename to framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageBusBase.java index 30a847f0f9a..9cf5e77ce6e 100644 --- a/framework/ipc/src/org/apache/cloudstack/framework/eventbus/EventBusBase.java +++ b/framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageBusBase.java @@ -17,7 +17,7 @@ * under the License. */ -package org.apache.cloudstack.framework.eventbus; +package org.apache.cloudstack.framework.messagebus; import java.util.ArrayList; import java.util.Arrays; @@ -28,7 +28,7 @@ import java.util.Map; import org.apache.cloudstack.framework.serializer.MessageSerializer; -public class EventBusBase implements EventBus { +public class MessageBusBase implements MessageBus { private Gate _gate; private List _pendingActions; @@ -36,11 +36,11 @@ public class EventBusBase implements EventBus { private SubscriptionNode _subscriberRoot; private MessageSerializer _messageSerializer; - public EventBusBase() { + public MessageBusBase() { _gate = new Gate(); _pendingActions = new ArrayList(); - _subscriberRoot = new SubscriptionNode("/", null); + _subscriberRoot = new SubscriptionNode(null, "/", null); } @Override @@ -54,7 +54,7 @@ public class EventBusBase implements EventBus { } @Override - public void subscribe(String subject, Subscriber subscriber) { + public void subscribe(String subject, MessageSubscriber subscriber) { assert(subject != null); assert(subscriber != null); if(_gate.enter()) { @@ -70,12 +70,15 @@ public class EventBusBase implements EventBus { } @Override - public void unsubscribe(String subject, Subscriber subscriber) { + public void unsubscribe(String subject, MessageSubscriber subscriber) { if(_gate.enter()) { - SubscriptionNode current = locate(subject, null, false); - if(current != null) - current.removeSubscriber(subscriber); - + if(subject != null) { + SubscriptionNode current = locate(subject, null, false); + if(current != null) + current.removeSubscriber(subscriber, false); + } else { + this._subscriberRoot.removeSubscriber(subscriber, true); + } _gate.leave(); } else { synchronized(_pendingActions) { @@ -83,7 +86,48 @@ public class EventBusBase implements EventBus { } } } - + + @Override + public void clearAll() { + if(_gate.enter()) { + _subscriberRoot.clearAll(); + doPrune(); + _gate.leave(); + } else { + synchronized(_pendingActions) { + _pendingActions.add(new ActionRecord(ActionType.ClearAll, null, null)); + } + } + } + + @Override + public void prune() { + if(_gate.enter()) { + doPrune(); + _gate.leave(); + } else { + synchronized(_pendingActions) { + _pendingActions.add(new ActionRecord(ActionType.Prune, null, null)); + } + } + } + + private void doPrune() { + List trimNodes = new ArrayList(); + _subscriberRoot.prune(trimNodes); + + while(trimNodes.size() > 0) { + SubscriptionNode node = trimNodes.remove(0); + SubscriptionNode parent = node.getParent(); + if(parent != null) { + parent.removeChild(node.getNodeKey()); + if(parent.isTrimmable()) { + trimNodes.add(parent); + } + } + } + } + @Override public void publish(String senderAddress, String subject, PublishScope scope, Object args) { @@ -119,12 +163,22 @@ public class EventBusBase implements EventBus { break; case Unsubscribe : - { + if(record.getSubject() != null) { SubscriptionNode current = locate(record.getSubject(), null, false); if(current != null) - current.removeSubscriber(record.getSubscriber()); + current.removeSubscriber(record.getSubscriber(), false); + } else { + this._subscriberRoot.removeSubscriber(record.getSubscriber(), true); } break; + + case ClearAll : + _subscriberRoot.clearAll(); + break; + + case Prune : + doPrune(); + break; default : assert(false); @@ -136,11 +190,13 @@ public class EventBusBase implements EventBus { } } - private SubscriptionNode locate(String subject, List chainFromTop, boolean createPath) { assert(subject != null); + // "/" is special name for root node + if(subject.equals("/")) + return _subscriberRoot; String[] subjectPathTokens = subject.split("\\."); return locate(subjectPathTokens, _subscriberRoot, chainFromTop, createPath); @@ -159,7 +215,7 @@ public class EventBusBase implements EventBus { SubscriptionNode next = current.getChild(subjectPathTokens[0]); if(next == null) { if(createPath) { - next = new SubscriptionNode(subjectPathTokens[0], null); + next = new SubscriptionNode(current, subjectPathTokens[0], null); current.addChild(subjectPathTokens[0], next); } else { return null; @@ -180,15 +236,17 @@ public class EventBusBase implements EventBus { // private static enum ActionType { Subscribe, - Unsubscribe + Unsubscribe, + ClearAll, + Prune } private static class ActionRecord { private ActionType _type; private String _subject; - private Subscriber _subscriber; + private MessageSubscriber _subscriber; - public ActionRecord(ActionType type, String subject, Subscriber subscriber) { + public ActionRecord(ActionType type, String subject, MessageSubscriber subscriber) { _type = type; _subject = subject; _subscriber = subscriber; @@ -202,7 +260,7 @@ public class EventBusBase implements EventBus { return _subject; } - public Subscriber getSubscriber() { + public MessageSubscriber getSubscriber() { return _subscriber; } } @@ -262,15 +320,16 @@ public class EventBusBase implements EventBus { } private static class SubscriptionNode { - @SuppressWarnings("unused") private String _nodeKey; - private List _subscribers; + private List _subscribers; private Map _children; + private SubscriptionNode _parent; - public SubscriptionNode(String nodeKey, Subscriber subscriber) { + public SubscriptionNode(SubscriptionNode parent, String nodeKey, MessageSubscriber subscriber) { assert(nodeKey != null); + _parent = parent; _nodeKey = nodeKey; - _subscribers = new ArrayList(); + _subscribers = new ArrayList(); if(subscriber != null) _subscribers.add(subscriber); @@ -278,16 +337,30 @@ public class EventBusBase implements EventBus { _children = new HashMap(); } + public SubscriptionNode getParent() { + return _parent; + } + + public String getNodeKey() { + return _nodeKey; + } + @SuppressWarnings("unused") - public List getSubscriber() { + public List getSubscriber() { return _subscribers; } - public void addSubscriber(Subscriber subscriber) { - _subscribers.add(subscriber); + public void addSubscriber(MessageSubscriber subscriber) { + if(!_subscribers.contains(subscriber)) + _subscribers.add(subscriber); } - public void removeSubscriber(Subscriber subscriber) { + public void removeSubscriber(MessageSubscriber subscriber, boolean recursively) { + if(recursively) { + for(Map.Entry entry : _children.entrySet()) { + entry.getValue().removeSubscriber(subscriber, true); + } + } _subscribers.remove(subscriber); } @@ -299,10 +372,37 @@ public class EventBusBase implements EventBus { _children.put(key, childNode); } - public void notifySubscribers(String senderAddress, String subject, Object args) { - for(Subscriber subscriber : _subscribers) { - subscriber.onPublishEvent(senderAddress, subject, args); + public void removeChild(String key) { + _children.remove(key); + } + + public void clearAll() { + // depth-first + for(Map.Entry entry : _children.entrySet()) { + entry.getValue().clearAll(); } + _subscribers.clear(); + } + + public void prune(List trimNodes) { + assert(trimNodes != null); + + for(Map.Entry entry : _children.entrySet()) { + entry.getValue().prune(trimNodes); + } + + if(isTrimmable()) + trimNodes.add(this); + } + + public void notifySubscribers(String senderAddress, String subject, Object args) { + for(MessageSubscriber subscriber : _subscribers) { + subscriber.onPublishMessage(senderAddress, subject, args); + } + } + + public boolean isTrimmable() { + return _children.size() == 0 && _subscribers.size() == 0; } } } diff --git a/framework/ipc/src/org/apache/cloudstack/framework/eventbus/EventBusEndpoint.java b/framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageBusEndpoint.java similarity index 77% rename from framework/ipc/src/org/apache/cloudstack/framework/eventbus/EventBusEndpoint.java rename to framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageBusEndpoint.java index 19a9b03dad9..0824e131e25 100644 --- a/framework/ipc/src/org/apache/cloudstack/framework/eventbus/EventBusEndpoint.java +++ b/framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageBusEndpoint.java @@ -17,26 +17,26 @@ * under the License. */ -package org.apache.cloudstack.framework.eventbus; +package org.apache.cloudstack.framework.messagebus; -public class EventBusEndpoint { - private EventBus _eventBus; +public class MessageBusEndpoint { + private MessageBus _eventBus; private String _sender; private PublishScope _scope; - public EventBusEndpoint(EventBus eventBus, String sender, PublishScope scope) { + public MessageBusEndpoint(MessageBus eventBus, String sender, PublishScope scope) { _eventBus = eventBus; _sender = sender; _scope = scope; } - public EventBusEndpoint setEventBus(EventBus eventBus) { + public MessageBusEndpoint setEventBus(MessageBus eventBus) { _eventBus = eventBus; return this; } - public EventBusEndpoint setScope(PublishScope scope) { + public MessageBusEndpoint setScope(PublishScope scope) { _scope = scope; return this; } @@ -45,7 +45,7 @@ public class EventBusEndpoint { return _scope; } - public EventBusEndpoint setSender(String sender) { + public MessageBusEndpoint setSender(String sender) { _sender = sender; return this; } diff --git a/framework/ipc/src/org/apache/cloudstack/framework/eventbus/EventDispatcher.java b/framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageDispatcher.java similarity index 83% rename from framework/ipc/src/org/apache/cloudstack/framework/eventbus/EventDispatcher.java rename to framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageDispatcher.java index 336a994a6cc..ac75afb7c7d 100644 --- a/framework/ipc/src/org/apache/cloudstack/framework/eventbus/EventDispatcher.java +++ b/framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageDispatcher.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.framework.eventbus; +package org.apache.cloudstack.framework.messagebus; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -24,27 +24,27 @@ import java.util.HashMap; import java.util.Map; -public class EventDispatcher implements Subscriber { +public class MessageDispatcher implements MessageSubscriber { private static Map, Method> s_handlerCache = new HashMap, Method>(); - private static Map s_targetMap = new HashMap(); + private static Map s_targetMap = new HashMap(); private Object _targetObject; - public EventDispatcher(Object targetObject) { + public MessageDispatcher(Object targetObject) { _targetObject = targetObject; } @Override - public void onPublishEvent(String senderAddress, String subject, Object args) { + public void onPublishMessage(String senderAddress, String subject, Object args) { dispatch(_targetObject, subject, senderAddress, args); } - public static EventDispatcher getDispatcher(Object targetObject) { - EventDispatcher dispatcher; + public static MessageDispatcher getDispatcher(Object targetObject) { + MessageDispatcher dispatcher; synchronized(s_targetMap) { dispatcher = s_targetMap.get(targetObject); if(dispatcher == null) { - dispatcher = new EventDispatcher(targetObject); + dispatcher = new MessageDispatcher(targetObject); s_targetMap.put(targetObject, dispatcher); } } @@ -85,7 +85,7 @@ public class EventDispatcher implements Subscriber { return handler; for(Method method : handlerClz.getMethods()) { - EventHandler annotation = method.getAnnotation(EventHandler.class); + MessageHandler annotation = method.getAnnotation(MessageHandler.class); if(annotation != null) { if(match(annotation.topic(), subject)) { s_handlerCache.put(handlerClz, method); diff --git a/framework/ipc/src/org/apache/cloudstack/framework/eventbus/EventHandler.java b/framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageHandler.java similarity index 92% rename from framework/ipc/src/org/apache/cloudstack/framework/eventbus/EventHandler.java rename to framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageHandler.java index 1ed3a00b96f..d9f51df1a11 100644 --- a/framework/ipc/src/org/apache/cloudstack/framework/eventbus/EventHandler.java +++ b/framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageHandler.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.framework.eventbus; +package org.apache.cloudstack.framework.messagebus; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -25,6 +25,6 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) -public @interface EventHandler { +public @interface MessageHandler { public String topic(); } diff --git a/framework/ipc/src/org/apache/cloudstack/framework/eventbus/Subscriber.java b/framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageSubscriber.java similarity index 83% rename from framework/ipc/src/org/apache/cloudstack/framework/eventbus/Subscriber.java rename to framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageSubscriber.java index 28b86de050e..072f98d9d1e 100644 --- a/framework/ipc/src/org/apache/cloudstack/framework/eventbus/Subscriber.java +++ b/framework/ipc/src/org/apache/cloudstack/framework/messagebus/MessageSubscriber.java @@ -17,8 +17,8 @@ * under the License. */ -package org.apache.cloudstack.framework.eventbus; +package org.apache.cloudstack.framework.messagebus; -public interface Subscriber { - void onPublishEvent(String senderAddress, String subject, Object args); +public interface MessageSubscriber { + void onPublishMessage(String senderAddress, String subject, Object args); } diff --git a/framework/ipc/src/org/apache/cloudstack/framework/eventbus/PublishScope.java b/framework/ipc/src/org/apache/cloudstack/framework/messagebus/PublishScope.java similarity index 94% rename from framework/ipc/src/org/apache/cloudstack/framework/eventbus/PublishScope.java rename to framework/ipc/src/org/apache/cloudstack/framework/messagebus/PublishScope.java index 539a242a55f..2b3d8acc841 100644 --- a/framework/ipc/src/org/apache/cloudstack/framework/eventbus/PublishScope.java +++ b/framework/ipc/src/org/apache/cloudstack/framework/messagebus/PublishScope.java @@ -17,7 +17,7 @@ * under the License. */ -package org.apache.cloudstack.framework.eventbus; +package org.apache.cloudstack.framework.messagebus; public enum PublishScope { LOCAL, GLOBAL diff --git a/framework/ipc/src/org/apache/cloudstack/framework/server/ServerEventBus.java b/framework/ipc/src/org/apache/cloudstack/framework/server/ServerEventBus.java index 11bc428a42b..f3b782d6d35 100644 --- a/framework/ipc/src/org/apache/cloudstack/framework/server/ServerEventBus.java +++ b/framework/ipc/src/org/apache/cloudstack/framework/server/ServerEventBus.java @@ -18,10 +18,10 @@ */ package org.apache.cloudstack.framework.server; -import org.apache.cloudstack.framework.eventbus.EventBusBase; +import org.apache.cloudstack.framework.messagebus.MessageBusBase; import org.apache.cloudstack.framework.transport.TransportMultiplexier; -public class ServerEventBus extends EventBusBase implements TransportMultiplexier { +public class ServerEventBus extends MessageBusBase implements TransportMultiplexier { @Override public void onTransportMessage(String senderEndpointAddress, diff --git a/framework/ipc/test/org/apache/cloudstack/framework/sampleserver/SampleManagerComponent.java b/framework/ipc/test/org/apache/cloudstack/framework/sampleserver/SampleManagerComponent.java index 7b0a2eca192..d59fe42d5ea 100644 --- a/framework/ipc/test/org/apache/cloudstack/framework/sampleserver/SampleManagerComponent.java +++ b/framework/ipc/test/org/apache/cloudstack/framework/sampleserver/SampleManagerComponent.java @@ -24,9 +24,9 @@ import java.util.TimerTask; import javax.annotation.PostConstruct; import javax.inject.Inject; -import org.apache.cloudstack.framework.eventbus.EventBus; -import org.apache.cloudstack.framework.eventbus.EventDispatcher; -import org.apache.cloudstack.framework.eventbus.EventHandler; +import org.apache.cloudstack.framework.messagebus.MessageBus; +import org.apache.cloudstack.framework.messagebus.MessageDispatcher; +import org.apache.cloudstack.framework.messagebus.MessageHandler; import org.apache.cloudstack.framework.rpc.RpcCallbackListener; import org.apache.cloudstack.framework.rpc.RpcException; import org.apache.cloudstack.framework.rpc.RpcProvider; @@ -41,7 +41,7 @@ public class SampleManagerComponent { private static final Logger s_logger = Logger.getLogger(SampleManagerComponent.class); @Inject - private EventBus _eventBus; + private MessageBus _eventBus; @Inject private RpcProvider _rpcProvider; @@ -58,7 +58,7 @@ public class SampleManagerComponent { // subscribe to all network events (for example) _eventBus.subscribe("network", - EventDispatcher.getDispatcher(this)); + MessageDispatcher.getDispatcher(this)); _timer.schedule(new TimerTask() { public void run() { @@ -72,7 +72,7 @@ public class SampleManagerComponent { call.completeCall("NetworkPrepare completed"); } - @EventHandler(topic="network.prepare") + @MessageHandler(topic="network.prepare") void onPrepareNetwork(String sender, String topic, Object args) { } diff --git a/framework/ipc/test/org/apache/cloudstack/framework/sampleserver/SampleManagerComponent2.java b/framework/ipc/test/org/apache/cloudstack/framework/sampleserver/SampleManagerComponent2.java index dc482c035fb..448c37b4c45 100644 --- a/framework/ipc/test/org/apache/cloudstack/framework/sampleserver/SampleManagerComponent2.java +++ b/framework/ipc/test/org/apache/cloudstack/framework/sampleserver/SampleManagerComponent2.java @@ -21,9 +21,9 @@ package org.apache.cloudstack.framework.sampleserver; import javax.annotation.PostConstruct; import javax.inject.Inject; -import org.apache.cloudstack.framework.eventbus.EventBus; -import org.apache.cloudstack.framework.eventbus.EventDispatcher; -import org.apache.cloudstack.framework.eventbus.EventHandler; +import org.apache.cloudstack.framework.messagebus.MessageBus; +import org.apache.cloudstack.framework.messagebus.MessageDispatcher; +import org.apache.cloudstack.framework.messagebus.MessageHandler; import org.apache.cloudstack.framework.rpc.RpcProvider; import org.apache.cloudstack.framework.rpc.RpcServerCall; import org.apache.cloudstack.framework.rpc.RpcServiceDispatcher; @@ -36,7 +36,7 @@ public class SampleManagerComponent2 { private static final Logger s_logger = Logger.getLogger(SampleManagerComponent2.class); @Inject - private EventBus _eventBus; + private MessageBus _eventBus; @Inject private RpcProvider _rpcProvider; @@ -51,7 +51,7 @@ public class SampleManagerComponent2 { // subscribe to all network events (for example) _eventBus.subscribe("storage", - EventDispatcher.getDispatcher(this)); + MessageDispatcher.getDispatcher(this)); } @RpcServiceHandler(command="StoragePrepare") @@ -66,7 +66,7 @@ public class SampleManagerComponent2 { call.completeCall(answer); } - @EventHandler(topic="storage.prepare") + @MessageHandler(topic="storage.prepare") void onPrepareNetwork(String sender, String topic, Object args) { } diff --git a/framework/ipc/test/org/apache/cloudstack/messagebus/TestMessageBus.java b/framework/ipc/test/org/apache/cloudstack/messagebus/TestMessageBus.java new file mode 100644 index 00000000000..dabfdd3b102 --- /dev/null +++ b/framework/ipc/test/org/apache/cloudstack/messagebus/TestMessageBus.java @@ -0,0 +1,116 @@ +/* + * 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. + */ +package org.apache.cloudstack.messagebus; + +import javax.inject.Inject; + +import junit.framework.TestCase; + +import org.apache.cloudstack.framework.messagebus.MessageBus; +import org.apache.cloudstack.framework.messagebus.MessageSubscriber; +import org.apache.cloudstack.framework.messagebus.PublishScope; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations="classpath:/MessageBusTestContext.xml") +public class TestMessageBus extends TestCase { + + @Inject MessageBus _messageBus; + + @Test + public void testExactSubjectMatch() { + _messageBus.subscribe("Host", new MessageSubscriber() { + + @Override + public void onPublishMessage(String senderAddress, String subject, Object args) { + Assert.assertEquals(subject, "Host"); + } + }); + + _messageBus.publish(null, "Host", PublishScope.LOCAL, null); + _messageBus.publish(null, "VM", PublishScope.LOCAL, null); + _messageBus.clearAll(); + } + + @Test + public void testRootSubjectMatch() { + _messageBus.subscribe("/", new MessageSubscriber() { + + @Override + public void onPublishMessage(String senderAddress, String subject, Object args) { + Assert.assertTrue(subject.equals("Host") || subject.equals("VM")); + } + }); + + _messageBus.publish(null, "Host", PublishScope.LOCAL, null); + _messageBus.publish(null, "VM", PublishScope.LOCAL, null); + _messageBus.clearAll(); + } + + @Test + public void testMiscMatch() { + MessageSubscriber subscriberAtParentLevel = new MessageSubscriber() { + @Override + public void onPublishMessage(String senderAddress, String subject, Object args) { + Assert.assertTrue(subject.startsWith(("Host")) || subject.startsWith("VM")); + } + }; + + MessageSubscriber subscriberAtChildLevel = new MessageSubscriber() { + @Override + public void onPublishMessage(String senderAddress, String subject, Object args) { + Assert.assertTrue(subject.equals("Host.123")); + } + }; + + subscriberAtParentLevel = Mockito.spy(subscriberAtParentLevel); + subscriberAtChildLevel = Mockito.spy(subscriberAtChildLevel); + + _messageBus.subscribe("Host", subscriberAtParentLevel); + _messageBus.subscribe("VM", subscriberAtParentLevel); + _messageBus.subscribe("Host.123", subscriberAtChildLevel); + + _messageBus.publish(null, "Host.123", PublishScope.LOCAL, null); + _messageBus.publish(null, "Host.321", PublishScope.LOCAL, null); + _messageBus.publish(null, "VM.123", PublishScope.LOCAL, null); + + Mockito.verify(subscriberAtParentLevel).onPublishMessage(null, "Host.123", null); + Mockito.verify(subscriberAtParentLevel).onPublishMessage(null, "Host.321", null); + Mockito.verify(subscriberAtParentLevel).onPublishMessage(null, "VM.123", null); + Mockito.verify(subscriberAtChildLevel).onPublishMessage(null, "Host.123", null); + + Mockito.reset(subscriberAtParentLevel); + Mockito.reset(subscriberAtChildLevel); + + _messageBus.unsubscribe(null, subscriberAtParentLevel); + _messageBus.publish(null, "Host.123", PublishScope.LOCAL, null); + _messageBus.publish(null, "VM.123", PublishScope.LOCAL, null); + + Mockito.verify(subscriberAtChildLevel).onPublishMessage(null, "Host.123", null); + Mockito.verify(subscriberAtParentLevel, Mockito.times(0)).onPublishMessage(null, "Host.123", null); + Mockito.verify(subscriberAtParentLevel, Mockito.times(0)).onPublishMessage(null, "VM.123", null); + + _messageBus.clearAll(); + } +} diff --git a/framework/ipc/test/resources/MessageBusTestContext.xml b/framework/ipc/test/resources/MessageBusTestContext.xml new file mode 100644 index 00000000000..fcfcb08416b --- /dev/null +++ b/framework/ipc/test/resources/MessageBusTestContext.xml @@ -0,0 +1,51 @@ + + + + + + + + org.apache.cloudstack.framework + + + + + + + + + + + + + diff --git a/framework/jobs/pom.xml b/framework/jobs/pom.xml index 56490216f16..5ae63af77ad 100644 --- a/framework/jobs/pom.xml +++ b/framework/jobs/pom.xml @@ -18,12 +18,31 @@ --> 4.0.0 - org.apache.cloudstack cloud-framework-jobs - 4.0.0-SNAPSHOT - - org.quartz-scheduler - quartz - 2.1.6 - + + org.apache.cloudstack + cloudstack-framework + 4.2.0-SNAPSHOT + ../pom.xml + + + + org.quartz-scheduler + quartz + 2.1.6 + + + org.apache.cloudstack + cloud-utils + ${project.version} + + + org.apache.cloudstack + cloud-api + ${project.version} + + + + install + diff --git a/framework/pom.xml b/framework/pom.xml index 4633dab2b30..ddcdcb0439a 100644 --- a/framework/pom.xml +++ b/framework/pom.xml @@ -33,6 +33,6 @@ ipc rest events - api + jobs diff --git a/packaging/centos63/package.sh b/packaging/centos63/package.sh index faa089b73fa..c466f588776 100755 --- a/packaging/centos63/package.sh +++ b/packaging/centos63/package.sh @@ -44,7 +44,7 @@ if echo $VERSION | grep SNAPSHOT ; then else DEFVER="-D_ver $REALVER" DEFPRE= - DEFREL= + DEFREL="-D_rel 1" fi mkdir -p $RPMDIR/SPECS @@ -78,7 +78,7 @@ else REALVER=`echo $VERSION` DEFVER="-D_ver $REALVER" DEFPRE= - DEFREL= + DEFREL="-D_rel 1" fi mkdir -p $RPMDIR/SPECS diff --git a/patches/systemvm/debian/config/etc/dnsmasq.conf b/patches/systemvm/debian/config/etc/dnsmasq.conf.tmpl similarity index 99% rename from patches/systemvm/debian/config/etc/dnsmasq.conf rename to patches/systemvm/debian/config/etc/dnsmasq.conf.tmpl index 7d656cb2b77..38e5a8bbc96 100644 --- a/patches/systemvm/debian/config/etc/dnsmasq.conf +++ b/patches/systemvm/debian/config/etc/dnsmasq.conf.tmpl @@ -27,7 +27,7 @@ bogus-priv # so don't use it if you use eg Kerberos, SIP, XMMP or Google-talk. # This option only affects forwarding, SRV records originating for # dnsmasq (via srv-host= lines) are not suppressed by it. -filterwin2k +# filterwin2k # Change this line if you want dns to get its upstream servers from # somewhere other that /etc/resolv.conf diff --git a/patches/systemvm/debian/config/etc/init.d/cloud-early-config b/patches/systemvm/debian/config/etc/init.d/cloud-early-config index 187ae25c40c..a457f228653 100755 --- a/patches/systemvm/debian/config/etc/init.d/cloud-early-config +++ b/patches/systemvm/debian/config/etc/init.d/cloud-early-config @@ -442,6 +442,9 @@ setup_dnsmasq() { [ -z $DHCP_RANGE ] && [ $ETH0_IP ] && DHCP_RANGE=$ETH0_IP [ $ETH0_IP6 ] && DHCP_RANGE_IP6=$ETH0_IP6 [ -z $DOMAIN ] && DOMAIN="cloudnine.internal" + + #get the template + cp /etc/dnsmasq.conf.tmpl /etc/dnsmasq.conf if [ -n "$DOMAIN" ] then @@ -520,6 +523,7 @@ setup_sshd(){ local eth=$2 [ -f /etc/ssh/sshd_config ] && sed -i -e "s/^[#]*ListenAddress.*$/ListenAddress $ip/" /etc/ssh/sshd_config sed -i "/3922/s/eth./$eth/" /etc/iptables/rules.v4 + sed -i "/3922/s/eth./$eth/" /etc/iptables/rules } @@ -692,6 +696,8 @@ setup_router() { enable_fwding 1 chkconfig nfs-common off cp /etc/iptables/iptables-router /etc/iptables/rules.v4 +#for old templates + cp /etc/iptables/iptables-router /etc/iptables/rules setup_sshd $ETH1_IP "eth1" } @@ -764,6 +770,7 @@ EOF disable_rpfilter enable_fwding 1 cp /etc/iptables/iptables-vpcrouter /etc/iptables/rules.v4 + cp /etc/iptables/iptables-vpcrouter /etc/iptables/rules setup_sshd $ETH0_IP "eth0" cp /etc/vpcdnsmasq.conf /etc/dnsmasq.conf cp /etc/cloud-nic.rules /etc/udev/rules.d/cloud-nic.rules @@ -790,6 +797,7 @@ setup_dhcpsrvr() { enable_fwding 0 chkconfig nfs-common off cp /etc/iptables/iptables-router /etc/iptables/rules.v4 + cp /etc/iptables/iptables-router /etc/iptables/rules if [ "$SSHONGUEST" == "true" ] then setup_sshd $ETH0_IP "eth0" @@ -825,6 +833,7 @@ setup_secstorage() { echo "$public_ip $NAME" >> /etc/hosts cp /etc/iptables/iptables-secstorage /etc/iptables/rules.v4 + cp /etc/iptables/iptables-secstorage /etc/iptables/rules if [ "$hyp" == "vmware" ]; then setup_sshd $ETH1_IP "eth1" else @@ -849,6 +858,7 @@ setup_console_proxy() { sed -i /gateway/d /etc/hosts echo "$public_ip $NAME" >> /etc/hosts cp /etc/iptables/iptables-consoleproxy /etc/iptables/rules.v4 + cp /etc/iptables/iptables-consoleproxy /etc/iptables/rules if [ "$hyp" == "vmware" ]; then setup_sshd $ETH1_IP "eth1" else @@ -874,6 +884,7 @@ setup_elbvm() { echo "$public_ip $NAME" >> /etc/hosts cp /etc/iptables/iptables-elbvm /etc/iptables/rules.v4 + cp /etc/iptables/iptables-elbvm /etc/iptables/rules if [ "$SSHONGUEST" == "true" ] then setup_sshd $ETH0_IP "eth0" @@ -890,6 +901,28 @@ setup_elbvm() { chkconfig portmap off } +setup_ilbvm() { + log_it "Setting up Internal Load Balancer system vm" + local hyp=$1 + setup_common eth0 eth1 + #eth0 = guest network, eth1=control network + + sed -i /$NAME/d /etc/hosts + echo "$ETH0_IP $NAME" >> /etc/hosts + + cp /etc/iptables/iptables-ilbvm /etc/iptables/rules.v4 + cp /etc/iptables/iptables-ilbvm /etc/iptables/rules + setup_sshd $ETH1_IP "eth1" + + enable_fwding 0 + enable_svc haproxy 1 + enable_svc dnsmasq 0 + enable_svc cloud-passwd-srvr 0 + enable_svc cloud 0 + chkconfig nfs-common off + chkconfig portmap off +} + setup_default() { cat > /etc/network/interfaces << EOF auto lo @@ -940,6 +973,10 @@ start() { [ "$NAME" == "" ] && NAME=elb setup_elbvm ;; + ilbvm) + [ "$NAME" == "" ] && NAME=ilb + setup_ilbvm + ;; unknown) [ "$NAME" == "" ] && NAME=systemvm setup_default; diff --git a/patches/systemvm/debian/config/etc/iptables/iptables-ilbvm b/patches/systemvm/debian/config/etc/iptables/iptables-ilbvm new file mode 100755 index 00000000000..8d5ca651c75 --- /dev/null +++ b/patches/systemvm/debian/config/etc/iptables/iptables-ilbvm @@ -0,0 +1,33 @@ +# 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. + +*nat +:PREROUTING ACCEPT [0:0] +:POSTROUTING ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] +COMMIT +*filter +:INPUT DROP [0:0] +:FORWARD DROP [0:0] +:OUTPUT ACCEPT [0:0] +-A INPUT -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT +-A INPUT -i eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT +-A INPUT -p icmp -j ACCEPT +-A INPUT -i lo -j ACCEPT +-A INPUT -i eth1 -p tcp -m state --state NEW --dport 3922 -j ACCEPT +COMMIT + diff --git a/patches/systemvm/debian/config/etc/vpcdnsmasq.conf b/patches/systemvm/debian/config/etc/vpcdnsmasq.conf index 3717fc8a80c..3622d0e7916 100644 --- a/patches/systemvm/debian/config/etc/vpcdnsmasq.conf +++ b/patches/systemvm/debian/config/etc/vpcdnsmasq.conf @@ -460,6 +460,3 @@ log-facility=/var/log/dnsmasq.log # Include a another lot of configuration options. #conf-file=/etc/dnsmasq.more.conf conf-dir=/etc/dnsmasq.d - -# Don't reply Windows's periodical DNS request -filterwin2k diff --git a/patches/systemvm/debian/config/opt/cloud/bin/ilb.sh b/patches/systemvm/debian/config/opt/cloud/bin/ilb.sh new file mode 100755 index 00000000000..2a298925be3 --- /dev/null +++ b/patches/systemvm/debian/config/opt/cloud/bin/ilb.sh @@ -0,0 +1,211 @@ +#!/usr/bin/env bash +# 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. + +source /root/func.sh + +lock="biglock" +locked=$(getLockFile $lock) +if [ "$locked" != "1" ] +then + exit 1 +fi + +usage() { + printf "Usage: %s: -a -d -f -s \n" $(basename $0) >&2 +} + +#set -x + +fw_remove_backup() { + logger -t cloud "$(basename $0): Entering fw_remove_backup" + local lb_vif_list=eth0 + for vif in $lb_vif_list; do + sudo iptables -F back_load_balancer_$vif 2> /dev/null + sudo iptables -D INPUT -i $vif -p tcp -j back_load_balancer_$vif 2> /dev/null + sudo iptables -X back_load_balancer_$vif 2> /dev/null + done + sudo iptables -F back_lb_stats 2> /dev/null + sudo iptables -D INPUT -p tcp -j back_lb_stats 2> /dev/null + sudo iptables -X back_lb_stats 2> /dev/null +} + +fw_restore() { + logger -t cloud "$(basename $0): Entering fw_restore" + local lb_vif_list="eth0" + for vif in $lb_vif_list; do + sudo iptables -F load_balancer_$vif 2> /dev/null + sudo iptables -D INPUT -i $vif -p tcp -j load_balancer_$vif 2> /dev/null + sudo iptables -X load_balancer_$vif 2> /dev/null + sudo iptables -E back_load_balancer_$vif load_balancer_$vif 2> /dev/null + done + sudo iptables -F lb_stats 2> /dev/null + sudo iptables -D INPUT -p tcp -j lb_stats 2> /dev/null + sudo iptables -X lb_stats 2> /dev/null + sudo iptables -E back_lb_stats lb_stats 2> /dev/null +} + +# firewall entry to ensure that haproxy can receive on specified port +fw_entry() { + logger -t cloud "$(basename $0): Entering fw_entry" + local added=$1 + local removed=$2 + local stats=$3 + + if [ "$added" == "none" ] + then + added="" + fi + + if [ "$removed" == "none" ] + then + removed="" + fi + + local a=$(echo $added | cut -d, -f1- --output-delimiter=" ") + local r=$(echo $removed | cut -d, -f1- --output-delimiter=" ") + +# back up the iptable rules by renaming before creating new. + local lb_vif_list=eth0 + for vif in $lb_vif_list; do + sudo iptables -E load_balancer_$vif back_load_balancer_$vif 2> /dev/null + sudo iptables -N load_balancer_$vif 2> /dev/null + sudo iptables -A INPUT -i $vif -p tcp -j load_balancer_$vif + done + sudo iptables -E lb_stats back_lb_stats 2> /dev/null + sudo iptables -N lb_stats 2> /dev/null + sudo iptables -A INPUT -p tcp -j lb_stats + + for i in $a + do + local pubIp=$(echo $i | cut -d: -f1) + local dport=$(echo $i | cut -d: -f2) + local lb_vif_list="eth0" + for vif in $lb_vif_list; do + sudo iptables -A load_balancer_$vif -p tcp -d $pubIp --dport $dport -j ACCEPT + if [ $? -gt 0 ] + then + return 1 + fi + done + done + local pubIp=$(echo $stats | cut -d: -f1) + local dport=$(echo $stats | cut -d: -f2) + local cidrs=$(echo $stats | cut -d: -f3 | sed 's/-/,/') + sudo iptables -A lb_stats -s $cidrs -p tcp -m state --state NEW -d $pubIp --dport $dport -j ACCEPT + + return 0 +} + +#Hot reconfigure HA Proxy in the routing domain +reconfig_lb() { + /root/reconfigLB.sh + return $? +} + +# Restore the HA Proxy to its previous state, and revert iptables rules on loadbalancer +restore_lb() { + logger -t cloud "Restoring HA Proxy to previous state" + # Copy the old version of haproxy.cfg into the file that reconfigLB.sh uses + cp /etc/haproxy/haproxy.cfg.old /etc/haproxy/haproxy.cfg.new + + if [ $? -eq 0 ] + then + # Run reconfigLB.sh again + /root/reconfigLB.sh + fi +} + + +logger -t cloud "$(basename $0): Entering $(dirname $0)/$(basename $0)" + +iflag= +aflag= +dflag= +sflag= + +while getopts 'i:a:d:s:' OPTION +do + case $OPTION in + i) iflag=1 + domRIp="$OPTARG" #unused but passed in + ;; + a) aflag=1 + addedIps="$OPTARG" + ;; + d) dflag=1 + removedIps="$OPTARG" + ;; + + s) sflag=1 + statsIp="$OPTARG" + ;; + ?) usage + unlock_exit 2 $lock $locked + ;; + esac +done + +if [[ "$aflag$dflag" != "1" && "$aflag$dflag" != "11" ]] +then + usage + unlock_exit 2 $lock $locked +fi + +if [ "$addedIps" == "" ] +then + addedIps="none" +fi + + +if [ "$removedIps" == "" ] +then + removedIps="none" +fi + + +# hot reconfigure haproxy +reconfig_lb $cfgfile + +if [ $? -gt 0 ] +then + logger -t cloud "Reconfiguring ilb failed" + unlock_exit 1 $lock $locked +fi + +logger -t cloud "HAProxy reconfigured successfully, configuring firewall" + +# iptables entry to ensure that haproxy receives traffic +fw_entry $addedIps $removedIps $statsIp + +if [ $? -gt 0 ] +then + logger -t cloud "Failed to apply firewall rules for internal load balancing, reverting HA Proxy config" + # Restore the LB + restore_lb + + logger -t cloud "Reverting firewall config" + fw_restore + + unlock_exit 1 $lock $locked +else + # Remove backedup iptable rules + logger -t cloud "Firewall configured successfully, deleting backup firewall config" + fw_remove_backup +fi + +unlock_exit 0 $lock $locked diff --git a/patches/systemvm/debian/config/opt/cloud/bin/patchsystemvm.sh b/patches/systemvm/debian/config/opt/cloud/bin/patchsystemvm.sh index 8816ad7c068..9cb02502ef1 100755 --- a/patches/systemvm/debian/config/opt/cloud/bin/patchsystemvm.sh +++ b/patches/systemvm/debian/config/opt/cloud/bin/patchsystemvm.sh @@ -135,6 +135,19 @@ elbvm_svcs() { echo "cloud dnsmasq cloud-passwd-srvr apache2 nfs-common portmap" > /var/cache/cloud/disabled_svcs } + +ilbvm_svcs() { + chkconfig cloud off + chkconfig haproxy on ; + chkconfig ssh on + chkconfig nfs-common off + chkconfig portmap off + chkconfig keepalived off + chkconfig conntrackd off + echo "ssh haproxy" > /var/cache/cloud/enabled_svcs + echo "cloud dnsmasq cloud-passwd-srvr apache2 nfs-common portmap" > /var/cache/cloud/disabled_svcs +} + enable_pcihotplug() { sed -i -e "/acpiphp/d" /etc/modules sed -i -e "/pci_hotplug/d" /etc/modules @@ -253,4 +266,14 @@ then fi fi +if [ "$TYPE" == "ilbvm" ] +then + ilbvm_svcs + if [ $? -gt 0 ] + then + printf "Failed to execute ilbvm svcs\n" >$logfile + exit 9 + fi +fi + exit $? diff --git a/patches/systemvm/debian/config/opt/cloud/bin/vpc_loadbalancer.sh b/patches/systemvm/debian/config/opt/cloud/bin/vpc_loadbalancer.sh index 334c6177392..36a2347a297 100755 --- a/patches/systemvm/debian/config/opt/cloud/bin/vpc_loadbalancer.sh +++ b/patches/systemvm/debian/config/opt/cloud/bin/vpc_loadbalancer.sh @@ -18,6 +18,29 @@ # @VERSION@ +do_ilb_if_ilb () { + local typ="" + local pattern="type=(.*)" + + for keyval in $(cat /var/cache/cloud/cmdline) + do + if [[ $keyval =~ $pattern ]]; then + typ=${BASH_REMATCH[1]}; + fi + done + if [ "$typ" == "ilbvm" ] + then + logger -t cloud "$(basename $0): Detected that we are running in an internal load balancer vm" + $(dirname $0)/ilb.sh "$@" + exit $? + fi + +} + +logger -t cloud "$(basename $0): Entering $(dirname $0)/$(basename $0)" + +do_ilb_if_ilb "$@" + source /root/func.sh source /opt/cloud/bin/vpc_func.sh diff --git a/patches/systemvm/debian/config/opt/cloud/bin/vpc_privateGateway.sh b/patches/systemvm/debian/config/opt/cloud/bin/vpc_privateGateway.sh index a09d8f7e38b..3635e1cd44c 100755 --- a/patches/systemvm/debian/config/opt/cloud/bin/vpc_privateGateway.sh +++ b/patches/systemvm/debian/config/opt/cloud/bin/vpc_privateGateway.sh @@ -91,7 +91,7 @@ fi if [ "$Dflag" == "1" ] then - remove_sat $publicIp + remove_snat $publicIp unlock_exit $? $lock $locked fi diff --git a/patches/systemvm/debian/config/root/edithosts.sh b/patches/systemvm/debian/config/root/edithosts.sh index 1f98fbf96ae..fb0c34fbd42 100755 --- a/patches/systemvm/debian/config/root/edithosts.sh +++ b/patches/systemvm/debian/config/root/edithosts.sh @@ -19,12 +19,6 @@ # edithosts.sh -- edit the dhcphosts file on the routing domain -# $mac : the mac address -# $ip : the associated ip address -# $host : the hostname -# $4 : default router -# $5 : nameserver on default nic -# $6 : comma separated static routes usage() { printf "Usage: %s: -m -4 -6 -h -d -n -s -u [-N]\n" $(basename $0) >&2 @@ -84,6 +78,9 @@ fi grep "redundant_router=1" /var/cache/cloud/cmdline > /dev/null no_redundant=$? +command -v dhcp_release > /dev/null 2>&1 +no_dhcp_release=$? + wait_for_dnsmasq () { local _pid=$(pidof dnsmasq) for i in 0 1 2 3 4 5 6 7 8 9 10 @@ -97,7 +94,15 @@ wait_for_dnsmasq () { return 1 } -logger -t cloud "edithosts: update $1 $2 $3 to hosts" +if [ $no_dhcp_release -eq 0 ] +then + #release previous dhcp lease if present + logger -t cloud "edithosts: releasing $ipv4" + dhcp_release lo $ipv4 $(grep $ipv4 $DHCP_LEASES | awk '{print $2}') > /dev/null 2>&1 + logger -t cloud "edithosts: released $ipv4" +fi + +logger -t cloud "edithosts: update $mac $ipv4 $ipv6 $host to hosts" [ ! -f $DHCP_HOSTS ] && touch $DHCP_HOSTS [ ! -f $DHCP_OPTS ] && touch $DHCP_OPTS @@ -113,7 +118,8 @@ if [ $ipv6 ] then sed -i /$ipv6,/d $DHCP_HOSTS fi -sed -i /$host,/d $DHCP_HOSTS +# don't want to do this in the future, we can have same VM with multiple nics/entries +#sed -i /$host,/d $DHCP_HOSTS #put in the new entry @@ -200,8 +206,13 @@ fi pid=$(pidof dnsmasq) if [ "$pid" != "" ] then - #service dnsmasq restart - kill -HUP $pid + # use SIGHUP to avoid service outage if dhcp_release is available. + if [ $no_dhcp_release -eq 0 ] + then + kill -HUP $pid + else + service dnsmasq restart + fi else if [ $no_redundant -eq 1 ] then diff --git a/plugins/api/discovery/src/org/apache/cloudstack/discovery/ApiDiscoveryServiceImpl.java b/plugins/api/discovery/src/org/apache/cloudstack/discovery/ApiDiscoveryServiceImpl.java index 2d7dbd18671..860240faef0 100755 --- a/plugins/api/discovery/src/org/apache/cloudstack/discovery/ApiDiscoveryServiceImpl.java +++ b/plugins/api/discovery/src/org/apache/cloudstack/discovery/ApiDiscoveryServiceImpl.java @@ -83,6 +83,9 @@ public class ApiDiscoveryServiceImpl implements ApiDiscoveryService { } String apiName = apiCmdAnnotation.name(); + if (s_logger.isTraceEnabled()) { + s_logger.trace("Found api: " + apiName); + } ApiDiscoveryResponse response = getCmdRequestMap(cmdClass, apiCmdAnnotation); String responseName = apiCmdAnnotation.responseObject().getName(); @@ -216,6 +219,7 @@ public class ApiDiscoveryServiceImpl implements ApiDiscoveryService { try { apiChecker.checkAccess(user, name); } catch (Exception ex) { + s_logger.debug("API discovery access check failed for " + name + " with " + ex.getMessage()); return null; } } diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 0064edf6a68..8fe8c88d0f8 100755 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -1756,7 +1756,7 @@ ServerResource { String netmask = Long.toString(NetUtils.getCidrSize(ip.getVlanNetmask())); String subnet = NetUtils.getSubNet(ip.getPublicIp(), ip.getVlanNetmask()); _virtRouterResource.assignVpcIpToRouter(routerIP, ip.isAdd(), ip.getPublicIp(), - nicName, ip.getVlanGateway(), netmask, subnet); + nicName, ip.getVlanGateway(), netmask, subnet, ip.isSourceNat()); results[i++] = ip.getPublicIp() + " - success"; } diff --git a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/SimulatorManagerImpl.java b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/SimulatorManagerImpl.java index c234cc5cb2e..ab6eec3394a 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/SimulatorManagerImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/SimulatorManagerImpl.java @@ -16,12 +16,74 @@ // under the License. package com.cloud.agent.manager; -import com.cloud.agent.api.*; +import java.util.HashMap; +import java.util.Map; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.AttachIsoCommand; +import com.cloud.agent.api.AttachVolumeCommand; +import com.cloud.agent.api.BackupSnapshotCommand; +import com.cloud.agent.api.BumpUpPriorityCommand; +import com.cloud.agent.api.CheckHealthCommand; +import com.cloud.agent.api.CheckNetworkCommand; +import com.cloud.agent.api.CheckRouterCommand; +import com.cloud.agent.api.CheckVirtualMachineCommand; +import com.cloud.agent.api.CleanupNetworkRulesCmd; +import com.cloud.agent.api.ClusterSyncCommand; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.ComputeChecksumCommand; +import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand; +import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand; +import com.cloud.agent.api.CreateStoragePoolCommand; +import com.cloud.agent.api.CreateVolumeFromSnapshotCommand; +import com.cloud.agent.api.DeleteSnapshotBackupCommand; +import com.cloud.agent.api.DeleteStoragePoolCommand; +import com.cloud.agent.api.GetDomRVersionCmd; +import com.cloud.agent.api.GetHostStatsCommand; +import com.cloud.agent.api.GetStorageStatsCommand; +import com.cloud.agent.api.GetVmStatsCommand; +import com.cloud.agent.api.GetVncPortCommand; +import com.cloud.agent.api.MaintainCommand; +import com.cloud.agent.api.ManageSnapshotCommand; +import com.cloud.agent.api.MigrateCommand; +import com.cloud.agent.api.ModifyStoragePoolCommand; +import com.cloud.agent.api.NetworkUsageCommand; +import com.cloud.agent.api.PingTestCommand; +import com.cloud.agent.api.PrepareForMigrationCommand; +import com.cloud.agent.api.RebootCommand; +import com.cloud.agent.api.SecStorageSetupCommand; +import com.cloud.agent.api.SecStorageVMSetupCommand; +import com.cloud.agent.api.SecurityGroupRulesCmd; +import com.cloud.agent.api.StartCommand; +import com.cloud.agent.api.StopCommand; +import com.cloud.agent.api.StoragePoolInfo; import com.cloud.agent.api.check.CheckSshCommand; import com.cloud.agent.api.proxy.CheckConsoleProxyLoadCommand; import com.cloud.agent.api.proxy.WatchConsoleProxyLoadCommand; -import com.cloud.agent.api.routing.*; -import com.cloud.agent.api.storage.*; +import com.cloud.agent.api.routing.DhcpEntryCommand; +import com.cloud.agent.api.routing.IpAssocCommand; +import com.cloud.agent.api.routing.LoadBalancerConfigCommand; +import com.cloud.agent.api.routing.SavePasswordCommand; +import com.cloud.agent.api.routing.SetFirewallRulesCommand; +import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; +import com.cloud.agent.api.routing.SetStaticNatRulesCommand; +import com.cloud.agent.api.routing.VmDataCommand; +import com.cloud.agent.api.storage.CopyVolumeCommand; +import com.cloud.agent.api.storage.CreateCommand; +import com.cloud.agent.api.storage.DeleteTemplateCommand; +import com.cloud.agent.api.storage.DestroyCommand; +import com.cloud.agent.api.storage.DownloadCommand; +import com.cloud.agent.api.storage.DownloadProgressCommand; +import com.cloud.agent.api.storage.ListTemplateCommand; +import com.cloud.agent.api.storage.ListVolumeCommand; +import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; import com.cloud.simulator.MockConfigurationVO; import com.cloud.simulator.MockHost; import com.cloud.simulator.MockVMVO; @@ -34,14 +96,6 @@ import com.cloud.utils.db.DB; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VirtualMachine.State; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; -import java.util.HashMap; -import java.util.Map; @Component @Local(value = { SimulatorManager.class }) @@ -256,7 +310,7 @@ public class SimulatorManagerImpl extends ManagerBase implements SimulatorManage return Answer.createUnsupportedCommandAnswer(cmd); } } catch(Exception e) { - s_logger.error("Failed execute cmd: " + e.toString()); + s_logger.error("Failed execute cmd: ", e); txn.rollback(); return new Answer(cmd, false, e.toString()); } finally { diff --git a/plugins/hypervisors/simulator/src/com/cloud/simulator/MockSecStorageVO.java b/plugins/hypervisors/simulator/src/com/cloud/simulator/MockSecStorageVO.java index 532d2a7ff56..87905eedbd1 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/simulator/MockSecStorageVO.java +++ b/plugins/hypervisors/simulator/src/com/cloud/simulator/MockSecStorageVO.java @@ -48,6 +48,7 @@ public class MockSecStorageVO implements InternalIdentity { } + @Override public long getId() { return this.id; } @@ -57,7 +58,7 @@ public class MockSecStorageVO implements InternalIdentity { } public void setMountPoint(String mountPoint) { - this.mountPoint = mountPoint; + this.mountPoint = mountPoint.replace('\\', '/'); } public String getUrl() { diff --git a/plugins/hypervisors/simulator/src/com/cloud/simulator/MockStoragePoolVO.java b/plugins/hypervisors/simulator/src/com/cloud/simulator/MockStoragePoolVO.java index 06aa169a62a..7f1b7ccf610 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/simulator/MockStoragePoolVO.java +++ b/plugins/hypervisors/simulator/src/com/cloud/simulator/MockStoragePoolVO.java @@ -66,6 +66,7 @@ public class MockStoragePoolVO implements InternalIdentity { this.hostGuid = hostGuid; } + @Override public long getId() { return this.id; } @@ -91,7 +92,7 @@ public class MockStoragePoolVO implements InternalIdentity { } public void setMountPoint(String mountPoint) { - this.mountPoint = mountPoint; + this.mountPoint = mountPoint.replace('\\', '/'); } public long getCapacity() { diff --git a/plugins/hypervisors/simulator/src/com/cloud/simulator/MockVolumeVO.java b/plugins/hypervisors/simulator/src/com/cloud/simulator/MockVolumeVO.java index 6dd59e8507c..b7191b887f6 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/simulator/MockVolumeVO.java +++ b/plugins/hypervisors/simulator/src/com/cloud/simulator/MockVolumeVO.java @@ -66,6 +66,7 @@ public class MockVolumeVO implements InternalIdentity { @Enumerated(value=EnumType.STRING) private VMTemplateStorageResourceAssoc.Status status; + @Override public long getId() { return id; } @@ -90,7 +91,7 @@ public class MockVolumeVO implements InternalIdentity { } public void setPath(String path) { - this.path = path; + this.path = path.replace('\\', '/'); } public long getPoolId() { diff --git a/plugins/hypervisors/vmware/pom.xml b/plugins/hypervisors/vmware/pom.xml index d65ef640655..79779decf62 100644 --- a/plugins/hypervisors/vmware/pom.xml +++ b/plugins/hypervisors/vmware/pom.xml @@ -58,5 +58,15 @@ wsdl4j 1.4 + + junit + junit + 4.10 + + + org.mockito + mockito-all + 1.9.5 + diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java index ee1b3245126..55bb1e98366 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java @@ -38,6 +38,8 @@ import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand; import com.cloud.agent.api.CreateVolumeFromSnapshotCommand; import com.cloud.agent.api.UnregisterVMCommand; import com.cloud.agent.api.storage.CopyVolumeCommand; +import com.cloud.agent.api.storage.CreateVolumeOVACommand; +import com.cloud.agent.api.storage.PrepareOVAPackingCommand; import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; @@ -282,10 +284,18 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru { cmd instanceof CreatePrivateTemplateFromVolumeCommand || cmd instanceof CreatePrivateTemplateFromSnapshotCommand || cmd instanceof CopyVolumeCommand || + cmd instanceof CreateVolumeOVACommand || + cmd instanceof PrepareOVAPackingCommand || cmd instanceof CreateVolumeFromSnapshotCommand) { needDelegation = true; } + /* Fang: remove this before checking in */ + // needDelegation = false; + if (cmd instanceof PrepareOVAPackingCommand || + cmd instanceof CreateVolumeOVACommand ) { + cmd.setContextParam("hypervisor", HypervisorType.VMware.toString()); + } if(needDelegation) { HostVO host = _hostDao.findById(hostId); assert(host != null); @@ -311,6 +321,8 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru { cmd instanceof CreatePrivateTemplateFromVolumeCommand || cmd instanceof CreatePrivateTemplateFromSnapshotCommand || cmd instanceof CopyVolumeCommand || + cmd instanceof CreateVolumeOVACommand || + cmd instanceof PrepareOVAPackingCommand || cmd instanceof CreateVolumeFromSnapshotCommand) { String workerName = _vmwareMgr.composeWorkerName(); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java index eb09af0d67e..9f260f1812c 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -494,7 +494,8 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw s_logger.info("Inject SSH key pairs before copying systemvm.iso into secondary storage"); _configServer.updateKeyPairs(); - + s_logger.info("Copy System VM patch ISO file to secondary storage. source ISO: " + srcIso.getAbsolutePath() + + ", destination: " + destIso.getAbsolutePath()); try { FileUtil.copyfile(srcIso, destIso); } catch(IOException e) { diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java index a2e517d1fdb..8c0603e29e7 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java @@ -25,6 +25,8 @@ import com.cloud.agent.api.CreateVolumeFromSnapshotCommand; import com.cloud.agent.api.DeleteVMSnapshotCommand; import com.cloud.agent.api.RevertToVMSnapshotCommand; import com.cloud.agent.api.storage.CopyVolumeCommand; +import com.cloud.agent.api.storage.PrepareOVAPackingCommand; +import com.cloud.agent.api.storage.CreateVolumeOVACommand; import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; public interface VmwareStorageManager { @@ -33,6 +35,8 @@ public interface VmwareStorageManager { Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromVolumeCommand cmd); Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromSnapshotCommand cmd); Answer execute(VmwareHostService hostService, CopyVolumeCommand cmd); + Answer execute(VmwareHostService hostService, CreateVolumeOVACommand cmd); + Answer execute(VmwareHostService hostService, PrepareOVAPackingCommand cmd); Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCommand cmd); Answer execute(VmwareHostService hostService, CreateVMSnapshotCommand cmd); Answer execute(VmwareHostService hostService, DeleteVMSnapshotCommand cmd); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java index 1f116455761..9f1351e96f3 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java @@ -18,12 +18,14 @@ package com.cloud.hypervisor.vmware.manager; import java.io.BufferedWriter; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.OutputStreamWriter; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Properties; import java.util.Map; import java.util.UUID; @@ -44,6 +46,10 @@ import com.cloud.agent.api.RevertToVMSnapshotAnswer; import com.cloud.agent.api.RevertToVMSnapshotCommand; import com.cloud.agent.api.storage.CopyVolumeAnswer; import com.cloud.agent.api.storage.CopyVolumeCommand; +import com.cloud.agent.api.storage.PrepareOVAPackingAnswer; +import com.cloud.agent.api.storage.PrepareOVAPackingCommand; +import com.cloud.agent.api.storage.CreateVolumeOVAAnswer; +import com.cloud.agent.api.storage.CreateVolumeOVACommand; import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer; import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer; import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; @@ -102,6 +108,109 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { _timeout = NumbersUtil.parseInt(value, 1440) * 1000; } + //Fang note: use Answer here instead of the PrepareOVAPackingAnswer + @Override + public Answer execute(VmwareHostService hostService, PrepareOVAPackingCommand cmd) { + String secStorageUrl = ((PrepareOVAPackingCommand) cmd).getSecondaryStorageUrl(); + assert (secStorageUrl != null); + String installPath = cmd.getTemplatePath(); + String details = null; + boolean success = false; + String ovafileName = ""; + s_logger.info("Fang: execute OVAPacking cmd at vmwareMngImpl. "); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + // String installPath = getTemplateRelativeDirInSecStorage(accountId, templateId); + String installFullPath = secondaryMountPoint + "/" + installPath; + + String templateName = installFullPath; // should be a file ending .ova; + s_logger.info("Fang: execute vmwareMgrImpl: templateNAme " + templateName); + // Fang: Dir list, if there is ova file, done; Fang: add answer cmd; + // if not, from ova.meta, create a new OVA file; + // change the install path to *.ova , not ova.meta; + // VmwareContext context = hostService.getServiceContext(cmd); //Fang: we may not have the CTX here + try { + if (templateName.endsWith(".ova")) { + if(new File(templateName).exists()) { + details = "OVA files exists. succeed. "; + return new Answer(cmd, true, details); + } else { + if (new File(templateName + ".meta").exists()) { //Fang parse the meta file + //execute the tar command; + s_logger.info("Fang: execute vmwareMgrImpl: getfromMeta " + templateName); + ovafileName = getOVAFromMetafile(templateName + ".meta"); + details = "OVA file in meta file is " + ovafileName; + return new Answer(cmd, true, details); + } else { + String msg = "Unable to find ova meta or ova file to prepare template (vmware)"; + s_logger.error(msg); + throw new Exception(msg); + } + } + } + } catch (Throwable e) { + if (e instanceof RemoteException) { + //hostService.invalidateServiceContext(context); do not need context + s_logger.error("Unable to connect to remote service "); + details = "Unable to connect to remote service "; + return new Answer(cmd, false, details); + } + String msg = "Unable to execute PrepareOVAPackingCommand due to exception"; + s_logger.error(msg, e); + return new Answer(cmd, false, details); + } + return new Answer(cmd, true, details); + } + + //Fang: new command added; + // Important! we need to sync file system before we can safely use tar to work around a linux kernal bug(or feature) + @Override + public Answer execute(VmwareHostService hostService, CreateVolumeOVACommand cmd) { + String secStorageUrl = ((CreateVolumeOVACommand) cmd).getSecondaryStorageUrl(); + assert (secStorageUrl != null); + String installPath = cmd.getVolPath(); + String details = null; + boolean success = false; + + s_logger.info("volss: execute CreateVolumeOVA cmd at vmwareMngImpl. "); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + // String installPath = getTemplateRelativeDirInSecStorage(accountId, templateId); + s_logger.info("volss: mountPoint: " + secondaryMountPoint + "installPath:" + installPath); + String installFullPath = secondaryMountPoint + "/" + installPath; + + String volName = cmd.getVolName(); // should be a UUID, without ova ovf, etc; + s_logger.info("volss: execute vmwareMgrImpl: VolName " + volName); + // Fang: Dir list, if there is ova file, done; Note: add answer cmd; + + try { + if(new File(volName + ".ova").exists()) { + details = "OVA files exists. succeed. "; + return new CreateVolumeOVAAnswer(cmd, true, details); + } else { + File ovaFile = new File(installFullPath); + String exportDir = ovaFile.getParent(); + + s_logger.info("Fang: exportDir is (for VolumeOVA): " + exportDir); + s_logger.info("Sync file system before we package OVA..."); + + Script commandSync = new Script(true, "sync", 0, s_logger); + commandSync.execute(); + + Script command = new Script(false, "tar", 0, s_logger); + command.setWorkDir(exportDir); + command.add("-cf", volName + ".ova"); + command.add(volName + ".ovf"); // OVF file should be the first file in OVA archive + command.add(volName + "-disk0.vmdk"); + + s_logger.info("Package Volume OVA with commmand: " + command.toString()); + command.execute(); + return new CreateVolumeOVAAnswer(cmd, true, details); + } + } catch (Throwable e) { + s_logger.info("Exception for createVolumeOVA"); + } + return new CreateVolumeOVAAnswer(cmd, true, "fail to pack OVA for volume"); + } + @Override public Answer execute(VmwareHostService hostService, PrimaryStorageDownloadCommand cmd) { String secondaryStorageUrl = cmd.getSecondaryStorageUrl(); @@ -570,11 +679,14 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); String installPath = getTemplateRelativeDirInSecStorage(accountId, templateId); String installFullPath = secondaryMountPoint + "/" + installPath; - String installFullName = installFullPath + "/" + templateUniqueName + ".ova"; - String snapshotFullName = secondaryMountPoint + "/" + getSnapshotRelativeDirInSecStorage(accountId, volumeId) - + "/" + backedUpSnapshotUuid + ".ova"; + String installFullOVAName = installFullPath + "/" + templateUniqueName + ".ova"; //Note: volss for tmpl + String snapshotRoot = secondaryMountPoint + "/" + getSnapshotRelativeDirInSecStorage(accountId, volumeId); + String snapshotFullOVAName = snapshotRoot + "/" + backedUpSnapshotUuid + ".ova"; + String snapshotFullOvfName = snapshotRoot + "/" + backedUpSnapshotUuid + ".ovf"; String result; Script command; + String templateVMDKName = ""; + String snapshotFullVMDKName = snapshotRoot + "/"; synchronized(installPath.intern()) { command = new Script(false, "mkdir", _timeout, s_logger); @@ -591,40 +703,85 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { } try { - command = new Script(false, "cp", _timeout, s_logger); - command.add(snapshotFullName); - command.add(installFullName); - result = command.execute(); - if(result != null) { - String msg = "unable to copy snapshot " + snapshotFullName + " to " + installFullPath; + if(new File(snapshotFullOVAName).exists()) { + command = new Script(false, "cp", _timeout, s_logger); + command.add(snapshotFullOVAName); + command.add(installFullOVAName); + result = command.execute(); + if(result != null) { + String msg = "unable to copy snapshot " + snapshotFullOVAName + " to " + installFullPath; + s_logger.error(msg); + throw new Exception(msg); + } + + // untar OVA file at template directory + command = new Script("tar", 0, s_logger); + command.add("--no-same-owner"); + command.add("-xf", installFullOVAName); + command.setWorkDir(installFullPath); + s_logger.info("Executing command: " + command.toString()); + result = command.execute(); + if(result != null) { + String msg = "unable to untar snapshot " + snapshotFullOVAName + " to " + + installFullPath; + s_logger.error(msg); + throw new Exception(msg); + } + + } else { // there is no ova file, only ovf originally; + if(new File(snapshotFullOvfName).exists()) { + command = new Script(false, "cp", _timeout, s_logger); + command.add(snapshotFullOvfName); + //command.add(installFullOvfName); + command.add(installFullPath); + result = command.execute(); + if(result != null) { + String msg = "unable to copy snapshot " + snapshotFullOvfName + " to " + installFullPath; + s_logger.error(msg); + throw new Exception(msg); + } + + File snapshotdir = new File(snapshotRoot); + File[] ssfiles = snapshotdir.listFiles(); + // List filenames = new ArrayList(); + for (int i = 0; i < ssfiles.length; i++) { + String vmdkfile = ssfiles[i].getName(); + if(vmdkfile.toLowerCase().startsWith(backedUpSnapshotUuid) && vmdkfile.toLowerCase().endsWith(".vmdk")) { + snapshotFullVMDKName += vmdkfile; + templateVMDKName += vmdkfile; + break; + } + } + if (snapshotFullVMDKName != null) { + command = new Script(false, "cp", _timeout, s_logger); + command.add(snapshotFullVMDKName); + command.add(installFullPath); + result = command.execute(); + s_logger.info("Copy VMDK file: " + snapshotFullVMDKName); + if(result != null) { + String msg = "unable to copy snapshot vmdk file " + snapshotFullVMDKName + " to " + installFullPath; + s_logger.error(msg); + throw new Exception(msg); + } + } + } else { + String msg = "unable to find any snapshot ova/ovf files" + snapshotFullOVAName + " to " + installFullPath; s_logger.error(msg); throw new Exception(msg); + } } - // untar OVA file at template directory - command = new Script("tar", 0, s_logger); - command.add("--no-same-owner"); - command.add("-xf", installFullName); - command.setWorkDir(installFullPath); - s_logger.info("Executing command: " + command.toString()); - result = command.execute(); - if(result != null) { - String msg = "unable to untar snapshot " + snapshotFullName + " to " - + installFullPath; - s_logger.error(msg); - throw new Exception(msg); - } - - long physicalSize = new File(installFullPath + "/" + templateUniqueName + ".ova").length(); + long physicalSize = new File(installFullPath + "/" + templateVMDKName).length(); VmdkProcessor processor = new VmdkProcessor(); + // long physicalSize = new File(installFullPath + "/" + templateUniqueName + ".ova").length(); Map params = new HashMap(); params.put(StorageLayer.InstanceConfigKey, _storage); processor.configure("VMDK Processor", params); long virtualSize = processor.getTemplateVirtualSize(installFullPath, templateUniqueName); postCreatePrivateTemplate(installFullPath, templateId, templateUniqueName, physicalSize, virtualSize); + writeMetaOvaForTemplate(installFullPath, backedUpSnapshotUuid + ".ovf", templateVMDKName, templateUniqueName, physicalSize); return new Ternary(installPath + "/" + templateUniqueName + ".ova", physicalSize, virtualSize); - } catch(Exception e) { // TODO, clean up left over files throw e; @@ -648,7 +805,8 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { out.newLine(); out.write("size=" + size); out.newLine(); - out.write("ova=true"); + //out.write("ova=true"); + out.write("ova=false"); //volss: the real ova file is not created out.newLine(); out.write("id=" + templateId); out.newLine(); @@ -670,6 +828,31 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { } } + private void writeMetaOvaForTemplate(String installFullPath, String ovfFilename, String vmdkFilename, + String templateName, long diskSize) throws Exception { + + // TODO a bit ugly here + BufferedWriter out = null; + try { + out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(installFullPath + "/" + templateName +".ova.meta"))); + out.write("ova.filename=" + templateName + ".ova"); + out.newLine(); + out.write("version=1.0"); + out.newLine(); + out.write("ovf=" + ovfFilename); + out.newLine(); + out.write("numDisks=1"); + out.newLine(); + out.write("disk1.name=" + vmdkFilename); + out.newLine(); + out.write("disk1.size=" + diskSize); + out.newLine(); + } finally { + if(out != null) + out.close(); + } + } + private String createVolumeFromSnapshot(VmwareHypervisorHost hyperHost, DatastoreMO primaryDsMo, String newVolumeName, long accountId, long volumeId, String secStorageUrl, String snapshotBackupUuid) throws Exception { @@ -688,23 +871,35 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { if (backupName.contains("/")){ snapshotDir = backupName.split("/")[0]; } - String srcFileName = getOVFFilePath(srcOVAFileName); - if(srcFileName == null) { - Script command = new Script("tar", 0, s_logger); - command.add("--no-same-owner"); - command.add("-xf", srcOVAFileName); - command.setWorkDir(secondaryMountPoint + "/" + secStorageDir + "/" + snapshotDir); - s_logger.info("Executing command: " + command.toString()); - String result = command.execute(); - if(result != null) { - String msg = "Unable to unpack snapshot OVA file at: " + srcOVAFileName; - s_logger.error(msg); - throw new Exception(msg); - } - } - srcFileName = getOVFFilePath(srcOVAFileName); - if(srcFileName == null) { + File ovafile = new File(srcOVAFileName); + String srcOVFFileName = secondaryMountPoint + "/" + secStorageDir + "/" + + backupName + ".ovf"; + File ovfFile = new File(srcOVFFileName); + // String srcFileName = getOVFFilePath(srcOVAFileName); + if (!ovfFile.exists()) { + srcOVFFileName = getOVFFilePath(srcOVAFileName); + if(srcOVFFileName == null && ovafile.exists() ) { // volss: ova file exists; o/w can't do tar + Script command = new Script("tar", 0, s_logger); + command.add("--no-same-owner"); + command.add("-xf", srcOVAFileName); + command.setWorkDir(secondaryMountPoint + "/" + secStorageDir + "/" + snapshotDir); + s_logger.info("Executing command: " + command.toString()); + String result = command.execute(); + if(result != null) { + String msg = "Unable to unpack snapshot OVA file at: " + srcOVAFileName; + s_logger.error(msg); + throw new Exception(msg); + } + } else { + String msg = "Unable to find snapshot OVA file at: " + srcOVAFileName; + s_logger.error(msg); + throw new Exception(msg); + } + + srcOVFFileName = getOVFFilePath(srcOVAFileName); + } + if(srcOVFFileName == null) { String msg = "Unable to locate OVF file in template package directory: " + srcOVAFileName; s_logger.error(msg); throw new Exception(msg); @@ -712,7 +907,7 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { VirtualMachineMO clonedVm = null; try { - hyperHost.importVmFromOVF(srcFileName, newVolumeName, primaryDsMo, "thin"); + hyperHost.importVmFromOVF(srcOVFFileName, newVolumeName, primaryDsMo, "thin"); clonedVm = hyperHost.findVmOnHyperHost(newVolumeName); if(clonedVm == null) throw new Exception("Unable to create container VM for volume creation"); @@ -774,7 +969,7 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { throw new Exception(msg); } - clonedVm.exportVm(exportPath, exportName, true, true); + clonedVm.exportVm(exportPath, exportName, false, false); //Note: volss: not to create ova. } finally { if(clonedVm != null) { clonedVm.detachAllDisks(); @@ -787,17 +982,31 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); String snapshotMountRoot = secondaryMountPoint + "/" + getSnapshotRelativeDirInSecStorage(accountId, volumeId); - File file = new File(snapshotMountRoot + "/" + backupUuid + ".ova"); + File file = new File(snapshotMountRoot + "/" + backupUuid + ".ovf"); if(file.exists()) { - if(file.delete()) - return null; - - } else { - return "Backup file does not exist. backupUuid: " + backupUuid; - } - - return "Failed to delete snapshot backup file, backupUuid: " + backupUuid; - } + File snapshotdir = new File(snapshotMountRoot); + File[] ssfiles = snapshotdir.listFiles(); + // List filenames = new ArrayList(); + for (int i = 0; i < ssfiles.length; i++) { + String vmdkfile = ssfiles[i].getName(); + if(vmdkfile.toLowerCase().startsWith(backupUuid) && vmdkfile.toLowerCase().endsWith(".vmdk")) { + // filenames.add(vmdkfile); + new File(vmdkfile).delete(); + } + } + if(file.delete()) + return null; + } else { + File file1 = new File(snapshotMountRoot + "/" + backupUuid + ".ova"); + if(file1.exists()) { + if(file1.delete()) + return null; + } else { + return "Backup file does not exist. backupUuid: " + backupUuid; + } + } + return "Failed to delete snapshot backup file, backupUuid: " + backupUuid; + } private Pair copyVolumeToSecStorage(VmwareHostService hostService, VmwareHypervisorHost hyperHost, CopyVolumeCommand cmd, String vmName, long volumeId, String poolId, String volumePath, @@ -881,6 +1090,92 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { return new Pair(volumeFolder, newVolume); } + //Fang: here I use a method to return the ovf and vmdk file names; Another way to do it: + // create a new class, and like TemplateLocation.java and create templateOvfInfo.java to handle it; + private String getOVAFromMetafile(String metafileName) throws Exception { + File ova_metafile = new File(metafileName); + Properties props = null; + FileInputStream strm = null; + String ovaFileName = ""; + s_logger.info("Fang: getOVAfromMetaFile: metafileName " + metafileName); + try { + strm = new FileInputStream(ova_metafile); + if (null == strm) { + String msg = "Cannot read ova meat file. Error"; + s_logger.error(msg); + throw new Exception(msg); + } + + s_logger.info("Fang: getOVAfromMetaFile: load strm " ); + if (null != ova_metafile) { + props = new Properties(); + props.load(strm); + if (props == null) { + s_logger.info("Fang: getOVAfromMetaFile: props is null. " ); + } + } + if (null != props) { + ovaFileName = props.getProperty("ova.filename"); + s_logger.info("Fang: ovafilename" + ovaFileName); + String ovfFileName = props.getProperty("ovf"); + s_logger.info("Fang: ovffilename" + ovfFileName); + int diskNum = Integer.parseInt(props.getProperty("numDisks")); + if (diskNum <= 0) { + String msg = "VMDK disk file number is 0. Error"; + s_logger.error(msg); + throw new Exception(msg); + } + String[] disks = new String[diskNum]; + for (int i = 0; i < diskNum; i++) { + //String diskNameKey = "disk" + Integer.toString(i+1) + ".name"; // Fang use this + String diskNameKey = "disk1.name"; + disks[i] = props.getProperty(diskNameKey); + s_logger.info("Fang: diskname " + disks[i]); + } + String exportDir = ova_metafile.getParent(); + s_logger.info("Fang: exportDir: " + exportDir); + // Important! we need to sync file system before we can safely use tar to work around a linux kernal bug(or feature) + s_logger.info("Fang: Sync file system before we package OVA..., before tar "); + s_logger.info("Fang: ova: " + ovaFileName+ ", ovf:" + ovfFileName + ", vmdk:" + disks[0] + "."); + Script commandSync = new Script(true, "sync", 0, s_logger); + commandSync.execute(); + Script command = new Script(false, "tar", 0, s_logger); + command.setWorkDir(exportDir); //Fang: pass this in to the method? + command.add("-cf", ovaFileName); + command.add(ovfFileName); // OVF file should be the first file in OVA archive + for(String diskName: disks) { + command.add(diskName); + } + command.execute(); + s_logger.info("Fang: Package OVA for template in dir: " + exportDir + "cmd: " + command.toString()); + // to be safe, physically test existence of the target OVA file + if((new File(exportDir + ovaFileName)).exists()) { + s_logger.info("Fang: ova file is created and ready to extract "); + return (ovaFileName); + } else { + String msg = exportDir + File.separator + ovaFileName + ".ova is not created as expected"; + s_logger.error(msg); + throw new Exception(msg); + } + } else { + String msg = "Error reading the ova meta file: " + metafileName; + s_logger.error(msg); + throw new Exception(msg); + } + } catch (Exception e) { + return null; + //Do something, re-throw the exception + } finally { + if (strm != null) { + try { + strm.close(); + } catch (Exception e) { + } + } + } + + } + private String getOVFFilePath(String srcOVAFileName) { File file = new File(srcOVAFileName); assert(_storage != null); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 99ad1ca60b2..6d7e0e7289c 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -111,6 +111,8 @@ import com.cloud.agent.api.RebootCommand; import com.cloud.agent.api.RebootRouterCommand; import com.cloud.agent.api.RevertToVMSnapshotAnswer; import com.cloud.agent.api.RevertToVMSnapshotCommand; +import com.cloud.agent.api.ScaleVmCommand; +import com.cloud.agent.api.ScaleVmAnswer; import com.cloud.agent.api.SetupAnswer; import com.cloud.agent.api.SetupCommand; import com.cloud.agent.api.SetupGuestNetworkAnswer; @@ -155,6 +157,10 @@ import com.cloud.agent.api.routing.VmDataCommand; import com.cloud.agent.api.routing.VpnUsersCfgCommand; import com.cloud.agent.api.storage.CopyVolumeAnswer; import com.cloud.agent.api.storage.CopyVolumeCommand; +import com.cloud.agent.api.storage.CreateVolumeOVACommand; +import com.cloud.agent.api.storage.CreateVolumeOVAAnswer; +import com.cloud.agent.api.storage.PrepareOVAPackingAnswer; +import com.cloud.agent.api.storage.PrepareOVAPackingCommand; import com.cloud.agent.api.storage.CreateAnswer; import com.cloud.agent.api.storage.CreateCommand; import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer; @@ -233,6 +239,7 @@ import com.vmware.vim25.ClusterDasConfigInfo; import com.vmware.vim25.ComputeResourceSummary; import com.vmware.vim25.DatastoreSummary; import com.vmware.vim25.DynamicProperty; +import com.vmware.vim25.GuestInfo; import com.vmware.vim25.HostCapability; import com.vmware.vim25.HostFirewallInfo; import com.vmware.vim25.HostFirewallRuleset; @@ -392,6 +399,10 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa answer = execute((DeleteStoragePoolCommand) cmd); } else if (clz == CopyVolumeCommand.class) { answer = execute((CopyVolumeCommand) cmd); + } else if (clz == CreateVolumeOVACommand.class) { + answer = execute((CreateVolumeOVACommand) cmd); + } else if (clz == PrepareOVAPackingCommand.class) { + answer = execute((PrepareOVAPackingCommand) cmd); } else if (clz == AttachVolumeCommand.class) { answer = execute((AttachVolumeCommand) cmd); } else if (clz == AttachIsoCommand.class) { @@ -476,6 +487,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa return execute((ResizeVolumeCommand) cmd); } else if (clz == UnregisterVMCommand.class) { return execute((UnregisterVMCommand) cmd); + } else if (clz == ScaleVmCommand.class) { + return execute((ScaleVmCommand) cmd); } else { answer = Answer.createUnsupportedCommandAnswer(cmd); } @@ -1318,6 +1331,12 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa throw new Exception(msg); } + if(!isVMWareToolsInstalled(vmMo)){ + String errMsg = "vmware tools is not installed or not running, cannot add nic to vm " + vmName; + s_logger.debug(errMsg); + return new PlugNicAnswer(cmd, false, "Unable to execute PlugNicCommand due to " + errMsg); + } + // TODO need a way to specify the control of NIC device type VirtualEthernetCardType nicDeviceType = VirtualEthernetCardType.E1000; @@ -1392,6 +1411,12 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa throw new Exception(msg); } + if(!isVMWareToolsInstalled(vmMo)){ + String errMsg = "vmware tools not installed or not running, cannot remove nic from vm " + vmName; + s_logger.debug(errMsg); + return new UnPlugNicAnswer(cmd, false, "Unable to execute unPlugNicCommand due to " + errMsg); + } + VirtualDevice nic = findVirtualNicDevice(vmMo, cmd.getNic().getMac()); if ( nic == null ) { return new UnPlugNicAnswer(cmd, true, "success"); @@ -1433,10 +1458,14 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } String args = ""; + String snatArgs = ""; + if (ip.isAdd()) { args += " -A "; + snatArgs += " -A "; } else { args += " -D "; + snatArgs += " -D "; } args += " -l "; @@ -1460,6 +1489,21 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa if (!result.first()) { throw new InternalErrorException("Unable to assign public IP address"); } + + if (ip.isSourceNat()) { + snatArgs += " -l "; + snatArgs += ip.getPublicIp(); + snatArgs += " -c "; + snatArgs += "eth" + ethDeviceNum; + + Pair result_gateway = SshHelper.sshExecute(routerIp, DEFAULT_DOMR_SSHPORT, "root", mgr.getSystemVMKeyFile(), null, + "/opt/cloud/bin/vpc_privateGateway.sh " + args); + + if (!result_gateway.first()) { + throw new InternalErrorException("Unable to configure source NAT for public IP address."); + } + + } } protected void assignPublicIpAddress(VirtualMachineMO vmMo, final String vmName, final String privateIpAddress, final String publicIpAddress, final boolean add, final boolean firstIP, @@ -2048,6 +2092,28 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa return validatedDisks.toArray(new VolumeTO[0]); } + protected ScaleVmAnswer execute(ScaleVmCommand cmd) { + + VmwareContext context = getServiceContext(); + VirtualMachineTO vmSpec = cmd.getVirtualMachine(); + try{ + VmwareHypervisorHost hyperHost = getHyperHost(context); + VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(cmd.getVmName()); + VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec(); + int ramMb = (int) (vmSpec.getMinRam()); + + VmwareHelper.setVmScaleUpConfig(vmConfigSpec, vmSpec.getCpus(), vmSpec.getSpeed(), vmSpec.getSpeed(),(int) (vmSpec.getMaxRam()), ramMb, vmSpec.getLimitCpuUse()); + + if(!vmMo.configureVm(vmConfigSpec)) { + throw new Exception("Unable to execute ScaleVmCommand"); + } + }catch(Exception e) { + s_logger.error("Unexpected exception: ", e); + return new ScaleVmAnswer(cmd, false, "Unable to execute ScaleVmCommand due to " + e.toString()); + } + return new ScaleVmAnswer(cmd, true, null); + } + protected StartAnswer execute(StartCommand cmd) { if (s_logger.isInfoEnabled()) { @@ -2151,7 +2217,10 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa VmwareHelper.setBasicVmConfig(vmConfigSpec, vmSpec.getCpus(), vmSpec.getMaxSpeed(), vmSpec.getMinSpeed(),(int) (vmSpec.getMaxRam()/(1024*1024)), ramMb, translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs()).value(), vmSpec.getLimitCpuUse()); - + + vmConfigSpec.setMemoryHotAddEnabled(true); + vmConfigSpec.setCpuHotAddEnabled(true); + if ("true".equals(vmSpec.getDetails().get(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG))) { s_logger.debug("Nested Virtualization enabled in configuration, checking hypervisor capability"); ManagedObjectReference hostMor = vmMo.getRunningHost().getMor(); @@ -3905,8 +3974,48 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } } + public CreateVolumeOVAAnswer execute(CreateVolumeOVACommand cmd) { + if (s_logger.isInfoEnabled()) { + s_logger.info("Executing resource CreateVolumeOVACommand: " + _gson.toJson(cmd)); + } + try { + VmwareContext context = getServiceContext(); + VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME); + return (CreateVolumeOVAAnswer) mgr.getStorageManager().execute(this, cmd); + } catch (Throwable e) { + if (e instanceof RemoteException) { + s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context"); + invalidateServiceContext(); + } + String msg = "CreateVolumeOVACommand failed due to " + VmwareHelper.getExceptionMessage(e); + s_logger.error(msg, e); + return new CreateVolumeOVAAnswer(cmd, false, msg); + } + } + + protected Answer execute(PrepareOVAPackingCommand cmd) { + if (s_logger.isInfoEnabled()) { + s_logger.info("Executing resource PrepareOVAPackingCommand: " + _gson.toJson(cmd)); + } + + try { + VmwareContext context = getServiceContext(); + VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME); + + return mgr.getStorageManager().execute(this, cmd); + } catch (Throwable e) { + if (e instanceof RemoteException) { + s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context"); + invalidateServiceContext(); + } + + String details = "PrepareOVAPacking for template failed due to " + VmwareHelper.getExceptionMessage(e); + s_logger.error(details, e); + return new PrepareOVAPackingAnswer(cmd, false, details); + } + } private boolean createVMFullClone(VirtualMachineMO vmTemplate, DatacenterMO dcMo, DatastoreMO dsMo, String vmdkName, ManagedObjectReference morDatastore, ManagedObjectReference morPool) throws Exception { @@ -5170,4 +5279,9 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa // TODO Auto-generated method stub } + + private boolean isVMWareToolsInstalled(VirtualMachineMO vmMo) throws Exception{ + GuestInfo guestInfo = vmMo.getVmGuestInfo(); + return (guestInfo != null && guestInfo.getGuestState() != null && guestInfo.getGuestState().equalsIgnoreCase("running")); + } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java index ce42f67bf1d..95ba317fa2c 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java @@ -28,6 +28,9 @@ import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand; import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand; import com.cloud.agent.api.CreateVolumeFromSnapshotCommand; import com.cloud.agent.api.storage.CopyVolumeCommand; +import com.cloud.agent.api.storage.CreateVolumeOVAAnswer; +import com.cloud.agent.api.storage.CreateVolumeOVACommand; +import com.cloud.agent.api.storage.PrepareOVAPackingCommand; import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; import com.cloud.hypervisor.vmware.manager.VmwareHostService; import com.cloud.hypervisor.vmware.manager.VmwareStorageManager; @@ -76,6 +79,10 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe answer = execute((CreatePrivateTemplateFromSnapshotCommand)cmd); } else if(cmd instanceof CopyVolumeCommand) { answer = execute((CopyVolumeCommand)cmd); + } else if(cmd instanceof CreateVolumeOVACommand) { + answer = execute((CreateVolumeOVACommand)cmd); + } else if (cmd instanceof PrepareOVAPackingCommand) { + answer = execute((PrepareOVAPackingCommand)cmd); } else if(cmd instanceof CreateVolumeFromSnapshotCommand) { answer = execute((CreateVolumeFromSnapshotCommand)cmd); } else { @@ -138,6 +145,23 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe return _storageMgr.execute(this, cmd); } + private Answer execute(PrepareOVAPackingCommand cmd) { + s_logger.info("Fang: VmwareSecStorageResourceHandler: exec cmd. cmd is " + cmd.toString()); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Executing resource PrepareOVAPackingCommand: " + _gson.toJson(cmd)); + } + + return _storageMgr.execute(this, cmd); + } + + private CreateVolumeOVAAnswer execute(CreateVolumeOVACommand cmd) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Executing resource CreateVolumeOVACommand: " + _gson.toJson(cmd)); + } + + return (CreateVolumeOVAAnswer) _storageMgr.execute(this, cmd); + } + private Answer execute(CreateVolumeFromSnapshotCommand cmd) { if (s_logger.isDebugEnabled()) { s_logger.debug("Executing resource CreateVolumeFromSnapshotCommand: " + _gson.toJson(cmd)); diff --git a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java new file mode 100644 index 00000000000..3ca0b600e36 --- /dev/null +++ b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java @@ -0,0 +1,82 @@ +// 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. +package com.cloud.hypervisor.vmware.resource; + +import com.cloud.agent.api.Command; +import com.cloud.agent.api.ScaleVmAnswer; +import com.cloud.agent.api.ScaleVmCommand; +import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.hypervisor.vmware.mo.VirtualMachineMO; +import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost; +import com.cloud.hypervisor.vmware.util.VmwareContext; +import com.cloud.hypervisor.vmware.util.VmwareHelper; +import com.vmware.vim25.VirtualMachineConfigSpec; +import org.junit.Test; +import org.junit.Before; + +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.MockitoAnnotations; +import static org.mockito.Mockito.*; + + +public class VmwareResourceTest { + + @Spy VmwareResource _resource = new VmwareResource() { + + @Override + public ScaleVmAnswer execute(ScaleVmCommand cmd) { + return super.execute(cmd); + } + @Override + public VmwareHypervisorHost getHyperHost(VmwareContext context, Command cmd) { + return hyperHost; + } + }; + + @Mock VmwareContext context; + @Mock ScaleVmCommand cmd; + @Mock VirtualMachineTO vmSpec; + @Mock + VmwareHypervisorHost hyperHost; + @Mock VirtualMachineMO vmMo; + @Mock VirtualMachineConfigSpec vmConfigSpec; + + @Before + public void setup(){ + MockitoAnnotations.initMocks(this); + doReturn(context).when(_resource).getServiceContext(null); + when(cmd.getVirtualMachine()).thenReturn(vmSpec); + } + //Test successful scaling up the vm + @Test + public void testScaleVMF1() throws Exception { + when(_resource.getHyperHost(context, null)).thenReturn(hyperHost); + doReturn("i-2-3-VM").when(cmd).getVmName(); + when(hyperHost.findVmOnHyperHost("i-2-3-VM")).thenReturn(vmMo); + doReturn(1024L).when(vmSpec).getMinRam(); + doReturn(1).when(vmSpec).getCpus(); + doReturn(1000).when(vmSpec).getSpeed(); + doReturn(1024L).when(vmSpec).getMaxRam(); + doReturn(false).when(vmSpec).getLimitCpuUse(); + when(vmMo.configureVm(vmConfigSpec)).thenReturn(true); + + ScaleVmAnswer answer = _resource.execute(cmd); + verify(_resource).execute(cmd); + } + +} diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java index 89bc1cf5708..562a7feb96f 100755 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java @@ -427,8 +427,11 @@ public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, L prodVersion = prodVersion.trim(); } - if(prodBrand.equals("XCP") && (prodVersion.equals("1.0.0") || prodVersion.equals("1.1.0") || prodVersion.equals("5.6.100") || prodVersion.startsWith("1.4") || prodVersion.startsWith("1.6"))) - return new XcpServerResource(); + if(prodBrand.equals("XCP") && (prodVersion.equals("1.0.0") || prodVersion.equals("1.1.0") || prodVersion.equals("5.6.100") || prodVersion.startsWith("1.4"))) { + return new XcpServerResource("1.1"); + } else if (prodBrand.equals("XCP") && prodVersion.startsWith("1.6")) { + return new XcpServerResource("1.6"); + } if(prodBrand.equals("XenServer") && prodVersion.equals("5.6.0")) return new XenServer56Resource(); diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixHelper.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixHelper.java index 828a8279f9a..34b8f2981e2 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixHelper.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixHelper.java @@ -28,6 +28,7 @@ import org.apache.log4j.Logger; public class CitrixHelper { private static final Logger s_logger = Logger.getLogger(CitrixHelper.class); private static final HashMap _xcp100GuestOsMap = new HashMap(70); + private static final HashMap _xcp160GuestOsMap = new HashMap(70); private static final HashMap _xenServerGuestOsMap = new HashMap(70); private static final HashMap _xenServer56FP1GuestOsMap = new HashMap(70); private static final HashMap _xenServer56FP2GuestOsMap = new HashMap(70); @@ -114,6 +115,83 @@ public class CitrixHelper { _xcp100GuestOsMap.put("Other PV (64-bit)", "CentOS 5 (64-bit)"); } + static { + _xcp160GuestOsMap.put("CentOS 4.5 (32-bit)", "CentOS 4.5 (32-bit)"); + _xcp160GuestOsMap.put("CentOS 4.6 (32-bit)", "CentOS 4.6 (32-bit)"); + _xcp160GuestOsMap.put("CentOS 4.7 (32-bit)", "CentOS 4.7 (32-bit)"); + _xcp160GuestOsMap.put("CentOS 4.8 (32-bit)", "CentOS 4.8 (32-bit)"); + _xcp160GuestOsMap.put("CentOS 5.0 (32-bit)", "CentOS 5 (32-bit)"); + _xcp160GuestOsMap.put("CentOS 5.0 (64-bit)", "CentOS 5 (64-bit)"); + _xcp160GuestOsMap.put("CentOS 5.1 (32-bit)", "CentOS 5 (32-bit)"); + _xcp160GuestOsMap.put("CentOS 5.1 (64-bit)", "CentOS 5 (64-bit)"); + _xcp160GuestOsMap.put("CentOS 5.2 (32-bit)", "CentOS 5 (32-bit)"); + _xcp160GuestOsMap.put("CentOS 5.2 (64-bit)", "CentOS 5 (64-bit)"); + _xcp160GuestOsMap.put("CentOS 5.3 (32-bit)", "CentOS 5 (32-bit)"); + _xcp160GuestOsMap.put("CentOS 5.3 (64-bit)", "CentOS 5 (64-bit)"); + _xcp160GuestOsMap.put("CentOS 5.4 (32-bit)", "CentOS 5 (32-bit)"); + _xcp160GuestOsMap.put("CentOS 5.4 (64-bit)", "CentOS 5 (64-bit)"); + _xcp160GuestOsMap.put("CentOS 5.5 (32-bit)", "CentOS 5 (32-bit)"); + _xcp160GuestOsMap.put("CentOS 5.5 (64-bit)", "CentOS 5 (64-bit)"); + _xcp160GuestOsMap.put("Debian GNU/Linux 5.0 (32-bit)", "Debian Lenny 5.0 (32-bit)"); + _xcp160GuestOsMap.put("Debian GNU/Linux 6(32-bit)", "Debian Squeeze 6.0 (32-bit)"); + _xcp160GuestOsMap.put("Debian GNU/Linux 6(64-bit)", "Debian Squeeze 6.0 (64-bit)"); + _xcp160GuestOsMap.put("Oracle Enterprise Linux 5.0 (32-bit)", "Oracle Enterprise Linux 5 (32-bit)"); + _xcp160GuestOsMap.put("Oracle Enterprise Linux 5.0 (64-bit)", "Oracle Enterprise Linux 5 (64-bit)"); + _xcp160GuestOsMap.put("Oracle Enterprise Linux 5.1 (32-bit)", "Oracle Enterprise Linux 5 (32-bit)"); + _xcp160GuestOsMap.put("Oracle Enterprise Linux 5.1 (64-bit)", "Oracle Enterprise Linux 5 (64-bit)"); + _xcp160GuestOsMap.put("Oracle Enterprise Linux 5.2 (32-bit)", "Oracle Enterprise Linux 5 (32-bit)"); + _xcp160GuestOsMap.put("Oracle Enterprise Linux 5.2 (64-bit)", "Oracle Enterprise Linux 5 (64-bit)"); + _xcp160GuestOsMap.put("Oracle Enterprise Linux 5.3 (32-bit)", "Oracle Enterprise Linux 5 (32-bit)"); + _xcp160GuestOsMap.put("Oracle Enterprise Linux 5.3 (64-bit)", "Oracle Enterprise Linux 5 (64-bit)"); + _xcp160GuestOsMap.put("Oracle Enterprise Linux 5.4 (32-bit)", "Oracle Enterprise Linux 5 (32-bit)"); + _xcp160GuestOsMap.put("Oracle Enterprise Linux 5.4 (64-bit)", "Oracle Enterprise Linux 5 (64-bit)"); + _xcp160GuestOsMap.put("Oracle Enterprise Linux 5.5 (32-bit)", "Oracle Enterprise Linux 5 (32-bit)"); + _xcp160GuestOsMap.put("Oracle Enterprise Linux 5.5 (64-bit)", "Oracle Enterprise Linux 5 (64-bit)"); + _xcp160GuestOsMap.put("Red Hat Enterprise Linux 4.5 (32-bit)", "Red Hat Enterprise Linux 4.5 (32-bit)"); + _xcp160GuestOsMap.put("Red Hat Enterprise Linux 4.6 (32-bit)", "Red Hat Enterprise Linux 4.6 (32-bit)"); + _xcp160GuestOsMap.put("Red Hat Enterprise Linux 4.7 (32-bit)", "Red Hat Enterprise Linux 4.7 (32-bit)"); + _xcp160GuestOsMap.put("Red Hat Enterprise Linux 4.8 (32-bit)", "Red Hat Enterprise Linux 4.8 (32-bit)"); + _xcp160GuestOsMap.put("Red Hat Enterprise Linux 5.0 (32-bit)", "Red Hat Enterprise Linux 5 (32-bit)"); + _xcp160GuestOsMap.put("Red Hat Enterprise Linux 5.0 (64-bit)", "Red Hat Enterprise Linux 5 (64-bit)"); + _xcp160GuestOsMap.put("Red Hat Enterprise Linux 5.1 (32-bit)", "Red Hat Enterprise Linux 5 (32-bit)"); + _xcp160GuestOsMap.put("Red Hat Enterprise Linux 5.1 (64-bit)", "Red Hat Enterprise Linux 5 (64-bit)"); + _xcp160GuestOsMap.put("Red Hat Enterprise Linux 5.2 (32-bit)", "Red Hat Enterprise Linux 5 (32-bit)"); + _xcp160GuestOsMap.put("Red Hat Enterprise Linux 5.2 (64-bit)", "Red Hat Enterprise Linux 5 (64-bit)"); + _xcp160GuestOsMap.put("Red Hat Enterprise Linux 5.3 (32-bit)", "Red Hat Enterprise Linux 5 (32-bit)"); + _xcp160GuestOsMap.put("Red Hat Enterprise Linux 5.3 (64-bit)", "Red Hat Enterprise Linux 5 (64-bit)"); + _xcp160GuestOsMap.put("Red Hat Enterprise Linux 5.4 (32-bit)", "Red Hat Enterprise Linux 5 (32-bit)"); + _xcp160GuestOsMap.put("Red Hat Enterprise Linux 5.4 (64-bit)", "Red Hat Enterprise Linux 5 (64-bit)"); + _xcp160GuestOsMap.put("Red Hat Enterprise Linux 5.5 (32-bit)", "Red Hat Enterprise Linux 5 (32-bit)"); + _xcp160GuestOsMap.put("Red Hat Enterprise Linux 5.5 (64-bit)", "Red Hat Enterprise Linux 5 (64-bit)"); + _xcp160GuestOsMap.put("Red Hat Enterprise Linux 6.0 (32-bit)", "Red Hat Enterprise Linux 6 (32-bit)"); + _xcp160GuestOsMap.put("Red Hat Enterprise Linux 6.0 (64-bit)", "Red Hat Enterprise Linux 6 (64-bit)"); + _xcp160GuestOsMap.put("SUSE Linux Enterprise Server 9 SP4 (32-bit)", "SUSE Linux Enterprise Server 9 SP4"); + _xcp160GuestOsMap.put("SUSE Linux Enterprise Server 10 SP1 (32-bit)", "SUSE Linux Enterprise Server 10 SP1"); + _xcp160GuestOsMap.put("SUSE Linux Enterprise Server 10 SP1 (64-bit)", "SUSE Linux Enterprise Server 10 SP1 x64"); + _xcp160GuestOsMap.put("SUSE Linux Enterprise Server 10 SP2 (32-bit)", "SUSE Linux Enterprise Server 10 SP2"); + _xcp160GuestOsMap.put("SUSE Linux Enterprise Server 10 SP2 (64-bit)", "SUSE Linux Enterprise Server 10 SP2 x64"); + _xcp160GuestOsMap.put("SUSE Linux Enterprise Server 10 SP3 (64-bit)", "Other install media"); + _xcp160GuestOsMap.put("SUSE Linux Enterprise Server 11 (32-bit)", "SUSE Linux Enterprise Server 11"); + _xcp160GuestOsMap.put("SUSE Linux Enterprise Server 11 (64-bit)", "SUSE Linux Enterprise Server 11 x64"); + _xcp160GuestOsMap.put("SUSE Linux Enterprise Server 11 SP1 (32-bit)", "SUSE Linux Enterprise Server 11 SP1 (32-bit)"); + _xcp160GuestOsMap.put("SUSE Linux Enterprise Server 11 SP1 (64-bit)", "SUSE Linux Enterprise Server 11 SP1 (64-bit)"); + _xcp160GuestOsMap.put("Windows 7 (32-bit)", "Windows 7 (32-bit)"); + _xcp160GuestOsMap.put("Windows 7 (64-bit)", "Windows 7 (64-bit)"); + _xcp160GuestOsMap.put("Windows Server 2003 (32-bit)", "Windows Server 2003 (32-bit)"); + _xcp160GuestOsMap.put("Windows Server 2003 (64-bit)", "Windows Server 2003 (64-bit)"); + _xcp160GuestOsMap.put("Windows Server 2008 (32-bit)", "Windows Server 2008 (32-bit)"); + _xcp160GuestOsMap.put("Windows Server 2008 (64-bit)", "Windows Server 2008 (64-bit)"); + _xcp160GuestOsMap.put("Windows Server 2008 R2 (64-bit)", "Windows Server 2008 R2 (64-bit)"); + _xcp160GuestOsMap.put("Windows XP SP3 (32-bit)", "Windows XP SP3 (32-bit)"); + _xcp160GuestOsMap.put("Windows Vista (32-bit)", "Windows Vista (32-bit)"); + _xcp160GuestOsMap.put("Ubuntu 10.04 (32-bit)", "Ubuntu Lucid Lynx 10.04 (32-bit) (experimental)"); + _xcp160GuestOsMap.put("Ubuntu 10.04 (64-bit)", "Ubuntu Lucid Lynx 10.04 (64-bit) (experimental)"); + _xcp160GuestOsMap.put("Other Linux (32-bit)", "Other install media"); + _xcp160GuestOsMap.put("Other Linux (64-bit)", "Other install media"); + _xcp160GuestOsMap.put("Other PV (32-bit)", "CentOS 5 (32-bit)"); + _xcp160GuestOsMap.put("Other PV (64-bit)", "CentOS 5 (64-bit)"); + } + static { _xenServerGuestOsMap.put("CentOS 4.5 (32-bit)", "CentOS 4.5 (32-bit)"); @@ -648,7 +726,7 @@ public class CitrixHelper { _xenServer610GuestOsMap.put("Windows 7 (32-bit)", "Windows 7 (32-bit)"); _xenServer610GuestOsMap.put("Windows 7 (64-bit)", "Windows 7 (64-bit)"); _xenServer610GuestOsMap.put("Windows 8 (32-bit)", "Windows 8 (32-bit) (experimental)"); - _xenServer610GuestOsMap.put("Windows 8 (64-bit)", "Windows 7 (64-bit) (experimental)"); + _xenServer610GuestOsMap.put("Windows 8 (64-bit)", "Windows 8 (64-bit) (experimental)"); _xenServer610GuestOsMap.put("Windows Server 2003 (32-bit)", "Windows Server 2003 (32-bit)"); _xenServer610GuestOsMap.put("Windows Server 2003 (64-bit)", "Windows Server 2003 (64-bit)"); _xenServer610GuestOsMap.put("Windows Server 2003 PAE (32-bit)", "Windows Server 2003 PAE (32-bit)"); @@ -661,6 +739,7 @@ public class CitrixHelper { _xenServer610GuestOsMap.put("Windows Server 2008 (32-bit)", "Windows Server 2008 (32-bit)"); _xenServer610GuestOsMap.put("Windows Server 2008 (64-bit)", "Windows Server 2008 (64-bit)"); _xenServer610GuestOsMap.put("Windows Server 2008 R2 (64-bit)", "Windows Server 2008 R2 (64-bit)"); + _xenServer610GuestOsMap.put("Windows Server 2012 (64-bit)", "Windows Server 2012 (64-bit) (experimental)"); _xenServer610GuestOsMap.put("Windows Server 8 (64-bit)", "Windows Server 2012 (64-bit) (experimental)"); _xenServer610GuestOsMap.put("Windows Vista (32-bit)", "Windows Vista (32-bit)"); _xenServer610GuestOsMap.put("Windows XP SP3 (32-bit)", "Windows XP SP3 (32-bit)"); @@ -693,6 +772,15 @@ public class CitrixHelper { return guestOS; } + public static String getXcp160GuestOsType(String stdType) { + String guestOS = _xcp160GuestOsMap.get(stdType); + if (guestOS == null) { + s_logger.debug("Can't find the guest os: " + stdType + " mapping into XCP's guestOS type, start it as HVM guest"); + guestOS = "Other install media"; + } + return guestOS; + } + public static String getXenServerGuestOsType(String stdType, boolean bootFromCD) { String guestOS = _xenServerGuestOsMap.get(stdType); diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index 46ae35a4a54..bac361d9133 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -2217,11 +2217,14 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } String args = "vpc_ipassoc.sh " + routerIp; + String snatArgs = "vpc_privateGateway.sh " + routerIp; if (ip.isAdd()) { args += " -A "; + snatArgs += " -A "; } else { args += " -D "; + snatArgs+= " -D "; } args += " -l "; @@ -2244,6 +2247,17 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe if (result == null || result.isEmpty()) { throw new InternalErrorException("Xen plugin \"vpc_ipassoc\" failed."); } + + if (ip.isSourceNat()) { + snatArgs += " -l " + ip.getPublicIp(); + snatArgs += " -c " + "eth" + correctVif.getDevice(conn); + + result = callHostPlugin(conn, "vmops", "routerProxy", "args", snatArgs); + if (result == null || result.isEmpty()) { + throw new InternalErrorException("Xen plugin \"vcp_privateGateway\" failed."); + } + } + } catch (Exception e) { String msg = "Unable to assign public IP address due to " + e.toString(); s_logger.warn(msg, e); diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XcpServerResource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XcpServerResource.java index 7a958708e76..6baf6a09e3f 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XcpServerResource.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XcpServerResource.java @@ -39,9 +39,10 @@ import com.xensource.xenapi.Types.XenAPIException; @Local(value=ServerResource.class) public class XcpServerResource extends CitrixResourceBase { private final static Logger s_logger = Logger.getLogger(XcpServerResource.class); - - public XcpServerResource() { + private String version; + public XcpServerResource(String version) { super(); + this.version = version; } @Override @@ -55,7 +56,11 @@ public class XcpServerResource extends CitrixResourceBase { @Override protected String getGuestOsType(String stdType, boolean bootFromCD) { - return CitrixHelper.getXcpGuestOsType(stdType); + if (version.equalsIgnoreCase("1.6")) { + return CitrixHelper.getXcp160GuestOsType(stdType); + } else { + return CitrixHelper.getXcpGuestOsType(stdType); + } } @Override diff --git a/plugins/network-elements/bigswitch-vns/src/com/cloud/network/element/BigSwitchVnsElement.java b/plugins/network-elements/bigswitch-vns/src/com/cloud/network/element/BigSwitchVnsElement.java index 4ee9c93ffcc..411feab7339 100644 --- a/plugins/network-elements/bigswitch-vns/src/com/cloud/network/element/BigSwitchVnsElement.java +++ b/plugins/network-elements/bigswitch-vns/src/com/cloud/network/element/BigSwitchVnsElement.java @@ -138,7 +138,7 @@ public class BigSwitchVnsElement extends AdapterBase implements if (network.getBroadcastDomainType() != BroadcastDomainType.Lswitch) { return false; } -/* + if (!_networkModel.isProviderForNetwork(getProvider(), network.getId())) { s_logger.debug("BigSwitchVnsElement is not a provider for network " @@ -153,7 +153,7 @@ public class BigSwitchVnsElement extends AdapterBase implements + network.getDisplayText()); return false; } -*/ + return true; } diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-egress-acl-rule.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-egress-acl-rule.xml index 930272ed8ee..05c066d6d53 100755 --- a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-egress-acl-rule.xml +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-egress-acl-rule.xml @@ -118,70 +118,38 @@ under the License. - - - - - - - - - - - - - - + + value="%deststartport%"/> - + + value="%destendport%"/> @@ -195,7 +163,6 @@ under the License. protocolvalue = "TCP" or "UDP" deststartip="destination start ip" destendip="destination end ip" - sourcestartport="start port at source" - sourceendport="end port at source" - sourceip="source ip" + deststartport="start port at destination" + destendport="end port at destination" --!> diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-egress-acl-no-protocol-rule.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-egress-acl-no-protocol-rule.xml new file mode 100755 index 00000000000..17cfa54a34e --- /dev/null +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-egress-acl-no-protocol-rule.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-egress-acl-rule.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-egress-acl-rule.xml index 92c25043dad..436e3eae790 100755 --- a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-egress-acl-rule.xml +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-generic-egress-acl-rule.xml @@ -118,5 +118,4 @@ under the License. protocolvalue = "TCP" or "UDP" or "ICMP" deststartip="destination start ip" destendip="destination end ip" - sourceip="source ip" --!> diff --git a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-ingress-acl-rule.xml b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-ingress-acl-rule.xml index 1af30b44416..f283ffeb333 100755 --- a/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-ingress-acl-rule.xml +++ b/plugins/network-elements/cisco-vnmc/scripts/network/cisco/create-ingress-acl-rule.xml @@ -118,7 +118,7 @@ under the License. @@ -127,56 +127,24 @@ under the License. dn="%aclruledn%/rule-cond-4/nw-expr2/nw-attr-qual" status="created"/> - - - - - - - - - - - - - - + - + diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoAsa1000vResourcesCmd.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoAsa1000vResourcesCmd.java index 509d39fb5f9..88ea2709325 100755 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoAsa1000vResourcesCmd.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoAsa1000vResourcesCmd.java @@ -89,6 +89,7 @@ public class ListCiscoAsa1000vResourcesCmd extends BaseListCmd { if (ciscoAsa1000vDevices != null && !ciscoAsa1000vDevices.isEmpty()) { for (CiscoAsa1000vDevice ciscoAsa1000vDeviceVO : ciscoAsa1000vDevices) { CiscoAsa1000vResourceResponse ciscoAsa1000vResourceResponse = _ciscoAsa1000vService.createCiscoAsa1000vResourceResponse(ciscoAsa1000vDeviceVO); + ciscoAsa1000vResourceResponse.setObjectName("CiscoAsa1000vResource"); ciscoAsa1000vResourcesResponse.add(ciscoAsa1000vResourceResponse); } } diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoVnmcResourcesCmd.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoVnmcResourcesCmd.java index ab553ee94ac..73128ecec2b 100644 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoVnmcResourcesCmd.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/commands/ListCiscoVnmcResourcesCmd.java @@ -77,18 +77,19 @@ public class ListCiscoVnmcResourcesCmd extends BaseListCmd { @Override public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { try { - List CiscoVnmcResources = _ciscoVnmcElementService.listCiscoVnmcResources(this); + List ciscoVnmcResources = _ciscoVnmcElementService.listCiscoVnmcResources(this); ListResponse response = new ListResponse(); - List CiscoVnmcResourcesResponse = new ArrayList(); + List ciscoVnmcResourcesResponse = new ArrayList(); - if (CiscoVnmcResources != null && !CiscoVnmcResources.isEmpty()) { - for (CiscoVnmcController CiscoVnmcResourceVO : CiscoVnmcResources) { - CiscoVnmcResourceResponse CiscoVnmcResourceResponse = _ciscoVnmcElementService.createCiscoVnmcResourceResponse(CiscoVnmcResourceVO); - CiscoVnmcResourcesResponse.add(CiscoVnmcResourceResponse); + if (ciscoVnmcResources != null && !ciscoVnmcResources.isEmpty()) { + for (CiscoVnmcController ciscoVnmcResourceVO : ciscoVnmcResources) { + CiscoVnmcResourceResponse ciscoVnmcResourceResponse = _ciscoVnmcElementService.createCiscoVnmcResourceResponse(ciscoVnmcResourceVO); + ciscoVnmcResourceResponse.setObjectName("CiscoVnmcResource"); + ciscoVnmcResourcesResponse.add(ciscoVnmcResourceResponse); } } - response.setResponses(CiscoVnmcResourcesResponse); + response.setResponses(ciscoVnmcResourcesResponse); response.setResponseName(getCommandName()); this.setResponseObject(response); } catch (InvalidParameterValueException invalidParamExcp) { diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoAsa1000vResourceResponse.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoAsa1000vResourceResponse.java index 9cd87da66a1..f857b352b4a 100755 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoAsa1000vResourceResponse.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoAsa1000vResourceResponse.java @@ -29,60 +29,69 @@ import com.google.gson.annotations.SerializedName; @EntityReference(value = CiscoAsa1000vDevice.class) public class CiscoAsa1000vResourceResponse extends BaseResponse { - public static final String RESOURCE_NAME = "resourcename"; - @SerializedName(ApiConstants.RESOURCE_ID) @Parameter(description="resource id of the Cisco ASA 1000v appliance") + @SerializedName(ApiConstants.RESOURCE_ID) + @Parameter(description="resource id of the Cisco ASA 1000v appliance") private String id; @SerializedName(ApiConstants.PHYSICAL_NETWORK_ID) @Parameter(description="the physical network to which this ASA 1000v belongs to", entityType = PhysicalNetworkResponse.class) - private Long physicalNetworkId ; - - public Long getPhysicalNetworkId() { - return physicalNetworkId; - } + private Long physicalNetworkId; @SerializedName(ApiConstants.HOST_NAME) @Parameter(description="management ip address of ASA 1000v") private String managementIp; - public String getManagementIp() { - return managementIp; - } - @SerializedName(ApiConstants.ASA_INSIDE_PORT_PROFILE) - @Parameter(description="management ip address of ASA 1000v") + @Parameter(description="port profile associated with inside interface of ASA 1000v") private String inPortProfile; - public String getInPortProfile() { - return inPortProfile; - } - @SerializedName(ApiConstants.NETWORK_ID) @Parameter(description="the guest network to which ASA 1000v is associated", entityType = NetworkResponse.class) private Long guestNetworkId; - public Long getGuestNetworkId() { - return guestNetworkId; + public String getId() { + return id; } public void setId(String ciscoAsa1000vResourceId) { this.id = ciscoAsa1000vResourceId; } + public Long getPhysicalNetworkId() { + return physicalNetworkId; + } + public void setPhysicalNetworkId(Long physicalNetworkId) { this.physicalNetworkId = physicalNetworkId; } + public String getManagementIp() { + return managementIp; + } + public void setManagementIp(String managementIp) { this.managementIp = managementIp; } + public String getInPortProfile() { + return inPortProfile; + } + public void setInPortProfile(String inPortProfile) { this.inPortProfile = inPortProfile; } + public Long getGuestNetworkId() { + return guestNetworkId; + } + public void setGuestNetworkId(Long guestNetworkId) { this.guestNetworkId = guestNetworkId; } + + @Override + public String getObjectId() { + return this.getId(); + } } diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoVnmcResourceResponse.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoVnmcResourceResponse.java index f5c9b727f8f..92a766d1bbf 100644 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoVnmcResourceResponse.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/api/response/CiscoVnmcResourceResponse.java @@ -25,6 +25,7 @@ import org.apache.cloudstack.api.response.PhysicalNetworkResponse; import com.cloud.network.cisco.CiscoVnmcController; import com.google.gson.annotations.SerializedName; + @EntityReference(value = CiscoVnmcController.class) public class CiscoVnmcResourceResponse extends BaseResponse { public static final String RESOURCE_NAME = "resourcename"; @@ -33,43 +34,52 @@ public class CiscoVnmcResourceResponse extends BaseResponse { @Parameter(description="resource id of the Cisco VNMC controller") private String id; - @SerializedName(ApiConstants.PHYSICAL_NETWORK_ID) + @SerializedName(ApiConstants.PHYSICAL_NETWORK_ID) @Parameter(description="the physical network to which this VNMC belongs to", entityType = PhysicalNetworkResponse.class) private Long physicalNetworkId; - public Long getPhysicalNetworkId() { - return physicalNetworkId; - } - - public String getProviderName() { - return providerName; - } - - public String getResourceName() { - return resourceName; - } - - @SerializedName(ApiConstants.PROVIDER) @Parameter(description="name of the provider") + @SerializedName(ApiConstants.PROVIDER) + @Parameter(description="name of the provider") private String providerName; - @SerializedName(RESOURCE_NAME) + @SerializedName(RESOURCE_NAME) @Parameter(description="Cisco VNMC resource name") private String resourceName; + public String getId() { + return id; + } + public void setId(String ciscoVnmcResourceId) { this.id = ciscoVnmcResourceId; } + public Long getPhysicalNetworkId() { + return physicalNetworkId; + } + public void setPhysicalNetworkId(Long physicalNetworkId) { this.physicalNetworkId = physicalNetworkId; } + public String getProviderName() { + return providerName; + } + public void setProviderName(String providerName) { this.providerName = providerName; } + public String getResourceName() { + return resourceName; + } + public void setResourceName(String resourceName) { this.resourceName = resourceName; - } + } + @Override + public String getObjectId() { + return this.getId(); + } } diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnection.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnection.java index f137148ab48..fed6724418d 100644 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnection.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnection.java @@ -140,23 +140,23 @@ public interface CiscoVnmcConnection { public boolean createTenantVDCIngressAclRule(String tenantName, String identifier, String policyIdentifier, String protocol, String sourceStartIp, String sourceEndIp, - String destStartPort, String destEndPort, String destIp) + String destStartPort, String destEndPort) throws ExecutionException; public boolean createTenantVDCIngressAclRule(String tenantName, String identifier, String policyIdentifier, - String protocol, String sourceStartIp, String sourceEndIp, String destIp) + String protocol, String sourceStartIp, String sourceEndIp) throws ExecutionException; public boolean createTenantVDCEgressAclRule(String tenantName, String identifier, String policyIdentifier, - String protocol, String sourceStartPort, String sourceEndPort, String sourceIp, - String destStartIp, String destEndIp) + String protocol, String destStartIp, String destEndIp, + String destStartPort, String destEndPort) throws ExecutionException; public boolean createTenantVDCEgressAclRule(String tenantName, String identifier, String policyIdentifier, - String protocol, String sourceIp, String destStartIp, String destEndIp) + String protocol, String destStartIp, String destEndIp) throws ExecutionException; public boolean deleteTenantVDCAclRule(String tenantName, diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnectionImpl.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnectionImpl.java index 527fb04698e..c7380ab11d8 100644 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnectionImpl.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/cisco/CiscoVnmcConnectionImpl.java @@ -95,6 +95,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { CREATE_EGRESS_ACL_RULE("create-egress-acl-rule.xml", "policy-mgr"), CREATE_GENERIC_INGRESS_ACL_RULE("create-generic-ingress-acl-rule.xml", "policy-mgr"), CREATE_GENERIC_EGRESS_ACL_RULE("create-generic-egress-acl-rule.xml", "policy-mgr"), + CREATE_GENERIC_EGRESS_ACL_NO_PROTOCOL_RULE("create-generic-egress-acl-no-protocol-rule.xml", "policy-mgr"), DELETE_RULE("delete-rule.xml", "policy-mgr"), @@ -279,7 +280,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { String xml = VnmcXml.CREATE_VDC.getXml(); String service = VnmcXml.CREATE_VDC.getService(); xml = replaceXmlValue(xml, "cookie", _cookie); - xml = replaceXmlValue(xml, "descr", "VDC for Tenant" + tenantName); + xml = replaceXmlValue(xml, "descr", "VDC for Tenant " + tenantName); xml = replaceXmlValue(xml, "name", getNameForTenantVDC(tenantName)); xml = replaceXmlValue(xml, "dn", getDnForTenantVDC(tenantName)); @@ -304,7 +305,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { String xml = VnmcXml.CREATE_EDGE_DEVICE_PROFILE.getXml(); String service = VnmcXml.CREATE_EDGE_DEVICE_PROFILE.getService(); xml = replaceXmlValue(xml, "cookie", _cookie); - xml = replaceXmlValue(xml, "descr", "Edge Device Profile for Tenant VDC" + tenantName); + xml = replaceXmlValue(xml, "descr", "Edge Device Profile for Tenant VDC " + tenantName); xml = replaceXmlValue(xml, "name", getNameForEdgeDeviceServiceProfile(tenantName)); xml = replaceXmlValue(xml, "dn", getDnForTenantVDCEdgeDeviceProfile(tenantName)); @@ -407,7 +408,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { String xml = VnmcXml.CREATE_EDGE_SECURITY_PROFILE.getXml(); String service = VnmcXml.CREATE_EDGE_SECURITY_PROFILE.getService(); xml = replaceXmlValue(xml, "cookie", _cookie); - xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC" + tenantName); + xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC " + tenantName); xml = replaceXmlValue(xml, "name", getNameForEdgeDeviceSecurityProfile(tenantName)); xml = replaceXmlValue(xml, "espdn", getDnForTenantVDCEdgeSecurityProfile(tenantName)); xml = replaceXmlValue(xml, "egressref", "default-egress"); @@ -505,7 +506,8 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { return createTenantVDCNatPolicyRef( getDnForSourceNatPolicyRef(tenantName), getNameForSourceNatPolicy(tenantName), - tenantName); + tenantName, + true); } @Override @@ -545,7 +547,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { String xml = VnmcXml.RESOLVE_NAT_POLICY_SET.getXml(); String service = VnmcXml.RESOLVE_NAT_POLICY_SET.getService(); xml = replaceXmlValue(xml, "cookie", _cookie); - xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC" + tenantName); + xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC " + tenantName); xml = replaceXmlValue(xml, "name", getNameForEdgeDeviceSecurityProfile(tenantName)); xml = replaceXmlValue(xml, "espdn", getDnForTenantVDCEdgeSecurityProfile(tenantName)); xml = replaceXmlValue(xml, "natpolicysetname", getNameForNatPolicySet(tenantName)); @@ -656,11 +658,10 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { String xml = VnmcXml.RESOLVE_ACL_POLICY_SET.getXml(); String service = VnmcXml.RESOLVE_ACL_POLICY_SET.getService(); xml = replaceXmlValue(xml, "cookie", _cookie); - xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC" + tenantName); + xml = replaceXmlValue(xml, "descr", "Edge Security Profile for Tenant VDC " + tenantName); xml = replaceXmlValue(xml, "name", getNameForEdgeDeviceSecurityProfile(tenantName)); xml = replaceXmlValue(xml, "espdn", getDnForTenantVDCEdgeSecurityProfile(tenantName)); - //xml = replaceXmlValue(xml, "egresspolicysetname", getNameForAclPolicySet(tenantName, false)); - xml = replaceXmlValue(xml, "egresspolicysetname", "default-egress"); + xml = replaceXmlValue(xml, "egresspolicysetname", getNameForAclPolicySet(tenantName, false)); xml = replaceXmlValue(xml, "ingresspolicysetname", getNameForAclPolicySet(tenantName, true)); xml = replaceXmlValue(xml, "natpolicysetname", getNameForNatPolicySet(tenantName)); @@ -672,7 +673,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { public boolean createTenantVDCIngressAclRule(String tenantName, String identifier, String policyIdentifier, String protocol, String sourceStartIp, String sourceEndIp, - String destStartPort, String destEndPort, String destIp) throws ExecutionException { + String destStartPort, String destEndPort) throws ExecutionException { String xml = VnmcXml.CREATE_INGRESS_ACL_RULE.getXml(); String service = VnmcXml.CREATE_INGRESS_ACL_RULE.getService(); @@ -686,7 +687,6 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { xml = replaceXmlValue(xml, "sourceendip", sourceEndIp); xml = replaceXmlValue(xml, "deststartport", destStartPort); xml = replaceXmlValue(xml, "destendport", destEndPort); - xml = replaceXmlValue(xml, "destip", destIp); List rules = listChildren(getDnForAclPolicy(tenantName, policyIdentifier)); int order = 100; @@ -702,8 +702,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { @Override public boolean createTenantVDCIngressAclRule(String tenantName, String identifier, String policyIdentifier, - String protocol, String sourceStartIp, String sourceEndIp, - String destIp) throws ExecutionException { + String protocol, String sourceStartIp, String sourceEndIp) throws ExecutionException { String xml = VnmcXml.CREATE_GENERIC_INGRESS_ACL_RULE.getXml(); String service = VnmcXml.CREATE_GENERIC_INGRESS_ACL_RULE.getService(); @@ -730,8 +729,8 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { @Override public boolean createTenantVDCEgressAclRule(String tenantName, String identifier, String policyIdentifier, - String protocol, String sourceStartPort, String sourceEndPort, String sourceIp, - String destStartIp, String destEndIp) throws ExecutionException { + String protocol, String destStartIp, String destEndIp, + String destStartPort, String destEndPort) throws ExecutionException { String xml = VnmcXml.CREATE_EGRESS_ACL_RULE.getXml(); String service = VnmcXml.CREATE_EGRESS_ACL_RULE.getService(); @@ -743,9 +742,8 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { xml = replaceXmlValue(xml, "protocolvalue", protocol); xml = replaceXmlValue(xml, "deststartip", destStartIp); xml = replaceXmlValue(xml, "destendip", destEndIp); - xml = replaceXmlValue(xml, "sourcestartport", sourceStartPort); - xml = replaceXmlValue(xml, "sourceendport", sourceEndPort); - xml = replaceXmlValue(xml, "sourceip", sourceIp); + xml = replaceXmlValue(xml, "deststartport", destStartPort); + xml = replaceXmlValue(xml, "destendport", destEndPort); List rules = listChildren(getDnForAclPolicy(tenantName, policyIdentifier)); int order = 100; @@ -761,17 +759,20 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { @Override public boolean createTenantVDCEgressAclRule(String tenantName, String identifier, String policyIdentifier, - String protocol, String sourceIp, - String destStartIp, String destEndIp) throws ExecutionException { + String protocol, String destStartIp, String destEndIp) throws ExecutionException { String xml = VnmcXml.CREATE_GENERIC_EGRESS_ACL_RULE.getXml(); String service = VnmcXml.CREATE_GENERIC_EGRESS_ACL_RULE.getService(); - + if (protocol.equalsIgnoreCase("all")) { // any protocol + xml = VnmcXml.CREATE_GENERIC_EGRESS_ACL_NO_PROTOCOL_RULE.getXml(); + service = VnmcXml.CREATE_GENERIC_EGRESS_ACL_NO_PROTOCOL_RULE.getService(); + } else { // specific protocol + xml = replaceXmlValue(xml, "protocolvalue", protocol); + } xml = replaceXmlValue(xml, "cookie", _cookie); xml = replaceXmlValue(xml, "aclruledn", getDnForAclRule(tenantName, identifier, policyIdentifier)); xml = replaceXmlValue(xml, "aclrulename", getNameForAclRule(tenantName, identifier)); xml = replaceXmlValue(xml, "descr", "Egress ACL rule for Tenant VDC " + tenantName); xml = replaceXmlValue(xml, "actiontype", "permit"); - xml = replaceXmlValue(xml, "protocolvalue", protocol); xml = replaceXmlValue(xml, "deststartip", destStartIp); xml = replaceXmlValue(xml, "destendip", destEndIp); @@ -838,17 +839,23 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { return verifySuccess(response); } - private boolean createTenantVDCNatPolicyRef(String policyRefDn, String name, String tenantName) throws ExecutionException { + private boolean createTenantVDCNatPolicyRef(String policyRefDn, String name, String tenantName, boolean isSourceNat) throws ExecutionException { String xml = VnmcXml.CREATE_NAT_POLICY_REF.getXml(); String service = VnmcXml.CREATE_NAT_POLICY_REF.getService(); xml = replaceXmlValue(xml, "cookie", _cookie); xml = replaceXmlValue(xml, "natpolicyrefdn", policyRefDn); xml = replaceXmlValue(xml, "natpolicyname", name); - List policies = listNatPolicies(tenantName); - int order = 100; - if (policies != null) { - order += policies.size(); + // PF and static NAT policies need to come before source NAT, so leaving buffer + // and creating source NAT with a high order value. + // Initially tried setting MAX_INT as the order but VNMC complains about it + int order = 10000; // TODO: For now value should be sufficient, if required may need to increase + if (!isSourceNat) { + List policies = listNatPolicies(tenantName); + order = 100; // order starts at 100 + if (policies != null) { + order += policies.size(); + } } xml = replaceXmlValue(xml, "order", Integer.toString(order)); @@ -1062,7 +1069,8 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { return createTenantVDCNatPolicyRef( getDnForPFPolicyRef(tenantName, identifier), getNameForPFPolicy(tenantName, identifier), - tenantName); + tenantName, + false); } @Override @@ -1180,7 +1188,8 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { return createTenantVDCNatPolicyRef( getDnForDNatPolicyRef(tenantName, identifier), getNameForDNatPolicy(tenantName, identifier), - tenantName); + tenantName, + false); } @Override diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElement.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElement.java index 443bb40f57f..b335edb9f63 100644 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElement.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/element/CiscoVnmcElement.java @@ -70,6 +70,7 @@ import com.cloud.deploy.DeployDestination; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.host.DetailVO; import com.cloud.host.Host; @@ -104,6 +105,7 @@ import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; import com.cloud.network.resource.CiscoVnmcResource; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.FirewallRule.TrafficType; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.StaticNat; import com.cloud.offering.NetworkOffering; @@ -113,6 +115,7 @@ import com.cloud.resource.ResourceStateAdapter; import com.cloud.resource.ServerResource; import com.cloud.resource.UnableDeleteHostException; import com.cloud.user.Account; +import com.cloud.user.UserContext; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; @@ -338,10 +341,31 @@ public class CiscoVnmcElement extends AdapterBase implements SourceNatServicePro publicGateways.add(vlanVO.getVlanGateway()); } + // due to VNMC limitation of not allowing source NAT ip as the outside ip of firewall, + // an additional public ip needs to acquired for assigning as firewall outside ip + IpAddress outsideIp = null; + try { + Account caller = UserContext.current().getCaller(); + long callerUserId = UserContext.current().getCallerUserId(); + outsideIp = _networkMgr.allocateIp(owner, false, caller, callerUserId, zone); + } catch (ResourceAllocationException e) { + s_logger.error("Unable to allocate additional public Ip address. Exception details " + e); + return false; + } + + try { + outsideIp = _networkMgr.associateIPToGuestNetwork(outsideIp.getId(), network.getId(), true); + } catch (ResourceAllocationException e) { + s_logger.error("Unable to assign allocated additional public Ip " + outsideIp.getAddress().addr() + " to network with vlan " + vlanId + ". Exception details " + e); + return false; + } + // create logical edge firewall in VNMC String gatewayNetmask = NetUtils.getCidrNetmask(network.getCidr()); + // due to ASA limitation of allowing single subnet to be assigned to firewall interfaces, + // all public ip addresses must be from same subnet, this essentially means single public subnet in zone if (!createLogicalEdgeFirewall(vlanId, network.getGateway(), gatewayNetmask, - sourceNatIp.getAddress().addr(), sourceNatIp.getNetmask(), publicGateways, ciscoVnmcHost.getId())) { + outsideIp.getAddress().addr(), sourceNatIp.getNetmask(), publicGateways, ciscoVnmcHost.getId())) { s_logger.error("Failed to create logical edge firewall in Cisco VNMC device for network " + network.getName()); return false; } @@ -356,10 +380,10 @@ public class CiscoVnmcElement extends AdapterBase implements SourceNatServicePro } // configure source NAT - //if (!configureSourceNat(vlanId, network.getCidr(), sourceNatIp, ciscoVnmcHost.getId())) { - // s_logger.error("Failed to configure source NAT in Cisco VNMC device for network " + network.getName()); - // return false; - //} + if (!configureSourceNat(vlanId, network.getCidr(), sourceNatIp, ciscoVnmcHost.getId())) { + s_logger.error("Failed to configure source NAT in Cisco VNMC device for network " + network.getName()); + return false; + } // associate Asa 1000v instance with logical edge firewall if (!associateAsaWithLogicalEdgeFirewall(vlanId, assignedAsa.getManagementIp(), ciscoVnmcHost.getId())) { @@ -434,16 +458,14 @@ public class CiscoVnmcElement extends AdapterBase implements SourceNatServicePro @Override public boolean isReady(PhysicalNetworkServiceProvider provider) { - // TODO Auto-generated method stub - return false; + return true; } @Override public boolean shutdownProviderInstances( PhysicalNetworkServiceProvider provider, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { - // TODO Auto-generated method stub - return false; + return true; } @Override @@ -656,8 +678,12 @@ public class CiscoVnmcElement extends AdapterBase implements SourceNatServicePro List rulesTO = new ArrayList(); for (FirewallRule rule : rules) { - IpAddress sourceIp = _networkModel.getIp(rule.getSourceIpAddressId()); - FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null, sourceIp.getAddress().addr(), rule.getPurpose(), rule.getTrafficType()); + String address = "0.0.0.0"; + if (rule.getTrafficType() == TrafficType.Ingress) { + IpAddress sourceIp = _networkModel.getIp(rule.getSourceIpAddressId()); + address = sourceIp.getAddress().addr(); + } + FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null, address, rule.getPurpose(), rule.getTrafficType()); rulesTO.add(ruleTO); } diff --git a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/resource/CiscoVnmcResource.java b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/resource/CiscoVnmcResource.java index 91559782304..906e0ae6e85 100644 --- a/plugins/network-elements/cisco-vnmc/src/com/cloud/network/resource/CiscoVnmcResource.java +++ b/plugins/network-elements/cisco-vnmc/src/com/cloud/network/resource/CiscoVnmcResource.java @@ -368,29 +368,29 @@ public class CiscoVnmcResource implements ServerResource { if (!_connection.createTenantVDCIngressAclRule(tenant, Long.toString(rule.getId()), policyIdentifier, rule.getProtocol().toUpperCase(), externalIpRange[0], externalIpRange[1], - Integer.toString(rule.getSrcPortRange()[0]), Integer.toString(rule.getSrcPortRange()[1]), publicIp)) { + Integer.toString(rule.getSrcPortRange()[0]), Integer.toString(rule.getSrcPortRange()[1]))) { throw new Exception("Failed to create ACL ingress rule in VNMC for guest network with vlan " + vlanId); } } else { if (!_connection.createTenantVDCIngressAclRule(tenant, Long.toString(rule.getId()), policyIdentifier, - rule.getProtocol().toUpperCase(), externalIpRange[0], externalIpRange[1], publicIp)) { + rule.getProtocol().toUpperCase(), externalIpRange[0], externalIpRange[1])) { throw new Exception("Failed to create ACL ingress rule in VNMC for guest network with vlan " + vlanId); } } } else { - if (!rule.getProtocol().equalsIgnoreCase("icmp")) { + if (rule.getProtocol().equalsIgnoreCase("tcp") || rule.getProtocol().equalsIgnoreCase("udp")) { if (!_connection.createTenantVDCEgressAclRule(tenant, Long.toString(rule.getId()), policyIdentifier, rule.getProtocol().toUpperCase(), - Integer.toString(rule.getSrcPortRange()[0]), Integer.toString(rule.getSrcPortRange()[1]), publicIp, - externalIpRange[0], externalIpRange[1])) { + externalIpRange[0], externalIpRange[1], + Integer.toString(rule.getSrcPortRange()[0]), Integer.toString(rule.getSrcPortRange()[1]))) { throw new Exception("Failed to create ACL egress rule in VNMC for guest network with vlan " + vlanId); } } else { if (!_connection.createTenantVDCEgressAclRule(tenant, Long.toString(rule.getId()), policyIdentifier, - rule.getProtocol().toUpperCase(), publicIp, externalIpRange[0], externalIpRange[1])) { + rule.getProtocol().toUpperCase(), externalIpRange[0], externalIpRange[1])) { throw new Exception("Failed to create ACL egress rule in VNMC for guest network with vlan " + vlanId); } } diff --git a/plugins/network-elements/cisco-vnmc/test/com/cloud/network/resource/CiscoVnmcResourceTest.java b/plugins/network-elements/cisco-vnmc/test/com/cloud/network/resource/CiscoVnmcResourceTest.java index e814fdcd4d5..acfc5ebaaa7 100755 --- a/plugins/network-elements/cisco-vnmc/test/com/cloud/network/resource/CiscoVnmcResourceTest.java +++ b/plugins/network-elements/cisco-vnmc/test/com/cloud/network/resource/CiscoVnmcResourceTest.java @@ -171,11 +171,11 @@ public class CiscoVnmcResourceTest { when(_connection.createTenantVDCIngressAclRule( anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), - anyString(), anyString(), anyString())).thenReturn(true); + anyString(), anyString())).thenReturn(true); when(_connection.createTenantVDCEgressAclRule( anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), - anyString(), anyString(), anyString())).thenReturn(true); + anyString(), anyString())).thenReturn(true); when(_connection.associateAclPolicySet(anyString())).thenReturn(true); Answer answer = _resource.executeRequest(cmd); diff --git a/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/element/ElasticLoadBalancerElement.java b/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/element/ElasticLoadBalancerElement.java index bebba3cb09d..8b1b4140a8d 100644 --- a/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/element/ElasticLoadBalancerElement.java +++ b/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/element/ElasticLoadBalancerElement.java @@ -35,6 +35,7 @@ import com.cloud.deploy.DeployDestination; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.exception.UnsupportedServiceException; import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; @@ -46,6 +47,7 @@ import com.cloud.network.PublicIpAddress; import com.cloud.network.dao.NetworkDao; import com.cloud.network.lb.ElasticLoadBalancerManager; import com.cloud.network.lb.LoadBalancingRule; +import com.cloud.network.rules.LoadBalancerContainer; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.utils.component.AdapterBase; @@ -68,12 +70,25 @@ public class ElasticLoadBalancerElement extends AdapterBase implements LoadBalan boolean _enabled; TrafficType _frontEndTrafficType = TrafficType.Guest; - private boolean canHandle(Network network) { + private boolean canHandle(Network network, List rules) { if (network.getGuestType() != Network.GuestType.Shared|| network.getTrafficType() != TrafficType.Guest) { s_logger.debug("Not handling network with type " + network.getGuestType() + " and traffic type " + network.getTrafficType()); return false; } + Map lbCaps = this.getCapabilities().get(Service.Lb); + if (!lbCaps.isEmpty()) { + String schemeCaps = lbCaps.get(Capability.LbSchemes); + if (schemeCaps != null) { + for (LoadBalancingRule rule : rules) { + if (!schemeCaps.contains(rule.getScheme().toString())) { + s_logger.debug("Scheme " + rules.get(0).getScheme() + " is not supported by the provider " + this.getName()); + return false; + } + } + } + } + return true; } @@ -94,6 +109,7 @@ public class ElasticLoadBalancerElement extends AdapterBase implements LoadBalan lbCapabilities.put(Capability.SupportedLBAlgorithms, "roundrobin,leastconn,source"); lbCapabilities.put(Capability.SupportedLBIsolation, "shared"); lbCapabilities.put(Capability.SupportedProtocols, "tcp, udp"); + lbCapabilities.put(Capability.LbSchemes, LoadBalancerContainer.Scheme.Public.toString()); capabilities.put(Service.Lb, lbCapabilities); return capabilities; @@ -139,10 +155,10 @@ public class ElasticLoadBalancerElement extends AdapterBase implements LoadBalan @Override public boolean applyLBRules(Network network, List rules) throws ResourceUnavailableException { - if (!canHandle(network)) { + if (!canHandle(network, rules)) { return false; } - + return _lbMgr.applyLoadBalancerRules(network, rules); } diff --git a/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManager.java b/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManager.java index aea795d436f..cce2b2c23c1 100644 --- a/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManager.java +++ b/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManager.java @@ -19,11 +19,11 @@ package com.cloud.network.lb; import java.util.List; import org.apache.cloudstack.api.command.user.loadbalancer.CreateLoadBalancerRuleCmd; + import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; -import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.LoadBalancer; import com.cloud.user.Account; @@ -32,7 +32,7 @@ public interface ElasticLoadBalancerManager { public static final int DEFAULT_ELB_VM_CPU_MHZ = 256; // 500 MHz public boolean applyLoadBalancerRules(Network network, - List rules) + List rules) throws ResourceUnavailableException; public LoadBalancer handleCreateLoadBalancerRule(CreateLoadBalancerRuleCmd lb, Account caller, long networkId) throws InsufficientAddressCapacityException, NetworkRuleConflictException; diff --git a/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java b/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java index 283b517dce9..b21e8f9dba3 100644 --- a/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java +++ b/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java @@ -102,7 +102,6 @@ import com.cloud.network.router.VirtualRouter.RedundantState; import com.cloud.network.router.VirtualRouter.Role; import com.cloud.network.router.VpcVirtualNetworkApplianceManager; import com.cloud.network.rules.FirewallRule; -import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.LoadBalancer; import com.cloud.offering.NetworkOffering; import com.cloud.offering.ServiceOffering; @@ -118,7 +117,6 @@ import com.cloud.user.UserContext; import com.cloud.user.dao.AccountDao; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; -import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.DB; @@ -126,6 +124,7 @@ import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; import com.cloud.vm.DomainRouterVO; import com.cloud.vm.NicProfile; import com.cloud.vm.ReservationContext; @@ -297,8 +296,7 @@ ElasticLoadBalancerManager, VirtualMachineGuru { String protocol = rule.getProtocol(); String algorithm = rule.getAlgorithm(); - String elbIp = _networkModel.getIp(rule.getSourceIpAddressId()).getAddress() - .addr(); + String elbIp = rule.getSourceIp().addr(); int srcPort = rule.getSourcePortStart(); String uuid = rule.getUuid(); List destinations = rule.getDestinations(); @@ -331,8 +329,10 @@ ElasticLoadBalancerManager, VirtualMachineGuru { return sendCommandsToRouter(elbVm, cmds); } - protected DomainRouterVO findElbVmForLb(FirewallRule lb) {//TODO: use a table to lookup - ElasticLbVmMapVO map = _elbVmMapDao.findOneByIp(lb.getSourceIpAddressId()); + protected DomainRouterVO findElbVmForLb(LoadBalancingRule lb) {//TODO: use a table to lookup + Network ntwk = _networkModel.getNetwork(lb.getNetworkId()); + long sourceIpId = _networkModel.getPublicIpAddress(lb.getSourceIp().addr(), ntwk.getDataCenterId()).getId(); + ElasticLbVmMapVO map = _elbVmMapDao.findOneByIp(sourceIpId); if (map == null) { return null; } @@ -342,15 +342,11 @@ ElasticLoadBalancerManager, VirtualMachineGuru { @Override public boolean applyLoadBalancerRules(Network network, - List rules) + List rules) throws ResourceUnavailableException { if (rules == null || rules.isEmpty()) { return true; } - if (rules.get(0).getPurpose() != Purpose.LoadBalancing) { - s_logger.warn("ELB: Not handling non-LB firewall rules"); - return false; - } DomainRouterVO elbVm = findElbVmForLb(rules.get(0)); @@ -363,14 +359,16 @@ ElasticLoadBalancerManager, VirtualMachineGuru { if (elbVm.getState() == State.Running) { //resend all rules for the public ip - List lbs = _lbDao.listByIpAddress(rules.get(0).getSourceIpAddressId()); + long sourceIpId = _networkModel.getPublicIpAddress(rules.get(0).getSourceIp().addr(), network.getDataCenterId()).getId(); + List lbs = _lbDao.listByIpAddress(sourceIpId); List lbRules = new ArrayList(); for (LoadBalancerVO lb : lbs) { List dstList = _lbMgr.getExistingDestinations(lb.getId()); List policyList = _lbMgr.getStickinessPolicies(lb.getId()); List hcPolicyList = _lbMgr.getHealthCheckPolicies(lb.getId()); + Ip sourceIp = _networkModel.getPublicIpAddress(lb.getSourceIpAddressId()).getAddress(); LoadBalancingRule loadBalancing = new LoadBalancingRule( - lb, dstList, policyList, hcPolicyList); + lb, dstList, policyList, hcPolicyList, sourceIp); lbRules.add(loadBalancing); } return applyLBRules(elbVm, lbRules, network.getId()); @@ -656,7 +654,10 @@ ElasticLoadBalancerManager, VirtualMachineGuru { LoadBalancer result = null; try { lb.setSourceIpAddressId(ipId); - result = _lbMgr.createLoadBalancer(lb, false); + + result = _lbMgr.createPublicLoadBalancer(lb.getXid(), lb.getName(), lb.getDescription(), + lb.getSourcePortStart(), lb.getDefaultPortStart(), ipId.longValue(), lb.getProtocol(), + lb.getAlgorithm(), false, UserContext.current()); } catch (NetworkRuleConflictException e) { s_logger.warn("Failed to create LB rule, not continuing with ELB deployment"); if (newIp) { @@ -943,7 +944,8 @@ ElasticLoadBalancerManager, VirtualMachineGuru { List dstList = _lbMgr.getExistingDestinations(lb.getId()); List policyList = _lbMgr.getStickinessPolicies(lb.getId()); List hcPolicyList = _lbMgr.getHealthCheckPolicies(lb.getId()); - LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList); + Ip sourceIp = _networkModel.getPublicIpAddress(lb.getSourceIpAddressId()).getAddress(); + LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList, sourceIp); lbRules.add(loadBalancing); } diff --git a/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java b/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java index e384e3cfd0d..80b42e030d8 100644 --- a/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java +++ b/plugins/network-elements/f5/src/com/cloud/network/element/F5ExternalLoadBalancerElement.java @@ -16,9 +16,30 @@ // under the License. package com.cloud.network.element; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.ejb.Local; +import javax.inject.Inject; + +import org.apache.cloudstack.api.response.ExternalLoadBalancerResponse; +import org.apache.cloudstack.network.ExternalNetworkDeviceManager.NetworkDevice; +import org.apache.log4j.Logger; + import com.cloud.agent.api.to.LoadBalancerTO; import com.cloud.api.ApiDBUtils; -import com.cloud.api.commands.*; +import com.cloud.api.commands.AddExternalLoadBalancerCmd; +import com.cloud.api.commands.AddF5LoadBalancerCmd; +import com.cloud.api.commands.ConfigureF5LoadBalancerCmd; +import com.cloud.api.commands.DeleteExternalLoadBalancerCmd; +import com.cloud.api.commands.DeleteF5LoadBalancerCmd; +import com.cloud.api.commands.ListExternalLoadBalancersCmd; +import com.cloud.api.commands.ListF5LoadBalancerNetworksCmd; +import com.cloud.api.commands.ListF5LoadBalancersCmd; import com.cloud.api.response.F5LoadBalancerResponse; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; @@ -27,22 +48,41 @@ import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; import com.cloud.dc.dao.DataCenterDao; import com.cloud.deploy.DeployDestination; -import com.cloud.exception.*; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InsufficientNetworkCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceUnavailableException; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.host.dao.HostDetailsDao; -import com.cloud.network.*; +import com.cloud.network.ExternalLoadBalancerDeviceManager; +import com.cloud.network.ExternalLoadBalancerDeviceManagerImpl; +import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; +import com.cloud.network.NetworkModel; import com.cloud.network.Networks.TrafficType; -import com.cloud.network.dao.*; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.PublicIpAddress; +import com.cloud.network.dao.ExternalLoadBalancerDeviceDao; +import com.cloud.network.dao.ExternalLoadBalancerDeviceVO; import com.cloud.network.dao.ExternalLoadBalancerDeviceVO.LBDeviceState; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkExternalLoadBalancerDao; +import com.cloud.network.dao.NetworkExternalLoadBalancerVO; +import com.cloud.network.dao.NetworkServiceMapDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.resource.F5BigIpResource; import com.cloud.network.rules.LbStickinessMethod; import com.cloud.network.rules.LbStickinessMethod.StickinessMethodType; +import com.cloud.network.rules.LoadBalancerContainer; import com.cloud.offering.NetworkOffering; import com.cloud.utils.NumbersUtil; import com.cloud.utils.exception.CloudRuntimeException; @@ -51,13 +91,6 @@ import com.cloud.vm.ReservationContext; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; import com.google.gson.Gson; -import org.apache.cloudstack.api.response.ExternalLoadBalancerResponse; -import org.apache.cloudstack.network.ExternalNetworkDeviceManager.NetworkDevice; -import org.apache.log4j.Logger; - -import javax.ejb.Local; -import javax.inject.Inject; -import java.util.*; @Local(value = {NetworkElement.class, LoadBalancingServiceProvider.class, IpDeployer.class}) public class F5ExternalLoadBalancerElement extends ExternalLoadBalancerDeviceManagerImpl implements LoadBalancingServiceProvider, IpDeployer, F5ExternalLoadBalancerElementService, ExternalLoadBalancerDeviceManager { @@ -87,11 +120,25 @@ public class F5ExternalLoadBalancerElement extends ExternalLoadBalancerDeviceMan @Inject ConfigurationDao _configDao; - private boolean canHandle(Network config) { + private boolean canHandle(Network config, List rules) { if ((config.getGuestType() != Network.GuestType.Isolated && config.getGuestType() != Network.GuestType.Shared) || config.getTrafficType() != TrafficType.Guest) { + s_logger.trace("Not handling network with Type " + config.getGuestType() + " and traffic type " + config.getTrafficType()); return false; } + + Map lbCaps = this.getCapabilities().get(Service.Lb); + if (!lbCaps.isEmpty()) { + String schemeCaps = lbCaps.get(Capability.LbSchemes); + if (schemeCaps != null && rules != null && !rules.isEmpty()) { + for (LoadBalancingRule rule : rules) { + if (!schemeCaps.contains(rule.getScheme().toString())) { + s_logger.debug("Scheme " + rules.get(0).getScheme() + " is not supported by the provider " + this.getName()); + return false; + } + } + } + } return (_networkManager.isProviderForNetwork(getProvider(), config.getId()) && _ntwkSrvcDao.canProviderSupportServiceInNetwork(config.getId(), Service.Lb, Network.Provider.F5BigIp)); } @@ -100,7 +147,7 @@ public class F5ExternalLoadBalancerElement extends ExternalLoadBalancerDeviceMan public boolean implement(Network guestConfig, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException, ConcurrentOperationException, InsufficientNetworkCapacityException { - if (!canHandle(guestConfig)) { + if (!canHandle(guestConfig, null)) { return false; } @@ -124,7 +171,7 @@ public class F5ExternalLoadBalancerElement extends ExternalLoadBalancerDeviceMan @Override public boolean shutdown(Network guestConfig, ReservationContext context, boolean cleanup) throws ResourceUnavailableException, ConcurrentOperationException { - if (!canHandle(guestConfig)) { + if (!canHandle(guestConfig, null)) { return false; } @@ -143,13 +190,16 @@ public class F5ExternalLoadBalancerElement extends ExternalLoadBalancerDeviceMan @Override public boolean validateLBRule(Network network, LoadBalancingRule rule) { - String algo = rule.getAlgorithm(); - return (algo.equals("roundrobin") || algo.equals("leastconn")); + if (canHandle(network, new ArrayList(Arrays.asList(rule)))) { + String algo = rule.getAlgorithm(); + return (algo.equals("roundrobin") || algo.equals("leastconn")); + } + return true; } @Override public boolean applyLBRules(Network config, List rules) throws ResourceUnavailableException { - if (!canHandle(config)) { + if (!canHandle(config, rules)) { return false; } @@ -180,6 +230,9 @@ public class F5ExternalLoadBalancerElement extends ExternalLoadBalancerDeviceMan // Support inline mode with firewall lbCapabilities.put(Capability.InlineMode, "true"); + + //support only for public lb + lbCapabilities.put(Capability.LbSchemes, LoadBalancerContainer.Scheme.Public.toString()); LbStickinessMethod method; List methodList = new ArrayList(); diff --git a/plugins/network-elements/internal-loadbalancer/pom.xml b/plugins/network-elements/internal-loadbalancer/pom.xml new file mode 100644 index 00000000000..48e664ee0e5 --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + cloud-plugin-network-internallb + Apache CloudStack Plugin - Network Internal Load Balancer + + org.apache.cloudstack + cloudstack-plugins + 4.2.0-SNAPSHOT + ../../pom.xml + + + install + src + test + + + resources + + **/*.xml + + + + + + test/resources + + %regex[.*[0-9]*To[0-9]*.*Test.*] + + + + + diff --git a/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java new file mode 100644 index 00000000000..4b9308b6606 --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java @@ -0,0 +1,548 @@ +// 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. + +package org.apache.cloudstack.network.element; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.ejb.Local; +import javax.inject.Inject; + +import org.apache.cloudstack.api.command.admin.internallb.ConfigureInternalLoadBalancerElementCmd; +import org.apache.cloudstack.api.command.admin.internallb.CreateInternalLoadBalancerElementCmd; +import org.apache.cloudstack.api.command.admin.internallb.ListInternalLoadBalancerElementsCmd; +import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; +import org.apache.cloudstack.network.lb.InternalLoadBalancerVMManager; +import org.apache.log4j.Logger; + +import com.cloud.agent.api.to.LoadBalancerTO; +import com.cloud.configuration.ConfigurationManager; +import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.deploy.DeployDestination; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Network; +import com.cloud.network.Network.Capability; +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.network.NetworkModel; +import com.cloud.network.Networks.TrafficType; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.PublicIpAddress; +import com.cloud.network.VirtualRouterProvider; +import com.cloud.network.VirtualRouterProvider.VirtualRouterProviderType; +import com.cloud.network.dao.NetworkServiceMapDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.VirtualRouterProviderDao; +import com.cloud.network.element.IpDeployer; +import com.cloud.network.element.LoadBalancingServiceProvider; +import com.cloud.network.element.NetworkElement; +import com.cloud.network.element.VirtualRouterElement; +import com.cloud.network.element.VirtualRouterProviderVO; +import com.cloud.network.lb.LoadBalancingRule; +import com.cloud.network.router.VirtualRouter; +import com.cloud.network.router.VirtualRouter.Role; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.LoadBalancerContainer; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.offering.NetworkOffering; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.User; +import com.cloud.utils.component.AdapterBase; +import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.utils.db.SearchCriteria2; +import com.cloud.utils.db.SearchCriteriaService; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; +import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.NicProfile; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.dao.DomainRouterDao; + +@Local(value = {NetworkElement.class}) +public class InternalLoadBalancerElement extends AdapterBase implements LoadBalancingServiceProvider, InternalLoadBalancerElementService, IpDeployer{ + private static final Logger s_logger = Logger.getLogger(InternalLoadBalancerElement.class); + protected static final Map> capabilities = setCapabilities(); + private static InternalLoadBalancerElement internalLbElement = null; + + @Inject NetworkModel _ntwkModel; + @Inject NetworkServiceMapDao _ntwkSrvcDao; + @Inject DomainRouterDao _routerDao; + @Inject VirtualRouterProviderDao _vrProviderDao; + @Inject PhysicalNetworkServiceProviderDao _pNtwkSvcProviderDao; + @Inject InternalLoadBalancerVMManager _internalLbMgr; + @Inject ConfigurationManager _configMgr; + @Inject AccountManager _accountMgr; + @Inject ApplicationLoadBalancerRuleDao _appLbDao; + + protected InternalLoadBalancerElement() { + } + + + public static InternalLoadBalancerElement getInstance() { + if ( internalLbElement == null) { + internalLbElement = new InternalLoadBalancerElement(); + } + return internalLbElement; + } + + + private boolean canHandle(Network config, Scheme lbScheme) { + //works in Advance zone only + DataCenter dc = _configMgr.getZone(config.getDataCenterId()); + if (dc.getNetworkType() != NetworkType.Advanced) { + s_logger.trace("Not hanling zone of network type " + dc.getNetworkType()); + return false; + } + if (config.getGuestType() != Network.GuestType.Isolated || config.getTrafficType() != TrafficType.Guest) { + s_logger.trace("Not handling network with Type " + config.getGuestType() + " and traffic type " + config.getTrafficType()); + return false; + } + + Map lbCaps = this.getCapabilities().get(Service.Lb); + if (!lbCaps.isEmpty()) { + String schemeCaps = lbCaps.get(Capability.LbSchemes); + if (schemeCaps != null && lbScheme != null) { + if (!schemeCaps.contains(lbScheme.toString())) { + s_logger.debug("Scheme " + lbScheme.toString() + " is not supported by the provider " + this.getName()); + return false; + } + } + } + + if (!_ntwkModel.isProviderSupportServiceInNetwork(config.getId(), Service.Lb, getProvider())) { + s_logger.trace("Element " + getProvider().getName() + " doesn't support service " + Service.Lb + + " in the network " + config); + return false; + } + return true; + } + + + @Override + public Map> getCapabilities() { + return capabilities; + } + + + @Override + public Provider getProvider() { + return Provider.InternalLbVm; + } + + + @Override + public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) + throws ConcurrentOperationException, ResourceUnavailableException, + InsufficientCapacityException { + + if (!canHandle(network, null)) { + s_logger.trace("No need to implement " + this.getName()); + return true; + } + + //1) Get all the Ips from the network having LB rules assigned + List ips = _appLbDao.listLbIpsBySourceIpNetworkIdAndScheme(network.getId(), Scheme.Internal); + + //2) Start those vms + for (String ip : ips) { + Ip sourceIp = new Ip(ip); + List internalLbVms; + try { + internalLbVms = _internalLbMgr.deployInternalLbVm(network, sourceIp, dest, _accountMgr.getAccount(network.getAccountId()), null); + } catch (InsufficientCapacityException e) { + s_logger.warn("Failed to deploy element " + this.getName() + " for ip " + sourceIp + " due to:", e); + return false; + } catch (ConcurrentOperationException e) { + s_logger.warn("Failed to deploy element " + this.getName() + " for ip " + sourceIp + " due to:", e); + return false; + } + + if (internalLbVms == null || internalLbVms.isEmpty()) { + throw new ResourceUnavailableException("Can't deploy " + this.getName() + " to handle LB rules", + DataCenter.class, network.getDataCenterId()); + } + } + + return true; + } + + + @Override + public boolean prepare(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, + ResourceUnavailableException, InsufficientCapacityException { + + if (!canHandle(network, null)) { + s_logger.trace("No need to prepare " + this.getName()); + return true; + } + + if (vm.getType() == VirtualMachine.Type.User) { + //1) Get all the Ips from the network having LB rules assigned + List ips = _appLbDao.listLbIpsBySourceIpNetworkIdAndScheme(network.getId(), Scheme.Internal); + + //2) Start those vms + for (String ip : ips) { + Ip sourceIp = new Ip(ip); + List internalLbVms; + try { + internalLbVms = _internalLbMgr.deployInternalLbVm(network, sourceIp, dest, _accountMgr.getAccount(network.getAccountId()), null); + } catch (InsufficientCapacityException e) { + s_logger.warn("Failed to deploy element " + this.getName() + " for ip " + sourceIp + " due to:", e); + return false; + } catch (ConcurrentOperationException e) { + s_logger.warn("Failed to deploy element " + this.getName() + " for ip " + sourceIp + " due to:", e); + return false; + } + + if (internalLbVms == null || internalLbVms.isEmpty()) { + throw new ResourceUnavailableException("Can't deploy " + this.getName() + " to handle LB rules", + DataCenter.class, network.getDataCenterId()); + } + } + } + + return true; + } + + @Override + public boolean release(Network network, NicProfile nic, VirtualMachineProfile vm, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { + return true; + } + + + @Override + public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { + List internalLbVms = _routerDao.listByNetworkAndRole(network.getId(), Role.INTERNAL_LB_VM); + if (internalLbVms == null || internalLbVms.isEmpty()) { + return true; + } + boolean result = true; + for (VirtualRouter internalLbVm : internalLbVms) { + result = result && _internalLbMgr.destroyInternalLbVm(internalLbVm.getId(), + context.getAccount(), context.getCaller().getId()); + if (cleanup) { + if (!result) { + s_logger.warn("Failed to stop internal lb element " + internalLbVm + ", but would try to process clean up anyway."); + } + result = (_internalLbMgr.destroyInternalLbVm(internalLbVm.getId(), + context.getAccount(), context.getCaller().getId())); + if (!result) { + s_logger.warn("Failed to clean up internal lb element " + internalLbVm); + } + } + } + return result; + } + + + @Override + public boolean destroy(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { + List internalLbVms = _routerDao.listByNetworkAndRole(network.getId(), Role.INTERNAL_LB_VM); + if (internalLbVms == null || internalLbVms.isEmpty()) { + return true; + } + boolean result = true; + for (VirtualRouter internalLbVm : internalLbVms) { + result = result && (_internalLbMgr.destroyInternalLbVm(internalLbVm.getId(), + context.getAccount(), context.getCaller().getId())); + } + return result; + } + + + @Override + public boolean isReady(PhysicalNetworkServiceProvider provider) { + VirtualRouterProviderVO element = _vrProviderDao.findByNspIdAndType(provider.getId(), + VirtualRouterProviderType.InternalLbVm); + if (element == null) { + return false; + } + return element.isEnabled(); + } + + + @Override + public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) + throws ConcurrentOperationException, ResourceUnavailableException { + VirtualRouterProviderVO element = _vrProviderDao.findByNspIdAndType(provider.getId(), + VirtualRouterProviderType.InternalLbVm); + if (element == null) { + return true; + } + long elementId = element.getId(); + List internalLbVms = _routerDao.listByElementId(elementId); + boolean result = true; + for (DomainRouterVO internalLbVm : internalLbVms) { + result = result && (_internalLbMgr.destroyInternalLbVm(internalLbVm.getId(), + context.getAccount(), context.getCaller().getId())); + } + _vrProviderDao.remove(elementId); + + return result; + } + + + @Override + public boolean canEnableIndividualServices() { + return true; + } + + + @Override + public boolean verifyServicesCombination(Set services) { + return true; + } + + + @Override + public IpDeployer getIpDeployer(Network network) { + return this; + } + + + @Override + public boolean applyLBRules(Network network, List rules) throws ResourceUnavailableException { + //1) Get Internal LB VMs to destroy + Set vmsToDestroy = getVmsToDestroy(rules); + + //2) Get rules to apply + Map> rulesToApply = getLbRulesToApply(rules); + s_logger.debug("Applying " + rulesToApply.size() + " on element " + this.getName()); + + + for (Ip sourceIp : rulesToApply.keySet()) { + if (vmsToDestroy.contains(sourceIp)) { + //2.1 Destroy internal lb vm + List vms = _internalLbMgr.findInternalLbVms(network.getId(), sourceIp); + if (vms.size() > 0) { + //only one internal lb per IP exists + try { + s_logger.debug("Destroying internal lb vm for ip " + sourceIp.addr() + " as all the rules for this vm are in Revoke state"); + return _internalLbMgr.destroyInternalLbVm(vms.get(0).getId(), _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM), + _accountMgr.getUserIncludingRemoved(User.UID_SYSTEM).getId()); + } catch (ConcurrentOperationException e) { + s_logger.warn("Failed to apply lb rule(s) for ip " + sourceIp.addr() + " on the element " + this.getName() + " due to:", e); + return false; + } + } + } else { + //2.2 Start Internal LB vm per IP address + List internalLbVms; + try { + DeployDestination dest = new DeployDestination(_configMgr.getZone(network.getDataCenterId()), null, null, null); + internalLbVms = _internalLbMgr.deployInternalLbVm(network, sourceIp, dest, _accountMgr.getAccount(network.getAccountId()), null); + } catch (InsufficientCapacityException e) { + s_logger.warn("Failed to apply lb rule(s) for ip " + sourceIp.addr() + "on the element " + this.getName() + " due to:", e); + return false; + } catch (ConcurrentOperationException e) { + s_logger.warn("Failed to apply lb rule(s) for ip " + sourceIp.addr() + "on the element " + this.getName() + " due to:", e); + return false; + } + + if (internalLbVms == null || internalLbVms.isEmpty()) { + throw new ResourceUnavailableException("Can't find/deploy internal lb vm to handle LB rules", + DataCenter.class, network.getDataCenterId()); + } + + //2.3 Apply Internal LB rules on the VM + if (!_internalLbMgr.applyLoadBalancingRules(network, rulesToApply.get(sourceIp), internalLbVms)) { + throw new CloudRuntimeException("Failed to apply load balancing rules for ip " + sourceIp.addr() + + " in network " + network.getId() + " on element " + this.getName()); + } + } + } + + return true; + } + + + protected Map> getLbRulesToApply(List rules) { + //Group rules by the source ip address as NetworkManager always passes the entire network lb config to the element + Map> rulesToApply = groupBySourceIp(rules); + + return rulesToApply; + } + + + protected Set getVmsToDestroy(List rules) { + //1) Group rules by the source ip address as NetworkManager always passes the entire network lb config to the element + Map> groupedRules = groupBySourceIp(rules); + + //2) Count rules in revoke state + Set vmsToDestroy = new HashSet(); + + for (Ip sourceIp : groupedRules.keySet()) { + List rulesToCheck = groupedRules.get(sourceIp); + int revoke = 0; + for (LoadBalancingRule ruleToCheck : rulesToCheck) { + if (ruleToCheck.getState() == FirewallRule.State.Revoke){ + revoke++; + } + } + + if (revoke == rulesToCheck.size()) { + s_logger.debug("Have to destroy internal lb vm for source ip " + sourceIp); + vmsToDestroy.add(sourceIp); + } + } + return vmsToDestroy; + } + + + protected Map> groupBySourceIp(List rules) { + Map> groupedRules = new HashMap>(); + for (LoadBalancingRule rule : rules) { + Ip sourceIp = rule.getSourceIp(); + if (!groupedRules.containsKey(sourceIp)) { + groupedRules.put(sourceIp, null); + } + + List rulesToApply = groupedRules.get(sourceIp); + if (rulesToApply == null) { + rulesToApply = new ArrayList(); + } + rulesToApply.add(rule); + groupedRules.put(sourceIp, rulesToApply); + } + return groupedRules; + } + + @Override + public boolean validateLBRule(Network network, LoadBalancingRule rule) { + List rules = new ArrayList(); + rules.add(rule); + if (canHandle(network, rule.getScheme())) { + List routers = _routerDao.listByNetworkAndRole(network.getId(), Role.INTERNAL_LB_VM); + if (routers == null || routers.isEmpty()) { + return true; + } + return VirtualRouterElement.validateHAProxyLBRule(rule); + } + return true; + } + + @Override + public List updateHealthChecks(Network network, List lbrules) { + return null; + } + + private static Map> setCapabilities() { + Map> capabilities = new HashMap>(); + + // Set capabilities for LB service + Map lbCapabilities = new HashMap(); + lbCapabilities.put(Capability.SupportedLBAlgorithms, "roundrobin,leastconn,source"); + lbCapabilities.put(Capability.SupportedLBIsolation, "dedicated"); + lbCapabilities.put(Capability.SupportedProtocols, "tcp, udp"); + lbCapabilities.put(Capability.SupportedStickinessMethods, VirtualRouterElement.getHAProxyStickinessCapability()); + lbCapabilities.put(Capability.LbSchemes, LoadBalancerContainer.Scheme.Internal.toString()); + + capabilities.put(Service.Lb, lbCapabilities); + return capabilities; + } + + @Override + public List> getCommands() { + List> cmdList = new ArrayList>(); + cmdList.add(CreateInternalLoadBalancerElementCmd.class); + cmdList.add(ConfigureInternalLoadBalancerElementCmd.class); + cmdList.add(ListInternalLoadBalancerElementsCmd.class); + return cmdList; + } + + @Override + public VirtualRouterProvider configureInternalLoadBalancerElement(long id, boolean enable) { + VirtualRouterProviderVO element = _vrProviderDao.findById(id); + if (element == null || element.getType() != VirtualRouterProviderType.InternalLbVm) { + throw new InvalidParameterValueException("Can't find " + this.getName() + " element with network service provider id " + id + + " to be used as a provider for " + this.getName()); + } + + element.setEnabled(enable); + element = _vrProviderDao.persist(element); + + return element; + } + + @Override + public VirtualRouterProvider addInternalLoadBalancerElement(long ntwkSvcProviderId) { + VirtualRouterProviderVO element = _vrProviderDao.findByNspIdAndType(ntwkSvcProviderId, VirtualRouterProviderType.InternalLbVm); + if (element != null) { + s_logger.debug("There is already an " + this.getName() + " with service provider id " + ntwkSvcProviderId); + return null; + } + + PhysicalNetworkServiceProvider provider = _pNtwkSvcProviderDao.findById(ntwkSvcProviderId); + if (provider == null || !provider.getProviderName().equalsIgnoreCase(this.getName())) { + throw new InvalidParameterValueException("Invalid network service provider is specified"); + } + + element = new VirtualRouterProviderVO(ntwkSvcProviderId, VirtualRouterProviderType.InternalLbVm); + element = _vrProviderDao.persist(element); + return element; + } + + + @Override + public VirtualRouterProvider getInternalLoadBalancerElement(long id) { + VirtualRouterProvider provider = _vrProviderDao.findById(id); + if (provider == null || provider.getType() != VirtualRouterProviderType.InternalLbVm) { + throw new InvalidParameterValueException("Unable to find " + this.getName() + " by id"); + } + return provider; + } + + @Override + public List searchForInternalLoadBalancerElements(Long id, Long ntwkSvsProviderId, Boolean enabled) { + + SearchCriteriaService sc = SearchCriteria2.create(VirtualRouterProviderVO.class); + if (id != null) { + sc.addAnd(sc.getEntity().getId(), Op.EQ, id); + } + if (ntwkSvsProviderId != null) { + sc.addAnd(sc.getEntity().getNspId(), Op.EQ, ntwkSvsProviderId); + } + if (enabled != null) { + sc.addAnd(sc.getEntity().isEnabled(), Op.EQ, enabled); + } + + //return only Internal LB elements + sc.addAnd(sc.getEntity().getType(), Op.EQ, VirtualRouterProvider.VirtualRouterProviderType.InternalLbVm); + + return sc.list(); + } + + @Override + public boolean applyIps(Network network, List ipAddress, Set services) throws ResourceUnavailableException { + //do nothing here; this element just has to extend the ip deployer + //as the LB service implements IPDeployerRequester + return true; + } + +} diff --git a/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManager.java b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManager.java new file mode 100644 index 00000000000..9faca562bfb --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManager.java @@ -0,0 +1,90 @@ +// 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. +package org.apache.cloudstack.network.lb; + +import java.util.List; +import java.util.Map; + +import com.cloud.deploy.DeployDestination; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Network; +import com.cloud.network.lb.LoadBalancingRule; +import com.cloud.network.router.VirtualRouter; +import com.cloud.user.Account; +import com.cloud.utils.component.Manager; +import com.cloud.utils.net.Ip; +import com.cloud.vm.VirtualMachineProfile.Param; + +public interface InternalLoadBalancerVMManager extends Manager, InternalLoadBalancerVMService{ + //RAM/CPU for the system offering used by Internal LB VMs + public static final int DEFAULT_INTERNALLB_VM_RAMSIZE = 128; // 128 MB + public static final int DEFAULT_INTERNALLB_VM_CPU_MHZ = 256; // 256 MHz + + /** + * Destroys Internal LB vm instance + * @param vmId + * @param caller + * @param callerUserId + * @return + * @throws ResourceUnavailableException + * @throws ConcurrentOperationException + */ + boolean destroyInternalLbVm(long vmId, Account caller, Long callerUserId) + throws ResourceUnavailableException, ConcurrentOperationException; + + + /** + * Deploys internal lb vm + * @param guestNetwork + * @param requestedGuestIp + * @param dest + * @param owner + * @param params + * @return + * @throws InsufficientCapacityException + * @throws ConcurrentOperationException + * @throws ResourceUnavailableException + */ + List deployInternalLbVm(Network guestNetwork, Ip requestedGuestIp, DeployDestination dest, Account owner, + Map params) throws InsufficientCapacityException, + ConcurrentOperationException, ResourceUnavailableException; + + + + /** + * + * @param network + * @param rules + * @param internalLbVms + * @return + * @throws ResourceUnavailableException + */ + boolean applyLoadBalancingRules(Network network, List rules, List internalLbVms) + throws ResourceUnavailableException; + + + /** + * Returns existing Internal Load Balancer elements based on guestNetworkId (required) and requestedIp (optional) + * @param guestNetworkId + * @param requestedGuestIp + * @return + */ + List findInternalLbVms(long guestNetworkId, Ip requestedGuestIp); + +} diff --git a/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java new file mode 100644 index 00000000000..fe32a7ba26f --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java @@ -0,0 +1,951 @@ +// 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. +package org.apache.cloudstack.network.lb; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.lb.ApplicationLoadBalancerRuleVO; +import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.AgentManager.OnError; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.GetDomRVersionAnswer; +import com.cloud.agent.api.GetDomRVersionCmd; +import com.cloud.agent.api.StopAnswer; +import com.cloud.agent.api.check.CheckSshAnswer; +import com.cloud.agent.api.check.CheckSshCommand; +import com.cloud.agent.api.routing.LoadBalancerConfigCommand; +import com.cloud.agent.api.routing.NetworkElementCommand; +import com.cloud.agent.api.to.LoadBalancerTO; +import com.cloud.agent.api.to.NicTO; +import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.agent.manager.Commands; +import com.cloud.configuration.Config; +import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.deploy.DataCenterDeployment; +import com.cloud.deploy.DeployDestination; +import com.cloud.deploy.DeploymentPlan; +import com.cloud.exception.AgentUnavailableException; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InsufficientServerCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.OperationTimedoutException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.exception.StorageUnavailableException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.Network; +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkModel; +import com.cloud.network.Networks.TrafficType; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.VirtualRouterProvider; +import com.cloud.network.VirtualRouterProvider.VirtualRouterProviderType; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.VirtualRouterProviderDao; +import com.cloud.network.lb.LoadBalancingRule; +import com.cloud.network.lb.LoadBalancingRule.LbDestination; +import com.cloud.network.lb.LoadBalancingRule.LbHealthCheckPolicy; +import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; +import com.cloud.network.lb.LoadBalancingRulesManager; +import com.cloud.network.router.VirtualRouter; +import com.cloud.network.router.VirtualRouter.RedundantState; +import com.cloud.network.router.VirtualRouter.Role; +import com.cloud.network.rules.FirewallRule; +import com.cloud.offering.NetworkOffering; +import com.cloud.offering.ServiceOffering; +import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.resource.ResourceManager; +import com.cloud.server.ConfigurationServer; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.User; +import com.cloud.utils.Pair; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.db.DB; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; +import com.cloud.utils.net.NetUtils; +import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.Nic; +import com.cloud.vm.NicProfile; +import com.cloud.vm.NicVO; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.State; +import com.cloud.vm.VirtualMachineGuru; +import com.cloud.vm.VirtualMachineManager; +import com.cloud.vm.VirtualMachineName; +import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.VirtualMachineProfile.Param; +import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.NicDao; + +@Component +@Local(value = { InternalLoadBalancerVMManager.class, InternalLoadBalancerVMService.class}) +public class InternalLoadBalancerVMManagerImpl extends ManagerBase implements + InternalLoadBalancerVMManager, VirtualMachineGuru { + private static final Logger s_logger = Logger + .getLogger(InternalLoadBalancerVMManagerImpl.class); + static final private String _internalLbVmNamePrefix = "b"; + + private String _instance; + private String _mgmtHost; + private String _mgmtCidr; + private long _internalLbVmOfferingId; + + @Inject VirtualMachineManager _itMgr; + @Inject DomainRouterDao _internalLbVmDao; + @Inject ConfigurationDao _configDao; + @Inject AgentManager _agentMgr; + @Inject DataCenterDao _dcDao; + @Inject VirtualRouterProviderDao _vrProviderDao; + @Inject ApplicationLoadBalancerRuleDao _lbDao; + @Inject NetworkModel _ntwkModel; + @Inject LoadBalancingRulesManager _lbMgr; + @Inject NicDao _nicDao; + @Inject AccountManager _accountMgr; + @Inject NetworkDao _networkDao; + @Inject NetworkManager _ntwkMgr; + @Inject ServiceOfferingDao _serviceOfferingDao; + @Inject PhysicalNetworkServiceProviderDao _physicalProviderDao; + @Inject NetworkOfferingDao _networkOfferingDao; + @Inject VMTemplateDao _templateDao; + @Inject ResourceManager _resourceMgr; + @Inject ConfigurationServer _configServer; + + @Override + public DomainRouterVO findByName(String name) { + if (!VirtualMachineName.isValidSystemVmName(name, _instance, _internalLbVmNamePrefix)) { + return null; + } + + return _internalLbVmDao.findById(VirtualMachineName.getRouterId(name)); + } + + @Override + public DomainRouterVO findById(long id) { + return _internalLbVmDao.findById(id); + } + + @Override + public DomainRouterVO persist(DomainRouterVO vm) { + DomainRouterVO virtualRouter = _internalLbVmDao.persist(vm); + return virtualRouter; + } + + @Override + public boolean finalizeVirtualMachineProfile(VirtualMachineProfile profile, + DeployDestination dest, ReservationContext context) { + + //Internal LB vm starts up with 2 Nics + //Nic #1 - Guest Nic with IP address that would act as the LB entry point + //Nic #2 - Control/Management Nic + + StringBuilder buf = profile.getBootArgsBuilder(); + buf.append(" template=domP"); + buf.append(" name=").append(profile.getHostName()); + + if (Boolean.valueOf(_configDao.getValue("system.vm.random.password"))) { + buf.append(" vmpassword=").append(_configDao.getValue("system.vm.password")); + } + + NicProfile controlNic = null; + Network guestNetwork = null; + + for (NicProfile nic : profile.getNics()) { + int deviceId = nic.getDeviceId(); + buf.append(" eth").append(deviceId).append("ip=").append(nic.getIp4Address()); + buf.append(" eth").append(deviceId).append("mask=").append(nic.getNetmask()); + + if (nic.isDefaultNic()) { + buf.append(" gateway=").append(nic.getGateway()); + buf.append(" dns1=").append(nic.getGateway()); + } + + if (nic.getTrafficType() == TrafficType.Guest) { + guestNetwork = _ntwkModel.getNetwork(nic.getNetworkId()); + } else if (nic.getTrafficType() == TrafficType.Management) { + buf.append(" localgw=").append(dest.getPod().getGateway()); + } else if (nic.getTrafficType() == TrafficType.Control) { + controlNic = nic; + // Internal LB control command is sent over management server in VMware + if (dest.getHost().getHypervisorType() == HypervisorType.VMware) { + if (s_logger.isInfoEnabled()) { + s_logger.info("Check if we need to add management server explicit route to Internal LB. pod cidr: " + + dest.getPod().getCidrAddress() + "/" + dest.getPod().getCidrSize() + + ", pod gateway: " + dest.getPod().getGateway() + ", management host: " + _mgmtHost); + } + + if (s_logger.isInfoEnabled()) { + s_logger.info("Add management server explicit route to Internal LB."); + } + + + buf.append(" mgmtcidr=").append(_mgmtCidr); + buf.append(" localgw=").append(dest.getPod().getGateway()); + } + } + } + + if (controlNic == null) { + throw new CloudRuntimeException("Didn't start a control port"); + } + + if (guestNetwork != null) { + String domain = guestNetwork.getNetworkDomain(); + if (domain != null) { + buf.append(" domain=" + domain); + } + } + + String type = "ilbvm"; + buf.append(" type=" + type); + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Boot Args for " + profile + ": " + buf.toString()); + } + + return true; + } + + @Override + public boolean finalizeDeployment(Commands cmds, VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException { + DomainRouterVO internalLbVm = profile.getVirtualMachine(); + + List nics = profile.getNics(); + for (NicProfile nic : nics) { + if (nic.getTrafficType() == TrafficType.Control) { + internalLbVm.setPrivateIpAddress(nic.getIp4Address()); + internalLbVm.setPrivateMacAddress(nic.getMacAddress()); + } + } + _internalLbVmDao.update(internalLbVm.getId(), internalLbVm); + + finalizeCommandsOnStart(cmds, profile); + return true; + } + + @Override + public boolean finalizeStart(VirtualMachineProfile profile, long hostId, Commands cmds, ReservationContext context) { + DomainRouterVO internalLbVm = profile.getVirtualMachine(); + + boolean result = true; + + Answer answer = cmds.getAnswer("checkSsh"); + if (answer != null && answer instanceof CheckSshAnswer) { + CheckSshAnswer sshAnswer = (CheckSshAnswer) answer; + if (sshAnswer == null || !sshAnswer.getResult()) { + s_logger.warn("Unable to ssh to the internal LB VM: " + sshAnswer.getDetails()); + result = false; + } + } else { + result = false; + } + if (result == false) { + return result; + } + + //Get guest network info + List guestNetworks = new ArrayList(); + List internalLbVmNics = _nicDao.listByVmId(profile.getId()); + for (Nic internalLbVmNic : internalLbVmNics) { + Network network = _ntwkModel.getNetwork(internalLbVmNic.getNetworkId()); + if (network.getTrafficType() == TrafficType.Guest) { + guestNetworks.add(network); + } + } + + answer = cmds.getAnswer("getDomRVersion"); + if (answer != null && answer instanceof GetDomRVersionAnswer) { + GetDomRVersionAnswer versionAnswer = (GetDomRVersionAnswer)answer; + if (answer == null || !answer.getResult()) { + s_logger.warn("Unable to get the template/scripts version of internal LB VM " + internalLbVm.getInstanceName() + + " due to: " + versionAnswer.getDetails()); + result = false; + } else { + internalLbVm.setTemplateVersion(versionAnswer.getTemplateVersion()); + internalLbVm.setScriptsVersion(versionAnswer.getScriptsVersion()); + internalLbVm = _internalLbVmDao.persist(internalLbVm, guestNetworks); + } + } else { + result = false; + } + + return result; + } + + @Override + public boolean finalizeCommandsOnStart(Commands cmds, VirtualMachineProfile profile) { + DomainRouterVO internalLbVm = profile.getVirtualMachine(); + NicProfile controlNic = getNicProfileByTrafficType(profile, TrafficType.Control); + + if (controlNic == null) { + s_logger.error("Control network doesn't exist for the internal LB vm " + internalLbVm); + return false; + } + + finalizeSshAndVersionOnStart(cmds, profile, internalLbVm, controlNic); + + // restart network if restartNetwork = false is not specified in profile parameters + boolean reprogramGuestNtwk = true; + if (profile.getParameter(Param.ReProgramGuestNetworks) != null + && (Boolean) profile.getParameter(Param.ReProgramGuestNetworks) == false) { + reprogramGuestNtwk = false; + } + + VirtualRouterProvider lbProvider = _vrProviderDao.findById(internalLbVm.getElementId()); + if (lbProvider == null) { + throw new CloudRuntimeException("Cannot find related element " + VirtualRouterProviderType.InternalLbVm + " of vm: " + internalLbVm.getHostName()); + } + + Provider provider = Network.Provider.getProvider(lbProvider.getType().toString()); + if (provider == null) { + throw new CloudRuntimeException("Cannot find related provider of provider: " + lbProvider.getType().toString()); + } + + if (reprogramGuestNtwk) { + NicProfile guestNic = getNicProfileByTrafficType(profile, TrafficType.Guest); + finalizeLbRulesForIp(cmds, internalLbVm, provider, new Ip(guestNic.getIp4Address()), guestNic.getNetworkId()); + } + + return true; + } + + @Override + public void finalizeStop(VirtualMachineProfile profile, StopAnswer answer) { + } + + @Override + public void finalizeExpunge(DomainRouterVO vm) { + } + + @Override + public Long convertToId(String vmName) { + if (!VirtualMachineName.isValidSystemVmName(vmName, _instance, _internalLbVmNamePrefix)) { + return null; + } + + return VirtualMachineName.getRouterId(vmName); + } + + @Override + public boolean plugNic(Network network, NicTO nic, VirtualMachineTO vm, ReservationContext context, DeployDestination dest) throws ConcurrentOperationException, ResourceUnavailableException, + InsufficientCapacityException { + //not supported + throw new UnsupportedOperationException("Plug nic is not supported for vm of type " + vm.getType()); + } + + @Override + public boolean unplugNic(Network network, NicTO nic, VirtualMachineTO vm, ReservationContext context, DeployDestination dest) throws ConcurrentOperationException, ResourceUnavailableException { + //not supported + throw new UnsupportedOperationException("Unplug nic is not supported for vm of type " + vm.getType()); + } + + @Override + public void prepareStop(VirtualMachineProfile profile) { + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + final Map configs = _configDao.getConfiguration("AgentManager", params); + _instance = configs.get("instance.name"); + if (_instance == null) { + _instance = "DEFAULT"; + } + + _mgmtHost = configs.get("host"); + _mgmtCidr = _configDao.getValue(Config.ManagementNetwork.key()); + + String offIdStr = configs.get(Config.InternalLbVmServiceOfferingId.key()); + if (offIdStr != null && !offIdStr.isEmpty()) { + _internalLbVmOfferingId = Long.parseLong(offIdStr); + } else { + boolean useLocalStorage = Boolean.parseBoolean(configs.get(Config.SystemVMUseLocalStorage.key())); + ServiceOfferingVO newOff = new ServiceOfferingVO("System Offering For Internal LB VM", 1, InternalLoadBalancerVMManager.DEFAULT_INTERNALLB_VM_RAMSIZE, InternalLoadBalancerVMManager.DEFAULT_INTERNALLB_VM_CPU_MHZ, null, + null, true, null, useLocalStorage, true, null, true, VirtualMachine.Type.InternalLoadBalancerVm, true); + newOff.setUniqueName(ServiceOffering.internalLbVmDefaultOffUniqueName); + newOff = _serviceOfferingDao.persistSystemServiceOffering(newOff); + _internalLbVmOfferingId = newOff.getId(); + } + + _itMgr.registerGuru(VirtualMachine.Type.InternalLoadBalancerVm, this); + + if (s_logger.isInfoEnabled()) { + s_logger.info(getName() + " has been configured"); + } + + return true; + } + + @Override + public String getName() { + return _name; + } + + protected NicProfile getNicProfileByTrafficType(VirtualMachineProfile profile, TrafficType trafficType) { + for (NicProfile nic : profile.getNics()) { + if (nic.getTrafficType() == trafficType && nic.getIp4Address() != null) { + return nic; + } + } + return null; + } + + protected void finalizeSshAndVersionOnStart(Commands cmds, VirtualMachineProfile profile, DomainRouterVO router, NicProfile controlNic) { + cmds.addCommand("checkSsh", new CheckSshCommand(profile.getInstanceName(), controlNic.getIp4Address(), 3922)); + + // Update internal lb vm template/scripts version + final GetDomRVersionCmd command = new GetDomRVersionCmd(); + command.setAccessDetail(NetworkElementCommand.ROUTER_IP, controlNic.getIp4Address()); + command.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); + cmds.addCommand("getDomRVersion", command); + } + + + protected void finalizeLbRulesForIp(Commands cmds, DomainRouterVO internalLbVm, Provider provider, Ip sourceIp, long guestNtwkId) { + s_logger.debug("Resending load balancing rules as a part of start for " + internalLbVm); + List lbs = _lbDao.listBySrcIpSrcNtwkId(sourceIp, guestNtwkId); + List lbRules = new ArrayList(); + if (_ntwkModel.isProviderSupportServiceInNetwork(guestNtwkId, Service.Lb, provider)) { + // Re-apply load balancing rules + for (ApplicationLoadBalancerRuleVO lb : lbs) { + List dstList = _lbMgr.getExistingDestinations(lb.getId()); + List policyList = _lbMgr.getStickinessPolicies(lb.getId()); + List hcPolicyList = _lbMgr.getHealthCheckPolicies(lb.getId()); + LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList, sourceIp); + lbRules.add(loadBalancing); + } + } + + s_logger.debug("Found " + lbRules.size() + " load balancing rule(s) to apply as a part of Intenrnal LB vm" + internalLbVm + " start."); + if (!lbRules.isEmpty()) { + createApplyLoadBalancingRulesCommands(lbRules, internalLbVm, cmds, guestNtwkId); + } + } + + private void createApplyLoadBalancingRulesCommands(List rules, VirtualRouter internalLbVm, Commands cmds, long guestNetworkId) { + + LoadBalancerTO[] lbs = new LoadBalancerTO[rules.size()]; + int i = 0; + boolean inline = false; + for (LoadBalancingRule rule : rules) { + boolean revoked = (rule.getState().equals(FirewallRule.State.Revoke)); + String protocol = rule.getProtocol(); + String algorithm = rule.getAlgorithm(); + String uuid = rule.getUuid(); + + String srcIp = rule.getSourceIp().addr(); + int srcPort = rule.getSourcePortStart(); + List destinations = rule.getDestinations(); + List stickinessPolicies = rule.getStickinessPolicies(); + LoadBalancerTO lb = new LoadBalancerTO(uuid, srcIp, srcPort, protocol, algorithm, revoked, false, inline, destinations, stickinessPolicies); + lbs[i++] = lb; + } + + Network guestNetwork = _ntwkModel.getNetwork(guestNetworkId); + Nic guestNic = _nicDao.findByNtwkIdAndInstanceId(guestNetwork.getId(), internalLbVm.getId()); + NicProfile guestNicProfile = new NicProfile(guestNic, guestNetwork, guestNic.getBroadcastUri(), guestNic.getIsolationUri(), + _ntwkModel.getNetworkRate(guestNetwork.getId(), internalLbVm.getId()), + _ntwkModel.isSecurityGroupSupportedInNetwork(guestNetwork), + _ntwkModel.getNetworkTag(internalLbVm.getHypervisorType(), guestNetwork)); + + LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lbs, guestNic.getIp4Address(), + guestNic.getIp4Address(), internalLbVm.getPrivateIpAddress(), + _itMgr.toNicTO(guestNicProfile, internalLbVm.getHypervisorType()), internalLbVm.getVpcId()); + + cmd.lbStatsVisibility = _configDao.getValue(Config.NetworkLBHaproxyStatsVisbility.key()); + cmd.lbStatsUri = _configDao.getValue(Config.NetworkLBHaproxyStatsUri.key()); + cmd.lbStatsAuth = _configDao.getValue(Config.NetworkLBHaproxyStatsAuth.key()); + cmd.lbStatsPort = _configDao.getValue(Config.NetworkLBHaproxyStatsPort.key()); + + cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, getInternalLbControlIp(internalLbVm.getId())); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, guestNic.getIp4Address()); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, internalLbVm.getInstanceName()); + DataCenterVO dcVo = _dcDao.findById(internalLbVm.getDataCenterId()); + cmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString()); + cmds.addCommand(cmd); + } + + + protected String getInternalLbControlIp(long internalLbVmId) { + String controlIpAddress = null; + List nics = _nicDao.listByVmId(internalLbVmId); + for (NicVO nic : nics) { + Network ntwk = _ntwkModel.getNetwork(nic.getNetworkId()); + if (ntwk.getTrafficType() == TrafficType.Control) { + controlIpAddress = nic.getIp4Address(); + } + } + + if(controlIpAddress == null) { + s_logger.warn("Unable to find Internal LB control ip in its attached NICs!. Internal LB vm: " + internalLbVmId); + DomainRouterVO internalLbVm = _internalLbVmDao.findById(internalLbVmId); + return internalLbVm.getPrivateIpAddress(); + } + + return controlIpAddress; + } + + @Override + public boolean destroyInternalLbVm(long vmId, Account caller, Long callerUserId) + throws ResourceUnavailableException, ConcurrentOperationException { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Attempting to destroy Internal LB vm " + vmId); + } + + DomainRouterVO internalLbVm = _internalLbVmDao.findById(vmId); + if (internalLbVm == null) { + return true; + } + + _accountMgr.checkAccess(caller, null, true, internalLbVm); + + return _itMgr.expunge(internalLbVm, _accountMgr.getActiveUser(callerUserId), caller); + } + + + @Override + public VirtualRouter stopInternalLbVm(long vmId, boolean forced, Account caller, long callerUserId) throws ConcurrentOperationException, + ResourceUnavailableException { + DomainRouterVO internalLbVm = _internalLbVmDao.findById(vmId); + if (internalLbVm == null || internalLbVm.getRole() != Role.INTERNAL_LB_VM) { + throw new InvalidParameterValueException("Can't find internal lb vm by id specified"); + } + + return stopInternalLbVm(internalLbVm, forced, caller, callerUserId); + } + + protected VirtualRouter stopInternalLbVm(DomainRouterVO internalLbVm, boolean forced, Account caller, long callerUserId) throws ResourceUnavailableException, ConcurrentOperationException { + s_logger.debug("Stopping internal lb vm " + internalLbVm); + try { + if (_itMgr.advanceStop((DomainRouterVO) internalLbVm, forced, _accountMgr.getActiveUser(callerUserId), caller)) { + return _internalLbVmDao.findById(internalLbVm.getId()); + } else { + return null; + } + } catch (OperationTimedoutException e) { + throw new CloudRuntimeException("Unable to stop " + internalLbVm, e); + } + } + + + @Override + public List deployInternalLbVm(Network guestNetwork, Ip requestedGuestIp, DeployDestination dest, + Account owner, Map params) throws InsufficientCapacityException, + ConcurrentOperationException, ResourceUnavailableException { + + List internalLbVms = findOrDeployInternalLbVm(guestNetwork, requestedGuestIp, dest, owner, params); + + return startInternalLbVms(params, internalLbVms); + } + + protected List startInternalLbVms(Map params, List internalLbVms) + throws StorageUnavailableException, InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { + List runningInternalLbVms = null; + + if (internalLbVms != null) { + runningInternalLbVms = new ArrayList(); + } else { + s_logger.debug("Have no internal lb vms to start"); + return null; + } + + for (DomainRouterVO internalLbVm : internalLbVms) { + if (internalLbVm.getState() != VirtualMachine.State.Running) { + internalLbVm = startInternalLbVm(internalLbVm, _accountMgr.getSystemAccount(), User.UID_SYSTEM, params); + } + + if (internalLbVm != null) { + runningInternalLbVms.add(internalLbVm); + } + } + return runningInternalLbVms; + } + + + + @DB + protected List findOrDeployInternalLbVm(Network guestNetwork, Ip requestedGuestIp, DeployDestination dest, + Account owner, Map params) throws ConcurrentOperationException, + InsufficientCapacityException, ResourceUnavailableException { + + List internalLbVms = new ArrayList(); + Network lock = _networkDao.acquireInLockTable(guestNetwork.getId(), _ntwkMgr.getNetworkLockTimeout()); + if (lock == null) { + throw new ConcurrentOperationException("Unable to lock network " + guestNetwork.getId()); + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Lock is acquired for network id " + lock.getId() + " as a part of internal lb startup in " + dest); + } + + long internalLbProviderId = getInternalLbProviderId(guestNetwork); + + try { + assert guestNetwork.getState() == Network.State.Implemented || guestNetwork.getState() == Network.State.Setup || + guestNetwork.getState() == Network.State.Implementing : "Network is not yet fully implemented: " + + guestNetwork; + assert guestNetwork.getTrafficType() == TrafficType.Guest; + + //deploy internal lb vm + Pair> planAndInternalLbVms = getDeploymentPlanAndInternalLbVms(dest, guestNetwork.getId(), requestedGuestIp); + internalLbVms = planAndInternalLbVms.second(); + DeploymentPlan plan = planAndInternalLbVms.first(); + + if (internalLbVms.size() > 0) { + s_logger.debug("Found " + internalLbVms.size() + " internal lb vms for the requested IP " + requestedGuestIp.addr()); + return internalLbVms; + } + + List> networks = createInternalLbVmNetworks(guestNetwork, plan, requestedGuestIp); + //Pass startVm=false as we are holding the network lock that needs to be released at the end of vm allocation + DomainRouterVO internalLbVm = deployInternalLbVm(owner, dest, plan, params, internalLbProviderId, _internalLbVmOfferingId, guestNetwork.getVpcId(), + networks, false); + if (internalLbVm != null) { + _internalLbVmDao.addRouterToGuestNetwork(internalLbVm, guestNetwork); + internalLbVms.add(internalLbVm); + } + } finally { + if (lock != null) { + _networkDao.releaseFromLockTable(lock.getId()); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Lock is released for network id " + lock.getId() + " as a part of internal lb vm startup in " + dest); + } + } + } + return internalLbVms; + } + + protected long getInternalLbProviderId(Network guestNetwork) { + VirtualRouterProviderType type = VirtualRouterProviderType.InternalLbVm; + long physicalNetworkId = _ntwkModel.getPhysicalNetworkId(guestNetwork); + + PhysicalNetworkServiceProvider provider = _physicalProviderDao.findByServiceProvider(physicalNetworkId, type.toString()); + if (provider == null) { + throw new CloudRuntimeException("Cannot find service provider " + type.toString() + " in physical network " + physicalNetworkId); + } + + VirtualRouterProvider internalLbProvider = _vrProviderDao.findByNspIdAndType(provider.getId(), type); + if (internalLbProvider == null) { + throw new CloudRuntimeException("Cannot find provider " + type.toString() + " as service provider " + provider.getId()); + } + + return internalLbProvider.getId(); + } + + protected List> createInternalLbVmNetworks(Network guestNetwork, DeploymentPlan plan, Ip guestIp) throws ConcurrentOperationException, + InsufficientAddressCapacityException { + + //Form networks + List> networks = new ArrayList>(3); + + //1) Guest network - default + if (guestNetwork != null) { + s_logger.debug("Adding nic for Internal LB in Guest network " + guestNetwork); + NicProfile guestNic = new NicProfile(); + if (guestIp != null) { + guestNic.setIp4Address(guestIp.addr()); + } else { + guestNic.setIp4Address(_ntwkMgr.acquireGuestIpAddress(guestNetwork, null)); + } + guestNic.setGateway(guestNetwork.getGateway()); + guestNic.setBroadcastUri(guestNetwork.getBroadcastUri()); + guestNic.setBroadcastType(guestNetwork.getBroadcastDomainType()); + guestNic.setIsolationUri(guestNetwork.getBroadcastUri()); + guestNic.setMode(guestNetwork.getMode()); + String gatewayCidr = guestNetwork.getCidr(); + guestNic.setNetmask(NetUtils.getCidrNetmask(gatewayCidr)); + guestNic.setDefaultNic(true); + networks.add(new Pair((NetworkVO) guestNetwork, guestNic)); + } + + //2) Control network + s_logger.debug("Adding nic for Internal LB vm in Control network "); + List offerings = _ntwkModel.getSystemAccountNetworkOfferings(NetworkOffering.SystemControlNetwork); + NetworkOffering controlOffering = offerings.get(0); + NetworkVO controlConfig = _ntwkMgr.setupNetwork(_accountMgr.getSystemAccount(), controlOffering, plan, null, null, false).get(0); + networks.add(new Pair(controlConfig, null)); + + return networks; + } + + + protected Pair> getDeploymentPlanAndInternalLbVms(DeployDestination dest, long guestNetworkId, Ip requestedGuestIp) { + long dcId = dest.getDataCenter().getId(); + DeploymentPlan plan = new DataCenterDeployment(dcId); + List internalLbVms = findInternalLbVms(guestNetworkId, requestedGuestIp); + + return new Pair>(plan, internalLbVms); + + } + + @Override + public List findInternalLbVms(long guestNetworkId, Ip requestedGuestIp) { + List internalLbVms = _internalLbVmDao.listByNetworkAndRole(guestNetworkId, Role.INTERNAL_LB_VM); + if (requestedGuestIp != null && !internalLbVms.isEmpty()) { + Iterator it = internalLbVms.iterator(); + while (it.hasNext()) { + DomainRouterVO vm = it.next(); + Nic nic = _nicDao.findByNtwkIdAndInstanceId(guestNetworkId, vm.getId()); + if (!nic.getIp4Address().equalsIgnoreCase(requestedGuestIp.addr())) { + it.remove(); + } + } + } + return internalLbVms; + } + + + protected DomainRouterVO deployInternalLbVm(Account owner, DeployDestination dest, DeploymentPlan plan, Map params, + long internalLbProviderId, long svcOffId, Long vpcId, + List> networks, boolean startVm) throws ConcurrentOperationException, + InsufficientAddressCapacityException, InsufficientServerCapacityException, InsufficientCapacityException, + StorageUnavailableException, ResourceUnavailableException { + + long id = _internalLbVmDao.getNextInSequence(Long.class, "id"); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Creating the internal lb vm " + id + " in datacenter " + dest.getDataCenter()); + } + + ServiceOfferingVO routerOffering = _serviceOfferingDao.findById(svcOffId); + + // Internal lb is the network element, we don't know the hypervisor type yet. + // Try to allocate the internal lb twice using diff hypervisors, and when failed both times, throw the exception up + List hypervisors = getHypervisors(dest, plan, null); + + int allocateRetry = 0; + int startRetry = 0; + DomainRouterVO internalLbVm = null; + for (Iterator iter = hypervisors.iterator(); iter.hasNext();) { + HypervisorType hType = iter.next(); + try { + s_logger.debug("Allocating the Internal lb with the hypervisor type " + hType); + String templateName = null; + switch (hType) { + case XenServer: + templateName = _configServer.getConfigValue(Config.RouterTemplateXen.key(), Config.ConfigurationParameterScope.zone.toString(), dest.getDataCenter().getId()); + break; + case KVM: + templateName = _configServer.getConfigValue(Config.RouterTemplateKVM.key(), Config.ConfigurationParameterScope.zone.toString(), dest.getDataCenter().getId()); + break; + case VMware: + templateName = _configServer.getConfigValue(Config.RouterTemplateVmware.key(), Config.ConfigurationParameterScope.zone.toString(), dest.getDataCenter().getId()); + break; + case Hyperv: + templateName = _configServer.getConfigValue(Config.RouterTemplateHyperv.key(), Config.ConfigurationParameterScope.zone.toString(), dest.getDataCenter().getId()); + break; + case LXC: + templateName = _configServer.getConfigValue(Config.RouterTemplateLXC.key(), Config.ConfigurationParameterScope.zone.toString(), dest.getDataCenter().getId()); + break; + default: break; + } + VMTemplateVO template = _templateDao.findRoutingTemplate(hType, templateName); + + if (template == null) { + s_logger.debug(hType + " won't support system vm, skip it"); + continue; + } + + internalLbVm = new DomainRouterVO(id, routerOffering.getId(), internalLbProviderId, + VirtualMachineName.getSystemVmName(id, _instance, _internalLbVmNamePrefix), template.getId(), template.getHypervisorType(), + template.getGuestOSId(), owner.getDomainId(), owner.getId(), false, 0, false, + RedundantState.UNKNOWN, false, false, VirtualMachine.Type.InternalLoadBalancerVm, vpcId); + internalLbVm.setRole(Role.INTERNAL_LB_VM); + internalLbVm = _itMgr.allocate(internalLbVm, template, routerOffering, networks, plan, null, owner); + } catch (InsufficientCapacityException ex) { + if (allocateRetry < 2 && iter.hasNext()) { + s_logger.debug("Failed to allocate the Internal lb vm with hypervisor type " + hType + ", retrying one more time"); + continue; + } else { + throw ex; + } + } finally { + allocateRetry++; + } + + if (startVm) { + try { + internalLbVm = startInternalLbVm(internalLbVm, _accountMgr.getSystemAccount(), User.UID_SYSTEM, params); + break; + } catch (InsufficientCapacityException ex) { + if (startRetry < 2 && iter.hasNext()) { + s_logger.debug("Failed to start the Internal lb vm " + internalLbVm + " with hypervisor type " + hType + ", " + + "destroying it and recreating one more time"); + // destroy the internal lb vm + destroyInternalLbVm(internalLbVm.getId(), _accountMgr.getSystemAccount(), User.UID_SYSTEM); + continue; + } else { + throw ex; + } + } finally { + startRetry++; + } + } else { + //return stopped internal lb vm + return internalLbVm; + } + } + return internalLbVm; + } + + + + protected DomainRouterVO startInternalLbVm(DomainRouterVO internalLbVm, Account caller, long callerUserId, Map params) + throws StorageUnavailableException, InsufficientCapacityException, + ConcurrentOperationException, ResourceUnavailableException { + s_logger.debug("Starting Internal LB VM " + internalLbVm); + if (_itMgr.start(internalLbVm, params, _accountMgr.getUserIncludingRemoved(callerUserId), caller, null) != null) { + if (internalLbVm.isStopPending()) { + s_logger.info("Clear the stop pending flag of Internal LB VM " + internalLbVm.getHostName() + " after start router successfully!"); + internalLbVm.setStopPending(false); + internalLbVm = _internalLbVmDao.persist(internalLbVm); + } + return _internalLbVmDao.findById(internalLbVm.getId()); + } else { + return null; + } + } + + + protected List getHypervisors(DeployDestination dest, DeploymentPlan plan, + List supportedHypervisors) throws InsufficientServerCapacityException { + List hypervisors = new ArrayList(); + + HypervisorType defaults = _resourceMgr.getDefaultHypervisor(dest.getDataCenter().getId()); + if (defaults != HypervisorType.None) { + hypervisors.add(defaults); + } else { + //if there is no default hypervisor, get it from the cluster + hypervisors = _resourceMgr.getSupportedHypervisorTypes(dest.getDataCenter().getId(), true, + plan.getPodId()); + } + + //keep only elements defined in supported hypervisors + StringBuilder hTypesStr = new StringBuilder(); + if (supportedHypervisors != null && !supportedHypervisors.isEmpty()) { + hypervisors.retainAll(supportedHypervisors); + for (HypervisorType hType : supportedHypervisors) { + hTypesStr.append(hType).append(" "); + } + } + + if (hypervisors.isEmpty()) { + throw new InsufficientServerCapacityException("Unable to create internal lb vm, " + + "there are no clusters in the zone ", DataCenter.class, dest.getDataCenter().getId()); + } + return hypervisors; + } + + @Override + public boolean applyLoadBalancingRules(Network network, final List rules, List internalLbVms) + throws ResourceUnavailableException { + if (rules == null || rules.isEmpty()) { + s_logger.debug("No lb rules to be applied for network " + network); + return true; + } + + //only one internal lb vm is supported per ip address at this time + if (internalLbVms == null || internalLbVms.isEmpty()) { + throw new CloudRuntimeException("Can't apply the lb rules on network " + network + " as the list of internal lb vms is empty"); + } + + VirtualRouter lbVm = internalLbVms.get(0); + if (lbVm.getState() == State.Running) { + return sendLBRules(lbVm, rules, network.getId()); + } else if (lbVm.getState() == State.Stopped || lbVm.getState() == State.Stopping) { + s_logger.debug("Internal LB VM " + lbVm.getInstanceName() + " is in " + lbVm.getState() + + ", so not sending apply lb rules commands to the backend"); + return true; + } else { + s_logger.warn("Unable to apply lb rules, Internal LB VM is not in the right state " + lbVm.getState()); + throw new ResourceUnavailableException("Unable to apply lb rules; Internal LB VM is not in the right state", DataCenter.class, lbVm.getDataCenterId()); + } + } + + protected boolean sendLBRules(VirtualRouter internalLbVm, List rules, long guestNetworkId) throws ResourceUnavailableException { + Commands cmds = new Commands(OnError.Continue); + createApplyLoadBalancingRulesCommands(rules, internalLbVm, cmds, guestNetworkId); + return sendCommandsToInternalLbVm(internalLbVm, cmds); + } + + + protected boolean sendCommandsToInternalLbVm(final VirtualRouter internalLbVm, Commands cmds) throws AgentUnavailableException { + Answer[] answers = null; + try { + answers = _agentMgr.send(internalLbVm.getHostId(), cmds); + } catch (OperationTimedoutException e) { + s_logger.warn("Timed Out", e); + throw new AgentUnavailableException("Unable to send commands to virtual router ", internalLbVm.getHostId(), e); + } + + if (answers == null) { + return false; + } + + if (answers.length != cmds.size()) { + return false; + } + + boolean result = true; + if (answers.length > 0) { + for (Answer answer : answers) { + if (!answer.getResult()) { + result = false; + break; + } + } + } + return result; + } + + + @Override + public VirtualRouter startInternalLbVm(long internalLbVmId, Account caller, long callerUserId) + throws StorageUnavailableException, InsufficientCapacityException, + ConcurrentOperationException, ResourceUnavailableException { + + DomainRouterVO internalLbVm = _internalLbVmDao.findById(internalLbVmId); + if (internalLbVm == null || internalLbVm.getRole() != Role.INTERNAL_LB_VM) { + throw new InvalidParameterValueException("Can't find internal lb vm by id specified"); + } + + return startInternalLbVm(internalLbVm, caller, callerUserId, null); + } +} diff --git a/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/ElementChildTestConfiguration.java b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/ElementChildTestConfiguration.java new file mode 100644 index 00000000000..8a67e84f951 --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/ElementChildTestConfiguration.java @@ -0,0 +1,125 @@ +// 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. +package org.apache.cloudstack.internallbelement; + +import java.io.IOException; + +import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; +import org.apache.cloudstack.network.lb.InternalLoadBalancerVMManager; +import org.apache.cloudstack.test.utils.SpringUtils; +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.filter.TypeFilter; + +import com.cloud.configuration.ConfigurationManager; +import com.cloud.dc.dao.AccountVlanMapDaoImpl; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkModel; +import com.cloud.network.dao.NetworkServiceMapDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.VirtualRouterProviderDao; +import com.cloud.user.AccountManager; +import com.cloud.utils.net.NetUtils; +import com.cloud.vm.dao.DomainRouterDao; + +@Configuration +@ComponentScan( + basePackageClasses={ + NetUtils.class, + }, + includeFilters={@Filter(value=ElementChildTestConfiguration.Library.class, type=FilterType.CUSTOM)}, + useDefaultFilters=false + ) + +public class ElementChildTestConfiguration { + public static class Library implements TypeFilter { + @Bean + public AccountManager accountManager() { + return Mockito.mock(AccountManager.class); + } + + + @Bean + public DomainRouterDao domainRouterDao() { + return Mockito.mock(DomainRouterDao.class); + } + + @Bean + public VirtualRouterProviderDao virtualRouterProviderDao() { + return Mockito.mock(VirtualRouterProviderDao.class); + } + + @Bean + public NetworkModel networkModel() { + return Mockito.mock(NetworkModel.class); + } + + + @Bean + public NetworkManager networkManager() { + return Mockito.mock(NetworkManager.class); + } + + + @Bean + public PhysicalNetworkServiceProviderDao physicalNetworkServiceProviderDao() { + return Mockito.mock(PhysicalNetworkServiceProviderDao.class); + } + + @Bean + public NetworkServiceMapDao networkServiceMapDao() { + return Mockito.mock(NetworkServiceMapDao.class); + } + + @Bean + public InternalLoadBalancerVMManager internalLoadBalancerVMManager() { + return Mockito.mock(InternalLoadBalancerVMManager.class); + } + + @Bean + public ConfigurationManager confugurationManager() { + return Mockito.mock(ConfigurationManager.class); + } + + + @Bean + public ApplicationLoadBalancerRuleDao applicationLoadBalancerRuleDao() { + return Mockito.mock(ApplicationLoadBalancerRuleDao.class); + } + + @Bean + public DataCenterDao dataCenterDao() { + return Mockito.mock(DataCenterDao.class); + } + + + + @Override + public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { + mdr.getClassMetadata().getClassName(); + ComponentScan cs = ElementChildTestConfiguration.class.getAnnotation(ComponentScan.class); + return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + } + } +} diff --git a/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/InternalLbElementServiceTest.java b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/InternalLbElementServiceTest.java new file mode 100644 index 00000000000..bdc50cafb8c --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/InternalLbElementServiceTest.java @@ -0,0 +1,189 @@ +// 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. +package org.apache.cloudstack.internallbelement; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import javax.inject.Inject; + +import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.VirtualRouterProvider; +import com.cloud.network.VirtualRouterProvider.VirtualRouterProviderType; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; +import com.cloud.network.dao.VirtualRouterProviderDao; +import com.cloud.network.element.VirtualRouterProviderVO; +import com.cloud.user.AccountManager; +import com.cloud.utils.component.ComponentContext; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations="classpath:/lb_element.xml") +public class InternalLbElementServiceTest { + //The interface to test + @Inject InternalLoadBalancerElementService _lbElSvc; + + //Mocked interfaces + @Inject AccountManager _accountMgr; + @Inject VirtualRouterProviderDao _vrProviderDao; + @Inject PhysicalNetworkServiceProviderDao _pNtwkProviderDao; + + long validElId = 1L; + long nonExistingElId = 2L; + long invalidElId = 3L; //not of VirtualRouterProviderType + + long validProviderId = 1L; + long nonExistingProviderId = 2L; + long invalidProviderId = 3L; + + + @Before + public void setUp() { + + ComponentContext.initComponentsLifeCycle(); + VirtualRouterProviderVO validElement = new VirtualRouterProviderVO(1, VirtualRouterProviderType.InternalLbVm); + VirtualRouterProviderVO invalidElement = new VirtualRouterProviderVO(1, VirtualRouterProviderType.VirtualRouter); + + Mockito.when(_vrProviderDao.findById(validElId)).thenReturn(validElement); + Mockito.when(_vrProviderDao.findById(invalidElId)).thenReturn(invalidElement); + + Mockito.when(_vrProviderDao.persist(validElement)).thenReturn(validElement); + + Mockito.when(_vrProviderDao.findByNspIdAndType(validProviderId, VirtualRouterProviderType.InternalLbVm)).thenReturn(validElement); + + PhysicalNetworkServiceProviderVO validProvider = new PhysicalNetworkServiceProviderVO(1, "InternalLoadBalancerElement"); + PhysicalNetworkServiceProviderVO invalidProvider = new PhysicalNetworkServiceProviderVO(1, "Invalid name!"); + + Mockito.when(_pNtwkProviderDao.findById(validProviderId)).thenReturn(validProvider); + Mockito.when(_pNtwkProviderDao.findById(invalidProviderId)).thenReturn(invalidProvider); + + Mockito.when(_vrProviderDao.persist(Mockito.any(VirtualRouterProviderVO.class))).thenReturn(validElement); + } + + //TESTS FOR getInternalLoadBalancerElement METHOD + + + @Test (expected = InvalidParameterValueException.class) + public void findNonExistingVm() { + String expectedExcText = null; + try { + _lbElSvc.getInternalLoadBalancerElement(nonExistingElId); + } catch (InvalidParameterValueException e) { + expectedExcText = e.getMessage(); + throw e; + } finally { + assertEquals("Test failed. The non-existing intenral lb provider was found" + + expectedExcText, expectedExcText, "Unable to find InternalLoadBalancerElementService by id"); + } + } + + + @Test (expected = InvalidParameterValueException.class) + public void findInvalidVm() { + String expectedExcText = null; + try { + _lbElSvc.getInternalLoadBalancerElement(invalidElId); + } catch (InvalidParameterValueException e) { + expectedExcText = e.getMessage(); + throw e; + } finally { + assertEquals("Test failed. The non-existing intenral lb provider was found" + + expectedExcText, expectedExcText, "Unable to find InternalLoadBalancerElementService by id"); + } + } + + + @Test + public void findValidVm() { + VirtualRouterProvider provider = null; + try { + provider = _lbElSvc.getInternalLoadBalancerElement(validElId); + } finally { + assertNotNull("Test failed. Couldn't find the VR provider by the valid id",provider); + } + } + + + //TESTS FOR configureInternalLoadBalancerElement METHOD + + @Test (expected = InvalidParameterValueException.class) + public void configureNonExistingVm() { + + _lbElSvc.configureInternalLoadBalancerElement(nonExistingElId, true); + + } + + + @Test (expected = InvalidParameterValueException.class) + public void ConfigureInvalidVm() { + _lbElSvc.configureInternalLoadBalancerElement(invalidElId, true); + } + + + @Test + public void enableProvider() { + VirtualRouterProvider provider = null; + try { + provider = _lbElSvc.configureInternalLoadBalancerElement(validElId, true); + } finally { + assertNotNull("Test failed. Couldn't find the VR provider by the valid id ",provider); + assertTrue("Test failed. The provider wasn't eanbled ", provider.isEnabled()); + } + } + + @Test + public void disableProvider() { + VirtualRouterProvider provider = null; + try { + provider = _lbElSvc.configureInternalLoadBalancerElement(validElId, false); + } finally { + assertNotNull("Test failed. Couldn't find the VR provider by the valid id ",provider); + assertFalse("Test failed. The provider wasn't disabled ", provider.isEnabled()); + } + } + + //TESTS FOR addInternalLoadBalancerElement METHOD + + @Test (expected = InvalidParameterValueException.class) + public void addToNonExistingProvider() { + + _lbElSvc.addInternalLoadBalancerElement(nonExistingProviderId); + + } + + public void addToInvalidProvider() { + _lbElSvc.addInternalLoadBalancerElement(invalidProviderId); + } + + @Test + public void addToExistingProvider() { + _lbElSvc.addInternalLoadBalancerElement(validProviderId); + } + +} + + diff --git a/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/InternalLbElementTest.java b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/InternalLbElementTest.java new file mode 100644 index 00000000000..f19612f6b0f --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/InternalLbElementTest.java @@ -0,0 +1,226 @@ +// 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. +package org.apache.cloudstack.internallbelement; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.lb.ApplicationLoadBalancerRuleVO; +import org.apache.cloudstack.network.element.InternalLoadBalancerElement; +import org.apache.cloudstack.network.lb.InternalLoadBalancerVMManager; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.cloud.agent.api.to.LoadBalancerTO; +import com.cloud.configuration.ConfigurationManager; +import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.dc.DataCenterVO; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.network.VirtualRouterProvider.VirtualRouterProviderType; +import com.cloud.network.addr.PublicIp; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; +import com.cloud.network.dao.VirtualRouterProviderDao; +import com.cloud.network.element.VirtualRouterProviderVO; +import com.cloud.network.lb.LoadBalancingRule; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.user.AccountManager; +import com.cloud.utils.component.ComponentContext; +import com.cloud.utils.net.Ip; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations="classpath:/lb_element.xml") +public class InternalLbElementTest { + //The class to test + @Inject InternalLoadBalancerElement _lbEl; + + //Mocked interfaces + @Inject AccountManager _accountMgr; + @Inject VirtualRouterProviderDao _vrProviderDao; + @Inject PhysicalNetworkServiceProviderDao _pNtwkProviderDao; + @Inject InternalLoadBalancerVMManager _internalLbMgr; + @Inject ConfigurationManager _configMgr; + + long validElId = 1L; + long nonExistingElId = 2L; + long invalidElId = 3L; //not of VirtualRouterProviderType + long notEnabledElId = 4L; + + long validProviderId = 1L; + long nonExistingProviderId = 2L; + long invalidProviderId = 3L; + + + @Before + public void setUp() { + + ComponentContext.initComponentsLifeCycle(); + VirtualRouterProviderVO validElement = new VirtualRouterProviderVO(1, VirtualRouterProviderType.InternalLbVm); + validElement.setEnabled(true); + VirtualRouterProviderVO invalidElement = new VirtualRouterProviderVO(1, VirtualRouterProviderType.VirtualRouter); + VirtualRouterProviderVO notEnabledElement = new VirtualRouterProviderVO(1, VirtualRouterProviderType.InternalLbVm); + + Mockito.when(_vrProviderDao.findByNspIdAndType(validElId, VirtualRouterProviderType.InternalLbVm)).thenReturn(validElement); + Mockito.when(_vrProviderDao.findByNspIdAndType(invalidElId, VirtualRouterProviderType.InternalLbVm)).thenReturn(invalidElement); + Mockito.when(_vrProviderDao.findByNspIdAndType(notEnabledElId, VirtualRouterProviderType.InternalLbVm)).thenReturn(notEnabledElement); + + Mockito.when(_vrProviderDao.persist(validElement)).thenReturn(validElement); + + Mockito.when(_vrProviderDao.findByNspIdAndType(validProviderId, VirtualRouterProviderType.InternalLbVm)).thenReturn(validElement); + + PhysicalNetworkServiceProviderVO validProvider = new PhysicalNetworkServiceProviderVO(1, "InternalLoadBalancerElement"); + PhysicalNetworkServiceProviderVO invalidProvider = new PhysicalNetworkServiceProviderVO(1, "Invalid name!"); + + Mockito.when(_pNtwkProviderDao.findById(validProviderId)).thenReturn(validProvider); + Mockito.when(_pNtwkProviderDao.findById(invalidProviderId)).thenReturn(invalidProvider); + + Mockito.when(_vrProviderDao.persist(Mockito.any(VirtualRouterProviderVO.class))).thenReturn(validElement); + + DataCenterVO dc = new DataCenterVO + (1L, null, null, null, null, null, null, null, null, null, NetworkType.Advanced, null, null); + Mockito.when(_configMgr.getZone(Mockito.anyLong())).thenReturn(dc); + } + + //TEST FOR getProvider() method + + @Test + public void verifyProviderName() { + Provider pr = _lbEl.getProvider(); + assertEquals("Wrong provider is returned", pr.getName(), Provider.InternalLbVm.getName()); + } + + //TEST FOR isReady() METHOD + + @Test + public void verifyValidProviderState() { + PhysicalNetworkServiceProviderVO provider = new PhysicalNetworkServiceProviderVO(); + provider = setId(provider, validElId); + boolean isReady = _lbEl.isReady(provider); + assertTrue("Valid provider is returned as not ready", isReady); + } + + + @Test + public void verifyNonExistingProviderState() { + PhysicalNetworkServiceProviderVO provider = new PhysicalNetworkServiceProviderVO(); + provider = setId(provider, nonExistingElId); + boolean isReady = _lbEl.isReady(provider); + assertFalse("Non existing provider is returned as ready", isReady); + } + + + @Test + public void verifyInvalidProviderState() { + PhysicalNetworkServiceProviderVO provider = new PhysicalNetworkServiceProviderVO(); + provider = setId(provider, invalidElId); + boolean isReady = _lbEl.isReady(provider); + assertFalse("Not valid provider is returned as ready", isReady); + } + + @Test + public void verifyNotEnabledProviderState() { + PhysicalNetworkServiceProviderVO provider = new PhysicalNetworkServiceProviderVO(); + provider = setId(provider, notEnabledElId); + boolean isReady = _lbEl.isReady(provider); + assertFalse("Not enabled provider is returned as ready", isReady); + } + + //TEST FOR canEnableIndividualServices METHOD + @Test + public void verifyCanEnableIndividualSvc() { + boolean result = _lbEl.canEnableIndividualServices(); + assertTrue("Wrong value is returned by canEnableIndividualSvc", result); + } + + //TEST FOR verifyServicesCombination METHOD + @Test + public void verifyServicesCombination() { + boolean result = _lbEl.verifyServicesCombination(new HashSet()); + assertTrue("Wrong value is returned by verifyServicesCombination", result); + } + + + //TEST FOR applyIps METHOD + @Test + public void verifyApplyIps() throws ResourceUnavailableException { + List ips = new ArrayList(); + boolean result = _lbEl.applyIps(new NetworkVO(), ips, new HashSet()); + assertTrue("Wrong value is returned by applyIps method", result); + } + + + //TEST FOR updateHealthChecks METHOD + @Test + public void verifyUpdateHealthChecks() throws ResourceUnavailableException { + List check = _lbEl.updateHealthChecks(new NetworkVO(), new ArrayList()); + assertNull("Wrong value is returned by updateHealthChecks method", check); + } + + //TEST FOR validateLBRule METHOD + @Test + public void verifyValidateLBRule() throws ResourceUnavailableException { + ApplicationLoadBalancerRuleVO lb = new ApplicationLoadBalancerRuleVO(null, null, 22, 22, "roundrobin", + 1L, 1L, 1L, new Ip("10.10.10.1"), 1L, Scheme.Internal); + lb.setState(FirewallRule.State.Add); + + LoadBalancingRule rule = new LoadBalancingRule(lb, null, + null, null, new Ip("10.10.10.1")); + + + boolean result = _lbEl.validateLBRule(new NetworkVO(), rule); + assertTrue("Wrong value is returned by validateLBRule method", result); + } + + + private static PhysicalNetworkServiceProviderVO setId(PhysicalNetworkServiceProviderVO vo, long id) { + PhysicalNetworkServiceProviderVO voToReturn = vo; + Class c = voToReturn.getClass(); + try { + Field f = c.getDeclaredField("id"); + f.setAccessible(true); + f.setLong(voToReturn, id); + } catch (NoSuchFieldException ex) { + return null; + } catch (IllegalAccessException ex) { + return null; + } + + return voToReturn; + } + + + +} + + diff --git a/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/InternalLBVMManagerTest.java b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/InternalLBVMManagerTest.java new file mode 100644 index 00000000000..a19a82e30c1 --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/InternalLBVMManagerTest.java @@ -0,0 +1,388 @@ +// 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. +package org.apache.cloudstack.internallbvmmgr; + +import java.lang.reflect.Field; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import junit.framework.TestCase; + +import org.apache.cloudstack.lb.ApplicationLoadBalancerRuleVO; +import org.apache.cloudstack.network.lb.InternalLoadBalancerVMManager; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.agent.manager.Commands; +import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.exception.AgentUnavailableException; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.OperationTimedoutException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.NetworkModel; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.lb.LoadBalancingRule; +import com.cloud.network.router.VirtualRouter; +import com.cloud.network.router.VirtualRouter.Role; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.User; +import com.cloud.utils.component.ComponentContext; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; +import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.NicProfile; +import com.cloud.vm.NicVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.State; +import com.cloud.vm.VirtualMachineManager; +import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.NicDao; + +/** + * Set of unittests for InternalLoadBalancerVMManager + * + */ + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations="classpath:/lb_mgr.xml") +public class InternalLBVMManagerTest extends TestCase { + //The interface to test + @Inject InternalLoadBalancerVMManager _lbVmMgr; + + //Mocked interfaces + @Inject AccountManager _accountMgr; + @Inject ServiceOfferingDao _svcOffDao; + @Inject DomainRouterDao _domainRouterDao; + @Inject NicDao _nicDao; + @Inject AgentManager _agentMgr; + @Inject NetworkModel _ntwkModel; + @Inject VirtualMachineManager _itMgr; + @Inject DataCenterDao _dcDao; + + long validNtwkId = 1L; + long invalidNtwkId = 2L; + String requestedIp = "10.1.1.1"; + DomainRouterVO vm = null; + NetworkVO ntwk = createNetwork(); + long validVmId = 1L; + long invalidVmId = 2L; + + @Before + public void setUp() { + //mock system offering creation as it's used by configure() method called by initComponentsLifeCycle + Mockito.when(_accountMgr.getAccount(1L)).thenReturn(new AccountVO()); + ServiceOfferingVO off = new ServiceOfferingVO("alena", 1, 1, + 1, 1, 1, false, "alena", false, false, null, false, VirtualMachine.Type.InternalLoadBalancerVm, false); + off = setId(off, 1); + Mockito.when(_svcOffDao.persistSystemServiceOffering(Mockito.any(ServiceOfferingVO.class))).thenReturn(off); + + ComponentContext.initComponentsLifeCycle(); + + vm = new DomainRouterVO(1L,off.getId(),1,"alena",1,HypervisorType.XenServer,1,1,1, + false, 0,false,null,false,false, + VirtualMachine.Type.InternalLoadBalancerVm, null); + vm.setRole(Role.INTERNAL_LB_VM); + vm = setId(vm, 1); + vm.setPrivateIpAddress("10.2.2.2"); + NicVO nic = new NicVO("somereserver", 1L, 1L, VirtualMachine.Type.InternalLoadBalancerVm); + nic.setIp4Address(requestedIp); + + List emptyList = new ArrayList(); + List nonEmptyList = new ArrayList(); + nonEmptyList.add(vm); + + Mockito.when(_domainRouterDao.listByNetworkAndRole(invalidNtwkId, Role.INTERNAL_LB_VM)).thenReturn(emptyList); + Mockito.when(_domainRouterDao.listByNetworkAndRole(validNtwkId, Role.INTERNAL_LB_VM)).thenReturn(nonEmptyList); + + Mockito.when(_nicDao.findByNtwkIdAndInstanceId(validNtwkId, 1)).thenReturn(nic); + Mockito.when(_nicDao.findByNtwkIdAndInstanceId(invalidNtwkId, 1)).thenReturn(nic); + + Answer answer= new Answer(null, true, null); + Answer[] answers = new Answer[1]; + answers[0] = answer; + + try { + Mockito.when(_agentMgr.send(Mockito.anyLong(), Mockito.any(Commands.class))).thenReturn(answers); + } catch (AgentUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (OperationTimedoutException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + createNetwork(); + Mockito.when(_ntwkModel.getNetwork(Mockito.anyLong())).thenReturn(ntwk); + + + Mockito.when(_itMgr.toNicTO(Mockito.any(NicProfile.class), Mockito.any(HypervisorType.class))).thenReturn(null); + Mockito.when(_domainRouterDao.findById(Mockito.anyLong())).thenReturn(vm); + DataCenterVO dc = new DataCenterVO + (1L, null, null, null, null, null, null, null, null, null, NetworkType.Advanced, null, null); + Mockito.when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + + try { + Mockito.when(_itMgr.expunge(Mockito.any(DomainRouterVO.class), Mockito.any(User.class), Mockito.any(Account.class))).thenReturn(true); + } catch (ResourceUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + Mockito.when(_domainRouterDao.findById(validVmId)).thenReturn(vm); + Mockito.when(_domainRouterDao.findById(invalidVmId)).thenReturn(null); + + } + + protected NetworkVO createNetwork() { + ntwk = new NetworkVO(); + try { + ntwk.setBroadcastUri(new URI("somevlan")); + } catch (URISyntaxException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + ntwk = setId(ntwk, 1L); + return ntwk; + } + + //TESTS FOR findInternalLbVms METHOD + + @Test + public void findInternalLbVmsForInvalidNetwork() { + List vms = _lbVmMgr.findInternalLbVms(invalidNtwkId, new Ip(requestedIp)); + assertTrue("Non empty vm list was returned for invalid network id", vms.isEmpty()); + } + + @Test + public void findInternalLbVmsForValidNetwork() { + List vms = _lbVmMgr.findInternalLbVms(validNtwkId, new Ip(requestedIp)); + assertTrue("Empty vm list was returned for valid network id", !vms.isEmpty()); + } + + + //TESTS FOR applyLoadBalancingRules METHOD + @Test + public void applyEmptyRulesSet() { + boolean result = false; + List vms = new ArrayList(); + try { + result = _lbVmMgr.applyLoadBalancingRules(new NetworkVO(), new ArrayList(), vms); + } catch (ResourceUnavailableException e) { + + } finally { + assertTrue("Got failure when tried to apply empty list of rules", result); + } + } + + @Test (expected = CloudRuntimeException.class) + public void applyWithEmptyVmsSet() { + boolean result = false; + List vms = new ArrayList(); + List rules = new ArrayList(); + LoadBalancingRule rule = new LoadBalancingRule(null, null, + null, null, null); + + rules.add(rule); + try { + result = _lbVmMgr.applyLoadBalancingRules(new NetworkVO(), rules, vms); + } catch (ResourceUnavailableException e) { + } finally { + assertFalse("Got success when tried to apply with the empty internal lb vm list", result); + } + } + + @Test (expected = ResourceUnavailableException.class) + public void applyToVmInStartingState() throws ResourceUnavailableException { + boolean result = false; + List vms = new ArrayList(); + vm.setState(State.Starting); + vms.add(vm); + + List rules = new ArrayList(); + LoadBalancingRule rule = new LoadBalancingRule(null, null, + null, null, null); + + rules.add(rule); + try { + result = _lbVmMgr.applyLoadBalancingRules(new NetworkVO(), rules, vms); + } finally { + assertFalse("Rules were applied to vm in Starting state", result); + } + } + + + @Test + public void applyToVmInStoppedState() throws ResourceUnavailableException { + boolean result = false; + List vms = new ArrayList(); + vm.setState(State.Stopped); + vms.add(vm); + + List rules = new ArrayList(); + LoadBalancingRule rule = new LoadBalancingRule(null, null, + null, null, null); + + rules.add(rule); + try { + result = _lbVmMgr.applyLoadBalancingRules(new NetworkVO(), rules, vms); + } finally { + assertTrue("Rules failed to apply to vm in Stopped state", result); + } + } + + + @Test + public void applyToVmInStoppingState() throws ResourceUnavailableException { + boolean result = false; + List vms = new ArrayList(); + vm.setState(State.Stopping); + vms.add(vm); + + List rules = new ArrayList(); + LoadBalancingRule rule = new LoadBalancingRule(null, null, + null, null, null); + + rules.add(rule); + try { + result = _lbVmMgr.applyLoadBalancingRules(new NetworkVO(), rules, vms); + } finally { + assertTrue("Rules failed to apply to vm in Stopping state", result); + } + } + + + @Test + public void applyToVmInRunningState() throws ResourceUnavailableException { + boolean result = false; + List vms = new ArrayList(); + vm.setState(State.Running); + vms.add(vm); + + List rules = new ArrayList(); + ApplicationLoadBalancerRuleVO lb = new ApplicationLoadBalancerRuleVO(null, null, 22, 22, "roundrobin", + 1L, 1L, 1L, new Ip(requestedIp), 1L, Scheme.Internal); + lb.setState(FirewallRule.State.Add); + + LoadBalancingRule rule = new LoadBalancingRule(lb, null, + null, null, new Ip(requestedIp)); + + rules.add(rule); + + ntwk.getId(); + + try { + result = _lbVmMgr.applyLoadBalancingRules(ntwk, rules, vms); + } finally { + assertTrue("Rules failed to apply to vm in Running state", result); + } + } + + + //TESTS FOR destroyInternalLbVm METHOD + @Test + public void destroyNonExistingVM() throws ResourceUnavailableException, ConcurrentOperationException { + boolean result = false; + + try { + result = _lbVmMgr.destroyInternalLbVm(invalidVmId, new AccountVO(), 1L); + } finally { + assertTrue("Failed to destroy non-existing vm", result); + } + } + + @Test + public void destroyExistingVM() throws ResourceUnavailableException, ConcurrentOperationException { + boolean result = false; + + try { + result = _lbVmMgr.destroyInternalLbVm(validVmId, new AccountVO(), 1L); + } finally { + assertTrue("Failed to destroy valid vm", result); + } + } + + + private static ServiceOfferingVO setId(ServiceOfferingVO vo, long id) { + ServiceOfferingVO voToReturn = vo; + Class c = voToReturn.getClass(); + try { + Field f = c.getSuperclass().getDeclaredField("id"); + f.setAccessible(true); + f.setLong(voToReturn, id); + } catch (NoSuchFieldException ex) { + return null; + } catch (IllegalAccessException ex) { + return null; + } + + return voToReturn; + } + + + private static NetworkVO setId(NetworkVO vo, long id) { + NetworkVO voToReturn = vo; + Class c = voToReturn.getClass(); + try { + Field f = c.getDeclaredField("id"); + f.setAccessible(true); + f.setLong(voToReturn, id); + } catch (NoSuchFieldException ex) { + return null; + } catch (IllegalAccessException ex) { + return null; + } + + return voToReturn; + } + + private static DomainRouterVO setId(DomainRouterVO vo, long id) { + DomainRouterVO voToReturn = vo; + Class c = voToReturn.getClass(); + try { + Field f = c.getSuperclass().getDeclaredField("id"); + f.setAccessible(true); + f.setLong(voToReturn, id); + } catch (NoSuchFieldException ex) { + return null; + } catch (IllegalAccessException ex) { + return null; + } + + return voToReturn; + } + +} diff --git a/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/InternalLBVMServiceTest.java b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/InternalLBVMServiceTest.java new file mode 100644 index 00000000000..75f54faf8f0 --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/InternalLBVMServiceTest.java @@ -0,0 +1,291 @@ +// 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. +package org.apache.cloudstack.internallbvmmgr; + +import java.lang.reflect.Field; +import java.util.Map; + +import javax.inject.Inject; + +import junit.framework.TestCase; + +import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.cloud.deploy.DeploymentPlan; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.OperationTimedoutException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.exception.StorageUnavailableException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.router.VirtualRouter; +import com.cloud.network.router.VirtualRouter.Role; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.User; +import com.cloud.utils.component.ComponentContext; +import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineManager; +import com.cloud.vm.dao.DomainRouterDao; + +/** + * Set of unittests for InternalLoadBalancerVMService + * + */ + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations="classpath:/lb_svc.xml") +@SuppressWarnings("unchecked") +public class InternalLBVMServiceTest extends TestCase { + //The interface to test + @Inject InternalLoadBalancerVMService _lbVmSvc; + + //Mocked interfaces + @Inject AccountManager _accountMgr; + @Inject ServiceOfferingDao _svcOffDao; + @Inject DomainRouterDao _domainRouterDao; + @Inject VirtualMachineManager _itMgr; + + long validVmId = 1L; + long nonExistingVmId = 2L; + long nonInternalLbVmId = 3L; + + @Before + public void setUp() { + //mock system offering creation as it's used by configure() method called by initComponentsLifeCycle + Mockito.when(_accountMgr.getAccount(1L)).thenReturn(new AccountVO()); + ServiceOfferingVO off = new ServiceOfferingVO("alena", 1, 1, + 1, 1, 1, false, "alena", false, false, null, false, VirtualMachine.Type.InternalLoadBalancerVm, false); + off = setId(off, 1); + Mockito.when(_svcOffDao.persistSystemServiceOffering(Mockito.any(ServiceOfferingVO.class))).thenReturn(off); + + ComponentContext.initComponentsLifeCycle(); + + DomainRouterVO validVm = new DomainRouterVO(validVmId,off.getId(),1,"alena",1,HypervisorType.XenServer,1,1,1, + false, 0,false,null,false,false, + VirtualMachine.Type.InternalLoadBalancerVm, null); + validVm.setRole(Role.INTERNAL_LB_VM); + DomainRouterVO nonInternalLbVm = new DomainRouterVO(validVmId,off.getId(),1,"alena",1,HypervisorType.XenServer,1,1,1, + false, 0,false,null,false,false, + VirtualMachine.Type.DomainRouter, null); + nonInternalLbVm.setRole(Role.VIRTUAL_ROUTER); + + Mockito.when(_domainRouterDao.findById(validVmId)).thenReturn(validVm); + Mockito.when(_domainRouterDao.findById(nonExistingVmId)).thenReturn(null); + Mockito.when(_domainRouterDao.findById(nonInternalLbVmId)).thenReturn(nonInternalLbVm); + + try { + Mockito.when(_itMgr.start(Mockito.any(DomainRouterVO.class), + Mockito.any(Map.class), Mockito.any(User.class), Mockito.any(Account.class), Mockito.any(DeploymentPlan.class))).thenReturn(validVm); + } catch (InsufficientCapacityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ResourceUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + try { + Mockito.when(_itMgr.advanceStop(Mockito.any(DomainRouterVO.class), Mockito.any(Boolean.class), Mockito.any(User.class), Mockito.any(Account.class))).thenReturn(true); + } catch (ResourceUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (OperationTimedoutException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ConcurrentOperationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + //TESTS FOR START COMMAND + + + @Test (expected = InvalidParameterValueException.class) + public void startNonExistingVm() { + String expectedExcText = null; + try { + _lbVmSvc.startInternalLbVm(nonExistingVmId, _accountMgr.getAccount(1L), 1L); + } catch (StorageUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InsufficientCapacityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ConcurrentOperationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ResourceUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvalidParameterValueException e) { + expectedExcText = e.getMessage(); + throw e; + } finally { + assertEquals("Test failed. The non-existing internal lb vm was attempted to start" + + expectedExcText, expectedExcText, "Can't find internal lb vm by id specified"); + } + } + + @Test (expected = InvalidParameterValueException.class) + public void startNonInternalLbVmVm() { + String expectedExcText = null; + try { + _lbVmSvc.startInternalLbVm(nonInternalLbVmId, _accountMgr.getAccount(1L), 1L); + } catch (StorageUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InsufficientCapacityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ConcurrentOperationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ResourceUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + }catch (InvalidParameterValueException e) { + expectedExcText = e.getMessage(); + throw e; + } finally { + assertEquals("Test failed. The existing vm of not Internal lb vm type was attempted to start" + + expectedExcText, expectedExcText, "Can't find internal lb vm by id specified"); + } + } + + @Test + public void startValidLbVmVm() { + VirtualRouter vr = null; + try { + vr = _lbVmSvc.startInternalLbVm(validVmId, _accountMgr.getAccount(1L), 1L); + } catch (StorageUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InsufficientCapacityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ConcurrentOperationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ResourceUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } finally { + assertNotNull("Internal LB vm is null which means it failed to start " + vr, vr); + } + } + + + //TEST FOR STOP COMMAND + @Test (expected = InvalidParameterValueException.class) + public void stopNonExistingVm() { + String expectedExcText = null; + try { + _lbVmSvc.stopInternalLbVm(nonExistingVmId, false,_accountMgr.getAccount(1L), 1L); + } catch (StorageUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ConcurrentOperationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ResourceUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvalidParameterValueException e) { + expectedExcText = e.getMessage(); + throw e; + } finally { + assertEquals("Test failed. The non-existing internal lb vm was attempted to stop" + + expectedExcText, expectedExcText, "Can't find internal lb vm by id specified"); + } + } + + + @Test (expected = InvalidParameterValueException.class) + public void stopNonInternalLbVmVm() { + String expectedExcText = null; + try { + _lbVmSvc.stopInternalLbVm(nonInternalLbVmId, false, _accountMgr.getAccount(1L), 1L); + } catch (StorageUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ConcurrentOperationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ResourceUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + }catch (InvalidParameterValueException e) { + expectedExcText = e.getMessage(); + throw e; + } finally { + assertEquals("Test failed. The existing vm of not Internal lb vm type was attempted to stop" + + expectedExcText, expectedExcText, "Can't find internal lb vm by id specified"); + } + } + + + @Test + public void stopValidLbVmVm() { + VirtualRouter vr = null; + try { + vr = _lbVmSvc.stopInternalLbVm(validVmId, false, _accountMgr.getAccount(1L), 1L); + } catch (StorageUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ConcurrentOperationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ResourceUnavailableException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } finally { + assertNotNull("Internal LB vm is null which means it failed to stop " + vr, vr); + } + } + + + + private static ServiceOfferingVO setId(ServiceOfferingVO vo, long id) { + ServiceOfferingVO voToReturn = vo; + Class c = voToReturn.getClass(); + try { + Field f = c.getSuperclass().getDeclaredField("id"); + f.setAccessible(true); + f.setLong(voToReturn, id); + } catch (NoSuchFieldException ex) { + return null; + } catch (IllegalAccessException ex) { + return null; + } + + return voToReturn; + } +} diff --git a/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/LbChildTestConfiguration.java b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/LbChildTestConfiguration.java new file mode 100644 index 00000000000..79354ef26e2 --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/LbChildTestConfiguration.java @@ -0,0 +1,172 @@ +// 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. +package org.apache.cloudstack.internallbvmmgr; + +import java.io.IOException; + +import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; +import org.apache.cloudstack.test.utils.SpringUtils; +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.filter.TypeFilter; + +import com.cloud.agent.AgentManager; +import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.dc.dao.AccountVlanMapDaoImpl; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkModel; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.VirtualRouterProviderDao; +import com.cloud.network.lb.LoadBalancingRulesManager; +import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.resource.ResourceManager; +import com.cloud.server.ConfigurationServer; +import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.user.AccountManager; +import com.cloud.utils.net.NetUtils; +import com.cloud.vm.VirtualMachineManager; +import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.NicDao; + + +@Configuration +@ComponentScan( + basePackageClasses={ + NetUtils.class, + }, + includeFilters={@Filter(value=LbChildTestConfiguration.Library.class, type=FilterType.CUSTOM)}, + useDefaultFilters=false + ) + + public class LbChildTestConfiguration { + + public static class Library implements TypeFilter { + + + @Bean + public AccountManager accountManager() { + return Mockito.mock(AccountManager.class); + } + + @Bean + public VirtualMachineManager virtualMachineManager() { + return Mockito.mock(VirtualMachineManager.class); + } + + @Bean + public DomainRouterDao domainRouterDao() { + return Mockito.mock(DomainRouterDao.class); + } + + @Bean + public ConfigurationDao configurationDao() { + return Mockito.mock(ConfigurationDao.class); + } + + @Bean + public VirtualRouterProviderDao virtualRouterProviderDao() { + return Mockito.mock(VirtualRouterProviderDao.class); + } + + @Bean + public ApplicationLoadBalancerRuleDao applicationLoadBalancerRuleDao() { + return Mockito.mock(ApplicationLoadBalancerRuleDao.class); + } + + @Bean + public NetworkModel networkModel() { + return Mockito.mock(NetworkModel.class); + } + + @Bean + public LoadBalancingRulesManager loadBalancingRulesManager() { + return Mockito.mock(LoadBalancingRulesManager.class); + } + + @Bean + public NicDao nicDao() { + return Mockito.mock(NicDao.class); + } + + @Bean + public NetworkDao networkDao() { + return Mockito.mock(NetworkDao.class); + } + + @Bean + public NetworkManager networkManager() { + return Mockito.mock(NetworkManager.class); + } + + @Bean + public ServiceOfferingDao serviceOfferingDao() { + return Mockito.mock(ServiceOfferingDao.class); + } + + @Bean + public PhysicalNetworkServiceProviderDao physicalNetworkServiceProviderDao() { + return Mockito.mock(PhysicalNetworkServiceProviderDao.class); + } + + @Bean + public NetworkOfferingDao networkOfferingDao() { + return Mockito.mock(NetworkOfferingDao.class); + } + + @Bean + public VMTemplateDao vmTemplateDao() { + return Mockito.mock(VMTemplateDao.class); + } + + @Bean + public ResourceManager resourceManager() { + return Mockito.mock(ResourceManager.class); + } + + @Bean + public AgentManager agentManager() { + return Mockito.mock(AgentManager.class); + } + + @Bean + public DataCenterDao dataCenterDao() { + return Mockito.mock(DataCenterDao.class); + } + + @Bean + public ConfigurationServer configurationServer() { + return Mockito.mock(ConfigurationServer.class); + } + + @Override + public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { + mdr.getClassMetadata().getClassName(); + ComponentScan cs = LbChildTestConfiguration.class.getAnnotation(ComponentScan.class); + return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + } + + } +} diff --git a/plugins/network-elements/internal-loadbalancer/test/resources/lb_element.xml b/plugins/network-elements/internal-loadbalancer/test/resources/lb_element.xml new file mode 100644 index 00000000000..5dec9c314f6 --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/test/resources/lb_element.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/internal-loadbalancer/test/resources/lb_mgr.xml b/plugins/network-elements/internal-loadbalancer/test/resources/lb_mgr.xml new file mode 100644 index 00000000000..1ad6403861c --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/test/resources/lb_mgr.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/internal-loadbalancer/test/resources/lb_svc.xml b/plugins/network-elements/internal-loadbalancer/test/resources/lb_svc.xml new file mode 100644 index 00000000000..fa822f35302 --- /dev/null +++ b/plugins/network-elements/internal-loadbalancer/test/resources/lb_svc.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java b/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java index 2bbdb0450be..60d6674fdb4 100644 --- a/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java +++ b/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java @@ -16,16 +16,38 @@ // under the License. package com.cloud.network.element; +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.ejb.Local; +import javax.inject.Inject; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.network.ExternalNetworkDeviceManager.NetworkDevice; +import org.apache.cloudstack.region.gslb.GslbServiceProvider; +import org.apache.log4j.Logger; + import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.routing.GlobalLoadBalancerConfigCommand; +import com.cloud.agent.api.routing.HealthCheckLBConfigAnswer; +import com.cloud.agent.api.routing.HealthCheckLBConfigCommand; import com.cloud.agent.api.routing.LoadBalancerConfigCommand; import com.cloud.agent.api.routing.SetStaticNatRulesAnswer; import com.cloud.agent.api.routing.SetStaticNatRulesCommand; import com.cloud.agent.api.to.LoadBalancerTO; import com.cloud.agent.api.to.StaticNatRuleTO; import com.cloud.api.ApiDBUtils; -import com.cloud.api.commands.*; +import com.cloud.api.commands.AddNetscalerLoadBalancerCmd; +import com.cloud.api.commands.ConfigureNetscalerLoadBalancerCmd; +import com.cloud.api.commands.DeleteNetscalerLoadBalancerCmd; +import com.cloud.api.commands.ListNetscalerLoadBalancerNetworksCmd; +import com.cloud.api.commands.ListNetscalerLoadBalancersCmd; import com.cloud.api.response.NetscalerLoadBalancerResponse; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; @@ -37,28 +59,52 @@ import com.cloud.dc.HostPodVO; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.DataCenterIpAddressDao; import com.cloud.deploy.DeployDestination; -import com.cloud.exception.*; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InsufficientNetworkCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceUnavailableException; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.host.dao.HostDetailsDao; -import com.cloud.network.*; +import com.cloud.network.ExternalLoadBalancerDeviceManager; +import com.cloud.network.ExternalLoadBalancerDeviceManagerImpl; +import com.cloud.network.IpAddress; +import com.cloud.network.NetScalerPodVO; +import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; +import com.cloud.network.NetworkModel; import com.cloud.network.Networks.TrafficType; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.PublicIpAddress; import com.cloud.network.as.AutoScaleCounter; import com.cloud.network.as.AutoScaleCounter.AutoScaleCounterType; -import com.cloud.network.dao.*; +import com.cloud.network.dao.ExternalLoadBalancerDeviceDao; +import com.cloud.network.dao.ExternalLoadBalancerDeviceVO; import com.cloud.network.dao.ExternalLoadBalancerDeviceVO.LBDeviceState; +import com.cloud.network.dao.NetScalerPodDao; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkExternalLoadBalancerDao; +import com.cloud.network.dao.NetworkExternalLoadBalancerVO; +import com.cloud.network.dao.NetworkServiceMapDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.resource.NetscalerResource; import com.cloud.network.rules.FirewallRule; -import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.LbStickinessMethod; import com.cloud.network.rules.LbStickinessMethod.StickinessMethodType; +import com.cloud.network.rules.LoadBalancerContainer; import com.cloud.network.rules.StaticNat; +import com.cloud.network.vpc.PrivateGateway; +import com.cloud.network.vpc.StaticRouteProfile; +import com.cloud.network.vpc.Vpc; import com.cloud.offering.NetworkOffering; import com.cloud.utils.NumbersUtil; import com.cloud.utils.db.DB; @@ -70,15 +116,6 @@ import com.cloud.vm.ReservationContext; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; import com.google.gson.Gson; -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.network.ExternalNetworkDeviceManager.NetworkDevice; -import org.apache.cloudstack.region.gslb.GslbServiceProvider; -import org.apache.log4j.Logger; - -import javax.ejb.Local; -import javax.inject.Inject; -import java.net.URI; -import java.util.*; @Local(value = {NetworkElement.class, StaticNatServiceProvider.class, LoadBalancingServiceProvider.class, GslbServiceProvider.class}) public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl implements LoadBalancingServiceProvider, @@ -202,6 +239,10 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl if (!canHandle(config, Service.Lb)) { return false; } + + if (canHandleLbRules(rules)) { + return false; + } if (isBasicZoneNetwok(config)) { return applyElasticLoadBalancerRules(config, rules); @@ -232,6 +273,9 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl // Specifies that load balancing rules can only be made with public IPs that aren't source NAT IPs lbCapabilities.put(Capability.LoadBalancingSupportedIps, "additional"); + // Supports only Public load balancing + lbCapabilities.put(Capability.LbSchemes, LoadBalancerContainer.Scheme.Public.toString()); + // Specifies that load balancing rules can support autoscaling and the list of counters it supports AutoScaleCounter counter; List counterList = new ArrayList(); @@ -639,14 +683,7 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl return this; } - public boolean applyElasticLoadBalancerRules(Network network, List rules) throws ResourceUnavailableException { - - List loadBalancingRules = new ArrayList(); - for (FirewallRule rule : rules) { - if (rule.getPurpose().equals(Purpose.LoadBalancing)) { - loadBalancingRules.add((LoadBalancingRule) rule); - } - } + public boolean applyElasticLoadBalancerRules(Network network, List loadBalancingRules) throws ResourceUnavailableException { if (loadBalancingRules == null || loadBalancingRules.isEmpty()) { return true; @@ -677,12 +714,12 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl String protocol = rule.getProtocol(); String algorithm = rule.getAlgorithm(); String lbUuid = rule.getUuid(); - String srcIp = _networkMgr.getIp(rule.getSourceIpAddressId()).getAddress().addr(); + String srcIp = rule.getSourceIp().addr(); int srcPort = rule.getSourcePortStart(); List destinations = rule.getDestinations(); if ((destinations != null && !destinations.isEmpty()) || rule.isAutoScaleConfig()) { - LoadBalancerTO loadBalancer = new LoadBalancerTO(lbUuid, srcIp, srcPort, protocol, algorithm, revoked, false, false, destinations, rule.getStickinessPolicies()); + LoadBalancerTO loadBalancer = new LoadBalancerTO(lbUuid, srcIp, srcPort, protocol, algorithm, revoked, false, false, destinations, rule.getStickinessPolicies(), rule.getHealthCheckPolicies()); if (rule.isAutoScaleConfig()) { loadBalancer.setAutoScaleVmGroup(rule.getAutoScaleVmGroup()); } @@ -808,11 +845,69 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl return null; } + public List getElasticLBRulesHealthCheck(Network network, List loadBalancingRules) + throws ResourceUnavailableException { + + HealthCheckLBConfigAnswer answer = null; + + if (loadBalancingRules == null || loadBalancingRules.isEmpty()) { + return null; + } + + String errMsg = null; + ExternalLoadBalancerDeviceVO lbDeviceVO = getExternalLoadBalancerForNetwork(network); + + if (lbDeviceVO == null) { + s_logger.warn("There is no external load balancer device assigned to this network either network is not implement are already shutdown so just returning"); + return null; + } + + if (!isNetscalerDevice(lbDeviceVO.getDeviceName())) { + errMsg = "There are no NetScaler load balancer assigned for this network. So NetScaler element can not be handle elastic load balancer rules."; + s_logger.error(errMsg); + throw new ResourceUnavailableException(errMsg, this.getClass(), 0); + } + + List loadBalancersToApply = new ArrayList(); + for (int i = 0; i < loadBalancingRules.size(); i++) { + LoadBalancingRule rule = loadBalancingRules.get(i); + boolean revoked = (rule.getState().equals(FirewallRule.State.Revoke)); + String protocol = rule.getProtocol(); + String algorithm = rule.getAlgorithm(); + String lbUuid = rule.getUuid(); + String srcIp = rule.getSourceIp().addr(); + int srcPort = rule.getSourcePortStart(); + List destinations = rule.getDestinations(); + + if ((destinations != null && !destinations.isEmpty()) || rule.isAutoScaleConfig()) { + LoadBalancerTO loadBalancer = new LoadBalancerTO(lbUuid, srcIp, srcPort, protocol, algorithm, revoked, + false, false, destinations, null, rule.getHealthCheckPolicies()); + loadBalancersToApply.add(loadBalancer); + } + } + + if (loadBalancersToApply.size() > 0) { + int numLoadBalancersForCommand = loadBalancersToApply.size(); + LoadBalancerTO[] loadBalancersForCommand = loadBalancersToApply + .toArray(new LoadBalancerTO[numLoadBalancersForCommand]); + HealthCheckLBConfigCommand cmd = new HealthCheckLBConfigCommand(loadBalancersForCommand); + HostVO externalLoadBalancer = _hostDao.findById(lbDeviceVO.getHostId()); + answer = (HealthCheckLBConfigAnswer) _agentMgr.easySend(externalLoadBalancer.getId(), cmd); + return answer.getLoadBalancers(); + } + return null; + } + public List updateHealthChecks(Network network, List lbrules) { - if (canHandle(network, Service.Lb)) { + if (canHandle(network, Service.Lb) && canHandleLbRules(lbrules)) { try { - return getLBHealthChecks(network, lbrules); + + if (isBasicZoneNetwok(network)) { + return getElasticLBRulesHealthCheck(network, lbrules); + } else { + return getLBHealthChecks(network, lbrules); + } } catch (ResourceUnavailableException e) { s_logger.error("Error in getting the LB Rules from NetScaler " + e); } @@ -822,7 +917,7 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl return null; } - public List getLBHealthChecks(Network network, List rules) + public List getLBHealthChecks(Network network, List rules) throws ResourceUnavailableException { return super.getLBHealthChecks(network, rules); } @@ -891,4 +986,21 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl } return null; } + + private boolean canHandleLbRules(List rules) { + Map lbCaps = this.getCapabilities().get(Service.Lb); + if (!lbCaps.isEmpty()) { + String schemeCaps = lbCaps.get(Capability.LbSchemes); + if (schemeCaps != null) { + for (LoadBalancingRule rule : rules) { + if (!schemeCaps.contains(rule.getScheme().toString())) { + s_logger.debug("Scheme " + rules.get(0).getScheme() + " is not supported by the provider " + this.getName()); + return false; + } + } + } + } + return true; + } + } diff --git a/plugins/network-elements/netscaler/src/com/cloud/network/resource/NetscalerResource.java b/plugins/network-elements/netscaler/src/com/cloud/network/resource/NetscalerResource.java index b82176b7e37..98e14618248 100644 --- a/plugins/network-elements/netscaler/src/com/cloud/network/resource/NetscalerResource.java +++ b/plugins/network-elements/netscaler/src/com/cloud/network/resource/NetscalerResource.java @@ -1211,6 +1211,18 @@ public class NetscalerResource implements ServerResource { try { gslbservice service; service = getServiceObject(client, serviceName); + String gslbServerName = generateGslbServerName(serviceIp); + + if (!gslbServerExists(client, gslbServerName)) { + base_response apiCallResult; + com.citrix.netscaler.nitro.resource.config.basic.server nsServer = new com.citrix.netscaler.nitro.resource.config.basic.server(); + nsServer.set_name(gslbServerName); + nsServer.set_ipaddress(serviceIp); + apiCallResult = com.citrix.netscaler.nitro.resource.config.basic.server.add(client, nsServer); + if ((apiCallResult.errorcode != 0) && (apiCallResult.errorcode != NitroError.NS_RESOURCE_EXISTS)) { + throw new ExecutionException("Failed to add server " + gslbServerName + " due to" + apiCallResult.message); + } + } boolean isUpdateSite = false; if (service == null) { @@ -1220,7 +1232,7 @@ public class NetscalerResource implements ServerResource { } service.set_sitename(siteName); - service.set_servername(serviceIp); + service.set_servername(gslbServerName); int port = Integer.parseInt(servicePort); service.set_port(port); service.set_servicename(serviceName); @@ -1236,7 +1248,7 @@ public class NetscalerResource implements ServerResource { s_logger.debug("Successfully created service: " + serviceName + " at site: " + siteName); } } catch (Exception e) { - String errMsg = "Failed to created service: " + serviceName + " at site: " + siteName; + String errMsg = "Failed to created service: " + serviceName + " at site: " + siteName + " due to " + e.getMessage(); if (s_logger.isDebugEnabled()) { s_logger.debug(errMsg); } @@ -1284,7 +1296,7 @@ public class NetscalerResource implements ServerResource { } } } catch (Exception e) { - String errMsg = "Failed to update service: " + serviceName + " at site: " + siteName; + String errMsg = "Failed to update service: " + serviceName + " at site: " + siteName + "due to " + e.getMessage(); if (s_logger.isDebugEnabled()) { s_logger.debug(errMsg); } @@ -1294,6 +1306,7 @@ public class NetscalerResource implements ServerResource { private static void createVserverServiceBinding(nitro_service client, String serviceName, String vserverName) throws ExecutionException { + String errMsg; try { gslbvserver_gslbservice_binding binding = new gslbvserver_gslbservice_binding(); binding.set_name(vserverName); @@ -1303,8 +1316,18 @@ public class NetscalerResource implements ServerResource { s_logger.debug("Successfully created service: " + serviceName + " and virtual server: " + vserverName + " binding"); } + } catch (nitro_exception ne) { + if (ne.getErrorCode() == 273) { + return; + } + errMsg = "Failed to create service: " + serviceName + " and virtual server: " + + vserverName + " binding due to " + ne.getMessage(); + if (s_logger.isDebugEnabled()) { + s_logger.debug(errMsg); + } + throw new ExecutionException(errMsg); } catch (Exception e) { - String errMsg = "Failed to create service: " + serviceName + " and virtual server: " + errMsg = "Failed to create service: " + serviceName + " and virtual server: " + vserverName + " binding due to " + e.getMessage(); if (s_logger.isDebugEnabled()) { s_logger.debug(errMsg); @@ -1437,6 +1460,39 @@ public class NetscalerResource implements ServerResource { private static String generateUniqueServiceName(String siteName, String publicIp, String publicPort) { return "cloud-gslb-service-" + siteName + "-" + publicIp + "-" + publicPort; } + + private static boolean gslbServerExists(nitro_service client, String serverName) throws ExecutionException { + try { + if (com.citrix.netscaler.nitro.resource.config.basic.server.get(client, serverName) != null) { + return true; + } else { + return false; + } + } catch (nitro_exception e) { + if (e.getErrorCode() == NitroError.NS_RESOURCE_NOT_EXISTS) { + return false; + } else { + throw new ExecutionException("Failed to verify Server " + serverName + " exists on the NetScaler device due to " + e.getMessage()); + } + } catch (Exception e) { + throw new ExecutionException("Failed to verify Server " + serverName + " exists on the NetScaler device due to " + e.getMessage()); + } + } + + private static String generateGslbServerName(String serverIP) { + return genGslbObjectName("Cloud-Server-", serverIP); + } + + private static String genGslbObjectName(Object... args) { + String objectName = ""; + for (int i = 0; i < args.length; i++) { + objectName += args[i]; + if (i != args.length -1) { + objectName += "-"; + } + } + return objectName; + } } @@ -1562,7 +1618,9 @@ public class NetscalerResource implements ServerResource { String srcIp = rule.getSrcIp(); String dstIP = rule.getDstIp(); String iNatRuleName = generateInatRuleName(srcIp, dstIP); + String rNatRuleName = generateRnatRuleName(srcIp, dstIP); inat iNatRule = null; + rnat rnatRule = null; if (!rule.revoked()) { try { @@ -1589,9 +1647,47 @@ public class NetscalerResource implements ServerResource { } s_logger.debug("Created Inat rule on the Netscaler device " + _ip + " to enable static NAT from " + srcIp + " to " + dstIP); } + try { + rnat[] rnatRules = rnat.get(_netscalerService); + if (rnatRules != null) { + for (rnat rantrule : rnatRules) { + if (rantrule.get_network().equalsIgnoreCase(rNatRuleName)) { + rnatRule = rantrule; + break; + } + } + } + } catch (nitro_exception e) { + throw e; + } + + if (rnatRule == null) { + rnatRule = new rnat(); + rnatRule.set_natip(srcIp); + rnatRule.set_network(dstIP); + rnatRule.set_netmask("255.255.255.255"); + try { + apiCallResult = rnat.update(_netscalerService, rnatRule); + } catch (nitro_exception e) { + if (e.getErrorCode() != NitroError.NS_RESOURCE_EXISTS) { + throw e; + } + } + s_logger.debug("Created Rnat rule on the Netscaler device " + _ip + " to enable revese static NAT from " + dstIP + " to " + srcIp); + } } else { try { inat.delete(_netscalerService, iNatRuleName); + rnat[] rnatRules = rnat.get(_netscalerService); + if (rnatRules != null) { + for (rnat rantrule : rnatRules) { + if (rantrule.get_network().equalsIgnoreCase(dstIP)) { + rnatRule = rantrule; + rnat.clear(_netscalerService, rnatRule); + break; + } + } + } } catch (nitro_exception e) { if (e.getErrorCode() != NitroError.NS_RESOURCE_NOT_EXISTS) { throw e; @@ -2201,6 +2297,7 @@ public class NetscalerResource implements ServerResource { } csMon.set_interval(hcp.getHealthcheckInterval()); + csMon.set_retries(Math.max(hcp.getHealthcheckThresshold(), hcp.getUnhealthThresshold()) + 1); csMon.set_resptimeout(hcp.getResponseTime()); csMon.set_failureretries(hcp.getUnhealthThresshold()); csMon.set_successretries(hcp.getHealthcheckThresshold()); @@ -3034,6 +3131,10 @@ public class NetscalerResource implements ServerResource { return genObjectName("Cloud-Inat", srcIp); } + private String generateRnatRuleName(String srcIp, String dstIP) { + return genObjectName("Cloud-Rnat", srcIp); + } + private String generateNSVirtualServerName(String srcIp, long srcPort) { return genObjectName("Cloud-VirtualServer", srcIp, srcPort); } diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/DeleteNiciraNvpDeviceCmd.java b/plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/DeleteNiciraNvpDeviceCmd.java old mode 100644 new mode 100755 index 8d21a55a65e..9ba1c836a98 --- a/plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/DeleteNiciraNvpDeviceCmd.java +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/DeleteNiciraNvpDeviceCmd.java @@ -95,7 +95,7 @@ public class DeleteNiciraNvpDeviceCmd extends BaseAsyncCmd { @Override public String getEventType() { - return EventTypes.EVENT_EXTERNAL_LB_DEVICE_DELETE; + return EventTypes.EVENT_EXTERNAL_NVP_CONTROLLER_DELETE; } @Override diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpTag.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpTag.java index f8282b86d9c..157c3b522c7 100644 --- a/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpTag.java +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpTag.java @@ -16,7 +16,10 @@ // under the License. package com.cloud.network.nicira; +import org.apache.log4j.Logger; + public class NiciraNvpTag { + private static final Logger s_logger = Logger.getLogger(NiciraNvpTag.class); private String scope; private String tag; @@ -24,7 +27,12 @@ public class NiciraNvpTag { public NiciraNvpTag(String scope, String tag) { this.scope = scope; - this.tag = tag; + if (tag.length() > 40) { + s_logger.warn("tag \"" + tag + "\" too long, truncating to 40 characters"); + this.tag = tag.substring(0, 40); + } else { + this.tag = tag; + } } public String getScope() { @@ -40,7 +48,12 @@ public class NiciraNvpTag { } public void setTag(String tag) { - this.tag = tag; + if (tag.length() > 40) { + s_logger.warn("tag \"" + tag + "\" too long, truncating to 40 characters"); + this.tag = tag.substring(0, 40); + } else { + this.tag = tag; + } } } diff --git a/plugins/network-elements/nicira-nvp/test/com/cloud/network/nicira/NiciraTagTest.java b/plugins/network-elements/nicira-nvp/test/com/cloud/network/nicira/NiciraTagTest.java new file mode 100644 index 00000000000..fd13e07ab59 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/test/com/cloud/network/nicira/NiciraTagTest.java @@ -0,0 +1,54 @@ +// 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. +package com.cloud.network.nicira; + +import org.junit.Test; +import static org.junit.Assert.*; + +public class NiciraTagTest { + @Test + public void testCreateTag() { + NiciraNvpTag tag = new NiciraNvpTag("scope","tag"); + assertEquals("scope part set", "scope", tag.getScope()); + assertEquals("tag part set", "tag", tag.getTag()); + } + + @Test + public void testCreateLongTag() { + NiciraNvpTag tag = new NiciraNvpTag("scope","verylongtagthatshouldattheminimumexceedthefortycharacterlenght"); + assertEquals("scope part set", "scope", tag.getScope()); + assertEquals("tag part set", "verylongtagthatshouldattheminimumexceedt", tag.getTag()); + } + + @Test + public void testSetTag() { + NiciraNvpTag tag = new NiciraNvpTag(); + tag.setScope("scope"); + tag.setTag("tag"); + assertEquals("scope part set", "scope", tag.getScope()); + assertEquals("tag part set", "tag", tag.getTag()); + } + + @Test + public void testSetLongTag() { + NiciraNvpTag tag = new NiciraNvpTag(); + tag.setScope("scope"); + tag.setTag("verylongtagthatshouldattheminimumexceedthefortycharacterlenght"); + assertEquals("scope part set", "scope", tag.getScope()); + assertEquals("tag part set", "verylongtagthatshouldattheminimumexceedt", tag.getTag()); + } +} \ No newline at end of file diff --git a/plugins/pom.xml b/plugins/pom.xml index 471253f0728..e49fac9533a 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -16,8 +16,7 @@ KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ---> - +--> 4.0.0 cloudstack-plugins Apache CloudStack Plugin POM @@ -63,6 +62,7 @@ storage/volume/default alert-handlers/snmp-alerts alert-handlers/syslog-alerts + network-elements/internal-loadbalancer diff --git a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java index a0c991b5ad6..7153282a2aa 100644 --- a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java +++ b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java @@ -30,12 +30,10 @@ import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; import org.apache.cloudstack.engine.subsystem.api.storage.HostScope; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters; -import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; @@ -46,17 +44,12 @@ import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.CreateStoragePoolCommand; import com.cloud.agent.api.DeleteStoragePoolCommand; -import com.cloud.agent.api.ModifyStoragePoolCommand; import com.cloud.agent.api.StoragePoolInfo; import com.cloud.alert.AlertManager; -import com.cloud.capacity.Capacity; -import com.cloud.capacity.CapacityVO; -import com.cloud.capacity.dao.CapacityDao; import com.cloud.exception.DiscoveryException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.host.Host; import com.cloud.host.HostVO; -import com.cloud.host.Status; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ResourceManager; import com.cloud.server.ManagementServer; @@ -67,29 +60,14 @@ import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolAutomation; import com.cloud.storage.StoragePoolDiscoverer; import com.cloud.storage.StoragePoolHostVO; -import com.cloud.storage.StoragePoolStatus; -import com.cloud.storage.StoragePoolWorkVO; -import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.storage.dao.StoragePoolWorkDao; import com.cloud.storage.dao.VolumeDao; -import com.cloud.user.Account; -import com.cloud.user.User; -import com.cloud.user.UserContext; import com.cloud.user.dao.UserDao; import com.cloud.utils.NumbersUtil; import com.cloud.utils.UriUtils; import com.cloud.utils.db.DB; -import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.exception.ExecutionException; -import com.cloud.vm.ConsoleProxyVO; -import com.cloud.vm.DomainRouterVO; -import com.cloud.vm.SecondaryStorageVmVO; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.VMInstanceVO; -import com.cloud.vm.VirtualMachine; -import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.VirtualMachineManager; import com.cloud.vm.dao.ConsoleProxyDao; import com.cloud.vm.dao.DomainRouterDao; @@ -157,7 +135,7 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements throw new InvalidParameterValueException( "Cluster id requires pod id"); } - + PrimaryDataStoreParameters parameters = new PrimaryDataStoreParameters(); URI uri = null; @@ -195,7 +173,7 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements String tags = (String) dsInfos.get("tags"); Map details = (Map) dsInfos .get("details"); - + parameters.setTags(tags); parameters.setDetails(details); @@ -208,7 +186,7 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements } String userInfo = uri.getUserInfo(); int port = uri.getPort(); - StoragePoolVO pool = null; + StoragePool pool = null; if (s_logger.isDebugEnabled()) { s_logger.debug("createPool Params @ scheme - " + scheme + " storageHost - " + storageHost + " hostPath - " @@ -272,7 +250,7 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements parameters.setPath(hostPath); } else { for (StoragePoolDiscoverer discoverer : _discoverers) { - Map> pools; + Map> pools; try { pools = discoverer.find(zoneId, podId, uri, details); } catch (DiscoveryException e) { @@ -281,7 +259,7 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements e); } if (pools != null) { - Map.Entry> entry = pools + Map.Entry> entry = pools .entrySet().iterator().next(); pool = entry.getKey(); details = entry.getValue(); @@ -310,7 +288,7 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements parameters.setPath(hostPath); } else { StoragePoolType type = Enum.valueOf(StoragePoolType.class, scheme); - + if (type != null) { parameters.setType(type); parameters.setHost(storageHost); @@ -332,7 +310,7 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements + " already in use by another pod (id=" + oldPodId + ")"); } } - + Object existingUuid = dsInfos.get("uuid"); String uuid = null; @@ -368,7 +346,7 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements parameters.setName(poolName); parameters.setClusterId(clusterId); parameters.setProviderName(providerName); - + return dataStoreHelper.createPrimaryDataStore(parameters); } @@ -457,7 +435,7 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements primaryDataStoreDao.expunge(primarystore.getId()); return false; } - + this.dataStoreHelper.attachCluster(store); return true; } @@ -527,11 +505,11 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements } } } - + if (!deleteFlag) { throw new CloudRuntimeException("Failed to delete storage pool on host"); } - + return this.dataStoreHelper.deletePrimaryDataStore(store); } diff --git a/pom.xml b/pom.xml index 7d5b4c3bdef..e8fdb2f83ea 100644 --- a/pom.xml +++ b/pom.xml @@ -1,23 +1,14 @@ - + + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4.0.0 @@ -34,8 +25,8 @@ Apache CloudStack is an IaaS (“Infrastracture as a Service”) cloud orchestration platform. http://www.cloudstack.org - scm:git:https://git-wip-us.apache.org/repos/asf/incubator-cloudstack.git - scm:git:https://git-wip-us.apache.org/repos/asf/incubator-cloudstack.git + scm:git:https://git-wip-us.apache.org/repos/asf/cloudstack.git + scm:git:https://git-wip-us.apache.org/repos/asf/cloudstack.git jira @@ -43,7 +34,7 @@ - + 1.6 UTF-8 @@ -92,6 +83,7 @@ 0.10 build/replace.properties 0.4.9 + target @@ -106,40 +98,49 @@ Apache CloudStack User List - cloudstack-users-subscribe@incubator.apache.org - cloudstack-users-unsubscribe@incubator.apache.org - cloudstack-users@incubator.apache.org - http://mail-archives.apache.org/mod_mbox/incubator-cloudstack-users + users-subscribe@cloudstack.apache.org + users-unsubscribe@cloudstack.apache.org + users@cloudstack.apache.org + http://mail-archives.apache.org/mod_mbox/cloudstack-users + + http://mail-archives.apache.org/mod_mbox/incubator-cloudstack-users + Apache CloudStack Developer List - cloudstack-dev-subscribe@incubator.apache.org - cloudstack-dev-unsubscribe@incubator.apache.org - cloudstack-dev@incubator.apache.org - http://mail-archives.apache.org/mod_mbox/incubator-cloudstack-dev + dev-subscribe@cloudstack.apache.org + dev-unsubscribe@cloudstack.apache.org + dev@cloudstack.apache.org + http://mail-archives.apache.org/mod_mbox/cloudstack-dev + + http://mail-archives.apache.org/mod_mbox/incubator-cloudstack-dev + Apache CloudStack Commits List - cloudstack-commits-subscribe@incubator.apache.org - cloudstack-commits-unsubscribe@incubator.apache.org - cloudstack-commits@incubator.apache.org - http://mail-archives.apache.org/mod_mbox/incubator-cloudstack-commits + commits-subscribe@cloudstack.apache.org + commits-unsubscribe@cloudstack.apache.org + commits@cloudstack.apache.org + http://mail-archives.apache.org/mod_mbox/cloudstack-commits + + http://mail-archives.apache.org/mod_mbox/incubator-cloudstack-commits + The Apache CloudStack Team - cloudstack-dev@incubator.apache.org - http://incubator.apache.org/projects/cloudstack.html + dev@cloudstack.apache.org + http://cloudstack.apache.org/ Apache Software Foundation http://apache.org/ - Jenkin - http://jenkins.cloudstack.org/ + Jenkins + http://builds.apache.org/ @@ -167,9 +168,9 @@ plugins patches framework - services test client + services @@ -204,6 +205,20 @@ spring-web ${org.springframework.version} + org.mockito mockito-all @@ -235,8 +250,31 @@ install + src + test + + + test/resources + + + ${basedir}/${cs.target.dir}/classes + ${basedir}/${cs.target.dir}/test-classes + + maven-clean-plugin + + true + + + target + + **/* + + + + + org.apache.maven.plugins maven-release-plugin @@ -253,8 +291,8 @@ - + org.eclipse.m2e lifecycle-mapping @@ -276,7 +314,7 @@ - + @@ -377,7 +415,7 @@ patches/systemvm/debian/config/etc/apache2/sites-available/default patches/systemvm/debian/config/etc/apache2/sites-available/default-ssl patches/systemvm/debian/config/etc/apache2/vhostexample.conf - patches/systemvm/debian/config/etc/dnsmasq.conf + patches/systemvm/debian/config/etc/dnsmasq.conf.tmpl patches/systemvm/debian/config/etc/vpcdnsmasq.conf patches/systemvm/debian/config/etc/ssh/sshd_config patches/systemvm/debian/config/etc/rsyslog.conf @@ -398,6 +436,8 @@ patches/systemvm/debian/config/var/www/html/userdata/.htaccess patches/systemvm/debian/config/var/www/html/latest/.htaccess patches/systemvm/debian/vpn/etc/ipsec.d/l2tp.conf + tools/transifex/.tx/config + tools/marvin/marvin/sandbox/advanced/sandbox.cfg @@ -469,6 +509,12 @@ awsapi + + eclipse + + target-eclipse + + developer @@ -479,6 +525,16 @@ tools + + impatient + + tools/devcloud/devcloud.cfg + + + developer + + + vmware diff --git a/scripts/network/exdhcp/dnsmasq_edithosts.sh b/scripts/network/exdhcp/dnsmasq_edithosts.sh index 05285d9accf..7990356edc4 100755 --- a/scripts/network/exdhcp/dnsmasq_edithosts.sh +++ b/scripts/network/exdhcp/dnsmasq_edithosts.sh @@ -35,6 +35,9 @@ wait_for_dnsmasq () { return 1 } +command -v dhcp_release > /dev/null 2>&1 +no_dhcp_release=$? + [ ! -f /etc/dhcphosts.txt ] && touch /etc/dhcphosts.txt [ ! -f /var/lib/misc/dnsmasq.leases ] && touch /var/lib/misc/dnsmasq.leases @@ -44,6 +47,12 @@ sed -i /$3,/d /etc/dhcphosts.txt echo "$1,$2,$3,infinite" >>/etc/dhcphosts.txt +#release previous dhcp lease if present +if [ $no_dhcp_release -eq 0 ] +then + dhcp_release lo $2 $(grep $2 $DHCP_LEASES | awk '{print $2}') > /dev/null 2>&1 +fi + #delete leases to supplied mac and ip addresses sed -i /$1/d /var/lib/misc/dnsmasq.leases sed -i /"$2 "/d /var/lib/misc/dnsmasq.leases @@ -61,9 +70,13 @@ echo "$2 $3" >> /etc/hosts pid=$(pidof dnsmasq) if [ "$pid" != "" ] then - # send SIGHUP to dnsmasq to reload /etc/hosts /etc/dhcphosts.txt - # this will not reload /etc/dnsmasq.conf - kill -s 1 $pid + # use SIGHUP to avoid service outage if dhcp_release is available. + if [ $no_dhcp_release -eq 0 ] + then + kill -HUP $pid + else + service dnsmasq restart + fi else service dnsmasq start wait_for_dnsmasq diff --git a/server/pom.xml b/server/pom.xml index 8b64335d50f..004d9c8e068 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -1,22 +1,14 @@ - - + + 4.0.0 cloud-server Apache CloudStack Server @@ -42,6 +34,11 @@ httpcore ${cs.httpcore.version} + + org.apache.cloudstack + cloud-framework-jobs + ${project.version} + org.apache.httpcomponents httpclient @@ -110,35 +107,35 @@ **/*.xml - + test/resources - - %regex[.*[0-9]*To[0-9]*.*Test.*] - + + %regex[.*[0-9]*To[0-9]*.*Test.*] + - - org.apache.maven.plugins - maven-compiler-plugin - - - default-testCompile - test-compile - - - **/com/cloud/upgrade/*.java - **/com/cloud/async/*.java - - - - testCompile - - - - + + org.apache.maven.plugins + maven-compiler-plugin + + + default-testCompile + test-compile + + + **/com/cloud/upgrade/*.java + **/com/cloud/async/*.java + + + + testCompile + + + + org.apache.maven.plugins maven-surefire-plugin @@ -146,8 +143,8 @@ -Xmx1024m %regex[.*[0-9]*To[0-9]*.*Test.*] - com/cloud/upgrade/AdvanceZone223To224UpgradeTest - com/cloud/upgrade/AdvanceZone217To224UpgradeTest + com/cloud/upgrade/AdvanceZone223To224UpgradeTest + com/cloud/upgrade/AdvanceZone217To224UpgradeTest com/cloud/async/* com/cloud/cluster/* com/cloud/snapshot/* @@ -157,7 +154,9 @@ com/cloud/network/vpn/RemoteAccessVpnTest.java com/cloud/network/security/SecurityGroupManagerImpl2Test.java com/cloud/network/security/SecurityGroupManagerImpl2Test.java - com/cloud/vpc/* + com/cloud/vpc/VpcTestConfiguration.java + com/cloud/vpc/VpcApiUnitTest.java + com/cloud/vpc/VpcManagerTest.java @@ -173,22 +172,18 @@ - + - - + + - + diff --git a/core/src/com/cloud/alert/AlertManager.java b/server/src/com/cloud/alert/AlertManager.java similarity index 100% rename from core/src/com/cloud/alert/AlertManager.java rename to server/src/com/cloud/alert/AlertManager.java diff --git a/server/src/com/cloud/alert/AlertManagerImpl.java b/server/src/com/cloud/alert/AlertManagerImpl.java index 655ed98ea60..9b7cd274a2e 100755 --- a/server/src/com/cloud/alert/AlertManagerImpl.java +++ b/server/src/com/cloud/alert/AlertManagerImpl.java @@ -70,6 +70,7 @@ import com.cloud.host.dao.HostDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.org.Grouping.AllocationState; import com.cloud.resource.ResourceManager; +import com.cloud.server.ConfigurationServer; import com.cloud.storage.StorageManager; import com.cloud.storage.dao.VolumeDao; import com.cloud.utils.NumbersUtil; @@ -106,7 +107,8 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager { @Inject private PrimaryDataStoreDao _storagePoolDao; @Inject private ConfigurationDao _configDao; @Inject private ResourceManager _resourceMgr; - @Inject private ConfigurationManager _configMgr; + @Inject private ConfigurationManager _configMgr; + @Inject ConfigurationServer _configServer; private Timer _timer = null; private float _cpuOverProvisioningFactor = 1; private long _capacityCheckPeriod = 60L * 60L * 1000L; // one hour by default @@ -562,19 +564,33 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager { float overProvFactor = 1f; capacity = _capacityDao.findCapacityBy(capacityType.intValue(), cluster.getDataCenterId(), null, cluster.getId()); - if (capacityType == Capacity.CAPACITY_TYPE_STORAGE){ - capacity.add(getUsedStats(capacityType, cluster.getDataCenterId(), cluster.getPodId(), cluster.getId())); + // cpu and memory allocated capacity notification threshold can be defined at cluster level, so getting the value if they are defined at cluster level + double capacityValue = 0; + switch (capacityType) { + case Capacity.CAPACITY_TYPE_STORAGE: + capacity.add(getUsedStats(capacityType, cluster.getDataCenterId(), cluster.getPodId(), cluster.getId())); + capacityValue = Double.parseDouble(_configServer.getConfigValue(Config.StorageCapacityThreshold.key(), Config.ConfigurationParameterScope.cluster.toString(), cluster.getId())); + break; + case Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED: + capacityValue = Double.parseDouble(_configServer.getConfigValue(Config.StorageAllocatedCapacityThreshold.key(), Config.ConfigurationParameterScope.cluster.toString(), cluster.getId())); + break; + case Capacity.CAPACITY_TYPE_CPU: + overProvFactor = ApiDBUtils.getCpuOverprovisioningFactor(); + capacityValue = Double.parseDouble(_configServer.getConfigValue(Config.CPUCapacityThreshold.key(), Config.ConfigurationParameterScope.cluster.toString(), cluster.getId())); + break; + case Capacity.CAPACITY_TYPE_MEMORY: + capacityValue = Double.parseDouble(_configServer.getConfigValue(Config.MemoryCapacityThreshold.key(), Config.ConfigurationParameterScope.cluster.toString(), cluster.getId())); + break; + default: + capacityValue = _capacityTypeThresholdMap.get(capacityType); } if (capacity == null || capacity.size() == 0){ continue; - } - if (capacityType == Capacity.CAPACITY_TYPE_CPU){ - overProvFactor = ApiDBUtils.getCpuOverprovisioningFactor(); } double totalCapacity = capacity.get(0).getTotalCapacity() * overProvFactor; double usedCapacity = capacity.get(0).getUsedCapacity() + capacity.get(0).getReservedCapacity(); - if (totalCapacity != 0 && usedCapacity/totalCapacity > _capacityTypeThresholdMap.get(capacityType)){ + if (totalCapacity != 0 && usedCapacity/totalCapacity > capacityValue){ generateEmailAlert(ApiDBUtils.findZoneById(cluster.getDataCenterId()), ApiDBUtils.findPodById(cluster.getPodId()), cluster, totalCapacity, usedCapacity, capacityType); } diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index 21ce63b8ae8..fce1f719086 100755 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -25,8 +25,6 @@ import java.util.Set; import javax.annotation.PostConstruct; import javax.inject.Inject; -import com.cloud.network.rules.LoadBalancer; -import com.cloud.region.ha.GlobalLoadBalancingRulesService; import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.affinity.dao.AffinityGroupDao; @@ -37,8 +35,8 @@ import org.apache.cloudstack.api.response.AsyncJobResponse; import org.apache.cloudstack.api.response.DiskOfferingResponse; import org.apache.cloudstack.api.response.DomainRouterResponse; import org.apache.cloudstack.api.response.EventResponse; -import org.apache.cloudstack.api.response.HostResponse; import org.apache.cloudstack.api.response.HostForMigrationResponse; +import org.apache.cloudstack.api.response.HostResponse; import org.apache.cloudstack.api.response.InstanceGroupResponse; import org.apache.cloudstack.api.response.ProjectAccountResponse; import org.apache.cloudstack.api.response.ProjectInvitationResponse; @@ -52,6 +50,7 @@ import org.apache.cloudstack.api.response.UserResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.api.response.VolumeResponse; import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.springframework.stereotype.Component; @@ -130,6 +129,8 @@ import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.host.dao.HostDetailsDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.dao.AccountGuestVlanMapDao; +import com.cloud.network.dao.AccountGuestVlanMapVO; import com.cloud.network.IpAddress; import com.cloud.network.Network; import com.cloud.network.Network.Capability; @@ -155,6 +156,8 @@ import com.cloud.network.as.dao.AutoScaleVmGroupPolicyMapDao; import com.cloud.network.as.dao.AutoScaleVmProfileDao; import com.cloud.network.as.dao.ConditionDao; import com.cloud.network.as.dao.CounterDao; +import com.cloud.network.dao.AccountGuestVlanMapDao; +import com.cloud.network.dao.AccountGuestVlanMapVO; import com.cloud.network.dao.FirewallRulesCidrsDao; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; @@ -179,6 +182,7 @@ import com.cloud.network.dao.Site2SiteVpnGatewayDao; import com.cloud.network.dao.Site2SiteVpnGatewayVO; import com.cloud.network.router.VirtualRouter; import com.cloud.network.rules.FirewallRuleVO; +import com.cloud.network.rules.LoadBalancer; import com.cloud.network.security.SecurityGroup; import com.cloud.network.security.SecurityGroupManager; import com.cloud.network.security.SecurityGroupVO; @@ -202,6 +206,7 @@ import com.cloud.projects.Project; import com.cloud.projects.ProjectAccount; import com.cloud.projects.ProjectInvitation; import com.cloud.projects.ProjectService; +import com.cloud.region.ha.GlobalLoadBalancingRulesService; import com.cloud.resource.ResourceManager; import com.cloud.server.Criteria; import com.cloud.server.ManagementServer; @@ -309,6 +314,7 @@ public class ApiDBUtils { static GuestOSDao _guestOSDao; static GuestOSCategoryDao _guestOSCategoryDao; static HostDao _hostDao; + static AccountGuestVlanMapDao _accountGuestVlanMapDao; static IPAddressDao _ipAddressDao; static LoadBalancerDao _loadBalancerDao; static SecurityGroupDao _securityGroupDao; @@ -416,6 +422,7 @@ public class ApiDBUtils { @Inject private GuestOSDao guestOSDao; @Inject private GuestOSCategoryDao guestOSCategoryDao; @Inject private HostDao hostDao; + @Inject private AccountGuestVlanMapDao accountGuestVlanMapDao; @Inject private IPAddressDao ipAddressDao; @Inject private LoadBalancerDao loadBalancerDao; @Inject private SecurityGroupDao securityGroupDao; @@ -495,6 +502,7 @@ public class ApiDBUtils { @Inject private VMSnapshotDao vmSnapshotDao; @Inject private NicSecondaryIpDao nicSecondaryIpDao; @Inject private VpcProvisioningService vpcProvSvc; + @Inject private ApplicationLoadBalancerRuleDao _appLbDao; @Inject private AffinityGroupDao affinityGroupDao; @Inject private AffinityGroupJoinDao affinityGroupJoinDao; @Inject private GlobalLoadBalancingRulesService gslbService; @@ -512,6 +520,7 @@ public class ApiDBUtils { _templateMgr = templateMgr; _accountDao = accountDao; + _accountGuestVlanMapDao = accountGuestVlanMapDao; _accountVlanMapDao = accountVlanMapDao; _clusterDao = clusterDao; _capacityDao = capacityDao; @@ -945,6 +954,15 @@ public class ApiDBUtils { } } + public static Long getAccountIdForGuestVlan(long vlanDbId) { + List accountGuestVlanMaps = _accountGuestVlanMapDao.listAccountGuestVlanMapsByVlan(vlanDbId); + if (accountGuestVlanMaps.isEmpty()) { + return null; + } else { + return accountGuestVlanMaps.get(0).getAccountId(); + } + } + public static HypervisorType getVolumeHyperType(long volumeId) { return _volumeDao.getHypervisorType(volumeId); } @@ -1034,7 +1052,7 @@ public class ApiDBUtils { } public static Integer getNetworkRate(long networkOfferingId) { - return _configMgr.getNetworkOfferingNetworkRate(networkOfferingId); + return _configMgr.getNetworkOfferingNetworkRate(networkOfferingId, null); } public static Account getVlanAccount(long vlanId) { diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 4cf261e6935..39327cfd351 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -36,12 +36,17 @@ import javax.inject.Inject; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.affinity.AffinityGroup; +import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.ApiConstants.HostDetails; import org.apache.cloudstack.api.ApiConstants.VMDetails; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.ResponseGenerator; import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd; import org.apache.cloudstack.api.response.AccountResponse; +import org.apache.cloudstack.api.response.ApplicationLoadBalancerInstanceResponse; +import org.apache.cloudstack.api.response.ApplicationLoadBalancerResponse; +import org.apache.cloudstack.api.response.ApplicationLoadBalancerRuleResponse; import org.apache.cloudstack.api.response.AsyncJobResponse; import org.apache.cloudstack.api.response.AutoScalePolicyResponse; import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse; @@ -64,12 +69,15 @@ import org.apache.cloudstack.api.response.FirewallResponse; import org.apache.cloudstack.api.response.FirewallRuleResponse; import org.apache.cloudstack.api.response.GlobalLoadBalancerResponse; import org.apache.cloudstack.api.response.GuestOSResponse; -import org.apache.cloudstack.api.response.HostResponse; +import org.apache.cloudstack.api.response.GuestVlanRangeResponse; import org.apache.cloudstack.api.response.HostForMigrationResponse; +import org.apache.cloudstack.api.response.HostResponse; import org.apache.cloudstack.api.response.HypervisorCapabilitiesResponse; import org.apache.cloudstack.api.response.IPAddressResponse; import org.apache.cloudstack.api.response.InstanceGroupResponse; +import org.apache.cloudstack.api.response.InternalLoadBalancerElementResponse; import org.apache.cloudstack.api.response.IpForwardingRuleResponse; +import org.apache.cloudstack.api.response.IsolationMethodResponse; import org.apache.cloudstack.api.response.LBHealthCheckPolicyResponse; import org.apache.cloudstack.api.response.LBHealthCheckResponse; import org.apache.cloudstack.api.response.LBStickinessPolicyResponse; @@ -126,6 +134,7 @@ import org.apache.cloudstack.api.response.VpcOfferingResponse; import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.api.response.VpnUsersResponse; import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule; import org.apache.cloudstack.region.Region; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.usage.Usage; @@ -179,12 +188,15 @@ import com.cloud.event.Event; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.hypervisor.HypervisorCapabilities; +import com.cloud.network.GuestVlan; import com.cloud.network.IpAddress; import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; +import com.cloud.network.NetworkModel; import com.cloud.network.NetworkProfile; +import com.cloud.network.Networks.IsolationType; import com.cloud.network.Networks.TrafficType; import com.cloud.network.PhysicalNetwork; import com.cloud.network.PhysicalNetworkServiceProvider; @@ -210,6 +222,7 @@ import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.HealthCheckPolicy; import com.cloud.network.rules.LoadBalancer; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.StaticNatRule; import com.cloud.network.rules.StickinessPolicy; @@ -223,6 +236,7 @@ import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.VpcOffering; import com.cloud.offering.DiskOffering; import com.cloud.offering.NetworkOffering; +import com.cloud.offering.NetworkOffering.Detail; import com.cloud.offering.ServiceOffering; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.org.Cluster; @@ -263,47 +277,19 @@ import com.cloud.user.UserContext; import com.cloud.uservm.UserVm; import com.cloud.utils.Pair; import com.cloud.utils.StringUtils; +import com.cloud.utils.net.Ip; import com.cloud.utils.net.NetUtils; import com.cloud.vm.ConsoleProxyVO; import com.cloud.vm.InstanceGroup; import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; +import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.NicVO; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.snapshot.VMSnapshot; -import org.apache.cloudstack.acl.ControlledEntity; -import org.apache.cloudstack.acl.ControlledEntity.ACLType; -import org.apache.cloudstack.affinity.AffinityGroup; -import org.apache.cloudstack.affinity.AffinityGroupResponse; -import org.apache.cloudstack.api.ApiConstants.HostDetails; -import org.apache.cloudstack.api.ApiConstants.VMDetails; -import org.apache.cloudstack.api.BaseCmd; -import org.apache.cloudstack.api.ResponseGenerator; -import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd; -import org.apache.cloudstack.api.response.*; -import org.apache.cloudstack.region.Region; -import org.apache.cloudstack.usage.Usage; -import org.apache.cloudstack.usage.UsageService; -import org.apache.cloudstack.usage.UsageTypes; -import com.cloud.vm.VmStats; -import com.cloud.vm.dao.UserVmData; -import com.cloud.vm.dao.UserVmData.NicData; -import com.cloud.vm.dao.UserVmData.SecurityGroupData; -import com.cloud.vm.snapshot.VMSnapshot; -import org.apache.cloudstack.api.ResponseGenerator; -import org.apache.cloudstack.api.response.VMSnapshotResponse; -import org.apache.log4j.Logger; - -import java.text.DecimalFormat; -import java.util.*; - -import javax.inject.Inject; - -import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; @Component public class ApiResponseHelper implements ResponseGenerator { @@ -312,6 +298,7 @@ public class ApiResponseHelper implements ResponseGenerator { private static final DecimalFormat s_percentFormat = new DecimalFormat("##.##"); @Inject private EntityManager _entityMgr = null; @Inject private UsageService _usageSvc = null; + @Inject NetworkModel _ntwkModel; @Override public UserResponse createUserResponse(User user) { @@ -773,7 +760,7 @@ public class ApiResponseHelper implements ResponseGenerator { } //set tag information - List tags = ApiDBUtils.listByResourceTypeAndId(TaggedResourceType.UserVm, loadBalancer.getId()); + List tags = ApiDBUtils.listByResourceTypeAndId(TaggedResourceType.LoadBalancer, loadBalancer.getId()); List tagResponses = new ArrayList(); for (ResourceTag tag : tags) { ResourceTagResponse tagResponse = createResourceTagResponse(tag, true); @@ -2286,6 +2273,13 @@ public class ApiResponseHelper implements ResponseGenerator { response.setForVpc(ApiDBUtils.isOfferingForVpc(offering)); response.setServices(serviceResponses); + + //set network offering details + Map details = _ntwkModel.getNtwkOffDetails(offering.getId()); + if (details != null && !details.isEmpty()) { + response.setDetails(details); + } + response.setObjectName("networkoffering"); return response; } @@ -2733,6 +2727,25 @@ public class ApiResponseHelper implements ResponseGenerator { return response; } + @Override + public GuestVlanRangeResponse createDedicatedGuestVlanRangeResponse(GuestVlan vlan) { + GuestVlanRangeResponse guestVlanRangeResponse = new GuestVlanRangeResponse(); + + guestVlanRangeResponse.setId(vlan.getUuid()); + Long accountId= ApiDBUtils.getAccountIdForGuestVlan(vlan.getId()); + Account owner = ApiDBUtils.findAccountById(accountId); + if (owner != null) { + populateAccount(guestVlanRangeResponse, owner.getId()); + populateDomain(guestVlanRangeResponse, owner.getDomainId()); + } + guestVlanRangeResponse.setGuestVlanRange(vlan.getGuestVlanRange()); + guestVlanRangeResponse.setPhysicalNetworkId(vlan.getPhysicalNetworkId()); + PhysicalNetworkVO physicalNetwork = ApiDBUtils.findPhysicalNetworkById(vlan.getPhysicalNetworkId()); + guestVlanRangeResponse.setZoneId(physicalNetwork.getDataCenterId()); + + return guestVlanRangeResponse; + } + @Override public ServiceResponse createNetworkServiceResponse(Service service) { ServiceResponse response = new ServiceResponse(); @@ -2831,6 +2844,11 @@ public class ApiResponseHelper implements ResponseGenerator { @Override public VirtualRouterProviderResponse createVirtualRouterProviderResponse(VirtualRouterProvider result) { + //generate only response of the VR/VPCVR provider type + if (!(result.getType() == VirtualRouterProvider.VirtualRouterProviderType.VirtualRouter + || result.getType() == VirtualRouterProvider.VirtualRouterProviderType.VPCVirtualRouter)) { + return null; + } VirtualRouterProviderResponse response = new VirtualRouterProviderResponse(); response.setId(result.getUuid()); PhysicalNetworkServiceProvider nsp = ApiDBUtils.findPhysicalNetworkServiceProviderById(result.getNspId()); @@ -3128,6 +3146,7 @@ public class ApiResponseHelper implements ResponseGenerator { populateAccount(response, result.getAccountId()); populateDomain(response, result.getDomainId()); response.setState(result.getState().toString()); + response.setSourceNat(result.getSourceNat()); response.setObjectName("privategateway"); @@ -3647,11 +3666,12 @@ public class ApiResponseHelper implements ResponseGenerator { return response; } - public NicSecondaryIpResponse createSecondaryIPToNicResponse(String ipAddr, Long nicId, Long networkId) { + public NicSecondaryIpResponse createSecondaryIPToNicResponse(NicSecondaryIp result) { NicSecondaryIpResponse response = new NicSecondaryIpResponse(); - NicVO nic = _entityMgr.findById(NicVO.class, nicId); - NetworkVO network = _entityMgr.findById(NetworkVO.class, networkId); - response.setIpAddr(ipAddr); + NicVO nic = _entityMgr.findById(NicVO.class, result.getNicId()); + NetworkVO network = _entityMgr.findById(NetworkVO.class, result.getNetworkId()); + response.setId(result.getUuid()); + response.setIpAddr(result.getIp4Address()); response.setNicId(nic.getUuid()); response.setNwId(network.getUuid()); response.setObjectName("nicsecondaryip"); @@ -3660,7 +3680,10 @@ public class ApiResponseHelper implements ResponseGenerator { public NicResponse createNicResponse(Nic result) { NicResponse response = new NicResponse(); + NetworkVO network = _entityMgr.findById(NetworkVO.class, result.getNetworkId()); + response.setId(result.getUuid()); + response.setNetworkid(network.getUuid()); response.setIpaddress(result.getIp4Address()); if (result.getSecondaryIp()) { @@ -3677,25 +3700,85 @@ public class ApiResponseHelper implements ResponseGenerator { } } - response.setGateway(result.getGateway()); - response.setId(result.getUuid()); response.setGateway(result.getGateway()); response.setNetmask(result.getNetmask()); response.setMacAddress(result.getMacAddress()); - if (result.getBroadcastUri() != null) { - response.setBroadcastUri(result.getBroadcastUri().toString()); - } - if (result.getIsolationUri() != null) { - response.setIsolationUri(result.getIsolationUri().toString()); - } + if (result.getIp6Address() != null) { - response.setId(result.getIp6Address()); + response.setIp6Address(result.getIp6Address()); } response.setIsDefault(result.isDefaultNic()); return response; } + + @Override + public ApplicationLoadBalancerResponse createLoadBalancerContainerReponse(ApplicationLoadBalancerRule lb, Map lbInstances) { + + ApplicationLoadBalancerResponse lbResponse = new ApplicationLoadBalancerResponse(); + lbResponse.setId(lb.getUuid()); + lbResponse.setName(lb.getName()); + lbResponse.setDescription(lb.getDescription()); + lbResponse.setAlgorithm(lb.getAlgorithm()); + Network nw = ApiDBUtils.findNetworkById(lb.getNetworkId()); + lbResponse.setNetworkId(nw.getUuid()); + populateOwner(lbResponse, lb); + + if (lb.getScheme() == Scheme.Internal) { + lbResponse.setSourceIp(lb.getSourceIp().addr()); + //TODO - create the view for the load balancer rule to reflect the network uuid + Network network = ApiDBUtils.findNetworkById(lb.getNetworkId()); + lbResponse.setSourceIpNetworkId(network.getUuid()); + } else { + //for public, populate the ip information from the ip address + IpAddress publicIp = ApiDBUtils.findIpAddressById(lb.getSourceIpAddressId()); + lbResponse.setSourceIp(publicIp.getAddress().addr()); + Network ntwk = ApiDBUtils.findNetworkById(publicIp.getNetworkId()); + lbResponse.setSourceIpNetworkId(ntwk.getUuid()); + } + + //set load balancer rules information (only one rule per load balancer in this release) + List ruleResponses = new ArrayList(); + ApplicationLoadBalancerRuleResponse ruleResponse = new ApplicationLoadBalancerRuleResponse(); + ruleResponse.setInstancePort(lb.getDefaultPortStart()); + ruleResponse.setSourcePort(lb.getSourcePortStart()); + String stateToSet = lb.getState().toString(); + if (stateToSet.equals(FirewallRule.State.Revoke)) { + stateToSet = "Deleting"; + } + ruleResponse.setState(stateToSet); + ruleResponse.setObjectName("loadbalancerrule"); + ruleResponses.add(ruleResponse); + lbResponse.setLbRules(ruleResponses); + + //set Lb instances information + List instanceResponses = new ArrayList(); + for (Ip ip : lbInstances.keySet()) { + ApplicationLoadBalancerInstanceResponse instanceResponse = new ApplicationLoadBalancerInstanceResponse(); + instanceResponse.setIpAddress(ip.addr()); + UserVm vm = lbInstances.get(ip); + instanceResponse.setId(vm.getUuid()); + instanceResponse.setName(vm.getInstanceName()); + instanceResponse.setObjectName("loadbalancerinstance"); + instanceResponses.add(instanceResponse); + } + + lbResponse.setLbInstances(instanceResponses); + + //set tag information + List tags = ApiDBUtils.listByResourceTypeAndId(TaggedResourceType.LoadBalancer, lb.getId()); + List tagResponses = new ArrayList(); + for (ResourceTag tag : tags) { + ResourceTagResponse tagResponse = createResourceTagResponse(tag, true); + tagResponses.add(tagResponse); + } + lbResponse.setTags(tagResponses); + + lbResponse.setObjectName("loadbalancer"); + return lbResponse; + } + @Override public AffinityGroupResponse createAffinityGroupResponse(AffinityGroup group) { @@ -3725,4 +3808,31 @@ public class ApiResponseHelper implements ResponseGenerator { return ag.getId(); } } + + + @Override + public InternalLoadBalancerElementResponse createInternalLbElementResponse(VirtualRouterProvider result) { + if (result.getType() != VirtualRouterProvider.VirtualRouterProviderType.InternalLbVm) { + return null; + } + InternalLoadBalancerElementResponse response = new InternalLoadBalancerElementResponse(); + response.setId(result.getUuid()); + PhysicalNetworkServiceProvider nsp = ApiDBUtils.findPhysicalNetworkServiceProviderById(result.getNspId()); + if (nsp != null) { + response.setNspId(nsp.getUuid()); + } + response.setEnabled(result.isEnabled()); + + response.setObjectName("internalloadbalancerelement"); + return response; + } + + + @Override + public IsolationMethodResponse createIsolationMethodResponse(IsolationType method) { + IsolationMethodResponse response = new IsolationMethodResponse(); + response.setIsolationMethodName(method.toString()); + response.setObjectName("isolationmethod"); + return response; + } } diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java index dd5fd4d5657..497be50a766 100755 --- a/server/src/com/cloud/api/ApiServer.java +++ b/server/src/com/cloud/api/ApiServer.java @@ -48,7 +48,7 @@ import javax.annotation.PostConstruct; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import javax.inject.Inject; -import javax.servlet.http.HttpServletRequest; +import javax.naming.ConfigurationException; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @@ -65,6 +65,7 @@ import org.apache.cloudstack.api.command.admin.host.ListHostsCmd; import org.apache.cloudstack.api.command.admin.router.ListRoutersCmd; import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolsCmd; import org.apache.cloudstack.api.command.admin.user.ListUsersCmd; +import com.cloud.event.ActionEventUtils; import org.apache.cloudstack.api.command.user.account.ListAccountsCmd; import org.apache.cloudstack.api.command.user.account.ListProjectAccountsCmd; import org.apache.cloudstack.api.command.user.event.ListEventsCmd; @@ -122,7 +123,6 @@ import com.cloud.configuration.ConfigurationVO; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; -import com.cloud.event.ActionEventUtils; import com.cloud.exception.AccountLimitException; import com.cloud.exception.CloudAuthenticationException; import com.cloud.exception.InsufficientCapacityException; @@ -142,6 +142,7 @@ import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.StringUtils; import com.cloud.utils.component.ComponentContext; +import com.cloud.utils.component.ManagerBase; import com.cloud.utils.component.PluggableService; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.SearchCriteria; @@ -149,7 +150,7 @@ import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; @Component -public class ApiServer implements HttpRequestHandler, ApiServerService { +public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiServerService { private static final Logger s_logger = Logger.getLogger(ApiServer.class.getName()); private static final Logger s_accessLogger = Logger.getLogger("apiserver." + ApiServer.class.getName()); @@ -180,13 +181,19 @@ public class ApiServer implements HttpRequestHandler, ApiServerService { @PostConstruct void initComponent() { s_instance = this; - init(); } public static ApiServer getInstance() { return s_instance; } - + + @Override + public boolean configure(String name, Map params) + throws ConfigurationException { + init(); + return true; + } + public void init() { Integer apiPort = null; // api port, null by default SearchCriteria sc = _configDao.createSearchCriteria(); diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index 9704f294503..6c1406a970c 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -32,7 +32,9 @@ import org.apache.cloudstack.affinity.AffinityGroupVMMapVO; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; import com.cloud.storage.VolumeDetailVO; import com.cloud.storage.dao.VolumeDetailsDao; +import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd; import org.apache.cloudstack.api.command.admin.host.ListHostsCmd; +import org.apache.cloudstack.api.command.admin.internallb.ListInternalLBVMsCmd; import org.apache.cloudstack.api.command.admin.router.ListRoutersCmd; import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolsCmd; import org.apache.cloudstack.api.command.admin.user.ListUsersCmd; @@ -981,7 +983,21 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { @Override public ListResponse searchForRouters(ListRoutersCmd cmd) { - Pair, Integer> result = searchForRoutersInternal(cmd); + Pair, Integer> result = searchForRoutersInternal(cmd, cmd.getId(), cmd.getRouterName(), + cmd.getState(), cmd.getZoneId(), cmd.getPodId(), cmd.getHostId(), cmd.getKeyword(), cmd.getNetworkId(), + cmd.getVpcId(), cmd.getForVpc(), cmd.getRole(), cmd.getZoneType()); + ListResponse response = new ListResponse(); + + List routerResponses = ViewResponseHelper.createDomainRouterResponse(result.first().toArray(new DomainRouterJoinVO[result.first().size()])); + response.setResponses(routerResponses, result.second()); + return response; + } + + @Override + public ListResponse searchForInternalLbVms(ListInternalLBVMsCmd cmd) { + Pair, Integer> result = searchForRoutersInternal(cmd, cmd.getId(), cmd.getRouterName(), + cmd.getState(), cmd.getZoneId(), cmd.getPodId(), cmd.getHostId(), cmd.getKeyword(), cmd.getNetworkId(), + cmd.getVpcId(), cmd.getForVpc(), cmd.getRole(), cmd.getZoneType()); ListResponse response = new ListResponse(); List routerResponses = ViewResponseHelper.createDomainRouterResponse(result.first().toArray(new DomainRouterJoinVO[result.first().size()])); @@ -990,17 +1006,9 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { } - private Pair, Integer> searchForRoutersInternal(ListRoutersCmd cmd) { - Long id = cmd.getId(); - String name = cmd.getRouterName(); - String state = cmd.getState(); - Long zone = cmd.getZoneId(); - Long pod = cmd.getPodId(); - Long hostId = cmd.getHostId(); - String keyword = cmd.getKeyword(); - Long networkId = cmd.getNetworkId(); - Long vpcId = cmd.getVpcId(); - Boolean forVpc = cmd.getForVpc(); + private Pair, Integer> searchForRoutersInternal(BaseListProjectAndAccountResourcesCmd cmd, Long id, + String name, String state, Long zoneId, Long podId, Long hostId, String keyword, Long networkId, Long vpcId, Boolean forVpc, String role, String zoneType) { + Account caller = UserContext.current().getCaller(); List permittedAccounts = new ArrayList(); @@ -1027,9 +1035,11 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { sb.and("accountId", sb.entity().getAccountId(), SearchCriteria.Op.IN); sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ); sb.and("dataCenterId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ); + sb.and("dataCenterType", sb.entity().getDataCenterType(), SearchCriteria.Op.EQ); sb.and("podId", sb.entity().getPodId(), SearchCriteria.Op.EQ); sb.and("hostId", sb.entity().getHostId(), SearchCriteria.Op.EQ); sb.and("vpcId", sb.entity().getVpcId(), SearchCriteria.Op.EQ); + sb.and("role", sb.entity().getRole(), SearchCriteria.Op.EQ); if (forVpc != null) { if (forVpc) { @@ -1067,14 +1077,19 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { sc.setParameters("state", state); } - if (zone != null) { - sc.setParameters("dataCenterId", zone); + if (zoneId != null) { + sc.setParameters("dataCenterId", zoneId); } - if (pod != null) { - sc.setParameters("podId", pod); + if (podId != null) { + sc.setParameters("podId", podId); } + if (zoneType != null) { + sc.setParameters("dataCenterType", zoneType); + } + + if (hostId != null) { sc.setParameters("hostId", hostId); } @@ -1086,6 +1101,10 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { if (vpcId != null) { sc.setParameters("vpcId", vpcId); } + + if (role != null) { + sc.setParameters("role", role); + } // search VR details by ids Pair, Integer> uniqueVrPair = _routerJoinDao.searchAndCount(sc, searchFilter); @@ -1400,6 +1419,7 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { public Pair, Integer> searchForServersInternal(ListHostsCmd cmd) { Long zoneId = _accountMgr.checkAccessAndSpecifyAuthority(UserContext.current().getCaller(), cmd.getZoneId()); + String zoneType = cmd.getZoneType(); Object name = cmd.getHostName(); Object type = cmd.getType(); Object state = cmd.getState(); @@ -1421,6 +1441,7 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { sb.and("type", sb.entity().getType(), SearchCriteria.Op.LIKE); sb.and("status", sb.entity().getStatus(), SearchCriteria.Op.EQ); sb.and("dataCenterId", sb.entity().getZoneId(), SearchCriteria.Op.EQ); + sb.and("dataCenterType", sb.entity().getZoneType(), SearchCriteria.Op.EQ); sb.and("podId", sb.entity().getPodId(), SearchCriteria.Op.EQ); sb.and("clusterId", sb.entity().getClusterId(), SearchCriteria.Op.EQ); sb.and("resourceState", sb.entity().getResourceState(), SearchCriteria.Op.EQ); @@ -1465,6 +1486,9 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { if (zoneId != null) { sc.setParameters("dataCenterId", zoneId); } + if (zoneType != null) { + sc.setParameters("dataCenterType", zoneType); + } if (pod != null) { sc.setParameters("podId", pod); } @@ -2266,10 +2290,14 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { Long id = cmd.getId(); String keyword = cmd.getKeyword(); String name = cmd.getName(); + String networkType = cmd.getZoneType(); Filter searchFilter = new Filter(DataCenterJoinVO.class, null, false, cmd.getStartIndex(), cmd.getPageSizeVal()); SearchCriteria sc = _dcJoinDao.createSearchCriteria(); + if(networkType != null) + sc.addAnd("networkType", SearchCriteria.Op.EQ, networkType); + if (id != null) { sc.addAnd("id", SearchCriteria.Op.EQ, id); } else if (name != null) { diff --git a/server/src/com/cloud/api/query/dao/AccountJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/AccountJoinDaoImpl.java index 796ae54d52f..528bdacffda 100644 --- a/server/src/com/cloud/api/query/dao/AccountJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/AccountJoinDaoImpl.java @@ -203,8 +203,10 @@ public class AccountJoinDaoImpl extends GenericDaoBase impl accountResponse.setObjectName("account"); // set async job - accountResponse.setJobId(account.getJobUuid()); - accountResponse.setJobStatus(account.getJobStatus()); + if (account.getJobId() != null) { + accountResponse.setJobId(account.getJobUuid()); + accountResponse.setJobStatus(account.getJobStatus()); + } return accountResponse; } diff --git a/server/src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java index 25cd62faf7b..a7a83de14a1 100644 --- a/server/src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java @@ -32,6 +32,7 @@ import com.cloud.api.query.vo.DomainRouterJoinVO; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.network.Networks.TrafficType; import com.cloud.network.router.VirtualRouter; +import com.cloud.network.router.VirtualRouter.Role; import com.cloud.user.Account; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; @@ -156,12 +157,20 @@ public class DomainRouterJoinDaoImpl extends GenericDaoBase implements hostResponse.setResourceState(host.getResourceState().toString()); // set async job - hostResponse.setJobId(host.getJobUuid()); - hostResponse.setJobStatus(host.getJobStatus()); + if (host.getJobId() != null) { + hostResponse.setJobId(host.getJobUuid()); + hostResponse.setJobStatus(host.getJobStatus()); + } hostResponse.setObjectName("host"); diff --git a/server/src/com/cloud/api/query/dao/SecurityGroupJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/SecurityGroupJoinDaoImpl.java index 3e579c179e2..2a6afca231e 100644 --- a/server/src/com/cloud/api/query/dao/SecurityGroupJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/SecurityGroupJoinDaoImpl.java @@ -117,8 +117,10 @@ public class SecurityGroupJoinDaoImpl extends GenericDaoBase implem } } userVmResponse.setPassword(userVm.getPassword()); - userVmResponse.setJobId(userVm.getJobUuid()); - userVmResponse.setJobStatus(userVm.getJobStatus()); + if (userVm.getJobId() != null) { + userVmResponse.setJobId(userVm.getJobUuid()); + userVmResponse.setJobStatus(userVm.getJobStatus()); + } //userVmResponse.setForVirtualNetwork(userVm.getForVirtualNetwork()); userVmResponse.setPublicIpId(userVm.getPublicIpUuid()); diff --git a/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java index 018745deda1..e27e2d93bef 100644 --- a/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java @@ -198,8 +198,10 @@ public class VolumeJoinDaoImpl extends GenericDaoBase implem volResponse.setDisplayVm(volume.isDisplayVolume()); // set async job - volResponse.setJobId(volume.getJobUuid()); - volResponse.setJobStatus(volume.getJobStatus()); + if (volume.getJobId() != null) { + volResponse.setJobId(volume.getJobUuid()); + volResponse.setJobStatus(volume.getJobStatus()); + } volResponse.setObjectName("volume"); return volResponse; diff --git a/server/src/com/cloud/api/query/vo/AccountJoinVO.java b/server/src/com/cloud/api/query/vo/AccountJoinVO.java index 800da7803fd..fbcc9342b22 100644 --- a/server/src/com/cloud/api/query/vo/AccountJoinVO.java +++ b/server/src/com/cloud/api/query/vo/AccountJoinVO.java @@ -177,7 +177,7 @@ public class AccountJoinVO extends BaseViewVO implements InternalIdentity, Ident private Long secondaryStorageTotal; @Column(name="job_id") - private long jobId; + private Long jobId; @Column(name="job_uuid") private String jobUuid; @@ -645,12 +645,12 @@ public class AccountJoinVO extends BaseViewVO implements InternalIdentity, Ident } - public long getJobId() { + public Long getJobId() { return jobId; } - public void setJobId(long jobId) { + public void setJobId(Long jobId) { this.jobId = jobId; } diff --git a/server/src/com/cloud/api/query/vo/DomainRouterJoinVO.java b/server/src/com/cloud/api/query/vo/DomainRouterJoinVO.java index 5f2b500fa57..9e9e4a2ba7b 100644 --- a/server/src/com/cloud/api/query/vo/DomainRouterJoinVO.java +++ b/server/src/com/cloud/api/query/vo/DomainRouterJoinVO.java @@ -28,6 +28,7 @@ import javax.persistence.Table; import com.cloud.network.Network.GuestType; import com.cloud.network.Networks.TrafficType; +import com.cloud.network.router.VirtualRouter; import com.cloud.network.router.VirtualRouter.RedundantState; import com.cloud.utils.db.GenericDao; import com.cloud.vm.VirtualMachine.State; @@ -210,7 +211,7 @@ public class DomainRouterJoinVO extends BaseViewVO implements ControlledViewEnti private String projectName; @Column(name="job_id") - private long jobId; + private Long jobId; @Column(name="job_uuid") private String jobUuid; @@ -238,14 +239,16 @@ public class DomainRouterJoinVO extends BaseViewVO implements ControlledViewEnti @Column(name="guest_type") @Enumerated(value=EnumType.STRING) private GuestType guestType; + + @Column(name="role") + @Enumerated(value=EnumType.STRING) + private VirtualRouter.Role role; public DomainRouterJoinVO() { } - - @Override public long getId() { return id; @@ -781,14 +784,14 @@ public class DomainRouterJoinVO extends BaseViewVO implements ControlledViewEnti } - public long getJobId() { + public Long getJobId() { return jobId; } - public void setJobId(long jobId) { + public void setJobId(Long jobId) { this.jobId = jobId; } @@ -1003,4 +1006,14 @@ public class DomainRouterJoinVO extends BaseViewVO implements ControlledViewEnti public void setIp6Dns2(String ip6Dns2) { this.ip6Dns2 = ip6Dns2; } + + + public VirtualRouter.Role getRole() { + return role; + } + + + public void setRole(VirtualRouter.Role role) { + this.role = role; + } } diff --git a/server/src/com/cloud/api/query/vo/HostJoinVO.java b/server/src/com/cloud/api/query/vo/HostJoinVO.java index 4aa45e5f593..4b70cfcaa10 100644 --- a/server/src/com/cloud/api/query/vo/HostJoinVO.java +++ b/server/src/com/cloud/api/query/vo/HostJoinVO.java @@ -168,7 +168,7 @@ public class HostJoinVO extends BaseViewVO implements InternalIdentity, Identity private long cpuReservedCapacity; @Column(name="job_id") - private long jobId; + private Long jobId; @Column(name="job_uuid") private String jobUuid; @@ -427,11 +427,11 @@ public class HostJoinVO extends BaseViewVO implements InternalIdentity, Identity this.osCategoryName = osCategoryName; } - public long getJobId() { + public Long getJobId() { return jobId; } - public void setJobId(long jobId) { + public void setJobId(Long jobId) { this.jobId = jobId; } diff --git a/server/src/com/cloud/api/query/vo/SecurityGroupJoinVO.java b/server/src/com/cloud/api/query/vo/SecurityGroupJoinVO.java index 922e130ed30..258b6136224 100644 --- a/server/src/com/cloud/api/query/vo/SecurityGroupJoinVO.java +++ b/server/src/com/cloud/api/query/vo/SecurityGroupJoinVO.java @@ -77,7 +77,7 @@ public class SecurityGroupJoinVO extends BaseViewVO implements ControlledViewEnt private String projectName; @Column(name="job_id") - private long jobId; + private Long jobId; @Column(name="job_uuid") private String jobUuid; @@ -269,11 +269,11 @@ public class SecurityGroupJoinVO extends BaseViewVO implements ControlledViewEnt this.projectName = projectName; } - public long getJobId() { + public Long getJobId() { return jobId; } - public void setJobId(long jobId) { + public void setJobId(Long jobId) { this.jobId = jobId; } diff --git a/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java b/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java index da06227ea66..d86726c3523 100644 --- a/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java +++ b/server/src/com/cloud/api/query/vo/StoragePoolJoinVO.java @@ -121,7 +121,7 @@ public class StoragePoolJoinVO extends BaseViewVO implements InternalIdentity, I @Column(name="job_id") - private long jobId; + private Long jobId; @Column(name="job_uuid") private String jobUuid; @@ -342,11 +342,11 @@ public class StoragePoolJoinVO extends BaseViewVO implements InternalIdentity, I this.reservedCapacity = reservedCapacity; } - public long getJobId() { + public Long getJobId() { return jobId; } - public void setJobId(long jobId) { + public void setJobId(Long jobId) { this.jobId = jobId; } diff --git a/server/src/com/cloud/api/query/vo/UserAccountJoinVO.java b/server/src/com/cloud/api/query/vo/UserAccountJoinVO.java index d85392fb85a..c44027b8bc0 100644 --- a/server/src/com/cloud/api/query/vo/UserAccountJoinVO.java +++ b/server/src/com/cloud/api/query/vo/UserAccountJoinVO.java @@ -109,7 +109,7 @@ public class UserAccountJoinVO extends BaseViewVO implements InternalIdentity, I private String domainPath = null; @Column(name="job_id") - private long jobId; + private Long jobId; @Column(name="job_uuid") private String jobUuid; @@ -324,11 +324,11 @@ public class UserAccountJoinVO extends BaseViewVO implements InternalIdentity, I this.loginAttempts = loginAttempts; } - public long getJobId() { + public Long getJobId() { return jobId; } - public void setJobId(long jobId) { + public void setJobId(Long jobId) { this.jobId = jobId; } diff --git a/server/src/com/cloud/api/query/vo/UserVmJoinVO.java b/server/src/com/cloud/api/query/vo/UserVmJoinVO.java index 7fdb93ea976..8ad0fdd6457 100644 --- a/server/src/com/cloud/api/query/vo/UserVmJoinVO.java +++ b/server/src/com/cloud/api/query/vo/UserVmJoinVO.java @@ -335,7 +335,7 @@ public class UserVmJoinVO extends BaseViewVO implements ControlledViewEntity { private String keypairName; @Column(name="job_id") - private long jobId; + private Long jobId; @Column(name="job_uuid") private String jobUuid; @@ -1618,14 +1618,14 @@ public class UserVmJoinVO extends BaseViewVO implements ControlledViewEntity { - public long getJobId() { + public Long getJobId() { return jobId; } - public void setJobId(long jobId) { + public void setJobId(Long jobId) { this.jobId = jobId; } diff --git a/server/src/com/cloud/api/query/vo/VolumeJoinVO.java b/server/src/com/cloud/api/query/vo/VolumeJoinVO.java index e5e50b04a63..6ef8c912efe 100644 --- a/server/src/com/cloud/api/query/vo/VolumeJoinVO.java +++ b/server/src/com/cloud/api/query/vo/VolumeJoinVO.java @@ -206,7 +206,7 @@ public class VolumeJoinVO extends BaseViewVO implements ControlledViewEntity { private Storage.TemplateType templateType; @Column(name="job_id") - private long jobId; + private Long jobId; @Column(name="job_uuid") private String jobUuid; @@ -827,13 +827,13 @@ public class VolumeJoinVO extends BaseViewVO implements ControlledViewEntity { - public long getJobId() { + public Long getJobId() { return jobId; } - public void setJobId(long jobId) { + public void setJobId(Long jobId) { this.jobId = jobId; } diff --git a/core/src/com/cloud/async/AsyncJobVO.java b/server/src/com/cloud/async/AsyncJobVO.java similarity index 99% rename from core/src/com/cloud/async/AsyncJobVO.java rename to server/src/com/cloud/async/AsyncJobVO.java index ad482b03a9d..c40fc987a4a 100644 --- a/core/src/com/cloud/async/AsyncJobVO.java +++ b/server/src/com/cloud/async/AsyncJobVO.java @@ -133,6 +133,7 @@ public class AsyncJobVO implements AsyncJob { this.callbackType = CALLBACK_POLLING; this.uuid = UUID.randomUUID().toString(); this.instanceId = instanceId; + this.instanceType = instanceType; } public AsyncJobVO(long userId, long accountId, String cmd, String cmdInfo, diff --git a/core/src/com/cloud/async/SyncQueueItemVO.java b/server/src/com/cloud/async/SyncQueueItemVO.java similarity index 100% rename from core/src/com/cloud/async/SyncQueueItemVO.java rename to server/src/com/cloud/async/SyncQueueItemVO.java diff --git a/core/src/com/cloud/async/SyncQueueVO.java b/server/src/com/cloud/async/SyncQueueVO.java similarity index 100% rename from core/src/com/cloud/async/SyncQueueVO.java rename to server/src/com/cloud/async/SyncQueueVO.java diff --git a/server/src/com/cloud/capacity/CapacityManagerImpl.java b/server/src/com/cloud/capacity/CapacityManagerImpl.java index 292ef0abd5c..1eb2fa5894a 100755 --- a/server/src/com/cloud/capacity/CapacityManagerImpl.java +++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java @@ -28,12 +28,6 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; -import com.cloud.dc.ClusterDetailsDao; -import com.cloud.dc.DataCenter; -import com.cloud.dc.dao.ClusterDao; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.InsufficientServerCapacityException; -import com.cloud.resource.ResourceState; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -50,7 +44,10 @@ import com.cloud.capacity.dao.CapacityDao; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.dao.ClusterDao; import com.cloud.exception.ConnectionException; +import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; @@ -104,9 +101,9 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, HostDao _hostDao; @Inject VMInstanceDao _vmDao; - @Inject + @Inject VolumeDao _volumeDao; - @Inject + @Inject VMTemplatePoolDao _templatePoolDao; @Inject AgentManager _agentManager; @@ -115,16 +112,16 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, @Inject StorageManager _storageMgr; @Inject - SwiftManager _swiftMgr; + SwiftManager _swiftMgr; @Inject - ConfigurationManager _configMgr; + ConfigurationManager _configMgr; @Inject HypervisorCapabilitiesDao _hypervisorCapabilitiesDao; @Inject protected VMSnapshotDao _vmSnapshotDao; @Inject protected UserVmDao _userVMDao; - + @Inject ClusterDetailsDao _clusterDetailsDao; @Inject @@ -142,7 +139,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("HostCapacity-Checker")); VirtualMachine.State.getStateMachine().registerListener(this); - _agentManager.registerForHostEvents(new StorageCapacityListener(_capacityDao, _storageOverProvisioningFactor), true, false, false); + _agentManager.registerForHostEvents(new StorageCapacityListener(_capacityDao, _storageMgr), true, false, false); _agentManager.registerForHostEvents(new ComputeCapacityListener(_capacityDao, this), true, false, false); return true; @@ -191,8 +188,8 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, long actualTotalCpu = capacityCpu.getTotalCapacity(); float cpuOvercommitRatio =Float.parseFloat(_clusterDetailsDao.findDetail(clusterId,"cpuOvercommitRatio").getValue()); float memoryOvercommitRatio = Float.parseFloat(_clusterDetailsDao.findDetail(clusterId,"memoryOvercommitRatio").getValue()); - int vmCPU = (int) (svo.getCpu() * svo.getSpeed()); - long vmMem = (long) (svo.getRamSize() * 1024L * 1024L); + int vmCPU = svo.getCpu() * svo.getSpeed(); + long vmMem = svo.getRamSize() * 1024L * 1024L; long actualTotalMem = capacityMemory.getTotalCapacity(); long totalMem = (long) (actualTotalMem * memoryOvercommitRatio); long totalCpu = (long) (actualTotalCpu * cpuOvercommitRatio); @@ -266,8 +263,8 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, return; } - int cpu = (int) (svo.getCpu() * svo.getSpeed()); - long ram = (long) (svo.getRamSize() * 1024L * 1024L); + int cpu = svo.getCpu() * svo.getSpeed(); + long ram = svo.getRamSize() * 1024L * 1024L; Transaction txn = Transaction.currentTxn(); @@ -398,10 +395,10 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, failureReason = "Host does not have enough reserved CPU available"; } } else { - + long reservedCpuValueToUse = reservedCpu; long reservedMemValueToUse = reservedMem; - + if(!considerReservedCapacity){ if (s_logger.isDebugEnabled()) { s_logger.debug("considerReservedCapacity is" + considerReservedCapacity + " , not considering reserved capacity for calculating free capacity"); @@ -458,7 +455,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, return hasCapacity; } - + private long getVMSnapshotAllocatedCapacity(StoragePoolVO pool){ List volumes = _volumeDao.findByPoolId(pool.getId()); long totalSize = 0; @@ -486,39 +483,39 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, } return totalSize; } - + @Override public long getAllocatedPoolCapacity(StoragePoolVO pool, VMTemplateVO templateForVmCreation){ - + // Get size for all the volumes Pair sizes = _volumeDao.getCountAndTotalByPool(pool.getId()); long totalAllocatedSize = sizes.second() + sizes.first() * _extraBytesPerVolume; - - // Get size for VM Snapshots + + // Get size for VM Snapshots totalAllocatedSize = totalAllocatedSize + getVMSnapshotAllocatedCapacity(pool); // Iterate through all templates on this storage pool boolean tmpinstalled = false; List templatePoolVOs; templatePoolVOs = _templatePoolDao.listByPoolId(pool.getId()); - - for (VMTemplateStoragePoolVO templatePoolVO : templatePoolVOs) { + + for (VMTemplateStoragePoolVO templatePoolVO : templatePoolVOs) { if ((templateForVmCreation != null) && !tmpinstalled && (templatePoolVO.getTemplateId() == templateForVmCreation.getId())) { tmpinstalled = true; } long templateSize = templatePoolVO.getTemplateSize(); totalAllocatedSize += templateSize + _extraBytesPerVolume; } - + // Add the size for the templateForVmCreation if its not already present /*if ((templateForVmCreation != null) && !tmpinstalled) { - + }*/ - + return totalAllocatedSize; } - - + + @DB @Override public void updateCapacityForHost(HostVO host){ @@ -528,7 +525,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, for (ServiceOfferingVO offering : offerings) { offeringsMap.put(offering.getId(), offering); } - + long usedCpu = 0; long usedMemory = 0; long reservedMemory = 0; @@ -574,7 +571,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, + usedCpu); cpuCap.setUsedCapacity(usedCpu); } - + if (memCap.getUsedCapacity() == usedMemory && memCap.getReservedCapacity() == reservedMemory) { s_logger.debug("No need to calibrate memory capacity, host:" + host.getId() + " usedMem: " + memCap.getUsedCapacity() + " reservedMem: " + memCap.getReservedCapacity()); @@ -591,7 +588,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, + " new usedMem: " + usedMemory); memCap.setUsedCapacity(usedMemory); } - + try { _capacityDao.update(cpuCap.getId(), cpuCap); _capacityDao.update(memCap.getId(), memCap); @@ -610,24 +607,24 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, capacity.setReservedCapacity(reservedMemory); capacity.setCapacityState(capacityState); _capacityDao.persist(capacity); - + capacity = new CapacityVO( host.getId(), host.getDataCenterId(), - host.getPodId(), + host.getPodId(), host.getClusterId(), usedCpu, - (long)(host.getCpus().longValue() * host.getSpeed().longValue()), + host.getCpus().longValue() * host.getSpeed().longValue(), CapacityVO.CAPACITY_TYPE_CPU); capacity.setReservedCapacity(reservedCpu); capacity.setCapacityState(capacityState); _capacityDao.persist(capacity); txn.commit(); - + } - + } - + @Override public boolean preStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vm, boolean transitionStatus, Object opaque) { return true; @@ -681,7 +678,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, releaseVmCapacity(vm, false, false, oldHostId); } } - + if ((newState == State.Starting || newState == State.Migrating || event == Event.AgentReportMigrated) && vm.getHostId() != null) { boolean fromLastHost = false; if (vm.getLastHostId() == vm.getHostId()) { @@ -729,7 +726,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, _capacityDao.update(CapacityVOCpu.getId(), CapacityVOCpu); } else { CapacityVO capacity = new CapacityVO(server.getId(), server.getDataCenterId(), server.getPodId(), server.getClusterId(), 0L, - (long) (server.getCpus().longValue() * server.getSpeed().longValue()), + server.getCpus().longValue() * server.getSpeed().longValue(), CapacityVO.CAPACITY_TYPE_CPU); _capacityDao.persist(capacity); } @@ -815,32 +812,32 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, @Override public void processCancelMaintenaceEventAfter(Long hostId) { - updateCapacityForHost(_hostDao.findById(hostId)); + updateCapacityForHost(_hostDao.findById(hostId)); } @Override public void processCancelMaintenaceEventBefore(Long hostId) { // TODO Auto-generated method stub - + } @Override - public void processDeletHostEventAfter(HostVO host) { + public void processDeletHostEventAfter(Host host) { // TODO Auto-generated method stub - + } @Override - public void processDeleteHostEventBefore(HostVO host) { + public void processDeleteHostEventBefore(Host host) { // TODO Auto-generated method stub - + } @Override public void processDiscoverEventAfter( Map> resources) { // TODO Auto-generated method stub - + } @Override @@ -848,11 +845,11 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, Long clusterId, URI uri, String username, String password, List hostTags) { // TODO Auto-generated method stub - + } @Override - public void processPrepareMaintenaceEventAfter(Long hostId) { + public void processPrepareMaintenaceEventAfter(Long hostId) { _capacityDao.removeBy(Capacity.CAPACITY_TYPE_MEMORY, null, null, null, hostId); _capacityDao.removeBy(Capacity.CAPACITY_TYPE_CPU, null, null, null, hostId); } @@ -860,7 +857,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, @Override public void processPrepareMaintenaceEventBefore(Long hostId) { // TODO Auto-generated method stub - + } @Override @@ -871,7 +868,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, Long maxGuestLimit = _hypervisorCapabilitiesDao.getMaxGuestsLimit(hypervisorType, hypervisorVersion); if(vmCount.longValue() >= maxGuestLimit.longValue()){ if (s_logger.isDebugEnabled()) { - s_logger.debug("Host name: " + host.getName() + ", hostId: "+ host.getId() + + s_logger.debug("Host name: " + host.getName() + ", hostId: "+ host.getId() + " already reached max Running VMs(count includes system VMs), limit is: " + maxGuestLimit + ",Running VM counts is: "+vmCount.longValue()); } return true; diff --git a/server/src/com/cloud/capacity/StorageCapacityListener.java b/server/src/com/cloud/capacity/StorageCapacityListener.java index d5751a34cc9..bc03f725e78 100755 --- a/server/src/com/cloud/capacity/StorageCapacityListener.java +++ b/server/src/com/cloud/capacity/StorageCapacityListener.java @@ -16,8 +16,10 @@ // under the License. package com.cloud.capacity; +import java.math.BigDecimal; import java.util.List; +import com.cloud.storage.StorageManager; import org.apache.log4j.Logger; import com.cloud.agent.Listener; @@ -39,14 +41,11 @@ import com.cloud.utils.db.SearchCriteria; public class StorageCapacityListener implements Listener { CapacityDao _capacityDao; - float _overProvisioningFactor = 1.0f; + StorageManager _storageMgr; - - public StorageCapacityListener(CapacityDao _capacityDao, - float _overProvisioningFactor) { - super(); - this._capacityDao = _capacityDao; - this._overProvisioningFactor = _overProvisioningFactor; + public StorageCapacityListener(CapacityDao capacityDao, StorageManager storageMgr) { + this._capacityDao = capacityDao; + this._storageMgr = storageMgr; } @@ -79,9 +78,10 @@ public class StorageCapacityListener implements Listener { StartupStorageCommand ssCmd = (StartupStorageCommand) startup; if (ssCmd.getResourceType() == Storage.StorageResourceType.STORAGE_HOST) { + BigDecimal overProvFactor = _storageMgr.getStorageOverProvisioningFactor(server.getDataCenterId()); CapacityVO capacity = new CapacityVO(server.getId(), server.getDataCenterId(), server.getPodId(), server.getClusterId(), 0L, - (long) (server.getTotalSize() * _overProvisioningFactor), + (overProvFactor.multiply(new BigDecimal(server.getTotalSize()))).longValue(), CapacityVO.CAPACITY_TYPE_STORAGE_ALLOCATED); _capacityDao.persist(capacity); } diff --git a/server/src/com/cloud/cluster/CheckPointVO.java b/server/src/com/cloud/cluster/CheckPointVO.java deleted file mode 100644 index db4f828721a..00000000000 --- a/server/src/com/cloud/cluster/CheckPointVO.java +++ /dev/null @@ -1,121 +0,0 @@ -// 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. -package com.cloud.cluster; - -import java.util.Date; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Table; - -import com.cloud.utils.db.GenericDao; -import org.apache.cloudstack.api.InternalIdentity; - -@Entity -@Table(name="stack_maid") -public class CheckPointVO implements InternalIdentity { - - @Id - @GeneratedValue(strategy=GenerationType.IDENTITY) - @Column(name="id") - private long id; - - @Column(name="msid") - private long msid; - - @Column(name="thread_id") - private long threadId; - - @Column(name="seq") - private long seq; - - @Column(name="cleanup_delegate", length=128) - private String delegate; - - @Column(name="cleanup_context", length=65535) - private String context; - - @Column(name=GenericDao.CREATED_COLUMN) - private Date created; - - public CheckPointVO() { - } - - public CheckPointVO(long seq) { - this.seq = seq; - } - - public long getId() { - return id; - } - - public long getMsid() { - return msid; - } - - public void setMsid(long msid) { - this.msid = msid; - } - - public long getThreadId() { - return threadId; - } - - public void setThreadId(long threadId) { - this.threadId = threadId; - } - - public long getSeq() { - return seq; - } - - public void setSeq(long seq) { - this.seq = seq; - } - - public String getDelegate() { - return delegate; - } - - public void setDelegate(String delegate) { - this.delegate = delegate; - } - - public String getContext() { - return context; - } - - public void setContext(String context) { - this.context = context; - } - - public Date getCreated() { - return this.created; - } - - public void setCreated(Date created) { - this.created = created; - } - - @Override - public String toString() { - return new StringBuilder("Task[").append(id).append("-").append(context).append("-").append(delegate).append("]").toString(); - } -} diff --git a/server/src/com/cloud/cluster/dao/StackMaidDao.java b/server/src/com/cloud/cluster/dao/StackMaidDao.java deleted file mode 100644 index eb13b5cb2c2..00000000000 --- a/server/src/com/cloud/cluster/dao/StackMaidDao.java +++ /dev/null @@ -1,44 +0,0 @@ -// 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. -package com.cloud.cluster.dao; - -import java.util.Date; -import java.util.List; - -import com.cloud.cluster.CheckPointVO; -import com.cloud.utils.db.GenericDao; - -public interface StackMaidDao extends GenericDao { - public long pushCleanupDelegate(long msid, int seq, String delegateClzName, Object context); - public CheckPointVO popCleanupDelegate(long msid); - public void clearStack(long msid); - - public List listLeftoversByMsid(long msid); - public List listLeftoversByCutTime(Date cutTime); - - /** - * Take over the task items of another management server and clean them up. - * - * @param takeOverMsid management server id to take over. - * @param selfId the management server id of this node. - * @return list of tasks to take over. - */ - boolean takeover(long takeOverMsid, long selfId); - - List listCleanupTasks(long selfId); - List listLeftoversByCutTime(Date cutTime, long msid); -} diff --git a/server/src/com/cloud/cluster/dao/StackMaidDaoImpl.java b/server/src/com/cloud/cluster/dao/StackMaidDaoImpl.java deleted file mode 100644 index 243b00ff4a3..00000000000 --- a/server/src/com/cloud/cluster/dao/StackMaidDaoImpl.java +++ /dev/null @@ -1,208 +0,0 @@ -// 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. -package com.cloud.cluster.dao; - -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.TimeZone; - -import javax.ejb.Local; - -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import com.cloud.cluster.CheckPointVO; -import com.cloud.serializer.SerializerHelper; -import com.cloud.utils.DateUtil; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.Filter; -import com.cloud.utils.db.GenericDaoBase; -import com.cloud.utils.db.SearchBuilder; -import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.SearchCriteria.Op; -import com.cloud.utils.db.Transaction; - -@Component -@Local(value = { StackMaidDao.class }) @DB(txn=false) -public class StackMaidDaoImpl extends GenericDaoBase implements StackMaidDao { - private static final Logger s_logger = Logger.getLogger(StackMaidDaoImpl.class); - - private SearchBuilder popSearch; - private SearchBuilder clearSearch; - private final SearchBuilder AllFieldsSearch; - - public StackMaidDaoImpl() { - popSearch = createSearchBuilder(); - popSearch.and("msid", popSearch.entity().getMsid(), SearchCriteria.Op.EQ); - popSearch.and("threadId", popSearch.entity().getThreadId(), SearchCriteria.Op.EQ); - - clearSearch = createSearchBuilder(); - clearSearch.and("msid", clearSearch.entity().getMsid(), SearchCriteria.Op.EQ); - - AllFieldsSearch = createSearchBuilder(); - AllFieldsSearch.and("msid", AllFieldsSearch.entity().getMsid(), Op.EQ); - AllFieldsSearch.and("thread", AllFieldsSearch.entity().getThreadId(), Op.EQ); - AllFieldsSearch.done(); - } - - @Override - public boolean takeover(long takeOverMsid, long selfId) { - CheckPointVO task = createForUpdate(); - task.setMsid(selfId); - task.setThreadId(0); - - SearchCriteria sc = AllFieldsSearch.create(); - sc.setParameters("msid", takeOverMsid); - return update(task, sc) > 0; - - } - - @Override - public List listCleanupTasks(long msId) { - SearchCriteria sc = AllFieldsSearch.create(); - sc.setParameters("msid", msId); - sc.setParameters("thread", 0); - - return this.search(sc, null); - } - - @Override - public long pushCleanupDelegate(long msid, int seq, String delegateClzName, Object context) { - CheckPointVO delegateItem = new CheckPointVO(); - delegateItem.setMsid(msid); - delegateItem.setThreadId(Thread.currentThread().getId()); - delegateItem.setSeq(seq); - delegateItem.setDelegate(delegateClzName); - delegateItem.setContext(SerializerHelper.toSerializedStringOld(context)); - delegateItem.setCreated(DateUtil.currentGMTTime()); - - super.persist(delegateItem); - return delegateItem.getId(); - } - - @Override - public CheckPointVO popCleanupDelegate(long msid) { - SearchCriteria sc = popSearch.create(); - sc.setParameters("msid", msid); - sc.setParameters("threadId", Thread.currentThread().getId()); - - Filter filter = new Filter(CheckPointVO.class, "seq", false, 0L, (long)1); - List l = listIncludingRemovedBy(sc, filter); - if(l != null && l.size() > 0) { - expunge(l.get(0).getId()); - return l.get(0); - } - - return null; - } - - @Override - public void clearStack(long msid) { - SearchCriteria sc = clearSearch.create(); - sc.setParameters("msid", msid); - - expunge(sc); - } - - @Override - @DB - public List listLeftoversByMsid(long msid) { - List l = new ArrayList(); - String sql = "select * from stack_maid where msid=? order by msid asc, thread_id asc, seq desc"; - - Transaction txn = Transaction.currentTxn(); - PreparedStatement pstmt = null; - try { - pstmt = txn.prepareAutoCloseStatement(sql); - pstmt.setLong(1, msid); - - ResultSet rs = pstmt.executeQuery(); - while(rs.next()) { - l.add(toEntityBean(rs, false)); - } - } catch (SQLException e) { - s_logger.error("unexcpected exception " + e.getMessage(), e); - } catch (Throwable e) { - s_logger.error("unexcpected exception " + e.getMessage(), e); - } finally { - txn.close(); - } - return l; - } - - @Override - @DB - public List listLeftoversByCutTime(Date cutTime) { - - List l = new ArrayList(); - String sql = "select * from stack_maid where created < ? order by msid asc, thread_id asc, seq desc"; - - Transaction txn = Transaction.open(Transaction.CLOUD_DB); - PreparedStatement pstmt = null; - try { - pstmt = txn.prepareAutoCloseStatement(sql); - String gmtCutTime = DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutTime); - pstmt.setString(1, gmtCutTime); - - ResultSet rs = pstmt.executeQuery(); - while(rs.next()) { - l.add(toEntityBean(rs, false)); - } - } catch (SQLException e) { - s_logger.error("unexcpected exception " + e.getMessage(), e); - } catch (Throwable e) { - s_logger.error("unexcpected exception " + e.getMessage(), e); - } finally { - txn.close(); - } - return l; - } - - @Override - @DB - public List listLeftoversByCutTime(Date cutTime, long msid) { - - List l = new ArrayList(); - String sql = "select * from stack_maid where created < ? and msid = ? order by msid asc, thread_id asc, seq desc"; - - Transaction txn = Transaction.open(Transaction.CLOUD_DB); - PreparedStatement pstmt = null; - try { - pstmt = txn.prepareAutoCloseStatement(sql); - String gmtCutTime = DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), cutTime); - pstmt.setString(1, gmtCutTime); - pstmt.setLong(2, msid); - - ResultSet rs = pstmt.executeQuery(); - while(rs.next()) { - l.add(toEntityBean(rs, false)); - } - } catch (SQLException e) { - s_logger.error("unexcpected exception " + e.getMessage(), e); - } catch (Throwable e) { - s_logger.error("unexcpected exception " + e.getMessage(), e); - } finally { - txn.close(); - } - return l; - } -} - diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index dbcbc5332d0..77ca2de1923 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -51,25 +51,25 @@ public enum Config { AlertSMTPUsername("Alert", ManagementServer.class, String.class, "alert.smtp.username", null, "Username for SMTP authentication (applies only if alert.smtp.useAuth is true).", null), AlertWait("Alert", AgentManager.class, Integer.class, "alert.wait", null, "Seconds to wait before alerting on a disconnected agent", null), CapacityCheckPeriod("Alert", ManagementServer.class, Integer.class, "capacity.check.period", "300000", "The interval in milliseconds between capacity checks", null), - StorageAllocatedCapacityThreshold("Alert", ManagementServer.class, Float.class, "cluster.storage.allocated.capacity.notificationthreshold", "0.75", "Percentage (as a value between 0 and 1) of allocated storage utilization above which alerts will be sent about low storage available.", null), - StorageCapacityThreshold("Alert", ManagementServer.class, Float.class, "cluster.storage.capacity.notificationthreshold", "0.75", "Percentage (as a value between 0 and 1) of storage utilization above which alerts will be sent about low storage available.", null), - CPUCapacityThreshold("Alert", ManagementServer.class, Float.class, "cluster.cpu.allocated.capacity.notificationthreshold", "0.75", "Percentage (as a value between 0 and 1) of cpu utilization above which alerts will be sent about low cpu available.", null), - MemoryCapacityThreshold("Alert", ManagementServer.class, Float.class, "cluster.memory.allocated.capacity.notificationthreshold", "0.75", "Percentage (as a value between 0 and 1) of memory utilization above which alerts will be sent about low memory available.", null), + StorageAllocatedCapacityThreshold("Alert", ManagementServer.class, Float.class, "cluster.storage.allocated.capacity.notificationthreshold", "0.75", "Percentage (as a value between 0 and 1) of allocated storage utilization above which alerts will be sent about low storage available.", null, ConfigurationParameterScope.cluster.toString()), + StorageCapacityThreshold("Alert", ManagementServer.class, Float.class, "cluster.storage.capacity.notificationthreshold", "0.75", "Percentage (as a value between 0 and 1) of storage utilization above which alerts will be sent about low storage available.", null, ConfigurationParameterScope.cluster.toString()), + CPUCapacityThreshold("Alert", ManagementServer.class, Float.class, "cluster.cpu.allocated.capacity.notificationthreshold", "0.75", "Percentage (as a value between 0 and 1) of cpu utilization above which alerts will be sent about low cpu available.", null, ConfigurationParameterScope.cluster.toString()), + MemoryCapacityThreshold("Alert", ManagementServer.class, Float.class, "cluster.memory.allocated.capacity.notificationthreshold", "0.75", "Percentage (as a value between 0 and 1) of memory utilization above which alerts will be sent about low memory available.", null, ConfigurationParameterScope.cluster.toString()), PublicIpCapacityThreshold("Alert", ManagementServer.class, Float.class, "zone.virtualnetwork.publicip.capacity.notificationthreshold", "0.75", "Percentage (as a value between 0 and 1) of public IP address space utilization above which alerts will be sent.", null), PrivateIpCapacityThreshold("Alert", ManagementServer.class, Float.class, "pod.privateip.capacity.notificationthreshold", "0.75", "Percentage (as a value between 0 and 1) of private IP address space utilization above which alerts will be sent.", null), SecondaryStorageCapacityThreshold("Alert", ManagementServer.class, Float.class, "zone.secstorage.capacity.notificationthreshold", "0.75", "Percentage (as a value between 0 and 1) of secondary storage utilization above which alerts will be sent about low storage available.", null), VlanCapacityThreshold("Alert", ManagementServer.class, Float.class, "zone.vlan.capacity.notificationthreshold", "0.75", "Percentage (as a value between 0 and 1) of Zone Vlan utilization above which alerts will be sent about low number of Zone Vlans.", null), DirectNetworkPublicIpCapacityThreshold("Alert", ManagementServer.class, Float.class, "zone.directnetwork.publicip.capacity.notificationthreshold", "0.75", "Percentage (as a value between 0 and 1) of Direct Network Public Ip Utilization above which alerts will be sent about low number of direct network public ips.", null), LocalStorageCapacityThreshold("Alert", ManagementServer.class, Float.class, "cluster.localStorage.capacity.notificationthreshold", "0.75", "Percentage (as a value between 0 and 1) of local storage utilization above which alerts will be sent about low local storage available.", null), - StorageAllocatedCapacityDisableThreshold("Alert", ManagementServer.class, Float.class, "pool.storage.allocated.capacity.disablethreshold", "0.85", "Percentage (as a value between 0 and 1) of allocated storage utilization above which allocators will disable using the pool for low allocated storage available.", null), - StorageCapacityDisableThreshold("Alert", ManagementServer.class, Float.class, "pool.storage.capacity.disablethreshold", "0.85", "Percentage (as a value between 0 and 1) of storage utilization above which allocators will disable using the pool for low storage available.", null), - CPUCapacityDisableThreshold("Alert", ManagementServer.class, Float.class, "cluster.cpu.allocated.capacity.disablethreshold", "0.85", "Percentage (as a value between 0 and 1) of cpu utilization above which allocators will disable using the cluster for low cpu available. Keep the corresponding notification threshold lower than this to be notified beforehand.", null), - MemoryCapacityDisableThreshold("Alert", ManagementServer.class, Float.class, "cluster.memory.allocated.capacity.disablethreshold", "0.85", "Percentage (as a value between 0 and 1) of memory utilization above which allocators will disable using the cluster for low memory available. Keep the corresponding notification threshold lower than this to be notified beforehand.", null), + StorageAllocatedCapacityDisableThreshold("Alert", ManagementServer.class, Float.class, "pool.storage.allocated.capacity.disablethreshold", "0.85", "Percentage (as a value between 0 and 1) of allocated storage utilization above which allocators will disable using the pool for low allocated storage available.", null, ConfigurationParameterScope.zone.toString()), + StorageCapacityDisableThreshold("Alert", ManagementServer.class, Float.class, "pool.storage.capacity.disablethreshold", "0.85", "Percentage (as a value between 0 and 1) of storage utilization above which allocators will disable using the pool for low storage available.", null, ConfigurationParameterScope.zone.toString()), + CPUCapacityDisableThreshold("Alert", ManagementServer.class, Float.class, "cluster.cpu.allocated.capacity.disablethreshold", "0.85", "Percentage (as a value between 0 and 1) of cpu utilization above which allocators will disable using the cluster for low cpu available. Keep the corresponding notification threshold lower than this to be notified beforehand.", null, ConfigurationParameterScope.cluster.toString()), + MemoryCapacityDisableThreshold("Alert", ManagementServer.class, Float.class, "cluster.memory.allocated.capacity.disablethreshold", "0.85", "Percentage (as a value between 0 and 1) of memory utilization above which allocators will disable using the cluster for low memory available. Keep the corresponding notification threshold lower than this to be notified beforehand.", null, ConfigurationParameterScope.cluster.toString()), // Storage - StorageOverprovisioningFactor("Storage", StoragePoolAllocator.class, String.class, "storage.overprovisioning.factor", "2", "Used for storage overprovisioning calculation; available storage will be (actualStorageSize * storage.overprovisioning.factor)", null), + StorageOverprovisioningFactor("Storage", StoragePoolAllocator.class, String.class, "storage.overprovisioning.factor", "2", "Used for storage overprovisioning calculation; available storage will be (actualStorageSize * storage.overprovisioning.factor)", null, ConfigurationParameterScope.zone.toString()), StorageStatsInterval("Storage", ManagementServer.class, String.class, "storage.stats.interval", "60000", "The interval (in milliseconds) when storage stats (per host) are retrieved from agents.", null), MaxVolumeSize("Storage", ManagementServer.class, Integer.class, "storage.max.volume.size", "2000", "The maximum size for a volume (in GB).", null), MaxUploadVolumeSize("Storage", ManagementServer.class, Integer.class, "storage.max.volume.upload.size", "500", "The maximum size for a uploaded volume(in GB).", null), @@ -93,8 +93,8 @@ public enum Config { GuestVlanBits("Network", ManagementServer.class, Integer.class, "guest.vlan.bits", "12", "The number of bits to reserve for the VLAN identifier in the guest subnet.", null), //MulticastThrottlingRate("Network", ManagementServer.class, Integer.class, "multicast.throttling.rate", "10", "Default multicast rate in megabits per second allowed.", null), - NetworkThrottlingRate("Network", ManagementServer.class, Integer.class, "network.throttling.rate", "200", "Default data transfer rate in megabits per second allowed in network.", null), - GuestDomainSuffix("Network", AgentManager.class, String.class, "guest.domain.suffix", "cloud.internal", "Default domain name for vms inside virtualized networks fronted by router", null), + NetworkThrottlingRate("Network", ManagementServer.class, Integer.class, "network.throttling.rate", "200", "Default data transfer rate in megabits per second allowed in network.", null, ConfigurationParameterScope.zone.toString()), + GuestDomainSuffix("Network", AgentManager.class, String.class, "guest.domain.suffix", "cloud.internal", "Default domain name for vms inside virtualized networks fronted by router", null, ConfigurationParameterScope.zone.toString()), DirectNetworkNoDefaultRoute("Network", ManagementServer.class, Boolean.class, "direct.network.no.default.route", "false", "Direct Network Dhcp Server should not send a default route", "true/false"), OvsTunnelNetwork("Network", ManagementServer.class, Boolean.class, "sdn.ovs.controller", "false", "Enable/Disable Open vSwitch SDN controller for L2-in-L3 overlay networks", null), OvsTunnelNetworkDefaultLabel("Network", ManagementServer.class, String.class, "sdn.ovs.controller.default.label", "cloud-public", "Default network label to be used when fetching interface for GRE endpoints", null), @@ -112,7 +112,7 @@ public enum Config { //VPN RemoteAccessVpnPskLength("Network", AgentManager.class, Integer.class, "remote.access.vpn.psk.length", "24", "The length of the ipsec preshared key (minimum 8, maximum 256)", null), - RemoteAccessVpnClientIpRange("Network", AgentManager.class, String.class, "remote.access.vpn.client.iprange", "10.1.2.1-10.1.2.8", "The range of ips to be allocated to remote access vpn clients. The first ip in the range is used by the VPN server", null), + RemoteAccessVpnClientIpRange("Network", AgentManager.class, String.class, "remote.access.vpn.client.iprange", "10.1.2.1-10.1.2.8", "The range of ips to be allocated to remote access vpn clients. The first ip in the range is used by the VPN server", null, ConfigurationParameterScope.account.toString()), RemoteAccessVpnUserLimit("Network", AgentManager.class, String.class, "remote.access.vpn.user.limit", "8", "The maximum number of VPN users that can be created per account", null), Site2SiteVpnConnectionPerVpnGatewayLimit("Network", ManagementServer.class, Integer.class, "site2site.vpn.vpngateway.connection.limit", "4", "The maximum number of VPN connection per VPN gateway", null), Site2SiteVpnSubnetsPerCustomerGatewayLimit("Network", ManagementServer.class, Integer.class, "site2site.vpn.customergateway.subnets.limit", "10", "The maximum number of subnets per customer gateway", null), @@ -149,7 +149,7 @@ public enum Config { S3Enable("Advanced", ManagementServer.class, Boolean.class, "s3.enable", "false", "enable s3 ", null), EventPurgeInterval("Advanced", ManagementServer.class, Integer.class, "event.purge.interval", "86400", "The interval (in seconds) to wait before running the event purge thread", null), AccountCleanupInterval("Advanced", ManagementServer.class, Integer.class, "account.cleanup.interval", "86400", "The interval (in seconds) between cleanup for removed accounts", null), - AllowPublicUserTemplates("Advanced", ManagementServer.class, Integer.class, "allow.public.user.templates", "true", "If false, users will not be able to create public templates.", null), + AllowPublicUserTemplates("Advanced", ManagementServer.class, Integer.class, "allow.public.user.templates", "true", "If false, users will not be able to create public templates.", null, ConfigurationParameterScope.account.toString()), InstanceName("Advanced", AgentManager.class, String.class, "instance.name", "VM", "Name of the deployment instance.", "instanceName"), ExpungeDelay("Advanced", UserVmManager.class, Integer.class, "expunge.delay", "86400", "Determines how long (in seconds) to wait before actually expunging destroyed vm. The default value = the default value of expunge.interval", null), ExpungeInterval("Advanced", UserVmManager.class, Integer.class, "expunge.interval", "86400", "The interval (in seconds) to wait before running the expunge thread.", null), @@ -173,6 +173,11 @@ public enum Config { RouterCheckInterval("Advanced", NetworkManager.class, Integer.class, "router.check.interval", "30", "Interval (in seconds) to report redundant router status.", null), RouterCheckPoolSize("Advanced", NetworkManager.class, Integer.class, "router.check.poolsize", "10", "Numbers of threads using to check redundant router status.", null), RouterTemplateId("Advanced", NetworkManager.class, Long.class, "router.template.id", "1", "Default ID for template.", null), + RouterTemplateXen("Advanced", NetworkManager.class, String.class, "router.template.xen", "SystemVM Template (XenServer)", "Name of the default router template on Xenserver.", null, ConfigurationParameterScope.zone.toString()), + RouterTemplateKVM("Advanced", NetworkManager.class, String.class, "router.template.kvm", "SystemVM Template (KVM)", "Name of the default router template on KVM.", null, ConfigurationParameterScope.zone.toString()), + RouterTemplateVmware("Advanced", NetworkManager.class, String.class, "router.template.vmware", "SystemVM Template (vSphere)", "Name of the default router template on Vmware.", null, ConfigurationParameterScope.zone.toString()), + RouterTemplateHyperv("Advanced", NetworkManager.class, String.class, "router.template.hyperv", "SystemVM Template (HyperV)", "Name of the default router template on Hyperv.", null, ConfigurationParameterScope.zone.toString()), + RouterTemplateLXC("Advanced", NetworkManager.class, String.class, "router.template.lxc", "SystemVM Template (LXC)", "Name of the default router template on LXC.", null, ConfigurationParameterScope.zone.toString()), RouterExtraPublicNics("Advanced", NetworkManager.class, Integer.class, "router.extra.public.nics", "2", "specify extra public nics used for virtual router(up to 5)", "0-5"), StartRetry("Advanced", AgentManager.class, Integer.class, "start.retry", "10", "Number of times to retry create and start commands", null), ScaleRetry("Advanced", AgentManager.class, Integer.class, "scale.retry", "2", "Number of times to retry scaling up the vm", null), @@ -191,8 +196,8 @@ public enum Config { SystemVMAutoReserveCapacity("Advanced", ManagementServer.class, Boolean.class, "system.vm.auto.reserve.capacity", "true", "Indicates whether or not to automatically reserver system VM standby capacity.", null), SystemVMDefaultHypervisor("Advanced", ManagementServer.class, String.class, "system.vm.default.hypervisor", null, "Hypervisor type used to create system vm", null), SystemVMRandomPassword("Advanced", ManagementServer.class, Boolean.class, "system.vm.random.password", "false", "Randomize system vm password the first time management server starts", null), - CPUOverprovisioningFactor("Advanced", ManagementServer.class, String.class, "cpu.overprovisioning.factor", "1", "Used for CPU overprovisioning calculation; available CPU will be (actualCpuCapacity * cpu.overprovisioning.factor)", null), - MemOverprovisioningFactor("Advanced", ManagementServer.class, String.class, "mem.overprovisioning.factor", "1", "Used for memory overprovisioning calculation", null), + CPUOverprovisioningFactor("Advanced", ManagementServer.class, String.class, "cpu.overprovisioning.factor", "1", "Used for CPU overprovisioning calculation; available CPU will be (actualCpuCapacity * cpu.overprovisioning.factor)", null, ConfigurationParameterScope.cluster.toString()), + MemOverprovisioningFactor("Advanced", ManagementServer.class, String.class, "mem.overprovisioning.factor", "1", "Used for memory overprovisioning calculation", null, ConfigurationParameterScope.cluster.toString()), LinkLocalIpNums("Advanced", ManagementServer.class, Integer.class, "linkLocalIp.nums", "10", "The number of link local ip that needed by domR(in power of 2)", null), HypervisorList("Advanced", ManagementServer.class, String.class, "hypervisor.list", HypervisorType.KVM + "," + HypervisorType.XenServer + "," + HypervisorType.VMware + "," + HypervisorType.BareMetal + "," + HypervisorType.Ovm + "," + HypervisorType.LXC, "The list of hypervisors that this deployment will use.", "hypervisorList"), ManagementHostIPAdr("Advanced", ManagementServer.class, String.class, "host", "localhost", "The ip address of management server", null), @@ -403,7 +408,10 @@ public enum Config { CloudDnsName("Advanced", ManagementServer.class, String.class, "cloud.dns.name", "default", " DNS name of the cloud", null), BlacklistedRoutes("Advanced", VpcManager.class, String.class, "blacklisted.routes", null, "Routes that are blacklisted, can not be used for Static Routes creation for the VPC Private Gateway", - "routes", ConfigurationParameterScope.zone.toString()); + "routes", ConfigurationParameterScope.zone.toString()), + + InternalLbVmServiceOfferingId("Advanced", ManagementServer.class, Long.class, "internallbvm.service.offering", null, "Uuid of the service offering used by internal lb vm; if NULL - default system internal lb offering will be used", null); + private final String _category; @@ -419,7 +427,7 @@ public enum Config { global, zone, cluster, - pool, + storagepool, account } @@ -427,7 +435,7 @@ public enum Config { static { _scopeLevelConfigsMap.put(ConfigurationParameterScope.zone.toString(), new ArrayList()); _scopeLevelConfigsMap.put(ConfigurationParameterScope.cluster.toString(), new ArrayList()); - _scopeLevelConfigsMap.put(ConfigurationParameterScope.pool.toString(), new ArrayList()); + _scopeLevelConfigsMap.put(ConfigurationParameterScope.storagepool.toString(), new ArrayList()); _scopeLevelConfigsMap.put(ConfigurationParameterScope.account.toString(), new ArrayList()); _scopeLevelConfigsMap.put(ConfigurationParameterScope.global.toString(), new ArrayList()); diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java index ca035afa4b4..2504cca766a 100755 --- a/server/src/com/cloud/configuration/ConfigurationManager.java +++ b/server/src/com/cloud/configuration/ConfigurationManager.java @@ -30,13 +30,13 @@ import com.cloud.dc.Vlan; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.ResourceAllocationException; import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.Networks.TrafficType; import com.cloud.offering.DiskOffering; +import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.Availability; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.org.Grouping.AllocationState; @@ -60,7 +60,7 @@ public interface ConfigurationManager extends ConfigurationService, Manager { * @param name * @param value */ - void updateConfiguration(long userId, String name, String category, String value, String scope, Long id); + String updateConfiguration(long userId, String name, String category, String value, String scope, Long id); /** * Creates a new service offering @@ -181,8 +181,6 @@ public interface ConfigurationManager extends ConfigurationService, Manager { * @param trafficType * @param tags * @param specifyVlan - * @param isPersistent - * ; * @param networkRate * TODO * @param serviceProviderMap @@ -198,14 +196,16 @@ public interface ConfigurationManager extends ConfigurationService, Manager { * ; * @param specifyIpRanges * TODO + * @param isPersistent + * ; + * @param details TODO * @param id - * * @return network offering object */ NetworkOfferingVO createNetworkOffering(String name, String displayText, TrafficType trafficType, String tags, boolean specifyVlan, Availability availability, Integer networkRate, Map> serviceProviderMap, boolean isDefault, Network.GuestType type, boolean systemOnly, Long serviceOfferingId, boolean conserveMode, Map> serviceCapabilityMap, - boolean specifyIpRanges, boolean isPersistent); + boolean specifyIpRanges, boolean isPersistent, Map details); Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, Long podId, String startIP, String endIP, String vlanGateway, String vlanNetmask, String vlanId, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr) throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException; diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 40cceb74a07..87fd8ff3c40 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -39,7 +39,11 @@ import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; + +import com.cloud.dc.*; import com.cloud.dc.dao.*; +import com.cloud.user.*; +import com.cloud.event.UsageEventUtils; import org.apache.cloudstack.acl.SecurityChecker; import org.apache.cloudstack.api.ApiConstants.LDAPParams; import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd; @@ -64,6 +68,10 @@ import org.apache.cloudstack.api.command.admin.zone.CreateZoneCmd; import org.apache.cloudstack.api.command.admin.zone.DeleteZoneCmd; import org.apache.cloudstack.api.command.admin.zone.UpdateZoneCmd; import org.apache.cloudstack.api.command.user.network.ListNetworkOfferingsCmd; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -72,20 +80,19 @@ import com.cloud.api.ApiDBUtils; import com.cloud.capacity.dao.CapacityDao; import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.dc.AccountVlanMapVO; -import com.cloud.dc.ClusterVO; -import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; -import com.cloud.dc.DataCenterIpAddressVO; -import com.cloud.dc.DataCenterLinkLocalIpAddressVO; -import com.cloud.dc.DataCenterVO; -import com.cloud.dc.DcDetailVO; -import com.cloud.dc.HostPodVO; -import com.cloud.dc.Pod; -import com.cloud.dc.PodVlanMapVO; -import com.cloud.dc.Vlan; import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.VlanVO; +import com.cloud.dc.dao.AccountVlanMapDao; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.DataCenterIpAddressDao; +import com.cloud.dc.dao.DataCenterLinkLocalIpAddressDao; +import com.cloud.dc.dao.DcDetailsDao; +import com.cloud.dc.dao.HostPodDao; +import com.cloud.dc.dao.PodVlanMapDao; +import com.cloud.dc.dao.VlanDao; + import com.cloud.deploy.DataCenterDeployment; import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; @@ -120,10 +127,12 @@ import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao; import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO; import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.vpc.VpcManager; import com.cloud.offering.DiskOffering; import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.Availability; +import com.cloud.offering.NetworkOffering.Detail; import com.cloud.offering.ServiceOffering; import com.cloud.offerings.NetworkOfferingServiceMapVO; import com.cloud.offerings.NetworkOfferingVO; @@ -133,6 +142,7 @@ import com.cloud.org.Grouping; import com.cloud.org.Grouping.AllocationState; import com.cloud.projects.Project; import com.cloud.projects.ProjectManager; +import com.cloud.server.ConfigurationServer; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.DiskOfferingVO; @@ -144,12 +154,6 @@ import com.cloud.storage.s3.S3Manager; import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.storage.swift.SwiftManager; import com.cloud.test.IPRangeConfig; -import com.cloud.user.Account; -import com.cloud.user.AccountManager; -import com.cloud.user.AccountVO; -import com.cloud.user.ResourceLimitService; -import com.cloud.user.User; -import com.cloud.user.UserContext; import com.cloud.user.dao.AccountDao; import com.cloud.utils.NumbersUtil; import com.cloud.utils.StringUtils; @@ -182,8 +186,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati @Inject DataCenterDao _zoneDao; @Inject - DcDetailsDao _zoneDetailsDao; - @Inject DomainDao _domainDao; @Inject SwiftDao _swiftDao; @@ -245,6 +247,18 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati FirewallRulesDao _firewallDao; @Inject VpcManager _vpcMgr; + @Inject + ConfigurationServer _configServer; + @Inject + DcDetailsDao _dcDetailsDao; + @Inject + ClusterDetailsDao _clusterDetailsDao; + @Inject + StoragePoolDetailsDao _storagePoolDetailsDao; + @Inject + AccountDetailsDao _accountDetailsDao; + @Inject + PrimaryDataStoreDao _storagePoolDao; // FIXME - why don't we have interface for DataCenterLinkLocalIpAddressDao? @Inject protected DataCenterLinkLocalIpAddressDao _LinkLocalIpAllocDao; @@ -323,7 +337,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati @Override @DB - public void updateConfiguration(long userId, String name, String category, String value, String scope, Long resourceId) { + public String updateConfiguration(long userId, String name, String category, String value, String scope, Long resourceId) { String validationMsg = validateConfigurationValue(name, value, scope); @@ -335,23 +349,61 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // If scope of the parameter is given then it needs to be updated in the corresponding details table, // if scope is mentioned as global or not mentioned then it is normal global parameter updation if (scope != null && !scope.isEmpty() && !Config.ConfigurationParameterScope.global.toString().equalsIgnoreCase(scope)) { - if (Config.ConfigurationParameterScope.zone.toString().equalsIgnoreCase(scope)) { - DataCenterVO zone = _zoneDao.findById(resourceId); - if (zone == null) { - throw new InvalidParameterValueException("unable to find zone by id " + resourceId); - } - DcDetailVO dcDetailVO = _zoneDetailsDao.findDetail(resourceId, name.toLowerCase()); - if (dcDetailVO == null) { - dcDetailVO = new DcDetailVO(zone.getId(), name, value); - _zoneDetailsDao.persist(dcDetailVO); - } else { - dcDetailVO.setValue(value); - _zoneDetailsDao.update(resourceId, dcDetailVO); - } - } else { - s_logger.error("TO Do for the remaining levels (cluster/pool/account)"); - throw new InvalidParameterValueException("The scope "+ scope +" yet to be implemented"); + switch (Config.ConfigurationParameterScope.valueOf(scope)) { + case zone: DataCenterVO zone = _zoneDao.findById(resourceId); + if (zone == null) { + throw new InvalidParameterValueException("unable to find zone by id " + resourceId); + } + DcDetailVO dcDetailVO = _dcDetailsDao.findDetail(resourceId, name.toLowerCase()); + if (dcDetailVO == null) { + dcDetailVO = new DcDetailVO(resourceId, name, value); + _dcDetailsDao.persist(dcDetailVO); + } else { + dcDetailVO.setValue(value); + _dcDetailsDao.update(dcDetailVO.getId(), dcDetailVO); + } break; + case cluster: ClusterVO cluster = _clusterDao.findById(resourceId); + if (cluster == null) { + throw new InvalidParameterValueException("unable to find cluster by id " + resourceId); + } + ClusterDetailsVO clusterDetailsVO = _clusterDetailsDao.findDetail(resourceId, name); + if (clusterDetailsVO == null) { + clusterDetailsVO = new ClusterDetailsVO(resourceId, name, value); + _clusterDetailsDao.persist(clusterDetailsVO); + } else { + clusterDetailsVO.setValue(value); + _clusterDetailsDao.update(clusterDetailsVO.getId(), clusterDetailsVO); + } break; + + case storagepool: StoragePoolVO pool = _storagePoolDao.findById(resourceId); + if (pool == null) { + throw new InvalidParameterValueException("unable to find storage pool by id " + resourceId); + } + StoragePoolDetailVO storagePoolDetailVO = _storagePoolDetailsDao.findDetail(resourceId, name); + if (storagePoolDetailVO == null) { + storagePoolDetailVO = new StoragePoolDetailVO(resourceId, name, value); + _storagePoolDetailsDao.persist(storagePoolDetailVO); + + } else { + storagePoolDetailVO.setValue(value); + _storagePoolDetailsDao.update(storagePoolDetailVO.getId(), storagePoolDetailVO); + } break; + + case account: AccountVO account = _accountDao.findById(resourceId); + if (account == null) { + throw new InvalidParameterValueException("unable to find account by id " + resourceId); + } + AccountDetailVO accountDetailVO = _accountDetailsDao.findDetail(resourceId, name); + if (accountDetailVO == null) { + accountDetailVO = new AccountDetailVO(resourceId, name, value); + _accountDetailsDao.persist(accountDetailVO); + } else { + accountDetailVO.setValue(value); + _accountDetailsDao.update(accountDetailVO.getId(), accountDetailVO); + } break; + default: throw new InvalidParameterValueException("Scope provided is invalid"); } + return value; } // Execute all updates in a single transaction @@ -450,16 +502,19 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } txn.commit(); + return _configDao.getValue(name); } @Override @ActionEvent(eventType = EventTypes.EVENT_CONFIGURATION_VALUE_EDIT, eventDescription = "updating configuration") - public Configuration updateConfiguration(UpdateCfgCmd cmd) { + public Configuration updateConfiguration(UpdateCfgCmd cmd) throws InvalidParameterValueException { Long userId = UserContext.current().getCallerUserId(); String name = cmd.getCfgName(); String value = cmd.getValue(); - String scope = cmd.getScope(); - Long id = cmd.getId(); + Long zoneId = cmd.getZoneId(); + Long clusterId = cmd.getClusterId(); + Long storagepoolId = cmd.getStoragepoolId(); + Long accountId = cmd.getAccountId(); UserContext.current().setEventDetails(" Name: " + name + " New Value: " + (((name.toLowerCase()).contains("password")) ? "*****" : (((value == null) ? "" : value)))); // check if config value exists @@ -476,11 +531,38 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati value = null; } - updateConfiguration(userId, name, config.getCategory(), value, scope, id); - String updatedValue = _configDao.getValue(name); + String scope = null; + Long id = null; + int paramCountCheck = 0; + + if (zoneId != null) { + scope = Config.ConfigurationParameterScope.zone.toString(); + id = zoneId; + paramCountCheck++; + } + if (clusterId != null) { + scope = Config.ConfigurationParameterScope.cluster.toString(); + id = clusterId; + paramCountCheck++; + } + if (accountId != null) { + scope = Config.ConfigurationParameterScope.account.toString(); + id = accountId; + paramCountCheck++; + } + if (storagepoolId != null) { + scope = Config.ConfigurationParameterScope.storagepool.toString(); + id = storagepoolId; + paramCountCheck++; + } + + if (paramCountCheck > 1) { + throw new InvalidParameterValueException("cannot handle multiple IDs, provide only one ID corresponding to the scope"); + } + + String updatedValue = updateConfiguration(userId, name, config.getCategory(), value, scope, id); if ((value == null && updatedValue == null) || updatedValue.equalsIgnoreCase(value)) { return _configDao.findByName(name); - } else { throw new CloudRuntimeException("Unable to update configuration parameter " + name); } @@ -494,10 +576,14 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati return "Invalid configuration variable."; } String configScope = c.getScope(); - if (scope != null && !scope.isEmpty()) { + if (scope != null) { if (!configScope.contains(scope)) { - s_logger.error("Invalid scope " + scope + " for the parameter " + name); - return "Invalid scope for the parameter."; + s_logger.error("Invalid scope id provided for the parameter " + name); + return "Invalid scope id provided for the parameter " + name; + } + if ((name.equalsIgnoreCase("cpu.overprovisioning.factor") || name.equalsIgnoreCase("mem.overprovisioning.factor")) && value == null) { + s_logger.error("value cannot be null for cpu.overprovisioning.factor/mem.overprovisioning.factor"); + return "value cannot be null for cpu.overprovisioning.factor/mem.overprovisioning.factor"; } } @@ -1847,6 +1933,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati vmType = VirtualMachine.Type.ConsoleProxy; } else if (VirtualMachine.Type.SecondaryStorageVm.toString().toLowerCase().equals(vmTypeString)) { vmType = VirtualMachine.Type.SecondaryStorageVm; + } else if (VirtualMachine.Type.InternalLoadBalancerVm.toString().toLowerCase().equals(vmTypeString)) { + vmType = VirtualMachine.Type.InternalLoadBalancerVm; } else { throw new InvalidParameterValueException("Invalid systemVmType. Supported types are: " + VirtualMachine.Type.DomainRouter + ", " + VirtualMachine.Type.ConsoleProxy + ", " + VirtualMachine.Type.SecondaryStorageVm); @@ -2637,6 +2725,14 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // This VLAN is account-specific, so create an AccountVlanMapVO entry AccountVlanMapVO accountVlanMapVO = new AccountVlanMapVO(vlanOwner.getId(), vlan.getId()); _accountVlanMapDao.persist(accountVlanMapVO); + + // generate usage event for dedication of every ip address in the range + List ips = _publicIpAddressDao.listByVlanId(vlan.getId()); + for (IPAddressVO ip : ips) { + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_ASSIGN, vlanOwner.getId(), + ip.getDataCenterId(), ip.getId(), ip.getAddress().toString(), ip.isSourceNat(), vlan.getVlanType().toString(), + ip.getSystem(), ip.getClass().getName(), ip.getUuid()); + } } else if (podId != null) { // This VLAN is pod-wide, so create a PodVlanMapVO entry PodVlanMapVO podVlanMapVO = new PodVlanMapVO(podId, vlan.getId()); @@ -2665,6 +2761,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // Check if the VLAN has any allocated public IPs long allocIpCount = _publicIpAddressDao.countIPs(vlan.getDataCenterId(), vlanDbId, true); + List ips = _publicIpAddressDao.listByVlanId(vlanDbId); boolean success = true; if (allocIpCount > 0) { if (isAccountSpecific) { @@ -2678,8 +2775,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati s_logger.debug("lock vlan " + vlanDbId + " is acquired"); } - List ips = _publicIpAddressDao.listByVlanId(vlanDbId); - for (IPAddressVO ip : ips) { if (ip.isOneToOneNat()) { throw new InvalidParameterValueException("Can't delete account specific vlan " + vlanDbId + @@ -2716,6 +2811,15 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati return false; } + // if ip range is dedicated to an account generate usage events for release of every ip in the range + if(isAccountSpecific) { + for (IPAddressVO ip : ips) { + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_RELEASE, acctVln.get(0).getId(), + ip.getDataCenterId(), ip.getId(), ip.getAddress().toString(), ip.isSourceNat(), vlan.getVlanType().toString(), + ip.getSystem(), ip.getClass().getName(), ip.getUuid()); + } + } + // Delete the VLAN return _vlanDao.expunge(vlanDbId); } else { @@ -2800,6 +2904,12 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati txn.commit(); + // generate usage event for dedication of every ip address in the range + for (IPAddressVO ip : ips) { + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_ASSIGN, vlanOwner.getId(), + ip.getDataCenterId(), ip.getId(), ip.getAddress().toString(), ip.isSourceNat(), vlan.getVlanType().toString(), + ip.getSystem(), ip.getClass().getName(), ip.getUuid()); + } return vlan; } @@ -2829,6 +2939,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // Check if range has any allocated public IPs long allocIpCount = _publicIpAddressDao.countIPs(vlan.getDataCenterId(), vlanDbId, true); + List ips = _publicIpAddressDao.listByVlanId(vlanDbId); boolean success = true; if (allocIpCount > 0) { try { @@ -2839,7 +2950,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if (s_logger.isDebugEnabled()) { s_logger.debug("lock vlan " + vlanDbId + " is acquired"); } - List ips = _publicIpAddressDao.listByVlanId(vlanDbId); for (IPAddressVO ip : ips) { // Disassociate allocated IP's that are not in use if ( !ip.isOneToOneNat() && !ip.isSourceNat() && !(_firewallDao.countRulesByIpId(ip.getId()) > 0) ) { @@ -2861,6 +2971,12 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // A Public IP range can only be dedicated to one account at a time if (_accountVlanMapDao.remove(acctVln.get(0).getId())) { + // generate usage events to remove dedication for every ip in the range + for (IPAddressVO ip : ips) { + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_RELEASE, acctVln.get(0).getId(), + ip.getDataCenterId(), ip.getId(), ip.getAddress().toString(), ip.isSourceNat(), vlan.getVlanType().toString(), + ip.getSystem(), ip.getClass().getName(), ip.getUuid()); + } return true; } else { return false; @@ -3242,6 +3358,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati Network.GuestType guestType = null; boolean specifyIpRanges = cmd.getSpecifyIpRanges(); boolean isPersistent = cmd.getIsPersistent(); + Map detailsStr = cmd.getDetails(); // Verify traffic type for (TrafficType tType : TrafficType.values()) { @@ -3334,10 +3451,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati Network.Service service = Network.Service.getService(serviceStr); if (serviceProviderMap.containsKey(service)) { Set providers = new HashSet(); - // in Acton, don't allow to specify more than 1 provider per service - if (svcPrv.get(serviceStr) != null && svcPrv.get(serviceStr).size() > 1) { + // Allow to specify more than 1 provider per service only if the service is LB + if (!serviceStr.equalsIgnoreCase(Service.Lb.getName()) && svcPrv.get(serviceStr) != null && svcPrv.get(serviceStr).size() > 1) { throw new InvalidParameterValueException("In the current release only one provider can be " + - "specified for the service"); + "specified for the service if the service is not LB"); } for (String prvNameStr : svcPrv.get(serviceStr)) { // check if provider is supported @@ -3410,9 +3527,26 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati firewallProviderSet.add(firewallProvider); serviceProviderMap.put(Service.Firewall, firewallProviderSet); } + + Map details = new HashMap(); + if (detailsStr != null) { + for (String detailStr : detailsStr.keySet()) { + NetworkOffering.Detail offDetail = null; + for (NetworkOffering.Detail supportedDetail: NetworkOffering.Detail.values()) { + if (detailStr.equalsIgnoreCase(supportedDetail.toString())) { + offDetail = supportedDetail; + break; + } + } + if (offDetail == null) { + throw new InvalidParameterValueException("Unsupported detail " + detailStr); + } + details.put(offDetail, detailsStr.get(detailStr)); + } + } return createNetworkOffering(name, displayText, trafficType, tags, specifyVlan, availability, networkRate, serviceProviderMap, false, guestType, false, - serviceOfferingId, conserveMode, serviceCapabilityMap, specifyIpRanges, isPersistent); + serviceOfferingId, conserveMode, serviceCapabilityMap, specifyIpRanges, isPersistent, details); } void validateLoadBalancerServiceCapabilities(Map lbServiceCapabilityMap) { @@ -3441,8 +3575,16 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if (!enabled && !disabled) { throw new InvalidParameterValueException("Unknown specified value for " + Capability.InlineMode.getName()); } + } else if (cap == Capability.LbSchemes) { + boolean internalLb = value.contains("internal"); + boolean publicLb = value.contains("public"); + if (!internalLb && !publicLb) { + throw new InvalidParameterValueException("Unknown specified value for " + Capability.LbSchemes.getName()); + } } else { - throw new InvalidParameterValueException("Only " + Capability.SupportedLBIsolation.getName() + ", " + Capability.ElasticLb.getName() + ", " + Capability.InlineMode.getName() + " capabilities can be sepcified for LB service"); + throw new InvalidParameterValueException("Only " + Capability.SupportedLBIsolation.getName() + + ", " + Capability.ElasticLb.getName() + ", " + Capability.InlineMode.getName() + + ", " + Capability.LbSchemes.getName() + " capabilities can be sepcified for LB service"); } } } @@ -3514,7 +3656,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati @DB public NetworkOfferingVO createNetworkOffering(String name, String displayText, TrafficType trafficType, String tags, boolean specifyVlan, Availability availability, Integer networkRate, Map> serviceProviderMap, boolean isDefault, Network.GuestType type, boolean systemOnly, Long serviceOfferingId, - boolean conserveMode, Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent) { + boolean conserveMode, Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent, Map details) { String multicastRateStr = _configDao.getValue("multicast.throttling.rate"); int multicastRate = ((multicastRateStr == null) ? 10 : Integer.parseInt(multicastRateStr)); @@ -3568,6 +3710,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati boolean elasticIp = false; boolean associatePublicIp = false; boolean inline = false; + boolean publicLb = false; + boolean internalLb = false; if (serviceCapabilityMap != null && !serviceCapabilityMap.isEmpty()) { Map lbServiceCapabilityMap = serviceCapabilityMap.get(Service.Lb); @@ -3592,6 +3736,23 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } else { inline = false; } + + String publicLbStr = lbServiceCapabilityMap.get(Capability.LbSchemes); + if (serviceProviderMap.containsKey(Service.Lb)) { + if (publicLbStr != null) { + _networkModel.checkCapabilityForProvider(serviceProviderMap.get(Service.Lb), Service.Lb, Capability.LbSchemes, publicLbStr); + internalLb = publicLbStr.contains("internal"); + publicLb = publicLbStr.contains("public"); + } else { + //if not specified, default public lb to true + publicLb = true; + } + } + } + + //in the current version of the code, publicLb and specificLb can't both be set to true for the same network offering + if (publicLb && internalLb) { + throw new InvalidParameterValueException("Public lb and internal lb can't be enabled at the same time on the offering"); } Map sourceNatServiceCapabilityMap = serviceCapabilityMap.get(Service.SourceNat); @@ -3626,18 +3787,23 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati NetworkOfferingVO offering = new NetworkOfferingVO(name, displayText, trafficType, systemOnly, specifyVlan, networkRate, multicastRate, isDefault, availability, tags, type, conserveMode, dedicatedLb, - sharedSourceNat, redundantRouter, elasticIp, elasticLb, specifyIpRanges, inline, isPersistent, associatePublicIp); + sharedSourceNat, redundantRouter, elasticIp, elasticLb, specifyIpRanges, inline, isPersistent, associatePublicIp, publicLb, internalLb); if (serviceOfferingId != null) { offering.setServiceOfferingId(serviceOfferingId); } + + //validate the details + if (details != null) { + validateNtwkOffDetails(details, serviceProviderMap); + } Transaction txn = Transaction.currentTxn(); txn.start(); - // create network offering object + //1) create network offering object s_logger.debug("Adding network offering " + offering); - offering = _networkOfferingDao.persist(offering); - // populate services and providers + offering = _networkOfferingDao.persist(offering, details); + //2) populate services and providers if (serviceProviderMap != null) { for (Network.Service service : serviceProviderMap.keySet()) { Set providers = serviceProviderMap.get(service); @@ -3671,6 +3837,42 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati return offering; } + protected void validateNtwkOffDetails(Map details, Map> serviceProviderMap) { + for (Detail detail : details.keySet()) { + + Provider lbProvider = null; + if (detail == NetworkOffering.Detail.InternalLbProvider || detail == NetworkOffering.Detail.PublicLbProvider) { + //1) Vaidate the detail values - have to match the lb provider name + String providerStr = details.get(detail); + if (Network.Provider.getProvider(providerStr) == null) { + throw new InvalidParameterValueException("Invalid value " + providerStr + " for the detail " + detail); + } + if (serviceProviderMap.get(Service.Lb) != null) { + for (Provider provider : serviceProviderMap.get(Service.Lb)) { + if (provider.getName().equalsIgnoreCase(providerStr)) { + lbProvider = provider; + break; + } + } + } + + if (lbProvider == null) { + throw new InvalidParameterValueException("Invalid value " + details.get(detail) + + " for the detail " + detail + ". The provider is not supported by the network offering"); + } + + //2) validate if the provider supports the scheme + Set lbProviders = new HashSet(); + lbProviders.add(lbProvider); + if (detail == NetworkOffering.Detail.InternalLbProvider) { + _networkModel.checkCapabilityForProvider(lbProviders, Service.Lb, Capability.LbSchemes, Scheme.Internal.toString()); + } else if (detail == NetworkOffering.Detail.PublicLbProvider){ + _networkModel.checkCapabilityForProvider(lbProviders, Service.Lb, Capability.LbSchemes, Scheme.Public.toString()); + } + } + } + } + @Override public List searchForNetworkOfferings(ListNetworkOfferingsCmd cmd) { @@ -3896,6 +4098,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati public boolean isOfferingForVpc(NetworkOffering offering) { boolean vpcProvider = _ntwkOffServiceMapDao.isProviderForNetworkOffering(offering.getId(), Provider.VPCVirtualRouter); + boolean internalLb = offering.getInternalLb(); return vpcProvider; } @@ -4079,7 +4282,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } @Override - public Integer getNetworkOfferingNetworkRate(long networkOfferingId) { + public Integer getNetworkOfferingNetworkRate(long networkOfferingId, Long dataCenterId) { // validate network offering information NetworkOffering no = getNetworkOffering(networkOfferingId); @@ -4091,7 +4294,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if (no.getRateMbps() != null) { networkRate = no.getRateMbps(); } else { - networkRate = Integer.parseInt(_configDao.getValue(Config.NetworkThrottlingRate.key())); + networkRate = Integer.parseInt(_configServer.getConfigValue(Config.NetworkThrottlingRate.key(), Config.ConfigurationParameterScope.zone.toString(), dataCenterId)); } // networkRate is unsigned int in netowrkOfferings table, and can't be @@ -4227,7 +4430,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } @Override - public Integer getServiceOfferingNetworkRate(long serviceOfferingId) { + public Integer getServiceOfferingNetworkRate(long serviceOfferingId, Long dataCenterId) { // validate network offering information ServiceOffering offering = _serviceOfferingDao.findById(serviceOfferingId); @@ -4241,7 +4444,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } else { // for domain router service offering, get network rate from if (offering.getSystemVmType() != null && offering.getSystemVmType().equalsIgnoreCase(VirtualMachine.Type.DomainRouter.toString())) { - networkRate = Integer.parseInt(_configDao.getValue(Config.NetworkThrottlingRate.key())); + networkRate = Integer.parseInt(_configServer.getConfigValue(Config.NetworkThrottlingRate.key(), Config.ConfigurationParameterScope.zone.toString(), dataCenterId)); } else { networkRate = Integer.parseInt(_configDao.getValue(Config.VmNetworkThrottlingRate.key())); } diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java index c4ad8170d6d..9a7a46faf3d 100755 --- a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java @@ -5,7 +5,7 @@ // 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, @@ -23,7 +23,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.UUID; import javax.ejb.Local; import javax.inject.Inject; @@ -98,7 +97,6 @@ import com.cloud.resource.UnableDeleteHostException; import com.cloud.server.ManagementServer; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; -import com.cloud.servlet.ConsoleProxyPasswordBasedEncryptor; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePoolStatus; import com.cloud.storage.VMTemplateHostVO; @@ -263,186 +261,6 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy private final GlobalLock _allocProxyLock = GlobalLock.getInternLock(getAllocProxyLockName()); - /* - * private final String keyContent = - * "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALV5vGlkiWwoZX4hTRplPXP8qtST\n" - * + "hwZhko8noeY5vf8ECwmd+vrCTw/JvnOtkx/8oYNbg/SeUt1EfOsk6gqJdBblGFBZRMcUJlIpqE9z\n" + - * "uv68U9G8Gfi/qvRSY336hibw0J5bZ4vn1QqmyHDB+Czea9AjFUV7AEVG15+vED7why+/AgMBAAEC\n" - * + "gYBmFBPnNKYYMKDmUdUNA+WNWJK/ADzzWe8WlzR6TACTcbLDthl289WFC/YVG42mcHRpbxDKiEQU\n" + - * "MnIR0rHTO34Qb/2HcuyweStU2gqR6omxBvMnFpJr90nD1HcOMJzeLHsphau0/EmKKey+gk4PyieD\n" - * + "KqTM7LTjjHv8xPM4n+WAAQJBAOMNCeFKlJ4kMokWhU74B5/w/NGyT1BHUN0VmilHSiJC8JqS4BiI\n" + - * "ZpAeET3VmilO6QTGh2XVhEDGteu3uZR6ipUCQQDMnRzMgQ/50LFeIQo4IBtwlEouczMlPQF4c21R\n" - * + "1d720moxILVPT0NJZTQUDDmmgbL+B7CgtcCR2NlP5sKPZVADAkEAh4Xq1cy8dMBKYcVNgNtPQcqI\n" + - * "PWpfKR3ISI5yXB0vRNAL6Vet5zbTcUZhKDVtNSbis3UEsGYH8NorEC2z2cpjGQJANhJi9Ow6c5Mh\n" - * + "/DURBUn+1l5pyCKrZnDbvaALSLATLvjmFTuGjoHszy2OeKnOZmEqExWnKKE/VYuPyhy6V7i3TwJA\n" + - * "f8skDgtPK0OsBCa6IljPaHoWBjPc4kFkSTSS1d56hUcWSikTmiuKdLyBb85AADSZYsvHWrte4opN\n" + "dhNukMJuRA==\n"; - * - * private final String certContent = "-----BEGIN CERTIFICATE-----\n" + - * "MIIE3jCCA8agAwIBAgIFAqv56tIwDQYJKoZIhvcNAQEFBQAwgcoxCzAJBgNVBAYT\n" - * + "AlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYD\n" + - * "VQQKExFHb0RhZGR5LmNvbSwgSW5jLjEzMDEGA1UECxMqaHR0cDovL2NlcnRpZmlj\n" - * + "YXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5MTAwLgYDVQQDEydHbyBEYWRkeSBT\n" + - * "ZWN1cmUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxETAPBgNVBAUTCDA3OTY5Mjg3\n" - * + "MB4XDTA5MDIxMTA0NTc1NloXDTEyMDIwNzA1MTEyM1owWTEZMBcGA1UECgwQKi5y\n" + - * "ZWFsaG9zdGlwLmNvbTEhMB8GA1UECwwYRG9tYWluIENvbnRyb2wgVmFsaWRhdGVk\n" - * + "MRkwFwYDVQQDDBAqLnJlYWxob3N0aXAuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GN\n" + - * "ADCBiQKBgQC1ebxpZIlsKGV+IU0aZT1z/KrUk4cGYZKPJ6HmOb3/BAsJnfr6wk8P\n" - * + "yb5zrZMf/KGDW4P0nlLdRHzrJOoKiXQW5RhQWUTHFCZSKahPc7r+vFPRvBn4v6r0\n" + - * "UmN9+oYm8NCeW2eL59UKpshwwfgs3mvQIxVFewBFRtefrxA+8IcvvwIDAQABo4IB\n" - * + "vTCCAbkwDwYDVR0TAQH/BAUwAwEBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB\n" + - * "BQUHAwIwDgYDVR0PAQH/BAQDAgWgMDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6Ly9j\n" - * + "cmwuZ29kYWRkeS5jb20vZ2RzMS0yLmNybDBTBgNVHSAETDBKMEgGC2CGSAGG/W0B\n" + - * "BxcBMDkwNwYIKwYBBQUHAgEWK2h0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j\n" - * + "b20vcmVwb3NpdG9yeS8wgYAGCCsGAQUFBwEBBHQwcjAkBggrBgEFBQcwAYYYaHR0\n" + - * "cDovL29jc3AuZ29kYWRkeS5jb20vMEoGCCsGAQUFBzAChj5odHRwOi8vY2VydGlm\n" - * + "aWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvZ2RfaW50ZXJtZWRpYXRlLmNy\n" + - * "dDAfBgNVHSMEGDAWgBT9rGEyk2xF1uLuhV+auud2mWjM5zArBgNVHREEJDAighAq\n" - * + "LnJlYWxob3N0aXAuY29tgg5yZWFsaG9zdGlwLmNvbTAdBgNVHQ4EFgQUHxwmdK5w\n" + - * "9/YVeZ/3fHyi6nQfzoYwDQYJKoZIhvcNAQEFBQADggEBABv/XinvId6oWXJtmku+\n" - * + "7m90JhSVH0ycoIGjgdaIkcExQGP08MCilbUsPcbhLheSFdgn/cR4e1MP083lacoj\n" + - * "OGauY7b8f/cuquGkT49Ns14awPlEzRjjycQEjjLxFEuL5CFWa2t2gKRE1dSfhDQ+\n" - * + "fJ6GBCs1XgZLuhkKS8fPf+YmG2ZjHzYDjYoSx7paDXgEm+kbYIZdCK51lA0BUAjP\n" + - * "9ZMGhsu/PpAbh5U/DtcIqxY0xeqD4TeGsBzXg6uLhv+jKHDtXg5fYPe+z0n5DCEL\n" - * + "k0fLF4+i/pt9hVCz0QrZ28RUhXf825+EOL0Gw+Uzt+7RV2cCaJrlu4cDrDom2FRy\n" + "E8I=\n" + - * "-----END CERTIFICATE-----\n"; - */ - public static final String keyContent = - "-----BEGIN PRIVATE KEY-----\n" + - "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCDT9AtEfs+s/I8QXp6rrCw0iNJ\n" + - "0+GgsybNHheU+JpL39LMTZykCrZhZnyDvwdxCoOfE38Sa32baHKNds+y2SHnMNsOkw8OcNucHEBX\n" + - "1FIpOBGph9D6xC+umx9od6xMWETUv7j6h2u+WC3OhBM8fHCBqIiAol31/IkcqDxxsHlQ8S/oCfTl\n" + - "XJUY6Yn628OA1XijKdRnadV0hZ829cv/PZKljjwQUTyrd0KHQeksBH+YAYSo2JUl8ekNLsOi8/cP\n" + - "tfojnltzRI1GXi0ZONs8VnDzJ0a2gqZY+uxlz+CGbLnGnlN4j9cBpE+MfUE+35Dq121sTpsSgF85\n" + - "Mz+pVhn2S633AgMBAAECggEAH/Szd9RxbVADenCA6wxKSa3KErRyq1YN8ksJeCKMAj0FIt0caruE\n" + - "qO11DebWW8cwQu1Otl/cYI6pmg24/BBldMrp9IELX/tNJo+lhPpRyGAxxC0eSXinFfoASb8d+jJd\n" + - "Bd1mmemM6fSxqRlxSP4LrzIhjhR1g2CiyYuTsiM9UtoVKGyHwe7KfFwirUOJo3Mr18zUVNm7YqY4\n" + - "IVhOSq59zkH3ULBlYq4bG50jpxa5mNSCZ7IpafPY/kE/CbR+FWNt30+rk69T+qb5abg6+XGm+OAm\n" + - "bnQ18yZEqX6nJLk7Ch0cfA5orGgrTMOrM71wK7tBBDQ308kOxDGebx6j0qD36QKBgQDTRDr8kuhA\n" + - "9sUyKr9vk2DQCMpNvEeiwI3JRMqmmxpNAtg01aJ3Ya57vX5Fc+zcuV87kP6FM1xgpHQvnw5LWo2J\n" + - "s7ANwQcP8ricEW5zkZhSjI4ssMeAubmsHOloGxmLFYZqwx0JI7CWViGTLMcUlqKblmHcjeQDeDfP\n" + - "P1TaCItFmwKBgQCfHZwVvIcaDs5vxVpZ4ftvflIrW8qq0uOVK6QIf9A/YTGhCXl2qxxTg2A6+0rg\n" + - "ZqI7zKzUDxIbVv0KlgCbpHDC9d5+sdtDB3wW2pimuJ3p1z4/RHb4n/lDwXCACZl1S5l24yXX2pFZ\n" + - "wdPCXmy5PYkHMssFLNhI24pprUIQs66M1QKBgQDQwjAjWisD3pRXESSfZRsaFkWJcM28hdbVFhPF\n" + - "c6gWhwQLmTp0CuL2RPXcPUPFi6sN2iWWi3zxxi9Eyz+9uBn6AsOpo56N5MME/LiOnETO9TKb+Ib6\n" + - "rQtKhjshcv3XkIqFPo2XdVvOAgglPO7vajX91iiXXuH7h7RmJud6l0y/lwKBgE+bi90gLuPtpoEr\n" + - "VzIDKz40ED5bNYHT80NNy0rpT7J2GVN9nwStRYXPBBVeZq7xCpgqpgmO5LtDAWULeZBlbHlOdBwl\n" + - "NhNKKl5wzdEUKwW0yBL1WSS5PQgWPwgARYP25/ggW22sj+49WIo1neXsEKPGWObk8e050f1fTt92\n" + - "Vo1lAoGAb1gCoyBCzvi7sqFxm4V5oapnJeiQQJFjhoYWqGa26rQ+AvXXNuBcigIeDXNJPctSF0Uc\n" + - "p11KbbCgiruBbckvM1vGsk6Sx4leRk+IFHRpJktFUek4o0eUg0shOsyyvyet48Dfg0a8FvcxROs0\n" + - "gD+IYds5doiob/hcm1hnNB/3vk4=\n" + - "-----END PRIVATE KEY-----\n"; - - public static final String certContent = - "-----BEGIN CERTIFICATE-----\n" + - "MIIFZTCCBE2gAwIBAgIHKBCduBUoKDANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE\n" + - "BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY\n" + - "BgNVBAoTEUdvRGFkZHkuY29tLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydGlm\n" + - "aWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkxMDAuBgNVBAMTJ0dvIERhZGR5\n" + - "IFNlY3VyZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTERMA8GA1UEBRMIMDc5Njky\n" + - "ODcwHhcNMTIwMjAzMDMzMDQwWhcNMTcwMjA3MDUxMTIzWjBZMRkwFwYDVQQKDBAq\n" + - "LnJlYWxob3N0aXAuY29tMSEwHwYDVQQLDBhEb21haW4gQ29udHJvbCBWYWxpZGF0\n" + - "ZWQxGTAXBgNVBAMMECoucmVhbGhvc3RpcC5jb20wggEiMA0GCSqGSIb3DQEBAQUA\n" + - "A4IBDwAwggEKAoIBAQCDT9AtEfs+s/I8QXp6rrCw0iNJ0+GgsybNHheU+JpL39LM\n" + - "TZykCrZhZnyDvwdxCoOfE38Sa32baHKNds+y2SHnMNsOkw8OcNucHEBX1FIpOBGp\n" + - "h9D6xC+umx9od6xMWETUv7j6h2u+WC3OhBM8fHCBqIiAol31/IkcqDxxsHlQ8S/o\n" + - "CfTlXJUY6Yn628OA1XijKdRnadV0hZ829cv/PZKljjwQUTyrd0KHQeksBH+YAYSo\n" + - "2JUl8ekNLsOi8/cPtfojnltzRI1GXi0ZONs8VnDzJ0a2gqZY+uxlz+CGbLnGnlN4\n" + - "j9cBpE+MfUE+35Dq121sTpsSgF85Mz+pVhn2S633AgMBAAGjggG+MIIBujAPBgNV\n" + - "HRMBAf8EBTADAQEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAOBgNV\n" + - "HQ8BAf8EBAMCBaAwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5nb2RhZGR5\n" + - "LmNvbS9nZHMxLTY0LmNybDBTBgNVHSAETDBKMEgGC2CGSAGG/W0BBxcBMDkwNwYI\n" + - "KwYBBQUHAgEWK2h0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3Np\n" + - "dG9yeS8wgYAGCCsGAQUFBwEBBHQwcjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au\n" + - "Z29kYWRkeS5jb20vMEoGCCsGAQUFBzAChj5odHRwOi8vY2VydGlmaWNhdGVzLmdv\n" + - "ZGFkZHkuY29tL3JlcG9zaXRvcnkvZ2RfaW50ZXJtZWRpYXRlLmNydDAfBgNVHSME\n" + - "GDAWgBT9rGEyk2xF1uLuhV+auud2mWjM5zArBgNVHREEJDAighAqLnJlYWxob3N0\n" + - "aXAuY29tgg5yZWFsaG9zdGlwLmNvbTAdBgNVHQ4EFgQUZyJz9/QLy5TWIIscTXID\n" + - "E8Xk47YwDQYJKoZIhvcNAQEFBQADggEBAKiUV3KK16mP0NpS92fmQkCLqm+qUWyN\n" + - "BfBVgf9/M5pcT8EiTZlS5nAtzAE/eRpBeR3ubLlaAogj4rdH7YYVJcDDLLoB2qM3\n" + - "qeCHu8LFoblkb93UuFDWqRaVPmMlJRnhsRkL1oa2gM2hwQTkBDkP7w5FG1BELCgl\n" + - "gZI2ij2yxjge6pOEwSyZCzzbCcg9pN+dNrYyGEtB4k+BBnPA3N4r14CWbk+uxjrQ\n" + - "6j2Ip+b7wOc5IuMEMl8xwTyjuX3lsLbAZyFI9RCyofwA9NqIZ1GeB6Zd196rubQp\n" + - "93cmBqGGjZUs3wMrGlm7xdjlX6GQ9UvmvkMub9+lL99A5W50QgCmFeI=\n" + - "-----END CERTIFICATE-----\n"; - - public static final String rootCa = - "-----BEGIN CERTIFICATE-----\n" + - "MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMx\n" + - "ITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g\n" + - "RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYw\n" + - "MTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH\n" + - "QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j\n" + - "b20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j\n" + - "b20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmlj\n" + - "YXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcN\n" + - "AQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3H\n" + - "KrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQm\n" + - "VZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpR\n" + - "SgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRT\n" + - "cDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ\n" + - "6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEu\n" + - "MB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDS\n" + - "kdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEB\n" + - "BCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0f\n" + - "BD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBv\n" + - "c2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUH\n" + - "AgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAO\n" + - "BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IG\n" + - "OgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMU\n" + - "A2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o\n" + - "0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTX\n" + - "RE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuH\n" + - "qDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWV\n" + - "U+4=\n" + - "-----END CERTIFICATE-----\n" + - "-----BEGIN CERTIFICATE-----\n" + - "MIIE+zCCBGSgAwIBAgICAQ0wDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1Zh\n" + - "bGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu\n" + - "Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g\n" + - "QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAe\n" + - "BgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MDYyMFoX\n" + - "DTI0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBE\n" + - "YWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0\n" + - "aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgC\n" + - "ggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv\n" + - "2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+q\n" + - "N1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiO\n" + - "r18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lN\n" + - "f4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+YihfukEH\n" + - "U1jPEX44dMX4/7VpkI+EdOqXG68CAQOjggHhMIIB3TAdBgNVHQ4EFgQU0sSw0pHU\n" + - "TBFxs2HLPaH+3ahq1OMwgdIGA1UdIwSByjCBx6GBwaSBvjCBuzEkMCIGA1UEBxMb\n" + - "VmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwg\n" + - "SW5jLjE1MDMGA1UECxMsVmFsaUNlcnQgQ2xhc3MgMiBQb2xpY3kgVmFsaWRhdGlv\n" + - "biBBdXRob3JpdHkxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQuY29tLzEg\n" + - "MB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb22CAQEwDwYDVR0TAQH/BAUw\n" + - "AwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmdv\n" + - "ZGFkZHkuY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jZXJ0aWZpY2F0ZXMu\n" + - "Z29kYWRkeS5jb20vcmVwb3NpdG9yeS9yb290LmNybDBLBgNVHSAERDBCMEAGBFUd\n" + - "IAAwODA2BggrBgEFBQcCARYqaHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNv\n" + - "bS9yZXBvc2l0b3J5MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQC1\n" + - "QPmnHfbq/qQaQlpE9xXUhUaJwL6e4+PrxeNYiY+Sn1eocSxI0YGyeR+sBjUZsE4O\n" + - "WBsUs5iB0QQeyAfJg594RAoYC5jcdnplDQ1tgMQLARzLrUc+cb53S8wGd9D0Vmsf\n" + - "SxOaFIqII6hR8INMqzW/Rn453HWkrugp++85j09VZw==\n" + - "-----END CERTIFICATE-----\n" + - "-----BEGIN CERTIFICATE-----\n" + - "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n" + - "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz\n" + - "BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y\n" + - "aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG\n" + - "9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy\n" + - "NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y\n" + - "azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs\n" + - "YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw\n" + - "Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl\n" + - "cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY\n" + - "dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9\n" + - "WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS\n" + - "v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v\n" + - "UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu\n" + - "IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC\n" + - "W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd\n" + - "-----END CERTIFICATE-----\n"; - @Inject private KeystoreDao _ksDao; @Inject @@ -781,7 +599,7 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy if(proxy.getActiveSession() >= _capacityPerProxy){ it.remove(); } - } + } if (s_logger.isTraceEnabled()) { s_logger.trace("Running proxy pool size : " + runningList.size()); for (ConsoleProxyVO proxy : runningList) { @@ -1338,7 +1156,7 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy //expunge the vm boolean result = _itMgr.expunge(proxy, _accountMgr.getSystemUser(), _accountMgr.getSystemAccount()); if (result) { - HostVO host = _hostDao.findByTypeNameAndZoneId(proxy.getDataCenterId(), proxy.getHostName(), + HostVO host = _hostDao.findByTypeNameAndZoneId(proxy.getDataCenterId(), proxy.getHostName(), Host.Type.ConsoleProxy); if (host != null) { s_logger.debug("Removing host entry for proxy id=" + vmId); @@ -1363,9 +1181,9 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy if (lock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) { KeystoreVO ksVo = _ksDao.findByName(CERTIFICATE_NAME); if (ksVo == null) { - _ksDao.save(CERTIFICATE_NAME, certContent, keyContent, "realhostip.com"); + _ksDao.save(CERTIFICATE_NAME, ConsoleProxyVO.certContent, ConsoleProxyVO.keyContent, "realhostip.com"); KeystoreVO caRoot = new KeystoreVO(); - caRoot.setCertificate(rootCa); + caRoot.setCertificate(ConsoleProxyVO.rootCa); caRoot.setDomainSuffix("realhostip.com"); caRoot.setName("root"); caRoot.setIndex(0); @@ -1906,5 +1724,5 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy @Override public void prepareStop(VirtualMachineProfile profile) { } - + } diff --git a/server/src/com/cloud/deploy/FirstFitPlanner.java b/server/src/com/cloud/deploy/FirstFitPlanner.java index 1647cf7dba9..e8504a991c1 100755 --- a/server/src/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/com/cloud/deploy/FirstFitPlanner.java @@ -452,21 +452,6 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { return disabledPods; } - private Map getCapacityThresholdMap(){ - // Lets build this real time so that the admin wont have to restart MS if he changes these values - Map disableThresholdMap = new HashMap(); - - String cpuDisableThresholdString = _configDao.getValue(Config.CPUCapacityDisableThreshold.key()); - float cpuDisableThreshold = NumbersUtil.parseFloat(cpuDisableThresholdString, 0.85F); - disableThresholdMap.put(Capacity.CAPACITY_TYPE_CPU, cpuDisableThreshold); - - String memoryDisableThresholdString = _configDao.getValue(Config.MemoryCapacityDisableThreshold.key()); - float memoryDisableThreshold = NumbersUtil.parseFloat(memoryDisableThresholdString, 0.85F); - disableThresholdMap.put(Capacity.CAPACITY_TYPE_MEMORY, memoryDisableThreshold); - - return disableThresholdMap; - } - private List getCapacitiesForCheckingThreshold(){ List capacityList = new ArrayList(); capacityList.add(Capacity.CAPACITY_TYPE_CPU); @@ -476,7 +461,6 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { private void removeClustersCrossingThreshold(List clusterListForVmAllocation, ExcludeList avoid, VirtualMachineProfile vmProfile, DeploymentPlan plan){ - Map capacityThresholdMap = getCapacityThresholdMap(); List capacityList = getCapacitiesForCheckingThreshold(); List clustersCrossingThreshold = new ArrayList(); @@ -491,12 +475,11 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { return; } if (capacity == Capacity.CAPACITY_TYPE_CPU) { - clustersCrossingThreshold = _capacityDao.listClustersCrossingThreshold(capacity, plan.getDataCenterId(), - capacityThresholdMap.get(capacity), cpu_requested); + clustersCrossingThreshold = _capacityDao.listClustersCrossingThreshold(capacity, plan.getDataCenterId(), Config.CPUCapacityDisableThreshold.key(), cpu_requested); } else if (capacity == Capacity.CAPACITY_TYPE_MEMORY ) { clustersCrossingThreshold = _capacityDao.listClustersCrossingThreshold(capacity, plan.getDataCenterId(), - capacityThresholdMap.get(capacity), ram_requested ); + Config.MemoryCapacityDisableThreshold.key(), ram_requested ); } @@ -506,8 +489,8 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { // Remove clusters crossing disabled threshold clusterListForVmAllocation.removeAll(clustersCrossingThreshold); - s_logger.debug("Cannot allocate cluster list " + clustersCrossingThreshold.toString() + " for vm creation since their allocated percentage" + - " crosses the disable capacity threshold: " + capacityThresholdMap.get(capacity) + " for capacity Type : " + capacity + ", skipping these clusters"); + s_logger.debug("Cannot allocate cluster list " + clustersCrossingThreshold.toString() + " for vm creation since their allocated percentage" + + " crosses the disable capacity threshold defined at each cluster/ at global value for capacity Type : " + capacity + ", skipping these clusters"); } } @@ -748,37 +731,43 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { //If the plan specifies a poolId, it means that this VM's ROOT volume is ready and the pool should be reused. //In this case, also check if rest of the volumes are ready and can be reused. if(plan.getPoolId() != null){ - s_logger.debug("Volume has pool already allocated, checking if pool can be reused, poolId: "+toBeCreated.getPoolId()); + s_logger.debug("Volume has pool(" + plan.getPoolId() + ") already allocated, checking if pool can be reused, poolId: "+toBeCreated.getPoolId()); List suitablePools = new ArrayList(); StoragePool pool = null; if(toBeCreated.getPoolId() != null){ + s_logger.debug("finding pool by id '" + toBeCreated.getPoolId() + "'"); pool = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(toBeCreated.getPoolId()); }else{ + s_logger.debug("finding pool by id '" + plan.getPoolId() + "'"); pool = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(plan.getPoolId()); } - if(!pool.isInMaintenance()){ - if(!avoid.shouldAvoid(pool)){ - long exstPoolDcId = pool.getDataCenterId(); + if(pool != null){ + if(!pool.isInMaintenance()){ + if(!avoid.shouldAvoid(pool)){ + long exstPoolDcId = pool.getDataCenterId(); - long exstPoolPodId = pool.getPodId() != null ? pool.getPodId() : -1; - long exstPoolClusterId = pool.getClusterId() != null ? pool.getClusterId() : -1; - if(plan.getDataCenterId() == exstPoolDcId && plan.getPodId() == exstPoolPodId && plan.getClusterId() == exstPoolClusterId){ - s_logger.debug("Planner need not allocate a pool for this volume since its READY"); - suitablePools.add(pool); - suitableVolumeStoragePools.put(toBeCreated, suitablePools); - if (!(toBeCreated.getState() == Volume.State.Allocated || toBeCreated.getState() == Volume.State.Creating)) { - readyAndReusedVolumes.add(toBeCreated); + long exstPoolPodId = pool.getPodId() != null ? pool.getPodId() : -1; + long exstPoolClusterId = pool.getClusterId() != null ? pool.getClusterId() : -1; + if(plan.getDataCenterId() == exstPoolDcId && plan.getPodId() == exstPoolPodId && plan.getClusterId() == exstPoolClusterId){ + s_logger.debug("Planner need not allocate a pool for this volume since its READY"); + suitablePools.add(pool); + suitableVolumeStoragePools.put(toBeCreated, suitablePools); + if (!(toBeCreated.getState() == Volume.State.Allocated || toBeCreated.getState() == Volume.State.Creating)) { + readyAndReusedVolumes.add(toBeCreated); + } + continue; + }else{ + s_logger.debug("Pool of the volume does not fit the specified plan, need to reallocate a pool for this volume"); } - continue; }else{ - s_logger.debug("Pool of the volume does not fit the specified plan, need to reallocate a pool for this volume"); + s_logger.debug("Pool of the volume is in avoid set, need to reallocate a pool for this volume"); } }else{ - s_logger.debug("Pool of the volume is in avoid set, need to reallocate a pool for this volume"); + s_logger.debug("Pool of the volume is in maintenance, need to reallocate a pool for this volume"); } }else{ - s_logger.debug("Pool of the volume is in maintenance, need to reallocate a pool for this volume"); + s_logger.debug("Unable to find pool by provided id"); } } diff --git a/server/src/com/cloud/maint/AgentUpgradeVO.java b/server/src/com/cloud/maint/AgentUpgradeVO.java deleted file mode 100644 index b36f5b7dd6c..00000000000 --- a/server/src/com/cloud/maint/AgentUpgradeVO.java +++ /dev/null @@ -1,63 +0,0 @@ -// 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. -package com.cloud.maint; - -import org.apache.cloudstack.api.InternalIdentity; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.Id; -import javax.persistence.Table; - - -@Entity -@Table(name="op_host_upgrade") -public class AgentUpgradeVO implements InternalIdentity { - @Id - @Column(name="host_id") - private long id; - - @Column(name="version") - private String version; - - @Column(name="state") - @Enumerated(value=EnumType.STRING) - private UpgradeManager.State state; - - protected AgentUpgradeVO() { - } - - public AgentUpgradeVO(long id, String version, UpgradeManager.State state) { - this.id = id; - this.version = version; - this.state = state; - } - - public long getId() { - return id; - } - - public String getVersion() { - return version; - } - - public UpgradeManager.State getState() { - return state; - } -} diff --git a/server/src/com/cloud/maint/UpgradeManager.java b/server/src/com/cloud/maint/UpgradeManager.java deleted file mode 100644 index 71bca225b32..00000000000 --- a/server/src/com/cloud/maint/UpgradeManager.java +++ /dev/null @@ -1,47 +0,0 @@ -// 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. -package com.cloud.maint; - -import com.cloud.utils.component.Manager; - -/** - * Upgrade Manager manages the upgrade of agents. - * - */ -public interface UpgradeManager extends Manager { - enum State { - RequiresUpdate, - WaitingForUpdate, - UpToDate; - }; - - /** - * Checks if the agent requires an upgrade before it can process - * any commands. - * - * @param hostId host id. - * @return state of the agent. - */ - State registerForUpgrade(long hostId, String version); - - /** - * @return the URL to download the new agent. - */ -// String getAgentUrl(); - - -} diff --git a/server/src/com/cloud/maint/UpgradeManagerImpl.java b/server/src/com/cloud/maint/UpgradeManagerImpl.java deleted file mode 100644 index 54e1ff4401e..00000000000 --- a/server/src/com/cloud/maint/UpgradeManagerImpl.java +++ /dev/null @@ -1,189 +0,0 @@ -// 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. -package com.cloud.maint; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.nio.ByteBuffer; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.nio.channels.WritableByteChannel; -import java.util.Date; -import java.util.Map; -import java.util.Properties; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpException; -import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; -import org.apache.commons.httpclient.methods.GetMethod; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.maint.dao.AgentUpgradeDao; -import com.cloud.utils.PropertiesUtil; -import com.cloud.utils.component.ManagerBase; - -/** - * - * UpgradeManagerImpl implements the upgrade process. It's functionalities - * include - * 1. Identifying agents that require an upgrade before it can connect. - * 2. Spread out a release update to agents so that the entire system - * does not come down at the same time. - */ -@Component -@Local(UpgradeManager.class) -public class UpgradeManagerImpl extends ManagerBase implements UpgradeManager { - private final static Logger s_logger = Logger.getLogger(UpgradeManagerImpl.class); - private static final MultiThreadedHttpConnectionManager s_httpClientManager = new MultiThreadedHttpConnectionManager(); - - String _minimalVersion; - String _recommendedVersion; -// String _upgradeUrl; - String _agentPath; - long _checkInterval; - - @Inject AgentUpgradeDao _upgradeDao; - @Inject ConfigurationDao _configDao; - - @Override - public State registerForUpgrade(long hostId, String version) { - State state = State.UpToDate; - s_logger.debug("Minimal version is " + _minimalVersion + "; version is " + version + "; recommended version is " + _recommendedVersion); - if (Version.compare(version, _minimalVersion) < 0) { - state = State.RequiresUpdate; - } else if (Version.compare(version, _recommendedVersion) < 0) { - state = State.WaitingForUpdate; - } else { - state = State.UpToDate; - } - - /* - if (state != State.UpToDate) { - AgentUpgradeVO vo = _upgradeDao.findById(hostId); - if (vo == null) { - vo = new AgentUpgradeVO(hostId, version, state); - _upgradeDao.persist(vo); - } - } - */ - - return state; - } - - public String deployNewAgent(String url) { - s_logger.info("Updating agent with binary from " + url); - - final HttpClient client = new HttpClient(s_httpClientManager); - final GetMethod method = new GetMethod(url); - int response; - File file = null; - try { - response = client.executeMethod(method); - if (response != HttpURLConnection.HTTP_OK) { - s_logger.warn("Retrieving the agent gives response code: " + response); - return "Retrieving the file from " + url + " got response code: " + response; - } - - final InputStream is = method.getResponseBodyAsStream(); - file = File.createTempFile("agent-", "-" + Long.toString(new Date().getTime())); - file.deleteOnExit(); - - s_logger.debug("Retrieving new agent into " + file.getAbsolutePath()); - - final FileOutputStream fos = new FileOutputStream(file); - - final ByteBuffer buffer = ByteBuffer.allocate(2048); - final ReadableByteChannel in = Channels.newChannel(is); - final WritableByteChannel out = fos.getChannel(); - - while (in.read(buffer) != -1) { - buffer.flip(); - out.write(buffer); - buffer.clear(); - } - - in.close(); - out.close(); - - s_logger.debug("New Agent zip file is now retrieved"); - } catch (final HttpException e) { - return "Unable to retrieve the file from " + url; - } catch (final IOException e) { - return "Unable to retrieve the file from " + url; - } finally { - method.releaseConnection(); - } - - file.delete(); - - return "File will be deployed."; - } - -// @Override -// public String getAgentUrl() { -// return _upgradeUrl; -// } - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - - final Map configs = _configDao.getConfiguration("UpgradeManager", params); - - File agentUpgradeFile = PropertiesUtil.findConfigFile("agent-update.properties"); - Properties agentUpgradeProps = new Properties(); - try { - if (agentUpgradeFile != null) { - agentUpgradeProps.load(new FileInputStream(agentUpgradeFile)); - } - - _minimalVersion = agentUpgradeProps.getProperty("agent.minimal.version"); - _recommendedVersion = agentUpgradeProps.getProperty("agent.recommended.version"); - - if (_minimalVersion == null) { - _minimalVersion = "0.0.0.0"; - } - - if (_recommendedVersion == null) { - _recommendedVersion = _minimalVersion; - } - - //_upgradeUrl = configs.get("upgrade.url"); - -// if (_upgradeUrl == null) { -// s_logger.debug("There is no upgrade url found in configuration table"); -// // _upgradeUrl = "http://updates.vmops.com/releases/rss.xml"; -// } - - return true; - } catch (IOException ex) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Error reading agent-update.properties: " + ex); - } - } - return false; - } -} diff --git a/server/src/com/cloud/migration/Db21to22MigrationUtil.java b/server/src/com/cloud/migration/Db21to22MigrationUtil.java deleted file mode 100755 index 66a7d59f53a..00000000000 --- a/server/src/com/cloud/migration/Db21to22MigrationUtil.java +++ /dev/null @@ -1,228 +0,0 @@ -// 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. -package com.cloud.migration; - -import java.io.File; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.util.List; - -import javax.inject.Inject; - -import org.apache.log4j.xml.DOMConfigurator; - -import com.cloud.configuration.Resource; -import com.cloud.configuration.Resource.ResourceType; -import com.cloud.configuration.ResourceCountVO; -import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.configuration.dao.ResourceCountDao; -import com.cloud.dc.DataCenter.NetworkType; -import com.cloud.dc.DataCenterVO; -import com.cloud.dc.dao.ClusterDao; -import com.cloud.dc.dao.DataCenterDao; -import com.cloud.domain.DomainVO; -import com.cloud.domain.dao.DomainDao; -import com.cloud.host.dao.HostDao; -import com.cloud.resource.ResourceManager; -import com.cloud.user.Account; -import com.cloud.user.dao.AccountDao; -import com.cloud.utils.PropertiesUtil; -import com.cloud.utils.db.SearchBuilder; -import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.Transaction; -import com.cloud.vm.InstanceGroupVMMapVO; -import com.cloud.vm.InstanceGroupVO; -import com.cloud.vm.dao.InstanceGroupDao; -import com.cloud.vm.dao.InstanceGroupVMMapDao; - -public class Db21to22MigrationUtil { - - @Inject private ClusterDao _clusterDao; - @Inject private HostDao _hostDao; - @Inject private AccountDao _accountDao; - @Inject private DomainDao _domainDao; - @Inject private ResourceCountDao _resourceCountDao; - @Inject private InstanceGroupDao _vmGroupDao; - @Inject private InstanceGroupVMMapDao _groupVMMapDao; - @Inject private ConfigurationDao _configurationDao; - @Inject private DataCenterDao _zoneDao; - @Inject private ResourceManager _resourceMgr; - - private void doMigration() { - setupComponents(); - - migrateResourceCounts(); - - setupInstanceGroups(); - - migrateZones(); - - setupClusterGuid(); - - System.out.println("Migration done"); - } - - /* add guid in cluster table */ - private void setupClusterGuid() { - - //FIXME moving out XenServer code out of server. This upgrade step need to be taken care of - /* - XenServerConnectionPool _connPool = XenServerConnectionPool.getInstance(); - List clusters = _clusterDao.listByHyTypeWithoutGuid(HypervisorType.XenServer.toString()); - for (ClusterVO cluster : clusters) { - List hosts = _resourceMgr.listAllHostsInCluster(cluster.getId()); - for (HostVO host : hosts) { - String ip = host.getPrivateIpAddress(); - String username = host.getDetail("username"); - String password = host.getDetail("password"); - if (ip == null || ip.isEmpty() || username == null || username.isEmpty() || password == null - || password.isEmpty()) { - continue; - } - Queue pass=new LinkedList(); - pass.add(password); - Connection conn = _connPool.slaveConnect(ip, username, pass); - if (conn == null) - continue; - Pool.Record pr = null; - try { - pr = XenServerConnectionPool.getPoolRecord(conn); - } catch (Exception e) { - continue; - } finally { - try { - Session.localLogout(conn); - } catch (Exception e) { - } - } - cluster.setGuid(pr.uuid); - _clusterDao.update(cluster.getId(), cluster); - break; - } - } - */ - } - - - /** - * This method migrates the zones based on bug: 7204 - * based on the param direct.attach.untagged.vlan.enabled, we update zone to basic or advanced for 2.2 - */ - private void migrateZones(){ - try { - System.out.println("Migrating zones"); - String val = _configurationDao.getValue("direct.attach.untagged.vlan.enabled"); - NetworkType networkType; - if(val == null || val.equalsIgnoreCase("true")){ - networkType = NetworkType.Basic; - }else{ - networkType = NetworkType.Advanced; - } - List existingZones = _zoneDao.listAll(); - for(DataCenterVO zone : existingZones){ - zone.setNetworkType(networkType); - _zoneDao.update(zone.getId(), zone); - } - } catch (Exception e) { - System.out.println("Unhandled exception in migrateZones()" + e); - } - } - - private void migrateResourceCounts() { - System.out.println("migrating resource counts"); - SearchBuilder sb = _resourceCountDao.createSearchBuilder(); - sb.and("type", sb.entity().getType(), SearchCriteria.Op.EQ); - - for (ResourceType type : Resource.ResourceType.values()) { - SearchCriteria sc = sb.create(); - sc.setParameters("type", type); - - List resourceCounts = _resourceCountDao.search(sc, null); - for (ResourceCountVO resourceCount : resourceCounts) { - if (resourceCount.getAccountId() != null) { - Account acct = _accountDao.findById(resourceCount.getAccountId()); - Long domainId = acct.getDomainId(); - while (domainId != null) { - _resourceCountDao.updateDomainCount(domainId, type, true, resourceCount.getCount()); - DomainVO domain = _domainDao.findById(domainId); - domainId = domain.getParent(); - } - } - } - } - System.out.println("done migrating resource counts"); - } - - private void setupComponents() { - } - - private void setupInstanceGroups() { - System.out.println("setting up vm instance groups"); - - //Search for all the vms that have not null groups - Long vmId = 0L; - Long accountId = 0L; - String groupName; - Transaction txn = Transaction.open(Transaction.CLOUD_DB); - txn.start(); - try { - String request = "SELECT vm.id, uservm.account_id, vm.group from vm_instance vm, user_vm uservm where vm.group is not null and vm.removed is null and vm.id=uservm.id order by id"; - System.out.println(request); - PreparedStatement statement = txn.prepareStatement(request); - ResultSet result = statement.executeQuery(); - while (result.next()) { - vmId = result.getLong(1); - accountId = result.getLong(2); - groupName = result.getString(3); - InstanceGroupVO group = _vmGroupDao.findByAccountAndName(accountId, groupName); - //Create vm group if the group doesn't exist for this account - if (group == null) { - group = new InstanceGroupVO(groupName, accountId); - group = _vmGroupDao.persist(group); - System.out.println("Created new isntance group with name " + groupName + " for account id=" + accountId); - } - - if (group != null) { - InstanceGroupVMMapVO groupVmMapVO = new InstanceGroupVMMapVO(group.getId(), vmId); - _groupVMMapDao.persist(groupVmMapVO); - System.out.println("Assigned vm id=" + vmId + " to group with name " + groupName + " for account id=" + accountId); - } - } - txn.commit(); - statement.close(); - } catch (Exception e) { - System.out.println("Unhandled exception: " + e); - } finally { - txn.close(); - } - } - - - public static void main(String[] args) { - File file = PropertiesUtil.findConfigFile("log4j-cloud.xml"); - - if (file != null) { - System.out.println("Log4j configuration from : " + file.getAbsolutePath()); - DOMConfigurator.configureAndWatch(file.getAbsolutePath(), 10000); - } else { - System.out.println("Configure log4j with default properties"); - } - - new Db21to22MigrationUtil().doMigration(); - System.exit(0); - } -} diff --git a/server/src/com/cloud/migration/Db22beta4to22GAMigrationUtil.java b/server/src/com/cloud/migration/Db22beta4to22GAMigrationUtil.java deleted file mode 100644 index 4487d654571..00000000000 --- a/server/src/com/cloud/migration/Db22beta4to22GAMigrationUtil.java +++ /dev/null @@ -1,128 +0,0 @@ -// 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. -package com.cloud.migration; - -import java.io.File; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import org.apache.log4j.xml.DOMConfigurator; - -import com.cloud.utils.PropertiesUtil; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.Transaction; -import com.cloud.utils.exception.CloudRuntimeException; - -@DB(txn=false) -public class Db22beta4to22GAMigrationUtil { - - private Map pfRuleIdToIpAddressIdMap = new HashMap(); - private final String FindPfIdToPublicIpId = "SELECT id,ip_address_id from firewall_rules where is_static_nat=1"; - private final String FindVmIdPerPfRule = "SELECT instance_id from port_forwarding_rules where id = ?"; - private final String WriteVmIdToIpAddrTable = "UPDATE user_ip_address set vm_id = ? where id = ?"; - protected Db22beta4to22GAMigrationUtil() { - } - - @DB - //This method gets us a map of pf/firewall id <-> ip address id - //Using the keyset, we will iterate over the pf table to find corresponding vm id - //When we get the vm id, we will use the val for each key to update the corresponding ip addr row with the vm id - public void populateMap(){ - Long key = null; - Long val = null; - - Transaction txn = Transaction.open(Transaction.CLOUD_DB); - - StringBuilder sql = new StringBuilder(FindPfIdToPublicIpId); - - PreparedStatement pstmt = null; - try { - pstmt = txn.prepareAutoCloseStatement(sql.toString()); - - ResultSet rs = pstmt.executeQuery(); - while (rs.next()) { - key = rs.getLong("id"); - val = rs.getLong("ip_address_id"); - pfRuleIdToIpAddressIdMap.put(key, val); - } - - } catch (SQLException e) { - throw new CloudRuntimeException("Unable to execute " + pstmt.toString(), e); - } - - } - - @DB - public void updateVmIdForIpAddresses(){ - Transaction txn = Transaction.open(Transaction.CLOUD_DB); - Set pfIds = pfRuleIdToIpAddressIdMap.keySet(); - StringBuilder sql = new StringBuilder(FindVmIdPerPfRule); - Long vmId = null; - Long ipAddressId = null; - PreparedStatement pstmt = null; - for(Long pfId : pfIds){ - try { - pstmt = txn.prepareAutoCloseStatement(sql.toString()); - pstmt.setLong(1, pfId); - ResultSet rs = pstmt.executeQuery(); - while(rs.next()) { - vmId = rs.getLong("instance_id"); - } - ipAddressId = pfRuleIdToIpAddressIdMap.get(pfId); - finallyUpdate(ipAddressId, vmId, txn); - } catch (SQLException e) { - throw new CloudRuntimeException("Unable to execute " + pstmt.toString(), e); - } - } - } - - @DB - public void finallyUpdate(Long ipAddressId, Long vmId, Transaction txn){ - - StringBuilder sql = new StringBuilder(WriteVmIdToIpAddrTable); - - PreparedStatement pstmt = null; - try { - pstmt = txn.prepareAutoCloseStatement(sql.toString()); - pstmt.setLong(1, vmId); - pstmt.setLong(2, ipAddressId); - int rs = pstmt.executeUpdate(); - } catch (SQLException e) { - throw new CloudRuntimeException("Unable to execute " + pstmt.toString(), e); - } - } - - public static void main(String[] args) { - - File file = PropertiesUtil.findConfigFile("log4j-cloud.xml"); - - if(file != null) { - System.out.println("Log4j configuration from : " + file.getAbsolutePath()); - DOMConfigurator.configureAndWatch(file.getAbsolutePath(), 10000); - } else { - System.out.println("Configure log4j with default properties"); - } - - Db22beta4to22GAMigrationUtil util = new Db22beta4to22GAMigrationUtil(); - util.populateMap(); - util.updateVmIdForIpAddresses(); - } -} diff --git a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManager.java b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManager.java index 9f11b850180..cb00614b086 100644 --- a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManager.java +++ b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManager.java @@ -23,7 +23,7 @@ import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.host.Host; import com.cloud.network.dao.ExternalLoadBalancerDeviceVO; -import com.cloud.network.rules.FirewallRule; +import com.cloud.network.lb.LoadBalancingRule; import com.cloud.resource.ServerResource; import com.cloud.utils.component.Manager; @@ -89,7 +89,7 @@ public interface ExternalLoadBalancerDeviceManager extends Manager{ * @return true if successfully applied rules * @throws ResourceUnavailableException */ - public boolean applyLoadBalancerRules(Network network, List rules) throws ResourceUnavailableException; + public boolean applyLoadBalancerRules(Network network, List rules) throws ResourceUnavailableException; /** * implements or shutdowns guest network on the load balancer device assigned to the guest network @@ -102,6 +102,6 @@ public interface ExternalLoadBalancerDeviceManager extends Manager{ public boolean manageGuestNetworkWithExternalLoadBalancer(boolean add, Network guestConfig) throws ResourceUnavailableException, InsufficientCapacityException; - public List getLBHealthChecks(Network network, List rules) + public List getLBHealthChecks(Network network, List rules) throws ResourceUnavailableException; } diff --git a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java index b4662d13df3..f93bf7ae9b5 100644 --- a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java +++ b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java @@ -270,7 +270,7 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase lbDeviceVO = new ExternalLoadBalancerDeviceVO(host.getId(), pNetwork.getId(), ntwkDevice.getNetworkServiceProvder(), deviceName, capacity, dedicatedUse, gslbProvider); if (gslbProvider) { - lbDeviceVO.setGslbSitePrivateIP(gslbSitePublicIp); + lbDeviceVO.setGslbSitePublicIP(gslbSitePublicIp); lbDeviceVO.setGslbSitePrivateIP(gslbSitePrivateIp); } _externalLoadBalancerDeviceDao.persist(lbDeviceVO); @@ -829,19 +829,11 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase } @Override - public boolean applyLoadBalancerRules(Network network, List rules) throws ResourceUnavailableException { + public boolean applyLoadBalancerRules(Network network, List loadBalancingRules) throws ResourceUnavailableException { // Find the external load balancer in this zone long zoneId = network.getDataCenterId(); DataCenterVO zone = _dcDao.findById(zoneId); - List loadBalancingRules = new ArrayList(); - - for (FirewallRule rule : rules) { - if (rule.getPurpose().equals(Purpose.LoadBalancing)) { - loadBalancingRules.add((LoadBalancingRule) rule); - } - } - if (loadBalancingRules == null || loadBalancingRules.isEmpty()) { return true; } @@ -870,12 +862,13 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase String protocol = rule.getProtocol(); String algorithm = rule.getAlgorithm(); String uuid = rule.getUuid(); - String srcIp = _networkModel.getIp(rule.getSourceIpAddressId()).getAddress().addr(); + String srcIp = rule.getSourceIp().addr(); int srcPort = rule.getSourcePortStart(); List destinations = rule.getDestinations(); if (externalLoadBalancerIsInline) { - MappingNic nic = getLoadBalancingIpNic(zone, network, rule.getSourceIpAddressId(), revoked, null); + long ipId = _networkModel.getPublicIpAddress(rule.getSourceIp().addr(), network.getDataCenterId()).getId(); + MappingNic nic = getLoadBalancingIpNic(zone, network, ipId, revoked, null); mappingStates.add(nic.getState()); NicVO loadBalancingIpNic = nic.getNic(); if (loadBalancingIpNic == null) { @@ -927,7 +920,8 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase } else { continue; } - getLoadBalancingIpNic(zone, network, rule.getSourceIpAddressId(), revoke, existedGuestIp); + long sourceIpId = _networkModel.getPublicIpAddress(rule.getSourceIp().addr(), network.getDataCenterId()).getId(); + getLoadBalancingIpNic(zone, network, sourceIpId, revoke, existedGuestIp); } } throw new ResourceUnavailableException(ex.getMessage(), DataCenter.class, network.getDataCenterId()); @@ -1113,7 +1107,7 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase } @Override - public List getLBHealthChecks(Network network, List rules) + public List getLBHealthChecks(Network network, List loadBalancingRules) throws ResourceUnavailableException { // Find the external load balancer in this zone @@ -1121,14 +1115,6 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase DataCenterVO zone = _dcDao.findById(zoneId); HealthCheckLBConfigAnswer answer = null; - List loadBalancingRules = new ArrayList(); - - for (FirewallRule rule : rules) { - if (rule.getPurpose().equals(Purpose.LoadBalancing)) { - loadBalancingRules.add((LoadBalancingRule) rule); - } - } - if (loadBalancingRules == null || loadBalancingRules.isEmpty()) { return null; } @@ -1158,12 +1144,13 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase String protocol = rule.getProtocol(); String algorithm = rule.getAlgorithm(); String uuid = rule.getUuid(); - String srcIp = _networkModel.getIp(rule.getSourceIpAddressId()).getAddress().addr(); + String srcIp = rule.getSourceIp().addr(); int srcPort = rule.getSourcePortStart(); List destinations = rule.getDestinations(); if (externalLoadBalancerIsInline) { - MappingNic nic = getLoadBalancingIpNic(zone, network, rule.getSourceIpAddressId(), revoked, null); + long sourceIpId = _networkModel.getPublicIpAddress(rule.getSourceIp().addr(), network.getDataCenterId()).getId(); + MappingNic nic = getLoadBalancingIpNic(zone, network, sourceIpId, revoked, null); mappingStates.add(nic.getState()); NicVO loadBalancingIpNic = nic.getNic(); if (loadBalancingIpNic == null) { diff --git a/server/src/com/cloud/network/ExternalLoadBalancerUsageManagerImpl.java b/server/src/com/cloud/network/ExternalLoadBalancerUsageManagerImpl.java index d405382f89c..2c8031c64f0 100644 --- a/server/src/com/cloud/network/ExternalLoadBalancerUsageManagerImpl.java +++ b/server/src/com/cloud/network/ExternalLoadBalancerUsageManagerImpl.java @@ -16,6 +16,22 @@ // under the License. package com.cloud.network; +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + import com.cloud.agent.AgentManager; import com.cloud.agent.api.ExternalNetworkResourceUsageAnswer; import com.cloud.agent.api.ExternalNetworkResourceUsageCommand; @@ -48,6 +64,7 @@ import com.cloud.network.dao.NetworkServiceMapDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.rules.PortForwardingRuleVO; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.offerings.dao.NetworkOfferingDao; @@ -68,20 +85,6 @@ import com.cloud.vm.DomainRouterVO; import com.cloud.vm.NicVO; import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.NicDao; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; @Component @Local(value = { ExternalLoadBalancerUsageManager.class }) @@ -647,9 +650,10 @@ public class ExternalLoadBalancerUsageManagerImpl extends ManagerBase implements // If an external load balancer is added, manage one entry for each load balancing rule in this network if (externalLoadBalancer != null && lbAnswer != null) { boolean inline = _networkMgr.isNetworkInlineMode(network); - List loadBalancers = _loadBalancerDao.listByNetworkId(network.getId()); + List loadBalancers = _loadBalancerDao.listByNetworkIdAndScheme(network.getId(), Scheme.Public); for (LoadBalancerVO loadBalancer : loadBalancers) { String publicIp = _networkMgr.getIp(loadBalancer.getSourceIpAddressId()).getAddress().addr(); + if (!createOrUpdateStatsEntry(create, accountId, zoneId, network.getId(), publicIp, externalLoadBalancer.getId(), lbAnswer, inline)) { throw new ExecutionException(networkErrorMsg + ", load balancing rule public IP = " + publicIp); } diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index 8a33a95314d..8577ec6aee2 100755 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -43,6 +43,7 @@ import com.cloud.network.element.StaticNatServiceProvider; import com.cloud.network.element.UserDataServiceProvider; import com.cloud.network.guru.NetworkGuru; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.rules.StaticNat; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.NetworkOfferingVO; @@ -333,7 +334,7 @@ public interface NetworkManager { int getRuleCountForIp(Long addressId, FirewallRule.Purpose purpose, FirewallRule.State state); - LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network); + LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network, Scheme lbScheme); boolean isSecondaryIpSetForNic(long nicId); diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 3bea76dc81e..eb3077aa137 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -31,6 +31,7 @@ import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.dao.AccountVlanMapDao; import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.DataCenterVnetDao; import com.cloud.dc.dao.PodVlanMapDao; import com.cloud.dc.dao.VlanDao; import com.cloud.deploy.DataCenterDeployment; @@ -46,6 +47,7 @@ import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; +import com.cloud.server.ConfigurationServer; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.IpAddress.State; import com.cloud.network.Network.*; @@ -60,6 +62,13 @@ import com.cloud.network.guru.NetworkGuru; import com.cloud.network.lb.LoadBalancingRulesManager; import com.cloud.network.rules.*; import com.cloud.network.rules.FirewallRule.Purpose; +import com.cloud.network.rules.FirewallRuleVO; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.network.rules.PortForwardingRuleVO; +import com.cloud.network.rules.RulesManager; +import com.cloud.network.rules.StaticNat; +import com.cloud.network.rules.StaticNatRule; +import com.cloud.network.rules.StaticNatRuleImpl; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.vpc.NetworkACLManager; import com.cloud.network.vpc.VpcManager; @@ -70,6 +79,7 @@ import com.cloud.offering.NetworkOffering.Availability; import com.cloud.offerings.NetworkOfferingServiceMapVO; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.offerings.dao.NetworkOfferingDetailsDao; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.org.Grouping; import com.cloud.user.*; @@ -153,6 +163,14 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L RemoteAccessVpnService _vpnMgr; @Inject PodVlanMapDao _podVlanMapDao; + @Inject + NetworkOfferingDetailsDao _ntwkOffDetailsDao; + @Inject + ConfigurationServer _configServer; + @Inject + AccountGuestVlanMapDao _accountGuestVlanMapDao; + @Inject + DataCenterVnetDao _datacenterVnetDao; List _networkGurus; public List getNetworkGurus() { @@ -245,7 +263,6 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L int _networkGcWait; int _networkGcInterval; - String _networkDomain; int _networkLockTimeout; private Map _configs; @@ -367,9 +384,12 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L VlanVO vlan = _vlanDao.findById(addr.getVlanId()); String guestType = vlan.getVlanType().toString(); - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_ASSIGN, owner.getId(), - addr.getDataCenterId(), addr.getId(), addr.getAddress().toString(), addr.isSourceNat(), guestType, - addr.getSystem(), addr.getClass().getName(), addr.getUuid()); + + if (!isIpDedicated(addr)) { + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_ASSIGN, owner.getId(), + addr.getDataCenterId(), addr.getId(), addr.getAddress().toString(), addr.isSourceNat(), guestType, + addr.getSystem(), addr.getClass().getName(), addr.getUuid()); + } // don't increment resource count for direct ip addresses if (addr.getAssociatedWithNetworkId() != null) { _resourceLimitMgr.incrementResourceCount(owner.getId(), ResourceType.public_ip); @@ -379,6 +399,12 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L txn.commit(); } + private boolean isIpDedicated(IPAddressVO addr) { + List maps = _accountVlanMapDao.listAccountVlanMapsByVlan(addr.getVlanId()); + if (maps != null && !maps.isEmpty()) + return true; + return false; + } @Override public PublicIp assignSourceNatIpAddressToGuestNetwork(Account owner, Network guestNetwork) @@ -866,7 +892,6 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L _networkGcInterval = NumbersUtil.parseInt(_configs.get(Config.NetworkGcInterval.key()), 600); _configs = _configDao.getConfiguration("Network", params); - _networkDomain = _configs.get(Config.GuestDomainSuffix.key()); _networkLockTimeout = NumbersUtil.parseInt(_configs.get(Config.NetworkLockTimeout.key()), 600); @@ -933,7 +958,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L _configMgr.createNetworkOffering(NetworkOffering.QuickCloudNoServices, "Offering for QuickCloud with no services", TrafficType.Guest, null, true, Availability.Optional, null, new HashMap>(), true, - Network.GuestType.Shared, false, null, true, null, true, false); + Network.GuestType.Shared, false, null, true, null, true, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -942,14 +967,14 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOfferingWithSGService, "Offering for Shared Security group enabled networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, - Network.GuestType.Shared, false, null, true, null, true, false); + Network.GuestType.Shared, false, null, true, null, true, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOffering, "Offering for Shared networks", TrafficType.Guest, null, true, Availability.Optional, null, - defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, null, true, false); + defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, null, true, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -972,7 +997,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingWithSourceNatService, "Offering for Isolated networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Required, null, defaultINetworkOfferingProvidersForVpcNetwork, - true, Network.GuestType.Isolated, false, null, true, null, false, false); + true, Network.GuestType.Isolated, false, null, true, null, false, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -981,7 +1006,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks, "Offering for Isolated VPC networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Optional, null, defaultVPCOffProviders, - true, Network.GuestType.Isolated, false, null, false, null, false, false); + true, Network.GuestType.Isolated, false, null, false, null, false, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -992,7 +1017,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksNoLB, "Offering for Isolated VPC networks with Source Nat service enabled and LB service disabled", TrafficType.Guest, null, false, Availability.Optional, null, defaultVPCOffProviders, - true, Network.GuestType.Isolated, false, null, false, null, false, false); + true, Network.GuestType.Isolated, false, null, false, null, false, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -1001,7 +1026,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOffering, "Offering for Isolated networks with no Source Nat service", TrafficType.Guest, null, true, Availability.Optional, null, defaultIsolatedNetworkOfferingProviders, true, Network.GuestType.Isolated, - false, null, true, null, true, false); + false, null, true, null, true, false, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -1030,7 +1055,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedEIPandELBNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedEIPandELBNetworkOffering, "Offering for Shared networks with Elastic IP and Elastic LB capabilities", TrafficType.Guest, null, true, - Availability.Optional, null, netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false); + Availability.Optional, null, netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, null); offering.setState(NetworkOffering.State.Enabled); offering.setDedicatedLB(false); _networkOfferingDao.update(offering.getId(), offering); @@ -1989,8 +2014,34 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L // For Isolated networks, don't allow to create network with vlan that already exists in the zone if (ntwkOff.getGuestType() == GuestType.Isolated) { if (_networksDao.countByZoneAndUri(zoneId, uri) > 0) { - throw new InvalidParameterValueException("Network with vlan " + vlanId + " already exists in zone " + zoneId); - } + throw new InvalidParameterValueException("Network with vlan " + vlanId + " already exists in zone " + zoneId); + } else { + List dcVnets = _datacenterVnetDao.findVnet(zoneId, vlanId.toString()); + //for the network that is created as part of private gateway, + //the vnet is not coming from the data center vnet table, so the list can be empty + if (!dcVnets.isEmpty()) { + DataCenterVnetVO dcVnet = dcVnets.get(0); + // Fail network creation if specified vlan is dedicated to a different account + if (dcVnet.getAccountGuestVlanMapId() != null) { + Long accountGuestVlanMapId = dcVnet.getAccountGuestVlanMapId(); + AccountGuestVlanMapVO map = _accountGuestVlanMapDao.findById(accountGuestVlanMapId); + if (map.getAccountId() != owner.getAccountId()) { + throw new InvalidParameterValueException("Vlan " + vlanId + " is dedicated to a different account"); + } + // Fail network creation if owner has a dedicated range of vlans but the specified vlan belongs to the system pool + } else { + List maps = _accountGuestVlanMapDao.listAccountGuestVlanMapsByAccount(owner.getAccountId()); + if (maps != null && !maps.isEmpty()) { + int vnetsAllocatedToAccount = _datacenterVnetDao.countVnetsAllocatedToAccount(zoneId, owner.getAccountId()); + int vnetsDedicatedToAccount = _datacenterVnetDao.countVnetsDedicatedToAccount(zoneId, owner.getAccountId()); + if (vnetsAllocatedToAccount < vnetsDedicatedToAccount) { + throw new InvalidParameterValueException("Specified vlan " + vlanId + " doesn't belong" + + " to the vlan range dedicated to the owner "+ owner.getAccountName()); + } + } + } + } + } } else { // don't allow to creating shared network with given Vlan ID, if there already exists a isolated network or // shared network with same Vlan ID in the zone @@ -1999,7 +2050,10 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L throw new InvalidParameterValueException("There is a isolated/shared network with vlan id: " + vlanId + " already exists " + "in zone " + zoneId); } - } + } + + + } // If networkDomain is not specified, take it from the global configuration @@ -2024,7 +2078,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L // 2) If null, generate networkDomain using domain suffix from the global config variables if (networkDomain == null) { - networkDomain = "cs" + Long.toHexString(owner.getId()) + _networkDomain; + networkDomain = "cs" + Long.toHexString(owner.getId()) + _configServer.getConfigValue(Config.GuestDomainSuffix.key(), Config.ConfigurationParameterScope.zone.toString(), zoneId); } } else { @@ -2608,9 +2662,15 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L success = false; } - // apply load balancer rules - if (!_lbMgr.applyLoadBalancersForNetwork(networkId)) { - s_logger.warn("Failed to reapply load balancer rules as a part of network id=" + networkId + " restart"); + // apply public load balancer rules + if (!_lbMgr.applyLoadBalancersForNetwork(networkId, Scheme.Public)) { + s_logger.warn("Failed to reapply Public load balancer rules as a part of network id=" + networkId + " restart"); + success = false; + } + + // apply internal load balancer rules + if (!_lbMgr.applyLoadBalancersForNetwork(networkId, Scheme.Internal)) { + s_logger.warn("Failed to reapply internal load balancer rules as a part of network id=" + networkId + " restart"); success = false; } @@ -2886,14 +2946,15 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L } // Save usage event - if (ip.getAllocatedToAccountId() != Account.ACCOUNT_ID_SYSTEM) { + if (ip.getAllocatedToAccountId() != null && ip.getAllocatedToAccountId() != Account.ACCOUNT_ID_SYSTEM) { VlanVO vlan = _vlanDao.findById(ip.getVlanId()); String guestType = vlan.getVlanType().toString(); - - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_RELEASE, - ip.getAllocatedToAccountId(), ip.getDataCenterId(), addrId, ip.getAddress().addr(), - ip.isSourceNat(), guestType, ip.getSystem(), ip.getClass().getName(), ip.getUuid()); + if (!isIpDedicated(ip)) { + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_RELEASE, + ip.getAllocatedToAccountId(), ip.getDataCenterId(), addrId, ip.getAddress().addr(), + ip.isSourceNat(), guestType, ip.getSystem(), ip.getClass().getName(), ip.getUuid()); + } } ip = _ipAddressDao.markAsUnavailable(addrId); @@ -3190,12 +3251,22 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L } try { - if (!_lbMgr.revokeLoadBalancersForNetwork(networkId)) { - s_logger.warn("Failed to cleanup lb rules as a part of shutdownNetworkRules"); + if (!_lbMgr.revokeLoadBalancersForNetwork(networkId, Scheme.Public)) { + s_logger.warn("Failed to cleanup public lb rules as a part of shutdownNetworkRules"); success = false; } } catch (ResourceUnavailableException ex) { - s_logger.warn("Failed to cleanup lb rules as a part of shutdownNetworkRules due to ", ex); + s_logger.warn("Failed to cleanup public lb rules as a part of shutdownNetworkRules due to ", ex); + success = false; + } + + try { + if (!_lbMgr.revokeLoadBalancersForNetwork(networkId, Scheme.Internal)) { + s_logger.warn("Failed to cleanup internal lb rules as a part of shutdownNetworkRules"); + success = false; + } + } catch (ResourceUnavailableException ex) { + s_logger.warn("Failed to cleanup public lb rules as a part of shutdownNetworkRules due to ", ex); success = false; } @@ -3601,7 +3672,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L } } } else { - NicVO nicVO = _nicDao.findByInstanceIdAndNetworkId(network.getId(), vm.getId()); + NicVO nicVO = _nicDao.findByNtwkIdAndInstanceId(network.getId(), vm.getId()); if (nicVO != null) { nic = _networkModel.getNicProfile(vm, network.getId(), null); } @@ -3703,35 +3774,62 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L return null; } - protected NetworkElement getElementForServiceInNetwork(Network network, Service service) { + protected List getElementForServiceInNetwork(Network network, Service service) { + List elements = new ArrayList(); List providers = getProvidersForServiceInNetwork(network, service); //Only support one provider now if (providers == null) { s_logger.error("Cannot find " + service.getName() + " provider for network " + network.getId()); return null; } - if (providers.size() != 1) { + if (providers.size() != 1 && service != Service.Lb) { + //support more than one LB providers only s_logger.error("Found " + providers.size() + " " + service.getName() + " providers for network!" + network.getId()); return null; + } + + for (Provider provider : providers) { + NetworkElement element = _networkModel.getElementImplementingProvider(provider.getName()); + s_logger.info("Let " + element.getName() + " handle " + service.getName() + " in network " + network.getId()); + elements.add(element); } - NetworkElement element = _networkModel.getElementImplementingProvider(providers.get(0).getName()); - s_logger.info("Let " + element.getName() + " handle " + service.getName() + " in network " + network.getId()); - return element; + return elements; } @Override public StaticNatServiceProvider getStaticNatProviderForNetwork(Network network) { - NetworkElement element = getElementForServiceInNetwork(network, Service.StaticNat); + //only one provider per Static nat service is supoprted + NetworkElement element = getElementForServiceInNetwork(network, Service.StaticNat).get(0); assert element instanceof StaticNatServiceProvider; return (StaticNatServiceProvider)element; } @Override - public LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network) { - NetworkElement element = getElementForServiceInNetwork(network, Service.Lb); - assert element instanceof LoadBalancingServiceProvider; - return (LoadBalancingServiceProvider)element; + public LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network, Scheme lbScheme) { + List lbElements = getElementForServiceInNetwork(network, Service.Lb); + NetworkElement lbElement = null; + if (lbElements.size() > 1) { + String providerName = null; + //get network offering details + NetworkOffering off = _configMgr.getNetworkOffering(network.getNetworkOfferingId()); + if (lbScheme == Scheme.Public) { + providerName = _ntwkOffDetailsDao.getDetail(off.getId(), NetworkOffering.Detail.PublicLbProvider); + } else { + providerName = _ntwkOffDetailsDao.getDetail(off.getId(), NetworkOffering.Detail.InternalLbProvider); + } + if (providerName == null) { + throw new InvalidParameterValueException("Can't find Lb provider supporting scheme " + lbScheme.toString() + " in network " + network); + } + lbElement = _networkModel.getElementImplementingProvider(providerName); + } else if (lbElements.size() == 1){ + lbElement = lbElements.get(0); + } + + assert lbElement != null; + assert lbElement instanceof LoadBalancingServiceProvider; + return (LoadBalancingServiceProvider)lbElement; } + @Override public boolean isNetworkInlineMode(Network network) { NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); diff --git a/server/src/com/cloud/network/NetworkModelImpl.java b/server/src/com/cloud/network/NetworkModelImpl.java index c5930d9315c..135fd290535 100755 --- a/server/src/com/cloud/network/NetworkModelImpl.java +++ b/server/src/com/cloud/network/NetworkModelImpl.java @@ -32,6 +32,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -84,11 +85,14 @@ import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.vpc.dao.PrivateIpDao; import com.cloud.offering.NetworkOffering; +import com.cloud.offering.NetworkOffering.Detail; import com.cloud.offerings.NetworkOfferingServiceMapVO; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.offerings.dao.NetworkOfferingDetailsDao; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.projects.dao.ProjectAccountDao; +import com.cloud.server.ConfigurationServer; import com.cloud.user.Account; import com.cloud.user.AccountVO; import com.cloud.user.DomainManager; @@ -143,6 +147,8 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { @Inject PodVlanMapDao _podVlanMapDao; + @Inject + ConfigurationServer _configServer; List _networkElements; public List getNetworkElements() { @@ -179,9 +185,13 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { @Inject UserIpv6AddressDao _ipv6Dao; @Inject - NicSecondaryIpDao _nicSecondaryIpDao;; + NicSecondaryIpDao _nicSecondaryIpDao; + @Inject + ApplicationLoadBalancerRuleDao _appLbRuleDao; @Inject private ProjectAccountDao _projectAccountDao; + @Inject + NetworkOfferingDetailsDao _ntwkOffDetailsDao; private final HashMap _systemNetworks = new HashMap(5); static Long _privateOfferingId = null; @@ -600,7 +610,6 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { NetworkElement element = getElementImplementingProvider(instance.getProvider()); if (element != null) { Map> elementCapabilities = element.getCapabilities(); - ; if (elementCapabilities != null) { networkCapabilities.put(service, elementCapabilities.get(service)); } @@ -913,7 +922,7 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { boolean isUserVmsDefaultNetwork = false; boolean isDomRGuestOrPublicNetwork = false; if (vm != null) { - Nic nic = _nicDao.findByInstanceIdAndNetworkId(networkId, vmId); + Nic nic = _nicDao.findByNtwkIdAndInstanceId(networkId, vmId); if (vm.getType() == Type.User && nic != null && nic.isDefaultNic()) { isUserVmsDefaultNetwork = true; } else if (vm.getType() == Type.DomainRouter && ntwkOff != null && (ntwkOff.getTrafficType() == TrafficType.Public || ntwkOff.getTrafficType() == TrafficType.Guest)) { @@ -921,9 +930,9 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { } } if (isUserVmsDefaultNetwork || isDomRGuestOrPublicNetwork) { - return _configMgr.getServiceOfferingNetworkRate(vm.getServiceOfferingId()); + return _configMgr.getServiceOfferingNetworkRate(vm.getServiceOfferingId(), network.getDataCenterId()); } else { - return _configMgr.getNetworkOfferingNetworkRate(ntwkOff.getId()); + return _configMgr.getNetworkOfferingNetworkRate(ntwkOff.getId(), network.getDataCenterId()); } } @@ -1461,10 +1470,8 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { throw new UnsupportedServiceException("Service " + service.getName() + " doesn't have capability " + cap.getName() + " for element=" + element.getName() + " implementing Provider=" + provider.getName()); } - - capValue = capValue.toLowerCase(); - - if (!value.contains(capValue)) { + + if (!value.toLowerCase().contains(capValue.toLowerCase())) { throw new UnsupportedServiceException("Service " + service.getName() + " doesn't support value " + capValue + " for capability " + cap.getName() + " for element=" + element.getName() + " implementing Provider=" + provider.getName()); } @@ -1564,8 +1571,8 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { } @Override - public String getDefaultNetworkDomain() { - return _networkDomain; + public String getDefaultNetworkDomain(long zoneId) { + return _configServer.getConfigValue(Config.GuestDomainSuffix.key(), Config.ConfigurationParameterScope.zone.toString(), zoneId); } @Override @@ -1660,23 +1667,19 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { @Override public Set getAvailableIps(Network network, String requestedIp) { String[] cidr = network.getCidr().split("/"); - List ips = _nicDao.listIpAddressInNetwork(network.getId()); - List secondaryIps = _nicSecondaryIpDao.listSecondaryIpAddressInNetwork(network.getId()); - ips.addAll(secondaryIps); - Set allPossibleIps = NetUtils.getAllIpsFromCidr(cidr[0], Integer.parseInt(cidr[1])); + List ips = getUsedIpsInNetwork(network); Set usedIps = new TreeSet(); - + for (String ip : ips) { if (requestedIp != null && requestedIp.equals(ip)) { s_logger.warn("Requested ip address " + requestedIp + " is already in use in network" + network); return null; } - + usedIps.add(NetUtils.ip2Long(ip)); } - if (usedIps.size() != 0) { - allPossibleIps.removeAll(usedIps); - } + + Set allPossibleIps = NetUtils.getAllIpsFromCidr(cidr[0], Integer.parseInt(cidr[1]), usedIps); String gateway = network.getGateway(); if ((gateway != null) && (allPossibleIps.contains(NetUtils.ip2Long(gateway)))) @@ -1684,6 +1687,19 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { return allPossibleIps; } + + @Override + public List getUsedIpsInNetwork(Network network) { + //Get all ips used by vms nics + List ips = _nicDao.listIpAddressInNetwork(network.getId()); + //Get all secondary ips for nics + List secondaryIps = _nicSecondaryIpDao.listSecondaryIpAddressInNetwork(network.getId()); + ips.addAll(secondaryIps); + //Get ips used by load balancers + List lbIps = _appLbRuleDao.listLbIpsBySourceIpNetworkId(network.getId()); + ips.addAll(lbIps); + return ips; + } @Override public String getDomainNetworkDomain(long domainId, long zoneId) { @@ -1791,7 +1807,7 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { if (broadcastUri != null) { nic = _nicDao.findByNetworkIdInstanceIdAndBroadcastUri(networkId, vm.getId(), broadcastUri); } else { - nic = _nicDao.findByInstanceIdAndNetworkId(networkId, vm.getId()); + nic = _nicDao.findByNtwkIdAndInstanceId(networkId, vm.getId()); } if (nic == null) { return null; @@ -2049,4 +2065,26 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { } return null; } + + + @Override + public IpAddress getPublicIpAddress(String ipAddress, long zoneId) { + List networks = _networksDao.listByZoneAndTrafficType(zoneId, TrafficType.Public); + if (networks.isEmpty() || networks.size() > 1) { + throw new CloudRuntimeException("Can't find public network in the zone specified"); + } + + return _ipAddressDao.findByIpAndSourceNetworkId(networks.get(0).getId(), ipAddress); + } + + @Override + public Map getNtwkOffDetails(long offId) { + return _ntwkOffDetailsDao.getNtwkOffDetails(offId); + } + + + @Override + public Networks.IsolationType[] listNetworkIsolationMethods() { + return Networks.IsolationType.values(); + } } diff --git a/server/src/com/cloud/network/dao/LoadBalancerDaoImpl.java b/server/src/com/cloud/network/dao/LoadBalancerDaoImpl.java deleted file mode 100644 index f211a7f1a79..00000000000 --- a/server/src/com/cloud/network/dao/LoadBalancerDaoImpl.java +++ /dev/null @@ -1,137 +0,0 @@ -// 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. -package com.cloud.network.dao; - -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.util.ArrayList; -import java.util.List; - -import javax.ejb.Local; -import javax.inject.Inject; - -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import com.cloud.network.rules.FirewallRule.State; -import com.cloud.utils.db.GenericDaoBase; -import com.cloud.utils.db.SearchBuilder; -import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.SearchCriteria.Op; -import com.cloud.utils.db.Transaction; - -@Component -@Local(value = { LoadBalancerDao.class }) -public class LoadBalancerDaoImpl extends GenericDaoBase implements LoadBalancerDao { - private static final Logger s_logger = Logger.getLogger(LoadBalancerDaoImpl.class); - private static final String LIST_INSTANCES_BY_LOAD_BALANCER = "SELECT vm.id " + - " FROM vm_instance vm, load_balancer lb, ip_forwarding fwd, user_ip_address ip " + - " WHERE lb.id = ? AND " + - " fwd.group_id = lb.id AND " + - " fwd.forwarding = 0 AND " + - " fwd.private_ip_address = vm.private_ip_address AND " + - " lb.ip_address = ip.public_ip_address AND " + - " ip.data_center_id = vm.data_center_id "; - private final SearchBuilder ListByIp; - private final SearchBuilder IpAndPublicPortSearch; - private final SearchBuilder AccountAndNameSearch; - protected final SearchBuilder TransitionStateSearch; - - @Inject protected FirewallRulesCidrsDao _portForwardingRulesCidrsDao; - - protected LoadBalancerDaoImpl() { - ListByIp = createSearchBuilder(); - ListByIp.and("ipAddressId", ListByIp.entity().getSourceIpAddressId(), SearchCriteria.Op.EQ); - ListByIp.and("networkId", ListByIp.entity().getNetworkId(), SearchCriteria.Op.EQ); - ListByIp.done(); - - IpAndPublicPortSearch = createSearchBuilder(); - IpAndPublicPortSearch.and("ipAddressId", IpAndPublicPortSearch.entity().getSourceIpAddressId(), SearchCriteria.Op.EQ); - IpAndPublicPortSearch.and("publicPort", IpAndPublicPortSearch.entity().getSourcePortStart(), SearchCriteria.Op.EQ); - IpAndPublicPortSearch.done(); - - AccountAndNameSearch = createSearchBuilder(); - AccountAndNameSearch.and("accountId", AccountAndNameSearch.entity().getAccountId(), SearchCriteria.Op.EQ); - AccountAndNameSearch.and("name", AccountAndNameSearch.entity().getName(), SearchCriteria.Op.EQ); - AccountAndNameSearch.done(); - - TransitionStateSearch = createSearchBuilder(); - TransitionStateSearch.and("networkId", TransitionStateSearch.entity().getNetworkId(), Op.EQ); - TransitionStateSearch.and("state", TransitionStateSearch.entity().getState(), Op.IN); - TransitionStateSearch.done(); - } - - @Override - public List listInstancesByLoadBalancer(long loadBalancerId) { - Transaction txn = Transaction.currentTxn(); - String sql = LIST_INSTANCES_BY_LOAD_BALANCER; - PreparedStatement pstmt = null; - List instanceList = new ArrayList(); - try { - pstmt = txn.prepareAutoCloseStatement(sql); - pstmt.setLong(1, loadBalancerId); - - ResultSet rs = pstmt.executeQuery(); - while (rs.next()) { - Long vmId = rs.getLong(1); - instanceList.add(vmId); - } - } catch (Exception ex) { - s_logger.error("error getting recent usage network stats", ex); - } - return instanceList; - } - - @Override - public List listByIpAddress(long ipAddressId) { - SearchCriteria sc = ListByIp.create(); - sc.setParameters("ipAddressId", ipAddressId); - return listBy(sc); - } - - @Override - public List listByNetworkId(long networkId) { - SearchCriteria sc = ListByIp.create(); - sc.setParameters("networkId", networkId); - return listBy(sc); - } - - @Override - public LoadBalancerVO findByIpAddressAndPublicPort(long ipAddressId, String publicPort) { - SearchCriteria sc = IpAndPublicPortSearch.create(); - sc.setParameters("ipAddressId", ipAddressId); - sc.setParameters("publicPort", publicPort); - return findOneBy(sc); - } - - @Override - public LoadBalancerVO findByAccountAndName(Long accountId, String name) { - SearchCriteria sc = AccountAndNameSearch.create(); - sc.setParameters("accountId", accountId); - sc.setParameters("name", name); - return findOneBy(sc); - } - - @Override - public List listInTransitionStateByNetworkId(long networkId) { - SearchCriteria sc = TransitionStateSearch.create(); - sc.setParameters("networkId", networkId); - sc.setParameters("state", State.Add.toString(), State.Revoke.toString()); - return listBy(sc); - } - -} diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java index f601f4fa2e4..28473cc7bc2 100755 --- a/server/src/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VirtualRouterElement.java @@ -25,7 +25,6 @@ import java.util.Set; import javax.ejb.Local; import javax.inject.Inject; -import com.cloud.utils.PropertiesUtil; import org.apache.cloudstack.api.command.admin.router.ConfigureVirtualRouterElementCmd; import org.apache.cloudstack.api.command.admin.router.CreateVirtualRouterElementCmd; import org.apache.cloudstack.api.command.admin.router.ListVirtualRouterElementsCmd; @@ -66,6 +65,7 @@ import com.cloud.network.router.VpcVirtualNetworkApplianceManager; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.LbStickinessMethod; import com.cloud.network.rules.LbStickinessMethod.StickinessMethodType; +import com.cloud.network.rules.LoadBalancerContainer; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.RulesManager; import com.cloud.network.rules.StaticNat; @@ -242,7 +242,7 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl * number like 12 2) time or tablesize like 12h, 34m, 45k, 54m , here * last character is non-digit but from known characters . */ - private boolean containsOnlyNumbers(String str, String endChar) { + private static boolean containsOnlyNumbers(String str, String endChar) { if (str == null) return false; @@ -271,7 +271,7 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl return true; } - private boolean validateHAProxyLBRule(LoadBalancingRule rule) { + public static boolean validateHAProxyLBRule(LoadBalancingRule rule) { String timeEndChar = "dhms"; for (LbStickinessPolicy stickinessPolicy : rule.getStickinessPolicies()) { @@ -338,7 +338,9 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl @Override public boolean validateLBRule(Network network, LoadBalancingRule rule) { - if (canHandle(network, Service.Lb)) { + List rules = new ArrayList(); + rules.add(rule); + if (canHandle(network, Service.Lb) && canHandleLbRules(rules)) { List routers = _routerDao.listByNetworkAndRole(network.getId(), Role.VIRTUAL_ROUTER); if (routers == null || routers.isEmpty()) { return true; @@ -351,6 +353,10 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl @Override public boolean applyLBRules(Network network, List rules) throws ResourceUnavailableException { if (canHandle(network, Service.Lb)) { + if (!canHandleLbRules(rules)) { + return false; + } + List routers = _routerDao.listByNetworkAndRole(network.getId(), Role.VIRTUAL_ROUTER); if (routers == null || routers.isEmpty()) { s_logger.debug("Virtual router elemnt doesn't need to apply firewall rules on the backend; virtual " + @@ -358,8 +364,8 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl return true; } - if (!_routerMgr.applyFirewallRules(network, rules, routers)) { - throw new CloudRuntimeException("Failed to apply firewall rules in network " + network.getId()); + if (!_routerMgr.applyLoadBalancingRules(network, rules, routers)) { + throw new CloudRuntimeException("Failed to apply load balancing rules in network " + network.getId()); } else { return true; } @@ -452,7 +458,7 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl return capabilities; } - private static String getHAProxyStickinessCapability() { + public static String getHAProxyStickinessCapability() { LbStickinessMethod method; List methodList = new ArrayList(1); @@ -557,8 +563,8 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl lbCapabilities.put(Capability.SupportedLBAlgorithms, "roundrobin,leastconn,source"); lbCapabilities.put(Capability.SupportedLBIsolation, "dedicated"); lbCapabilities.put(Capability.SupportedProtocols, "tcp, udp"); - lbCapabilities.put(Capability.SupportedStickinessMethods, getHAProxyStickinessCapability()); + lbCapabilities.put(Capability.LbSchemes, LoadBalancerContainer.Scheme.Public.toString()); capabilities.put(Service.Lb, lbCapabilities); @@ -715,8 +721,8 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl @Override public VirtualRouterProvider configure(ConfigureVirtualRouterElementCmd cmd) { VirtualRouterProviderVO element = _vrProviderDao.findById(cmd.getId()); - if (element == null) { - s_logger.debug("Can't find element with network service provider id " + cmd.getId()); + if (element == null || !(element.getType() == VirtualRouterProviderType.VirtualRouter || element.getType() == VirtualRouterProviderType.VPCVirtualRouter)) { + s_logger.debug("Can't find Virtual Router element with network service provider id " + cmd.getId()); return null; } @@ -728,6 +734,10 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl @Override public VirtualRouterProvider addElement(Long nspId, VirtualRouterProviderType providerType) { + if (!(providerType == VirtualRouterProviderType.VirtualRouter || providerType == VirtualRouterProviderType.VPCVirtualRouter)) { + throw new InvalidParameterValueException("Element " + this.getName() + " supports only providerTypes: " + + VirtualRouterProviderType.VirtualRouter.toString() + " and " + VirtualRouterProviderType.VPCVirtualRouter); + } VirtualRouterProviderVO element = _vrProviderDao.findByNspIdAndType(nspId, providerType); if (element != null) { s_logger.debug("There is already a virtual router element with service provider id " + nspId); @@ -801,7 +811,11 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl @Override public VirtualRouterProvider getCreatedElement(long id) { - return _vrProviderDao.findById(id); + VirtualRouterProvider provider = _vrProviderDao.findById(id); + if (!(provider.getType() == VirtualRouterProviderType.VirtualRouter || provider.getType() == VirtualRouterProviderType.VPCVirtualRouter)) { + throw new InvalidParameterValueException("Unable to find provider by id"); + } + return provider; } @Override @@ -911,6 +925,10 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl if (enabled != null) { sc.addAnd(sc.getEntity().isEnabled(), Op.EQ, enabled); } + + //return only VR and VPC VR + sc.addAnd(sc.getEntity().getType(), Op.IN, VirtualRouterProvider.VirtualRouterProviderType.VPCVirtualRouter, VirtualRouterProvider.VirtualRouterProviderType.VirtualRouter); + return sc.list(); } @@ -946,4 +964,20 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl // TODO Auto-generated method stub return null; } + + private boolean canHandleLbRules(List rules) { + Map lbCaps = this.getCapabilities().get(Service.Lb); + if (!lbCaps.isEmpty()) { + String schemeCaps = lbCaps.get(Capability.LbSchemes); + if (schemeCaps != null) { + for (LoadBalancingRule rule : rules) { + if (!schemeCaps.contains(rule.getScheme().toString())) { + s_logger.debug("Scheme " + rules.get(0).getScheme() + " is not supported by the provider " + this.getName()); + return false; + } + } + } + } + return true; + } } diff --git a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java index 080f7b0edf6..def4c1ed06f 100644 --- a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java +++ b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java @@ -27,16 +27,12 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.api.command.user.firewall.ListEgressFirewallRulesCmd; +import com.cloud.network.dao.*; import org.apache.cloudstack.api.command.user.firewall.ListFirewallRulesCmd; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import com.mysql.jdbc.ConnectionPropertiesImpl; -import org.apache.log4j.Logger; - -import org.apache.cloudstack.api.BaseListCmd; -import org.apache.cloudstack.api.command.user.firewall.ListEgressFirewallRulesCmd; -import org.apache.cloudstack.api.command.user.firewall.ListFirewallRulesCmd; import com.cloud.configuration.Config; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.domain.dao.DomainDao; @@ -52,22 +48,22 @@ import com.cloud.network.IpAddress; import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Service; -import com.cloud.network.Networks.TrafficType; import com.cloud.network.NetworkManager; import com.cloud.network.NetworkModel; import com.cloud.network.NetworkRuleApplier; -import com.cloud.network.dao.FirewallRulesCidrsDao; -import com.cloud.network.dao.FirewallRulesDao; -import com.cloud.network.dao.IPAddressDao; -import com.cloud.network.dao.IPAddressVO; import com.cloud.network.element.FirewallServiceProvider; import com.cloud.network.element.NetworkACLServiceProvider; import com.cloud.network.element.PortForwardingServiceProvider; import com.cloud.network.element.StaticNatServiceProvider; -import com.cloud.network.rules.*; +import com.cloud.network.rules.FirewallManager; +import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.FirewallRuleType; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRule.State; +import com.cloud.network.rules.FirewallRuleVO; +import com.cloud.network.rules.PortForwardingRule; +import com.cloud.network.rules.PortForwardingRuleVO; +import com.cloud.network.rules.StaticNat; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.vpc.VpcManager; import com.cloud.projects.Project.ListProjectResourcesCriteria; @@ -86,8 +82,8 @@ import com.cloud.utils.db.Filter; import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.*; import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.vm.UserVmVO; @@ -127,6 +123,8 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, @Inject ResourceTagDao _resourceTagDao; @Inject + NetworkDao _networkDao; + @Inject VpcManager _vpcMgr; @Inject List _firewallElements; @@ -150,6 +148,11 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, @Override public FirewallRule createEgressFirewallRule(FirewallRule rule) throws NetworkRuleConflictException { Account caller = UserContext.current().getCaller(); + + Network network = _networkDao.findById(rule.getNetworkId()); + if (network.getGuestType() == Network.GuestType.Shared) { + throw new InvalidParameterValueException("Egress firewall rules are not supported for " + network.getGuestType() + " networks"); + } return createFirewallRule(null, caller, rule.getXid(), rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol(), rule.getSourceCidrList(), rule.getIcmpCode(), @@ -434,22 +437,28 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, return; } - if (ipAddress!=null){ - if (ipAddress.getAssociatedWithNetworkId() == null) { - throw new InvalidParameterValueException("Unable to create firewall rule ; ip with specified id is not associated with any network"); - } else { - networkId = ipAddress.getAssociatedWithNetworkId(); - } - + if (ipAddress != null){ + if (ipAddress.getAssociatedWithNetworkId() == null) { + throw new InvalidParameterValueException("Unable to create firewall rule ; ip with specified id is not associated with any network"); + } else { + networkId = ipAddress.getAssociatedWithNetworkId(); + } + // Validate ip address _accountMgr.checkAccess(caller, null, true, ipAddress); - + } + + //network id either has to be passed explicitly, or implicitly as a part of ipAddress object + if (networkId == null) { + throw new InvalidParameterValueException("Unable to retrieve network id to validate the rule"); + } + Network network = _networkModel.getNetwork(networkId); - assert network != null : "Can't create port forwarding rule as network associated with public ip address is null?"; + assert network != null : "Can't create rule as network associated with public ip address is null?"; - if (trafficType == FirewallRule.TrafficType.Egress) { - _accountMgr.checkAccess(caller, null, true, network); - } + if (trafficType == FirewallRule.TrafficType.Egress) { + _accountMgr.checkAccess(caller, null, true, network); + } // Verify that the network guru supports the protocol specified Map caps = null; @@ -460,32 +469,32 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, } } else if (purpose == Purpose.PortForwarding) { caps = _networkModel.getNetworkServiceCapabilities(network.getId(), Service.PortForwarding); - }else if (purpose == Purpose.Firewall){ - caps = _networkModel.getNetworkServiceCapabilities(network.getId(),Service.Firewall); + } else if (purpose == Purpose.Firewall){ + caps = _networkModel.getNetworkServiceCapabilities(network.getId(),Service.Firewall); } if (caps != null) { - String supportedProtocols; - String supportedTrafficTypes = null; - if (purpose == FirewallRule.Purpose.Firewall) { - supportedTrafficTypes = caps.get(Capability.SupportedTrafficDirection).toLowerCase(); - } + String supportedProtocols; + String supportedTrafficTypes = null; + if (purpose == FirewallRule.Purpose.Firewall) { + supportedTrafficTypes = caps.get(Capability.SupportedTrafficDirection).toLowerCase(); + } - if (purpose == FirewallRule.Purpose.Firewall && trafficType == FirewallRule.TrafficType.Egress) { - supportedProtocols = caps.get(Capability.SupportedEgressProtocols).toLowerCase(); - } else { - supportedProtocols = caps.get(Capability.SupportedProtocols).toLowerCase(); - } + if (purpose == FirewallRule.Purpose.Firewall && trafficType == FirewallRule.TrafficType.Egress) { + supportedProtocols = caps.get(Capability.SupportedEgressProtocols).toLowerCase(); + } else { + supportedProtocols = caps.get(Capability.SupportedProtocols).toLowerCase(); + } if (!supportedProtocols.contains(proto.toLowerCase())) { throw new InvalidParameterValueException("Protocol " + proto + " is not supported in zone " + network.getDataCenterId()); } else if (proto.equalsIgnoreCase(NetUtils.ICMP_PROTO) && purpose != Purpose.Firewall) { throw new InvalidParameterValueException("Protocol " + proto + " is currently supported only for rules with purpose " + Purpose.Firewall); - } else if (purpose == Purpose.Firewall && !supportedTrafficTypes.contains(trafficType.toString().toLowerCase())) { - throw new InvalidParameterValueException("Traffic Type " + trafficType + " is currently supported by Firewall in network " + networkId); - } + } else if (purpose == Purpose.Firewall && !supportedTrafficTypes.contains(trafficType.toString().toLowerCase())) { + throw new InvalidParameterValueException("Traffic Type " + trafficType + " is currently supported by Firewall in network " + networkId); } } + } @Override diff --git a/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java b/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java index b1606db71b1..fe9e01f558d 100644 --- a/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java +++ b/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java @@ -118,7 +118,7 @@ public class ExternalGuestNetworkGuru extends GuestNetworkGuru { if (Boolean.parseBoolean(_configDao.getValue(Config.OvsTunnelNetwork.key()))) { return null; } - + if (!_networkModel.networkIsConfiguredForExternalNetworking(config.getDataCenterId(), config.getId())) { return super.implement(config, offering, dest, context); } @@ -145,25 +145,31 @@ public class ExternalGuestNetworkGuru extends GuestNetworkGuru { implemented.setBroadcastUri(config.getBroadcastUri()); } - // Determine the offset from the lowest vlan tag - int offset = getVlanOffset(config.getPhysicalNetworkId(), vlanTag); - // Determine the new gateway and CIDR String[] oldCidr = config.getCidr().split("/"); String oldCidrAddress = oldCidr[0]; - int cidrSize = getGloballyConfiguredCidrSize(); - - // If the offset has more bits than there is room for, return null - long bitsInOffset = 32 - Integer.numberOfLeadingZeros(offset); - if (bitsInOffset > (cidrSize - 8)) { - throw new CloudRuntimeException("The offset " + offset + " needs " + bitsInOffset + " bits, but only have " + (cidrSize - 8) + " bits to work with."); + int cidrSize = Integer.parseInt(oldCidr[1]); + long newCidrAddress = (NetUtils.ip2Long(oldCidrAddress)); + // if the implementing network is for vpc, no need to generate newcidr, use the cidr that came from super cidr + if (config.getVpcId() != null) { + implemented.setGateway(config.getGateway()); + implemented.setCidr(config.getCidr()); + implemented.setState(State.Implemented); + } else { + // Determine the offset from the lowest vlan tag + int offset = getVlanOffset(config.getPhysicalNetworkId(), vlanTag); + cidrSize = getGloballyConfiguredCidrSize(); + // If the offset has more bits than there is room for, return null + long bitsInOffset = 32 - Integer.numberOfLeadingZeros(offset); + if (bitsInOffset > (cidrSize - 8)) { + throw new CloudRuntimeException("The offset " + offset + " needs " + bitsInOffset + " bits, but only have " + (cidrSize - 8) + " bits to work with."); + } + newCidrAddress = (NetUtils.ip2Long(oldCidrAddress) & 0xff000000) | (offset << (32 - cidrSize)); + implemented.setGateway(NetUtils.long2Ip(newCidrAddress + 1)); + implemented.setCidr(NetUtils.long2Ip(newCidrAddress) + "/" + cidrSize); + implemented.setState(State.Implemented); } - long newCidrAddress = (NetUtils.ip2Long(oldCidrAddress) & 0xff000000) | (offset << (32 - cidrSize)); - implemented.setGateway(NetUtils.long2Ip(newCidrAddress + 1)); - implemented.setCidr(NetUtils.long2Ip(newCidrAddress) + "/" + cidrSize); - implemented.setState(State.Implemented); - // Mask the Ipv4 address of all nics that use this network with the new guest VLAN offset List nicsInNetwork = _nicDao.listByNetworkId(config.getId()); for (NicVO nic : nicsInNetwork) { @@ -172,8 +178,8 @@ public class ExternalGuestNetworkGuru extends GuestNetworkGuru { nic.setIp4Address(NetUtils.long2Ip(newCidrAddress | ipMask)); _nicDao.persist(nic); } - } - + } + // Mask the destination address of all port forwarding rules in this network with the new guest VLAN offset List pfRulesInNetwork = _pfRulesDao.listByNetwork(config.getId()); for (PortForwardingRuleVO pfRule : pfRulesInNetwork) { diff --git a/server/src/com/cloud/network/guru/GuestNetworkGuru.java b/server/src/com/cloud/network/guru/GuestNetworkGuru.java index 291e3ccbc77..32ce744979b 100755 --- a/server/src/com/cloud/network/guru/GuestNetworkGuru.java +++ b/server/src/com/cloud/network/guru/GuestNetworkGuru.java @@ -223,48 +223,7 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur nic.deallocate(); } } - - public Ip4Address acquireIp4Address(Network network, Ip4Address requestedIp, String reservationId) { - List ips = _nicDao.listIpAddressInNetwork(network.getId()); - String[] cidr = network.getCidr().split("/"); - SortedSet usedIps = new TreeSet(); - - if (requestedIp != null && requestedIp.equals(network.getGateway())) { - s_logger.warn("Requested ip address " + requestedIp + " is used as a gateway address in network " + network); - return null; - } - - for (String ip : ips) { - usedIps.add(NetUtils.ip2Long(ip)); - } - - if (network.getGateway() != null) { - usedIps.add(NetUtils.ip2Long(network.getGateway())); - } - - if (requestedIp != null) { - if (usedIps.contains(requestedIp.toLong())) { - s_logger.warn("Requested ip address " + requestedIp + " is already in used in " + network); - return null; - } - //check that requested ip has the same cidr - boolean isSameCidr = NetUtils.sameSubnetCIDR(requestedIp.ip4(), cidr[0], Integer.parseInt(cidr[1])); - if (!isSameCidr) { - s_logger.warn("Requested ip address " + requestedIp + " doesn't belong to the network " + network + " cidr"); - return null; - } - - return requestedIp; - } - - long ip = NetUtils.getRandomIpFromCidr(cidr[0], Integer.parseInt(cidr[1]), usedIps); - if (ip == -1) { - s_logger.warn("Unable to allocate any more ip address in " + network); - return null; - } - - return new Ip4Address(ip); - } + public int getVlanOffset(long physicalNetworkId, int vlanTag) { PhysicalNetworkVO pNetwork = _physicalNetworkDao.findById(physicalNetworkId); diff --git a/server/src/com/cloud/network/lb/LBHealthCheckManager.java b/server/src/com/cloud/network/lb/LBHealthCheckManager.java index 2e24965aa35..a9969eb7ce1 100644 --- a/server/src/com/cloud/network/lb/LBHealthCheckManager.java +++ b/server/src/com/cloud/network/lb/LBHealthCheckManager.java @@ -16,9 +16,11 @@ // under the License. package com.cloud.network.lb; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; + public interface LBHealthCheckManager { - void updateLBHealthCheck(); + void updateLBHealthCheck(Scheme scheme); } diff --git a/server/src/com/cloud/network/lb/LBHealthCheckManagerImpl.java b/server/src/com/cloud/network/lb/LBHealthCheckManagerImpl.java index 90547328714..62b738bb498 100644 --- a/server/src/com/cloud/network/lb/LBHealthCheckManagerImpl.java +++ b/server/src/com/cloud/network/lb/LBHealthCheckManagerImpl.java @@ -19,7 +19,6 @@ package com.cloud.network.lb; import static java.lang.String.format; import java.util.Map; - import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -34,6 +33,7 @@ import org.springframework.stereotype.Component; import com.cloud.configuration.Config; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.utils.NumbersUtil; import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; @@ -90,7 +90,8 @@ public class LBHealthCheckManagerImpl extends ManagerBase implements LBHealthChe @Override public void run() { try { - updateLBHealthCheck(); + updateLBHealthCheck(Scheme.Public); + updateLBHealthCheck(Scheme.Internal); } catch (Exception e) { s_logger.error("Exception in LB HealthCheck Update Checker", e); } @@ -98,9 +99,9 @@ public class LBHealthCheckManagerImpl extends ManagerBase implements LBHealthChe } @Override - public void updateLBHealthCheck() { + public void updateLBHealthCheck(Scheme scheme) { try { - _lbService.updateLBHealthChecks(); + _lbService.updateLBHealthChecks(scheme); } catch (ResourceUnavailableException e) { s_logger.debug("Error while updating the LB HealtCheck ", e); } diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManager.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManager.java index d98872a0906..a23d96f8aea 100644 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManager.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManager.java @@ -16,23 +16,24 @@ // under the License. package com.cloud.network.lb; +import java.util.List; + import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceUnavailableException; -import com.cloud.network.Network; import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.lb.LoadBalancingRule.LbHealthCheckPolicy; import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; -import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.LbStickinessMethod; import com.cloud.network.rules.LoadBalancer; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.user.Account; -import org.apache.cloudstack.api.command.user.loadbalancer.CreateLoadBalancerRuleCmd; - -import java.util.List; +import com.cloud.user.UserContext; public interface LoadBalancingRulesManager extends LoadBalancingRulesService { - LoadBalancer createLoadBalancer(CreateLoadBalancerRuleCmd lb, boolean openFirewall) throws NetworkRuleConflictException; + LoadBalancer createPublicLoadBalancer(String xId, String name, String description, + int srcPort, int destPort, long sourceIpId, String protocol, String algorithm, boolean openFirewall, UserContext caller) + throws NetworkRuleConflictException; boolean removeAllLoadBalanacersForIp(long ipId, Account caller, long callerUserId); boolean removeAllLoadBalanacersForNetwork(long networkId, Account caller, long callerUserId); @@ -47,9 +48,14 @@ public interface LoadBalancingRulesManager extends LoadBalancingRulesService { * @return true if removal is successful */ boolean removeVmFromLoadBalancers(long vmId); - boolean applyRules(Network network, FirewallRule.Purpose purpose, List rules) throws ResourceUnavailableException ; - boolean applyLoadBalancersForNetwork(long networkId) throws ResourceUnavailableException; + boolean applyLoadBalancersForNetwork(long networkId, Scheme scheme) throws ResourceUnavailableException; String getLBCapability(long networkid, String capabilityName); boolean configureLbAutoScaleVmGroup(long vmGroupid, String currentState) throws ResourceUnavailableException; - boolean revokeLoadBalancersForNetwork(long networkId) throws ResourceUnavailableException; + boolean revokeLoadBalancersForNetwork(long networkId, Scheme scheme) throws ResourceUnavailableException; + + boolean validateLbRule(LoadBalancingRule lbRule); + + void removeLBRule(LoadBalancer rule); + + void isLbServiceSupportedInNetwork(long networkId, Scheme scheme); } diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index 7ad1070e1c7..520dd763667 100755 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -16,6 +16,34 @@ // under the License. package com.cloud.network.lb; +import java.security.InvalidParameterException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.ejb.Local; +import javax.inject.Inject; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.command.user.loadbalancer.CreateLBHealthCheckPolicyCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.CreateLBStickinessPolicyCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListLBHealthCheckPoliciesCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListLBStickinessPoliciesCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerRuleInstancesCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerRulesCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.UpdateLoadBalancerRuleCmd; +import org.apache.cloudstack.api.response.ServiceResponse; +import org.apache.cloudstack.lb.ApplicationLoadBalancerRuleVO; +import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + import com.cloud.agent.api.to.LoadBalancerTO; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; @@ -30,21 +58,70 @@ import com.cloud.event.EventTypes; import com.cloud.event.UsageEventUtils; import com.cloud.event.dao.EventDao; import com.cloud.event.dao.UsageEventDao; -import com.cloud.exception.*; -import com.cloud.network.*; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.ExternalLoadBalancerUsageManager; +import com.cloud.network.IpAddress; +import com.cloud.network.LBHealthCheckPolicyVO; +import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; -import com.cloud.network.as.*; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkModel; +import com.cloud.network.addr.PublicIp; +import com.cloud.network.as.AutoScalePolicy; +import com.cloud.network.as.AutoScalePolicyConditionMapVO; +import com.cloud.network.as.AutoScaleVmGroup; +import com.cloud.network.as.AutoScaleVmGroupPolicyMapVO; +import com.cloud.network.as.AutoScaleVmGroupVO; +import com.cloud.network.as.AutoScaleVmProfile; import com.cloud.network.as.Condition; -import com.cloud.network.as.dao.*; -import com.cloud.network.dao.*; +import com.cloud.network.as.Counter; +import com.cloud.network.as.dao.AutoScalePolicyConditionMapDao; +import com.cloud.network.as.dao.AutoScalePolicyDao; +import com.cloud.network.as.dao.AutoScaleVmGroupDao; +import com.cloud.network.as.dao.AutoScaleVmGroupPolicyMapDao; +import com.cloud.network.as.dao.AutoScaleVmProfileDao; +import com.cloud.network.as.dao.ConditionDao; +import com.cloud.network.as.dao.CounterDao; +import com.cloud.network.dao.FirewallRulesCidrsDao; +import com.cloud.network.dao.FirewallRulesDao; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.LBHealthCheckPolicyDao; +import com.cloud.network.dao.LBStickinessPolicyDao; +import com.cloud.network.dao.LBStickinessPolicyVO; +import com.cloud.network.dao.LoadBalancerDao; +import com.cloud.network.dao.LoadBalancerVMMapDao; +import com.cloud.network.dao.LoadBalancerVMMapVO; +import com.cloud.network.dao.LoadBalancerVO; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkServiceMapDao; +import com.cloud.network.dao.NetworkVO; import com.cloud.network.element.LoadBalancingServiceProvider; -import com.cloud.network.lb.LoadBalancingRule.*; -import com.cloud.network.rules.*; +import com.cloud.network.lb.LoadBalancingRule.LbAutoScalePolicy; +import com.cloud.network.lb.LoadBalancingRule.LbAutoScaleVmGroup; +import com.cloud.network.lb.LoadBalancingRule.LbAutoScaleVmProfile; +import com.cloud.network.lb.LoadBalancingRule.LbCondition; +import com.cloud.network.lb.LoadBalancingRule.LbDestination; +import com.cloud.network.lb.LoadBalancingRule.LbHealthCheckPolicy; +import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; +import com.cloud.network.rules.FirewallManager; +import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.FirewallRuleType; import com.cloud.network.rules.FirewallRule.Purpose; +import com.cloud.network.rules.FirewallRuleVO; +import com.cloud.network.rules.HealthCheckPolicy; +import com.cloud.network.rules.LbStickinessMethod; import com.cloud.network.rules.LbStickinessMethod.LbStickinessMethodParam; +import com.cloud.network.rules.LoadBalancer; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.network.rules.RulesManager; +import com.cloud.network.rules.StickinessPolicy; import com.cloud.network.vpc.VpcManager; import com.cloud.offering.NetworkOffering; import com.cloud.projects.Project.ListProjectResourcesCriteria; @@ -53,15 +130,25 @@ import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.tags.ResourceTagVO; import com.cloud.tags.dao.ResourceTagDao; -import com.cloud.user.*; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.DomainService; +import com.cloud.user.User; +import com.cloud.user.UserContext; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; import com.cloud.uservm.UserVm; import com.cloud.utils.Pair; import com.cloud.utils.Ternary; import com.cloud.utils.component.ManagerBase; -import com.cloud.utils.db.*; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.JoinBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; import com.cloud.utils.net.NetUtils; import com.cloud.vm.Nic; import com.cloud.vm.UserVmVO; @@ -70,21 +157,11 @@ import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.UserVmDao; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.command.user.loadbalancer.*; -import org.apache.cloudstack.api.response.ServiceResponse; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import javax.ejb.Local; -import javax.inject.Inject; -import java.security.InvalidParameterException; -import java.util.*; @Component @Local(value = { LoadBalancingRulesManager.class, LoadBalancingRulesService.class }) public class LoadBalancingRulesManagerImpl extends ManagerBase implements LoadBalancingRulesManager, - LoadBalancingRulesService, NetworkRuleApplier { + LoadBalancingRulesService { private static final Logger s_logger = Logger.getLogger(LoadBalancingRulesManagerImpl.class); @Inject @@ -166,6 +243,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements UserDao _userDao; @Inject List _lbProviders; + @Inject ApplicationLoadBalancerRuleDao _appLbRuleDao; // Will return a string. For LB Stickiness this will be a json, for // autoscale this will be "," separated values @@ -261,8 +339,9 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements * Regular config like destinations need not be packed for applying * autoscale config as of today. */ - List policyList = getStickinessPolicies(lb.getId()); - LoadBalancingRule rule = new LoadBalancingRule(lb, null, policyList, null); + List policyList = getStickinessPolicies(lb.getId()); + Ip sourceIp = getSourceIp(lb); + LoadBalancingRule rule = new LoadBalancingRule(lb, null, policyList, null, sourceIp); rule.setAutoScaleVmGroup(lbAutoScaleVmGroup); if (!isRollBackAllowedForProvider(lb)) { @@ -273,7 +352,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements List rules = Arrays.asList(rule); - if (!_networkMgr.applyRules(rules, FirewallRule.Purpose.LoadBalancing, this, false)) { + if (!applyLbRules(rules, false)) { s_logger.debug("LB rules' autoscale config are not completely applied"); return false; } @@ -281,6 +360,17 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements return true; } + private Ip getSourceIp(LoadBalancer lb) { + Ip sourceIp = null; + if (lb.getScheme() == Scheme.Public) { + sourceIp = _networkModel.getPublicIpAddress(lb.getSourceIpAddressId()).getAddress(); + } else if (lb.getScheme() == Scheme.Internal) { + ApplicationLoadBalancerRuleVO appLbRule = _appLbRuleDao.findById(lb.getId()); + sourceIp = appLbRule.getSourceIp(); + } + return sourceIp; + } + @Override @DB public boolean configureLbAutoScaleVmGroup(long vmGroupid, String currentState) throws ResourceUnavailableException { @@ -454,9 +544,10 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements cmd.getStickinessMethodName(), cmd.getparamList(), cmd.getDescription()); List policyList = new ArrayList(); policyList.add(new LbStickinessPolicy(cmd.getStickinessMethodName(), lbpolicy.getParams())); + Ip sourceIp = getSourceIp(loadBalancer); LoadBalancingRule lbRule = new LoadBalancingRule(loadBalancer, getExistingDestinations(lbpolicy.getId()), - policyList, null); - if (!validateRule(lbRule)) { + policyList, null, sourceIp); + if (!validateLbRule(lbRule)) { throw new InvalidParameterValueException("Failed to create Stickiness policy: Validation Failed " + cmd.getLbRuleId()); } @@ -539,7 +630,8 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements return policy; } - private boolean validateRule(LoadBalancingRule lbRule) { + @Override + public boolean validateLbRule(LoadBalancingRule lbRule) { Network network = _networkDao.findById(lbRule.getNetworkId()); Purpose purpose = lbRule.getPurpose(); if (purpose != Purpose.LoadBalancing) { @@ -748,7 +840,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements // by CloudStack and update them in lbvmmap table @DB @Override - public void updateLBHealthChecks() throws ResourceUnavailableException { + public void updateLBHealthChecks(Scheme scheme) throws ResourceUnavailableException { List rules = _lbDao.listAll(); List networks = _networkDao.listAll(); List stateRules = null; @@ -763,7 +855,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements * "HealthCheck Manager :: LB Provider in the Network has the Healthcheck policy capability :: " * + provider.get(0).getName()); */ - rules = _lbDao.listByNetworkId(network.getId()); + rules = _lbDao.listByNetworkIdAndScheme(network.getId(), scheme); if (rules != null && rules.size() > 0) { List lbrules = new ArrayList(); for (LoadBalancerVO lb : rules) { @@ -772,7 +864,8 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements // adding to lbrules list only if the LB rule // hashealtChecks if (hcPolicyList != null && hcPolicyList.size() > 0) { - LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, null, hcPolicyList); + Ip sourceIp = getSourceIp(lb); + LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, null, hcPolicyList, sourceIp); lbrules.add(loadBalancing); } } @@ -1168,31 +1261,21 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements @Override @ActionEvent(eventType = EventTypes.EVENT_LOAD_BALANCER_CREATE, eventDescription = "creating load balancer") - public LoadBalancer createLoadBalancerRule(CreateLoadBalancerRuleCmd lb, boolean openFirewall) + public LoadBalancer createPublicLoadBalancerRule(String xId, String name, String description, + int srcPortStart, int srcPortEnd, int defPortStart, int defPortEnd, Long ipAddrId, String protocol, String algorithm, long networkId, long lbOwnerId, boolean openFirewall) throws NetworkRuleConflictException, InsufficientAddressCapacityException { - Account lbOwner = _accountMgr.getAccount(lb.getEntityOwnerId()); - - int defPortStart = lb.getDefaultPortStart(); - int defPortEnd = lb.getDefaultPortEnd(); - - if (!NetUtils.isValidPort(defPortEnd)) { - throw new InvalidParameterValueException("privatePort is an invalid value: " + defPortEnd); - } - if (defPortStart > defPortEnd) { - throw new InvalidParameterValueException("private port range is invalid: " + defPortStart + "-" - + defPortEnd); - } - if ((lb.getAlgorithm() == null) || !NetUtils.isValidAlgorithm(lb.getAlgorithm())) { - throw new InvalidParameterValueException("Invalid algorithm: " + lb.getAlgorithm()); + Account lbOwner = _accountMgr.getAccount(lbOwnerId); + + if (srcPortStart != srcPortEnd) { + throw new InvalidParameterValueException("Port ranges are not supported by the load balancer"); } - Long ipAddrId = lb.getSourceIpAddressId(); IPAddressVO ipVO = null; if (ipAddrId != null) { ipVO = _ipAddressDao.findById(ipAddrId); } - Network network = _networkModel.getNetwork(lb.getNetworkId()); + Network network = _networkModel.getNetwork(networkId); // FIXME: breaking the dependency on ELB manager. This breaks // functionality of ELB using virtual router @@ -1204,8 +1287,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements IpAddress systemIp = null; NetworkOffering off = _configMgr.getNetworkOffering(network.getNetworkOfferingId()); if (off.getElasticLb() && ipVO == null && network.getVpcId() == null) { - systemIp = _networkMgr.assignSystemIp(lb.getNetworkId(), lbOwner, true, false); - lb.setSourceIpAddressId(systemIp.getId()); + systemIp = _networkMgr.assignSystemIp(networkId, lbOwner, true, false); ipVO = _ipAddressDao.findById(systemIp.getId()); } @@ -1224,11 +1306,11 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements && ipVO.getVpcId().longValue() == network.getVpcId(); if (assignToVpcNtwk) { // set networkId just for verification purposes - _networkModel.checkIpForService(ipVO, Service.Lb, lb.getNetworkId()); + _networkModel.checkIpForService(ipVO, Service.Lb, networkId); - s_logger.debug("The ip is not associated with the VPC network id=" + lb.getNetworkId() + s_logger.debug("The ip is not associated with the VPC network id=" + networkId + " so assigning"); - ipVO = _networkMgr.associateIPToGuestNetwork(ipAddrId, lb.getNetworkId(), false); + ipVO = _networkMgr.associateIPToGuestNetwork(ipAddrId, networkId, false); performedIpAssoc = true; } } else { @@ -1240,10 +1322,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements + network); } - if (lb.getSourceIpAddressId() == null) { - throw new CloudRuntimeException("No ip address is defined to assign the LB to"); - } - result = createLoadBalancer(lb, openFirewall); + result = createPublicLoadBalancer(xId, name, description, srcPortStart, defPortStart, ipVO.getId(), protocol, algorithm, openFirewall, UserContext.current()); } catch (Exception ex) { s_logger.warn("Failed to create load balancer due to ", ex); if (ex instanceof NetworkRuleConflictException) { @@ -1258,27 +1337,31 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements // release ip address if ipassoc was perfored if (performedIpAssoc) { ipVO = _ipAddressDao.findById(ipVO.getId()); - _vpcMgr.unassignIPFromVpcNetwork(ipVO.getId(), lb.getNetworkId()); + _vpcMgr.unassignIPFromVpcNetwork(ipVO.getId(), networkId); } } } if (result == null) { - throw new CloudRuntimeException("Failed to create load balancer rule: " + lb.getName()); + throw new CloudRuntimeException("Failed to create load balancer rule: " + name); } return result; } - @Override @DB - public LoadBalancer createLoadBalancer(CreateLoadBalancerRuleCmd lb, boolean openFirewall) + @Override + public LoadBalancer createPublicLoadBalancer(String xId, String name, String description, + int srcPort, int destPort, long sourceIpId, String protocol, String algorithm, boolean openFirewall, UserContext caller) throws NetworkRuleConflictException { - UserContext caller = UserContext.current(); - int srcPortStart = lb.getSourcePortStart(); - int defPortStart = lb.getDefaultPortStart(); - int srcPortEnd = lb.getSourcePortEnd(); - long sourceIpId = lb.getSourceIpAddressId(); + + if (!NetUtils.isValidPort(destPort)) { + throw new InvalidParameterValueException("privatePort is an invalid value: " + destPort); + } + + if ((algorithm == null) || !NetUtils.isValidAlgorithm(algorithm)) { + throw new InvalidParameterValueException("Invalid algorithm: " + algorithm); + } IPAddressVO ipAddr = _ipAddressDao.findById(sourceIpId); // make sure ip address exists @@ -1293,6 +1376,9 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements ex.addProxyObject(ipAddr, sourceIpId, "sourceIpId"); throw ex; } + + _accountMgr.checkAccess(caller.getCaller(), null, true, ipAddr); + Long networkId = ipAddr.getAssociatedWithNetworkId(); if (networkId == null) { @@ -1301,39 +1387,34 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements ex.addProxyObject(ipAddr, sourceIpId, "sourceIpId"); throw ex; } - - _firewallMgr.validateFirewallRule(caller.getCaller(), ipAddr, srcPortStart, srcPortEnd, lb.getProtocol(), - Purpose.LoadBalancing, FirewallRuleType.User, networkId, null); - NetworkVO network = _networkDao.findById(networkId); - _accountMgr.checkAccess(caller.getCaller(), null, true, ipAddr); - + // verify that lb service is supported by the network - if (!_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Lb)) { - InvalidParameterValueException ex = new InvalidParameterValueException( - "LB service is not supported in specified network id"); - ex.addProxyObject(network, networkId, "networkId"); - throw ex; + isLbServiceSupportedInNetwork(networkId, Scheme.Public); + + _firewallMgr.validateFirewallRule(caller.getCaller(), ipAddr, srcPort, srcPort, protocol, + Purpose.LoadBalancing, FirewallRuleType.User, networkId, null); + + LoadBalancerVO newRule = new LoadBalancerVO(xId, name, description, + sourceIpId, srcPort, srcPort, algorithm, + networkId, ipAddr.getAllocatedToAccountId(), ipAddr.getAllocatedInDomainId()); + + // verify rule is supported by Lb provider of the network + Ip sourceIp = getSourceIp(newRule); + LoadBalancingRule loadBalancing = new LoadBalancingRule(newRule, new ArrayList(), + new ArrayList(), new ArrayList(), sourceIp); + if (!validateLbRule(loadBalancing)) { + throw new InvalidParameterValueException("LB service provider cannot support this rule"); } Transaction txn = Transaction.currentTxn(); txn.start(); - - LoadBalancerVO newRule = new LoadBalancerVO(lb.getXid(), lb.getName(), lb.getDescription(), - lb.getSourceIpAddressId(), lb.getSourcePortEnd(), lb.getDefaultPortStart(), lb.getAlgorithm(), - network.getId(), ipAddr.getAllocatedToAccountId(), ipAddr.getAllocatedInDomainId()); - - // verify rule is supported by Lb provider of the network - LoadBalancingRule loadBalancing = new LoadBalancingRule(newRule, new ArrayList(), - new ArrayList(), new ArrayList()); - if (!validateRule(loadBalancing)) { - throw new InvalidParameterValueException("LB service provider cannot support this rule"); - } - + newRule = _lbDao.persist(newRule); + //create rule for all CIDRs if (openFirewall) { - _firewallMgr.createRuleForAllCidrs(sourceIpId, caller.getCaller(), lb.getSourcePortStart(), - lb.getSourcePortEnd(), lb.getProtocol(), null, null, newRule.getId(), networkId); + _firewallMgr.createRuleForAllCidrs(sourceIpId, caller.getCaller(), srcPort, + srcPort, protocol, null, null, newRule.getId(), networkId); } boolean success = true; @@ -1344,7 +1425,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements throw new CloudRuntimeException("Unable to update the state to add for " + newRule); } s_logger.debug("Load balancer " + newRule.getId() + " for Ip address id=" + sourceIpId + ", public port " - + srcPortStart + ", private port " + defPortStart + " is added successfully."); + + srcPort + ", private port " + destPort + " is added successfully."); UserContext.current().setEventDetails("Load balancer Id: " + newRule.getId()); UsageEventUtils.publishUsageEvent(EventTypes.EVENT_LOAD_BALANCER_CREATE, ipAddr.getAllocatedToAccountId(), ipAddr.getDataCenterId(), newRule.getId(), null, LoadBalancingRule.class.getName(), @@ -1380,14 +1461,17 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements lbs = Arrays.asList(lb); } else { // get all rules in transition state - lbs = _lbDao.listInTransitionStateByNetworkId(lb.getNetworkId()); + lbs = _lbDao.listInTransitionStateByNetworkIdAndScheme(lb.getNetworkId(), lb.getScheme()); } return applyLoadBalancerRules(lbs, true); } @Override - public boolean revokeLoadBalancersForNetwork(long networkId) throws ResourceUnavailableException { - List lbs = _lbDao.listByNetworkId(networkId); + public boolean revokeLoadBalancersForNetwork(long networkId, Scheme scheme) throws ResourceUnavailableException { + List lbs = _lbDao.listByNetworkIdAndScheme(networkId, scheme); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Revoking " + lbs.size() + " " + scheme + " load balancing rules for network id=" + networkId); + } if (lbs != null) { for(LoadBalancerVO lb : lbs) { // called during restart, not persisting state in db lb.setState(FirewallRule.State.Revoke); @@ -1400,20 +1484,20 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements } @Override - public boolean applyLoadBalancersForNetwork(long networkId) throws ResourceUnavailableException { - List lbs = _lbDao.listByNetworkId(networkId); + public boolean applyLoadBalancersForNetwork(long networkId, Scheme scheme) throws ResourceUnavailableException { + List lbs = _lbDao.listByNetworkIdAndScheme(networkId, scheme); if (lbs != null) { + s_logger.debug("Applying load balancer rules of scheme " + scheme + " in network id=" + networkId); return applyLoadBalancerRules(lbs, true); } else { - s_logger.info("Network id=" + networkId + " doesn't have load balancer rules, nothing to apply"); + s_logger.info("Network id=" + networkId + " doesn't have load balancer rules of scheme " + scheme + ", nothing to apply"); return true; } } - @Override - public boolean applyRules(Network network, Purpose purpose, List rules) + + protected boolean applyLbRules(Network network, List rules) throws ResourceUnavailableException { - assert (purpose == Purpose.LoadBalancing) : "LB Manager asked to handle non-LB rules"; boolean handled = false; for (LoadBalancingServiceProvider lbElement : _lbProviders) { Provider provider = lbElement.getProvider(); @@ -1422,7 +1506,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements if (!isLbProvider) { continue; } - handled = lbElement.applyLBRules(network, (List) rules); + handled = lbElement.applyLBRules(network, rules); if (handled) break; } @@ -1432,7 +1516,8 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements private LoadBalancingRule getLoadBalancerRuleToApply(LoadBalancerVO lb) { List policyList = getStickinessPolicies(lb.getId()); - LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, null, policyList, null); + Ip sourceIp = getSourceIp(lb); + LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, null, policyList, null, sourceIp); if (_autoScaleVmGroupDao.isAutoScaleLoadBalancer(lb.getId())) { // Get the associated VmGroup @@ -1442,7 +1527,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements } else { List dstList = getExistingDestinations(lb.getId()); loadBalancing.setDestinations(dstList); - List hcPolicyList = getHealthCheckPolicies(lb.getId()); + List hcPolicyList = getHealthCheckPolicies(lb.getId()); loadBalancing.setHealthCheckPolicies(hcPolicyList); } @@ -1458,7 +1543,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements rules.add(getLoadBalancerRuleToApply(lb)); } - if (!_networkMgr.applyRules(rules, FirewallRule.Purpose.LoadBalancing, this, false)) { + if (!applyLbRules(rules, false)) { s_logger.debug("LB rules are not completely applied"); return false; } @@ -1515,7 +1600,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements } txn.commit(); - if (checkForReleaseElasticIp) { + if (checkForReleaseElasticIp && lb.getSourceIpAddressId() != null) { boolean success = true; long count = _firewallDao.countRulesByIpId(lb.getSourceIpAddressId()); if (count == 0) { @@ -1534,8 +1619,10 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements } // if the rule is the last one for the ip address assigned to // VPC, unassign it from the network - IpAddress ip = _ipAddressDao.findById(lb.getSourceIpAddressId()); - _vpcMgr.unassignIPFromVpcNetwork(ip.getId(), lb.getNetworkId()); + if (lb.getSourceIpAddressId() != null) { + IpAddress ip = _ipAddressDao.findById(lb.getSourceIpAddressId()); + _vpcMgr.unassignIPFromVpcNetwork(ip.getId(), lb.getNetworkId()); + } } } @@ -1902,32 +1989,115 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements count++; } } + + //list only Public load balancers using this command + sc.setParameters("scheme", Scheme.Public); Pair, Integer> result = _lbDao.searchAndCount(sc, searchFilter); return new Pair, Integer>(result.first(), result.second()); } - @Override - public List listByNetworkId(long networkId) { - List lbs = _lbDao.listByNetworkId(networkId); - List lbRules = new ArrayList(); - for (LoadBalancerVO lb : lbs) { - List dstList = getExistingDestinations(lb.getId()); - List policyList = this.getStickinessPolicies(lb.getId()); - List hcPolicyList = this.getHealthCheckPolicies(lb.getId()); - LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList); - lbRules.add(loadBalancing); - } - return lbRules; - } @Override public LoadBalancerVO findById(long lbId) { return _lbDao.findById(lbId); } - protected void removeLBRule(LoadBalancerVO rule) { + @Override + public void removeLBRule(LoadBalancer rule) { // remove the rule _lbDao.remove(rule.getId()); } + + + public boolean applyLbRules(List rules, boolean continueOnError) throws ResourceUnavailableException { + if (rules == null || rules.size() == 0) { + s_logger.debug("There are no Load Balancing Rules to forward to the network elements"); + return true; + } + + boolean success = true; + Network network = _networkModel.getNetwork(rules.get(0).getNetworkId()); + List publicIps = new ArrayList(); + + + // get the list of public ip's owned by the network + List userIps = _ipAddressDao.listByAssociatedNetwork(network.getId(), null); + if (userIps != null && !userIps.isEmpty()) { + for (IPAddressVO userIp : userIps) { + PublicIp publicIp = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId())); + publicIps.add(publicIp); + } + } + + // rules can not programmed unless IP is associated with network + // service provider, so run IP assoication for + // the network so as to ensure IP is associated before applying + // rules (in add state) + _networkMgr.applyIpAssociations(network, false, continueOnError, publicIps); + + + try { + applyLbRules(network, rules); + } catch (ResourceUnavailableException e) { + if (!continueOnError) { + throw e; + } + s_logger.warn("Problems with applying load balancing rules but pushing on", e); + success = false; + } + + // if all the rules configured on public IP are revoked then + // dis-associate IP with network service provider + _networkMgr.applyIpAssociations(network, true, continueOnError, publicIps); + + return success; + } + + @Override + public Map getLbInstances(long lbId) { + Map dstList = new HashMap(); + List lbVmMaps = _lb2VmMapDao.listByLoadBalancerId(lbId); + LoadBalancerVO lb = _lbDao.findById(lbId); + + for (LoadBalancerVMMapVO lbVmMap : lbVmMaps) { + UserVm vm = _vmDao.findById(lbVmMap.getInstanceId()); + Nic nic = _nicDao.findByInstanceIdAndNetworkIdIncludingRemoved(lb.getNetworkId(), vm.getId()); + Ip ip = new Ip(nic.getIp4Address()); + dstList.put(ip, vm); + } + return dstList; + } + + @Override + public void isLbServiceSupportedInNetwork(long networkId, Scheme scheme) { + Network network = _networkDao.findById(networkId); + + //1) Check if the LB service is supported + if (!_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Lb)) { + InvalidParameterValueException ex = new InvalidParameterValueException( + "LB service is not supported in specified network id"); + ex.addProxyObject(network, network.getId(), "networkId"); + throw ex; + } + + //2) Check if the Scheme is supported\ + NetworkOffering off = _configMgr.getNetworkOffering(network.getNetworkOfferingId()); + if (scheme == Scheme.Public) { + if (!off.getPublicLb()) { + throw new InvalidParameterValueException("Scheme " + scheme + " is not supported by the network offering " + off); + } + } else { + if (!off.getInternalLb()) { + throw new InvalidParameterValueException("Scheme " + scheme + " is not supported by the network offering " + off); + } + } + + //3) Check if the provider supports the scheme + LoadBalancingServiceProvider lbProvider = _networkMgr.getLoadBalancingProviderForNetwork(network, scheme); + if (lbProvider == null) { + throw new InvalidParameterValueException("Lb rule with scheme " + scheme.toString() + " is not supported by lb providers in network " + network); + } + } + } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java index f49ab79b500..fcf650f900c 100644 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java @@ -28,6 +28,7 @@ import com.cloud.network.PublicIpAddress; import com.cloud.network.RemoteAccessVpn; import com.cloud.network.VirtualNetworkApplianceService; import com.cloud.network.VpnUser; +import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.StaticNat; import com.cloud.user.Account; @@ -103,4 +104,7 @@ public interface VirtualNetworkApplianceManager extends Manager, VirtualNetworkA boolean applyUserData(Network config, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, List routers) throws ResourceUnavailableException; + + boolean applyLoadBalancingRules(Network network, List rules, List routers) throws ResourceUnavailableException; + } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 4c7bc75b2d3..e3dd06ba47c 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -173,6 +173,7 @@ import com.cloud.network.router.VirtualRouter.RedundantState; import com.cloud.network.router.VirtualRouter.Role; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.RulesManager; import com.cloud.network.rules.StaticNat; @@ -218,6 +219,7 @@ import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; import com.cloud.utils.net.MacAddress; import com.cloud.utils.net.NetUtils; import com.cloud.vm.DomainRouterVO; @@ -1526,7 +1528,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V for (int i = 0; i < count; i++) { List> networks = createRouterNetworks(owner, isRedundant, plan, guestNetwork, new Pair(publicNetwork, sourceNatIp)); - //don't start the router as we are holding the network lock that needs to be released at the end of router allocation + //don't start the router as we are holding the network lock that needs to be released at the end of router allocation DomainRouterVO router = deployRouter(owner, destination, plan, params, isRedundant, vrProvider, offeringId, null, networks, false, null); @@ -1591,7 +1593,26 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V HypervisorType hType = iter.next(); try { s_logger.debug("Allocating the domR with the hypervisor type " + hType); - VMTemplateVO template = _templateDao.findRoutingTemplate(hType); + String templateName = null; + switch (hType) { + case XenServer: + templateName = _configServer.getConfigValue(Config.RouterTemplateXen.key(), Config.ConfigurationParameterScope.zone.toString(), dest.getDataCenter().getId()); + break; + case KVM: + templateName = _configServer.getConfigValue(Config.RouterTemplateKVM.key(), Config.ConfigurationParameterScope.zone.toString(), dest.getDataCenter().getId()); + break; + case VMware: + templateName = _configServer.getConfigValue(Config.RouterTemplateVmware.key(), Config.ConfigurationParameterScope.zone.toString(), dest.getDataCenter().getId()); + break; + case Hyperv: + templateName = _configServer.getConfigValue(Config.RouterTemplateHyperv.key(), Config.ConfigurationParameterScope.zone.toString(), dest.getDataCenter().getId()); + break; + case LXC: + templateName = _configServer.getConfigValue(Config.RouterTemplateLXC.key(), Config.ConfigurationParameterScope.zone.toString(), dest.getDataCenter().getId()); + break; + default: break; + } + VMTemplateVO template = _templateDao.findRoutingTemplate(hType, templateName); if (template == null) { s_logger.debug(hType + " won't support system vm, skip it"); @@ -2391,7 +2412,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V } } - List lbs = _loadBalancerDao.listByNetworkId(guestNetworkId); + List lbs = _loadBalancerDao.listByNetworkIdAndScheme(guestNetworkId, Scheme.Public); List lbRules = new ArrayList(); if (_networkModel.isProviderSupportServiceInNetwork(guestNetworkId, Service.Lb, provider)) { // Re-apply load balancing rules @@ -2399,7 +2420,8 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V List dstList = _lbMgr.getExistingDestinations(lb.getId()); List policyList = _lbMgr.getStickinessPolicies(lb.getId()); List hcPolicyList = _lbMgr.getHealthCheckPolicies(lb.getId()); - LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList); + Ip sourceIp = _networkModel.getPublicIpAddress(lb.getSourceIpAddressId()).getAddress(); + LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList, sourceIp); lbRules.add(loadBalancing); } } @@ -2490,7 +2512,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V Network network = _networkModel.getNetwork(routerNic.getNetworkId()); if (network.getTrafficType() == TrafficType.Guest) { guestNetworks.add(network); - } + } } answer = cmds.getAnswer("getDomRVersion"); @@ -3017,7 +3039,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V String algorithm = rule.getAlgorithm(); String uuid = rule.getUuid(); - String srcIp = _networkModel.getIp(rule.getSourceIpAddressId()).getAddress().addr(); + String srcIp = rule.getSourceIp().addr(); int srcPort = rule.getSourcePortStart(); List destinations = rule.getDestinations(); List stickinessPolicies = rule.getStickinessPolicies(); @@ -3032,7 +3054,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V } Network guestNetwork = _networkModel.getNetwork(guestNetworkId); - Nic nic = _nicDao.findByInstanceIdAndNetworkId(guestNetwork.getId(), router.getId()); + Nic nic = _nicDao.findByNtwkIdAndInstanceId(guestNetwork.getId(), router.getId()); NicProfile nicProfile = new NicProfile(nic, guestNetwork, nic.getBroadcastUri(), nic.getIsolationUri(), _networkModel.getNetworkRate(guestNetwork.getId(), router.getId()), _networkModel.isSecurityGroupSupportedInNetwork(guestNetwork), @@ -3125,7 +3147,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V } if (createVmData) { - NicVO nic = _nicDao.findByInstanceIdAndNetworkId(guestNetworkId, vm.getId()); + NicVO nic = _nicDao.findByNtwkIdAndInstanceId(guestNetworkId, vm.getId()); if (nic != null) { s_logger.debug("Creating user data entry for vm " + vm + " on domR " + router); createVmDataCommand(router, vm, nic, null, cmds); @@ -3178,7 +3200,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V createDhcp = false; } if (createDhcp) { - NicVO nic = _nicDao.findByInstanceIdAndNetworkId(guestNetworkId, vm.getId()); + NicVO nic = _nicDao.findByNtwkIdAndInstanceId(guestNetworkId, vm.getId()); if (nic != null) { s_logger.debug("Creating dhcp entry for vm " + vm + " on domR " + router + "."); createDhcpEntryCommand(router, vm, nic, cmds); @@ -3296,13 +3318,14 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V public boolean execute(Network network, VirtualRouter router) throws ResourceUnavailableException { if (rules.get(0).getPurpose() == Purpose.LoadBalancing) { // for load balancer we have to resend all lb rules for the network - List lbs = _loadBalancerDao.listByNetworkId(network.getId()); + List lbs = _loadBalancerDao.listByNetworkIdAndScheme(network.getId(), Scheme.Public); List lbRules = new ArrayList(); for (LoadBalancerVO lb : lbs) { List dstList = _lbMgr.getExistingDestinations(lb.getId()); List policyList = _lbMgr.getStickinessPolicies(lb.getId()); - List hcPolicyList = _lbMgr.getHealthCheckPolicies(lb.getId() ); - LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList); + List hcPolicyList = _lbMgr.getHealthCheckPolicies(lb.getId()); + Ip sourceIp = _networkModel.getPublicIpAddress(lb.getSourceIpAddressId()).getAddress(); + LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList, sourceIp); lbRules.add(loadBalancing); } return sendLBRules(router, lbRules, network.getId()); @@ -3319,6 +3342,32 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V } }); } + + + @Override + public boolean applyLoadBalancingRules(Network network, final List rules, List routers) throws ResourceUnavailableException { + if (rules == null || rules.isEmpty()) { + s_logger.debug("No lb rules to be applied for network " + network.getId()); + return true; + } + return applyRules(network, routers, "loadbalancing rules", false, null, false, new RuleApplier() { + @Override + public boolean execute(Network network, VirtualRouter router) throws ResourceUnavailableException { + // for load balancer we have to resend all lb rules for the network + List lbs = _loadBalancerDao.listByNetworkIdAndScheme(network.getId(), Scheme.Public); + List lbRules = new ArrayList(); + for (LoadBalancerVO lb : lbs) { + List dstList = _lbMgr.getExistingDestinations(lb.getId()); + List policyList = _lbMgr.getStickinessPolicies(lb.getId()); + List hcPolicyList = _lbMgr.getHealthCheckPolicies(lb.getId()); + Ip sourceIp = _networkModel.getPublicIpAddress(lb.getSourceIpAddressId()).getAddress(); + LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList, sourceIp); + lbRules.add(loadBalancing); + } + return sendLBRules(router, lbRules, network.getId()); + } + }); + } protected boolean sendLBRules(VirtualRouter router, List rules, long guestNetworkId) throws ResourceUnavailableException { Commands cmds = new Commands(OnError.Continue); @@ -3715,4 +3764,11 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V } } } + + + + @Override + public VirtualRouter findRouter(long routerId) { + return _routerDao.findById(routerId); + } } diff --git a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java index bdfac060798..611100955e7 100644 --- a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java @@ -440,7 +440,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian defaultDns2 = guestNic.getDns2(); } - Nic nic = _nicDao.findByInstanceIdAndNetworkId(network.getId(), router.getId()); + Nic nic = _nicDao.findByNtwkIdAndInstanceId(network.getId(), router.getId()); String networkDomain = network.getNetworkDomain(); String dhcpRange = getGuestDhcpRange(guestNic, network, _configMgr.getZone(network.getDataCenterId())); @@ -1178,8 +1178,8 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian for (final PrivateIpAddress ipAddr : ipAddrList) { Network network = _networkModel.getNetwork(ipAddr.getNetworkId()); - IpAddressTO ip = new IpAddressTO(Account.ACCOUNT_ID_SYSTEM, ipAddr.getIpAddress(), add, false, - false, ipAddr.getVlanTag(), ipAddr.getGateway(), ipAddr.getNetmask(), ipAddr.getMacAddress(), + IpAddressTO ip = new IpAddressTO(Account.ACCOUNT_ID_SYSTEM, ipAddr.getIpAddress(), add, false, + ipAddr.getSourceNat(), ipAddr.getVlanTag(), ipAddr.getGateway(), ipAddr.getNetmask(), ipAddr.getMacAddress(), null, false); ip.setTrafficType(network.getTrafficType()); diff --git a/server/src/com/cloud/network/rules/RulesManager.java b/server/src/com/cloud/network/rules/RulesManager.java index 4b83e04eb28..cede987280d 100644 --- a/server/src/com/cloud/network/rules/RulesManager.java +++ b/server/src/com/cloud/network/rules/RulesManager.java @@ -24,6 +24,7 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.IpAddress; import com.cloud.user.Account; import com.cloud.uservm.UserVm; +import com.cloud.vm.Nic; import com.cloud.vm.VirtualMachine; /** @@ -87,4 +88,6 @@ public interface RulesManager extends RulesService { */ boolean applyStaticNatForNetwork(long networkId, boolean continueOnError, Account caller, boolean forRevoke); + List listAssociatedRulesForGuestNic(Nic nic); + } diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java index 8636d8503a3..c9b47b44bab 100755 --- a/server/src/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java @@ -50,8 +50,11 @@ import com.cloud.network.dao.FirewallRulesCidrsDao; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.LoadBalancerVMMapDao; +import com.cloud.network.dao.LoadBalancerVMMapVO; import com.cloud.network.rules.FirewallRule.FirewallRuleType; import com.cloud.network.rules.FirewallRule.Purpose; +import com.cloud.network.rules.FirewallRule.TrafficType; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.vpc.VpcManager; import com.cloud.offering.NetworkOffering; @@ -77,15 +80,18 @@ import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.Ip; +import com.cloud.utils.net.NetUtils; import com.cloud.vm.Nic; import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.UserVmVO; +import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.NicSecondaryIpDao; import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.VMInstanceDao; @Component @Local(value = { RulesManager.class, RulesService.class }) @@ -103,6 +109,8 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules @Inject UserVmDao _vmDao; @Inject + VMInstanceDao _vmInstanceDao; + @Inject AccountManager _accountMgr; @Inject NetworkManager _networkMgr; @@ -128,6 +136,8 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules VpcManager _vpcMgr; @Inject NicSecondaryIpDao _nicSecondaryDao; + @Inject + LoadBalancerVMMapDao _loadBalancerVMMapDao; @Override public void checkIpAndUserVm(IpAddress ipAddress, UserVm userVm, Account caller) { @@ -416,7 +426,12 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules @Override @ActionEvent(eventType = EventTypes.EVENT_ENABLE_STATIC_NAT, eventDescription = "enabling static nat") - public boolean enableStaticNat(long ipId, long vmId, long networkId, boolean isSystemVm, String vmGuestIp) + public boolean enableStaticNat(long ipId, long vmId, long networkId, String vmGuestIp) + throws NetworkRuleConflictException, ResourceUnavailableException { + return enableStaticNat(ipId, vmId, networkId, false, vmGuestIp); + } + + private boolean enableStaticNat(long ipId, long vmId, long networkId, boolean isSystemVm, String vmGuestIp) throws NetworkRuleConflictException, ResourceUnavailableException { UserContext ctx = UserContext.current(); Account caller = ctx.getCaller(); @@ -1370,7 +1385,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules throw new CloudRuntimeException("Ip address is not associated with any network"); } - UserVmVO vm = _vmDao.findById(sourceIp.getAssociatedWithVmId()); + VMInstanceVO vm = _vmInstanceDao.findById(sourceIp.getAssociatedWithVmId()); Network network = _networkModel.getNetwork(networkId); if (network == null) { CloudRuntimeException ex = new CloudRuntimeException("Unable to find an ip address to map to specified vm id"); @@ -1458,4 +1473,36 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules protected void removePFRule(PortForwardingRuleVO rule) { _portForwardingDao.remove(rule.getId()); } + + @Override + public List listAssociatedRulesForGuestNic(Nic nic){ + List result = new ArrayList(); + // add PF rules + result.addAll(_portForwardingDao.listByDestIpAddr(nic.getIp4Address())); + // add static NAT rules + List staticNatRules = _firewallDao.listStaticNatByVmId(nic.getInstanceId()); + for(FirewallRuleVO rule : staticNatRules){ + if(rule.getNetworkId() == nic.getNetworkId()) + result.add(rule); + } + List staticNatIps = _ipAddressDao.listStaticNatPublicIps(nic.getNetworkId()); + for(IpAddress ip : staticNatIps){ + if(ip.getVmIp() != null && ip.getVmIp().equals(nic.getIp4Address())){ + VMInstanceVO vm = _vmInstanceDao.findById(nic.getInstanceId()); + // generate a static Nat rule on the fly because staticNATrule does not persist into db anymore + // FIX ME + FirewallRuleVO staticNatRule = new FirewallRuleVO(null, ip.getId(), 0, 65535, NetUtils.ALL_PROTO.toString(), + nic.getNetworkId(), vm.getAccountId(), vm.getDomainId(), Purpose.StaticNat, null, null, null, null, null); + result.add(staticNatRule); + } + } + // add LB rules + List lbMapList = _loadBalancerVMMapDao.listByInstanceId(nic.getInstanceId()); + for(LoadBalancerVMMapVO lb : lbMapList){ + FirewallRuleVO lbRule = _firewallDao.findById(lb.getLoadBalancerId()); + if(lbRule.getNetworkId() == nic.getNetworkId()) + result.add(lbRule); + } + return result; + } } diff --git a/server/src/com/cloud/network/vpc/PrivateGatewayProfile.java b/server/src/com/cloud/network/vpc/PrivateGatewayProfile.java index 2595a6a0fa4..20947db0447 100644 --- a/server/src/com/cloud/network/vpc/PrivateGatewayProfile.java +++ b/server/src/com/cloud/network/vpc/PrivateGatewayProfile.java @@ -100,4 +100,9 @@ public class PrivateGatewayProfile implements PrivateGateway { public State getState() { return vpcGateway.getState(); } + + @Override + public boolean getSourceNat() { + return vpcGateway.getSourceNat(); + } } diff --git a/server/src/com/cloud/network/vpc/PrivateIpAddress.java b/server/src/com/cloud/network/vpc/PrivateIpAddress.java index 826bea22e25..2f3cf536e81 100644 --- a/server/src/com/cloud/network/vpc/PrivateIpAddress.java +++ b/server/src/com/cloud/network/vpc/PrivateIpAddress.java @@ -25,6 +25,7 @@ public class PrivateIpAddress implements PrivateIp{ String ipAddress; String macAddress; long networkId; + boolean sourceNat; /** * @param privateIp @@ -42,6 +43,7 @@ public class PrivateIpAddress implements PrivateIp{ this.netmask = netmask; this.macAddress = macAddress; this.networkId = privateIp.getNetworkId(); + this.sourceNat = privateIp.getSourceNat(); } @Override @@ -73,4 +75,9 @@ public class PrivateIpAddress implements PrivateIp{ public long getNetworkId() { return networkId; } + + @Override + public boolean getSourceNat() { + return sourceNat; + } } diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index 4e171aa5509..552332e128a 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -184,8 +184,9 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("VpcChecker")); private List vpcElements = null; private final List nonSupportedServices = Arrays.asList(Service.SecurityGroup, Service.Firewall); - private final List supportedProviders = Arrays.asList(Provider.VPCVirtualRouter, Provider.NiciraNvp); - + private final List supportedProviders = Arrays.asList(Provider.VPCVirtualRouter, Provider.NiciraNvp, Provider.InternalLbVm, Provider.Netscaler); + + int _cleanupInterval; int _maxNetworks; SearchBuilder IpAddressSearch; @@ -207,6 +208,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis if (svc == Service.Lb) { Set lbProviders = new HashSet(); lbProviders.add(Provider.VPCVirtualRouter); + lbProviders.add(Provider.InternalLbVm); svcProviderMap.put(svc, lbProviders); } else { svcProviderMap.put(svc, defaultProviders); @@ -215,7 +217,27 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis createVpcOffering(VpcOffering.defaultVPCOfferingName, VpcOffering.defaultVPCOfferingName, svcProviderMap, true, State.Enabled); } - + + //configure default vpc offering with Netscaler as LB Provider + if (_vpcOffDao.findByUniqueName(VpcOffering.defaultVPCNSOfferingName ) == null) { + s_logger.debug("Creating default VPC offering with Netscaler as LB Provider" + VpcOffering.defaultVPCNSOfferingName); + Map> svcProviderMap = new HashMap>(); + Set defaultProviders = new HashSet(); + defaultProviders.add(Provider.VPCVirtualRouter); + for (Service svc : getSupportedServices()) { + if (svc == Service.Lb) { + Set lbProviders = new HashSet(); + lbProviders.add(Provider.Netscaler); + lbProviders.add(Provider.InternalLbVm); + svcProviderMap.put(svc, lbProviders); + } else { + svcProviderMap.put(svc, defaultProviders); + } + } + createVpcOffering(VpcOffering.defaultVPCNSOfferingName, VpcOffering.defaultVPCNSOfferingName, + svcProviderMap, false, State.Enabled); + } + txn.commit(); Map configs = _configDao.getConfiguration(params); @@ -582,7 +604,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis // 2) If null, generate networkDomain using domain suffix from the global config variables if (networkDomain == null) { - networkDomain = "cs" + Long.toHexString(owner.getId()) + _ntwkModel.getDefaultNetworkDomain(); + networkDomain = "cs" + Long.toHexString(owner.getId()) + _ntwkModel.getDefaultNetworkDomain(zoneId); } } @@ -1038,16 +1060,17 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } } - //4) Only one network in the VPC can support LB - if (_ntwkModel.areServicesSupportedByNetworkOffering(guestNtwkOff.getId(), Service.Lb)) { + //4) Only one network in the VPC can support public LB inside the VPC. Internal LB can be supported on multiple VPC tiers + if (_ntwkModel.areServicesSupportedByNetworkOffering(guestNtwkOff.getId(), Service.Lb) && guestNtwkOff.getPublicLb()) { List networks = getVpcNetworks(vpc.getId()); for (Network network : networks) { if (networkId != null && network.getId() == networkId.longValue()) { //skip my own network continue; } else { - if (_ntwkModel.areServicesSupportedInNetwork(network.getId(), Service.Lb)) { - throw new InvalidParameterValueException("LB service is already supported " + + NetworkOffering otherOff = _configMgr.getNetworkOffering(network.getNetworkOfferingId()); + if (_ntwkModel.areServicesSupportedInNetwork(network.getId(), Service.Lb) && otherOff.getPublicLb()) { + throw new InvalidParameterValueException("Public LB service is already supported " + "by network " + network + " in VPC " + vpc); } } @@ -1084,6 +1107,12 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis if (guestNtwkOff.isConserveMode()) { throw new InvalidParameterValueException("Only networks with conserve mode Off can belong to VPC"); } + + //5) If Netscaler is LB provider make sure it is in dedicated mode + if ( providers.contains(Provider.Netscaler) && !guestNtwkOff.getDedicatedLB() ) { + throw new InvalidParameterValueException("Netscaler only with Dedicated LB can belong to VPC"); + } + return ; } @DB @@ -1285,8 +1314,8 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis @Override @DB @ActionEvent(eventType = EventTypes.EVENT_PRIVATE_GATEWAY_CREATE, eventDescription = "creating vpc private gateway", create=true) - public PrivateGateway createVpcPrivateGateway(long vpcId, Long physicalNetworkId, String vlan, String ipAddress, - String gateway, String netmask, long gatewayOwnerId) throws ResourceAllocationException, + public PrivateGateway createVpcPrivateGateway(long vpcId, Long physicalNetworkId, String vlan, String ipAddress, + String gateway, String netmask, long gatewayOwnerId, Boolean isSourceNat) throws ResourceAllocationException, ConcurrentOperationException, InsufficientCapacityException { //Validate parameters @@ -1312,11 +1341,11 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis //1) create private network String networkName = "vpc-" + vpc.getName() + "-privateNetwork"; Network privateNtwk = _ntwkSvc.createPrivateNetwork(networkName, networkName, physicalNetworkId, - vlan, ipAddress, null, gateway, netmask, gatewayOwnerId, vpcId); + vlan, ipAddress, null, gateway, netmask, gatewayOwnerId, vpcId, isSourceNat); //2) create gateway entry VpcGatewayVO gatewayVO = new VpcGatewayVO(ipAddress, VpcGateway.Type.Private, vpcId, privateNtwk.getDataCenterId(), - privateNtwk.getId(), vlan, gateway, netmask, vpc.getAccountId(), vpc.getDomainId()); + privateNtwk.getId(), vlan, gateway, netmask, vpc.getAccountId(), vpc.getDomainId(), isSourceNat); _vpcGatewayDao.persist(gatewayVO); s_logger.debug("Created vpc gateway entry " + gatewayVO); diff --git a/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java b/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java index 673535aaa42..062743b23af 100755 --- a/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java +++ b/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java @@ -62,6 +62,7 @@ import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.RulesManager; import com.cloud.projects.Project.ListProjectResourcesCriteria; +import com.cloud.server.ConfigurationServer; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.DomainManager; @@ -100,6 +101,7 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc @Inject UsageEventDao _usageEventDao; @Inject ConfigurationDao _configDao; @Inject List _vpnServiceProviders; + @Inject ConfigurationServer _configServer; int _userLimit; @@ -156,7 +158,7 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc } if (ipRange == null) { - ipRange = _clientIpRange; + ipRange = _configServer.getConfigValue(Config.RemoteAccessVpnClientIpRange.key(), Config.ConfigurationParameterScope.account.toString(), ipAddr.getAccountId()); } String[] range = ipRange.split("-"); if (range.length != 2) { @@ -200,7 +202,7 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc private void validateRemoteAccessVpnConfiguration() throws ConfigurationException { String ipRange = _clientIpRange; if (ipRange == null) { - s_logger.warn("Remote Access VPN configuration missing client ip range -- ignoring"); + s_logger.warn("Remote Access VPN global configuration missing client ip range -- ignoring"); return; } Integer pskLength = _pskLength; diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index c9c3f9c3722..0ab35dd00a2 100755 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -30,7 +30,6 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.dc.*; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.command.admin.cluster.AddClusterCmd; import org.apache.cloudstack.api.command.admin.cluster.DeleteClusterCmd; @@ -74,6 +73,13 @@ import com.cloud.cluster.ManagementServerNode; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.ClusterDetailsVO; +import com.cloud.dc.ClusterVO; +import com.cloud.dc.DataCenterIpAddressVO; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.HostPodVO; +import com.cloud.dc.PodCluster; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.ClusterVSMMapDao; import com.cloud.dc.dao.DataCenterDao; @@ -1638,10 +1644,10 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, private Object dispatchToStateAdapters(ResourceStateAdapter.Event event, boolean singleTaker, Object... args) { synchronized (_resourceStateAdapters) { - Iterator it = _resourceStateAdapters.entrySet().iterator(); + Iterator> it = _resourceStateAdapters.entrySet().iterator(); Object result = null; while (it.hasNext()) { - Map.Entry item = (Map.Entry) it + Map.Entry item = it .next(); ResourceStateAdapter adapter = item.getValue(); diff --git a/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java b/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java index e8805ae8910..5bb770871ca 100755 --- a/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java +++ b/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java @@ -582,7 +582,7 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim } //Convert max storage size from GiB to bytes - if (resourceType == ResourceType.primary_storage || resourceType == ResourceType.secondary_storage) { + if ((resourceType == ResourceType.primary_storage || resourceType == ResourceType.secondary_storage) && max >= 0) { max = max * ResourceType.bytesToGiB; } diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java index cd890ce8582..bc52e9a881c 100755 --- a/server/src/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/com/cloud/server/ConfigurationServerImpl.java @@ -48,8 +48,10 @@ import com.cloud.dc.*; import com.cloud.dc.dao.DcDetailsDao; import com.cloud.user.*; import com.cloud.utils.db.GenericDao; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO; import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.commons.codec.binary.Base64; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -59,6 +61,7 @@ import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.configuration.dao.ResourceCountDao; import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; import com.cloud.dc.dao.VlanDao; @@ -112,6 +115,8 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio @Inject private ConfigurationDao _configDao; @Inject private DataCenterDao _zoneDao; + @Inject private ClusterDao _clusterDao; + @Inject private PrimaryDataStoreDao _storagePoolDao; @Inject private HostPodDao _podDao; @Inject private DiskOfferingDao _diskOfferingDao; @Inject private ServiceOfferingDao _serviceOfferingDao; @@ -698,7 +703,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio return dcDetailVO.getValue(); } break; - case cluster: ClusterDetailsVO cluster = _clusterDetailsDao.findById(resourceId); + case cluster: ClusterVO cluster = _clusterDao.findById(resourceId); if (cluster == null) { throw new InvalidParameterValueException("unable to find cluster by id " + resourceId); } @@ -707,7 +712,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio return clusterDetailsVO.getValue(); } break; - case pool: StoragePoolDetailVO pool = _storagePoolDetailsDao.findById(resourceId); + case storagepool: StoragePoolVO pool = _storagePoolDao.findById(resourceId); if (pool == null) { throw new InvalidParameterValueException("unable to find storage pool by id " + resourceId); } @@ -716,7 +721,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio return storagePoolDetailVO.getValue(); } break; - case account: AccountDetailVO account = _accountDetailsDao.findById(resourceId); + case account: AccountVO account = _accountDao.findById(resourceId); if (account == null) { throw new InvalidParameterValueException("unable to find account by id " + resourceId); } @@ -1012,7 +1017,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio "Offering for Shared Security group enabled networks", TrafficType.Guest, false, true, null, null, true, Availability.Optional, - null, Network.GuestType.Shared, true, true, false); + null, Network.GuestType.Shared, true, true, false, false, false); defaultSharedSGNetworkOffering.setState(NetworkOffering.State.Enabled); defaultSharedSGNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultSharedSGNetworkOffering); @@ -1029,7 +1034,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio "Offering for Shared networks", TrafficType.Guest, false, true, null, null, true, Availability.Optional, - null, Network.GuestType.Shared, true, true, false); + null, Network.GuestType.Shared, true, true, false, false, false); defaultSharedNetworkOffering.setState(NetworkOffering.State.Enabled); defaultSharedNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultSharedNetworkOffering); @@ -1046,7 +1051,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio "Offering for Isolated networks with Source Nat service enabled", TrafficType.Guest, false, false, null, null, true, Availability.Required, - null, Network.GuestType.Isolated, true, false, false); + null, Network.GuestType.Isolated, true, false, false, false, true); defaultIsolatedSourceNatEnabledNetworkOffering.setState(NetworkOffering.State.Enabled); defaultIsolatedSourceNatEnabledNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultIsolatedSourceNatEnabledNetworkOffering); @@ -1064,7 +1069,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio "Offering for Isolated networks with no Source Nat service", TrafficType.Guest, false, true, null, null, true, Availability.Optional, - null, Network.GuestType.Isolated, true, true, false); + null, Network.GuestType.Isolated, true, true, false, false, false); defaultIsolatedEnabledNetworkOffering.setState(NetworkOffering.State.Enabled); defaultIsolatedEnabledNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultIsolatedEnabledNetworkOffering); @@ -1081,7 +1086,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio "Offering for Shared networks with Elastic IP and Elastic LB capabilities", TrafficType.Guest, false, true, null, null, true, Availability.Optional, - null, Network.GuestType.Shared, true, false, false, false, true, true, true, false, false, true); + null, Network.GuestType.Shared, true, false, false, false, true, true, true, false, false, true, true, false); defaultNetscalerNetworkOffering.setState(NetworkOffering.State.Enabled); defaultNetscalerNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultNetscalerNetworkOffering); @@ -1098,7 +1103,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio "Offering for Isolated Vpc networks with Source Nat service enabled", TrafficType.Guest, false, false, null, null, true, Availability.Optional, - null, Network.GuestType.Isolated, false, false, false); + null, Network.GuestType.Isolated, false, false, false, false, true); defaultNetworkOfferingForVpcNetworks.setState(NetworkOffering.State.Enabled); defaultNetworkOfferingForVpcNetworks = _networkOfferingDao.persistDefaultNetworkOffering(defaultNetworkOfferingForVpcNetworks); @@ -1128,7 +1133,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio "Offering for Isolated Vpc networks with Source Nat service enabled and LB service Disabled", TrafficType.Guest, false, false, null, null, true, Availability.Optional, - null, Network.GuestType.Isolated, false, false, false); + null, Network.GuestType.Isolated, false, false, false, false, false); defaultNetworkOfferingForVpcNetworksNoLB.setState(NetworkOffering.State.Enabled); defaultNetworkOfferingForVpcNetworksNoLB = _networkOfferingDao.persistDefaultNetworkOffering(defaultNetworkOfferingForVpcNetworksNoLB); diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 6d01b4799c0..60181381956 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -34,7 +34,6 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.TimeZone; -import java.util.UUID; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -44,85 +43,415 @@ import javax.crypto.spec.SecretKeySpec; import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.configuration.*; -import com.cloud.storage.dao.*; +import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.SecurityChecker.AccessType; -import org.apache.cloudstack.api.ApiConstants; - -import com.cloud.event.ActionEventUtils; -import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoCmd; -import org.apache.cloudstack.api.command.admin.account.*; -import org.apache.cloudstack.api.command.admin.domain.*; -import org.apache.cloudstack.api.command.admin.host.*; -import org.apache.cloudstack.api.command.admin.network.*; -import org.apache.cloudstack.api.command.admin.offering.*; -import org.apache.cloudstack.api.command.admin.resource.*; -import org.apache.cloudstack.api.command.admin.router.*; -import org.apache.cloudstack.api.command.admin.storage.*; -import org.apache.cloudstack.api.command.admin.systemvm.*; -import org.apache.cloudstack.api.command.admin.usage.*; -import org.apache.cloudstack.api.command.admin.user.*; -import org.apache.cloudstack.api.command.admin.vlan.*; -import org.apache.cloudstack.api.command.admin.vpc.*; -import org.apache.cloudstack.api.command.user.autoscale.*; -import org.apache.cloudstack.api.command.user.firewall.*; -import org.apache.cloudstack.api.command.user.iso.*; -import org.apache.cloudstack.api.command.user.loadbalancer.*; -import org.apache.cloudstack.api.command.user.nat.*; -import org.apache.cloudstack.api.command.user.network.*; -import org.apache.cloudstack.api.command.user.project.*; -import org.apache.cloudstack.api.command.user.resource.*; -import org.apache.cloudstack.api.command.user.securitygroup.*; -import org.apache.cloudstack.api.command.user.snapshot.*; -import org.apache.cloudstack.api.command.user.template.*; -import org.apache.cloudstack.api.command.user.vm.*; -import org.apache.cloudstack.api.command.user.volume.*; -import org.apache.cloudstack.api.command.user.vpc.*; -import org.apache.cloudstack.api.command.user.vpn.*; -import org.apache.cloudstack.api.response.ExtractResponse; -import org.apache.commons.codec.binary.Base64; -import org.apache.log4j.Logger; import org.apache.cloudstack.affinity.AffinityGroupProcessor; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; - +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoCmd; +import org.apache.cloudstack.api.command.admin.account.CreateAccountCmd; +import org.apache.cloudstack.api.command.admin.account.DeleteAccountCmd; +import org.apache.cloudstack.api.command.admin.account.DisableAccountCmd; +import org.apache.cloudstack.api.command.admin.account.EnableAccountCmd; +import org.apache.cloudstack.api.command.admin.account.LockAccountCmd; +import org.apache.cloudstack.api.command.admin.account.UpdateAccountCmd; +import org.apache.cloudstack.api.command.admin.autoscale.CreateCounterCmd; +import org.apache.cloudstack.api.command.admin.autoscale.DeleteCounterCmd; +import org.apache.cloudstack.api.command.admin.cluster.AddClusterCmd; +import org.apache.cloudstack.api.command.admin.cluster.DeleteClusterCmd; +import org.apache.cloudstack.api.command.admin.cluster.ListClustersCmd; +import org.apache.cloudstack.api.command.admin.cluster.UpdateClusterCmd; +import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd; +import org.apache.cloudstack.api.command.admin.config.ListHypervisorCapabilitiesCmd; +import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd; +import org.apache.cloudstack.api.command.admin.config.UpdateHypervisorCapabilitiesCmd; +import org.apache.cloudstack.api.command.admin.domain.CreateDomainCmd; +import org.apache.cloudstack.api.command.admin.domain.DeleteDomainCmd; +import org.apache.cloudstack.api.command.admin.domain.ListDomainChildrenCmd; +import org.apache.cloudstack.api.command.admin.domain.ListDomainsCmd; +import org.apache.cloudstack.api.command.admin.domain.UpdateDomainCmd; +import org.apache.cloudstack.api.command.admin.host.AddHostCmd; +import org.apache.cloudstack.api.command.admin.host.AddSecondaryStorageCmd; +import org.apache.cloudstack.api.command.admin.host.CancelMaintenanceCmd; +import org.apache.cloudstack.api.command.admin.host.DeleteHostCmd; +import org.apache.cloudstack.api.command.admin.host.FindHostsForMigrationCmd; +import org.apache.cloudstack.api.command.admin.host.ListHostsCmd; +import org.apache.cloudstack.api.command.admin.host.PrepareForMaintenanceCmd; +import org.apache.cloudstack.api.command.admin.host.ReconnectHostCmd; +import org.apache.cloudstack.api.command.admin.host.UpdateHostCmd; +import org.apache.cloudstack.api.command.admin.host.UpdateHostPasswordCmd; +import org.apache.cloudstack.api.command.admin.internallb.ConfigureInternalLoadBalancerElementCmd; +import org.apache.cloudstack.api.command.admin.internallb.CreateInternalLoadBalancerElementCmd; +import org.apache.cloudstack.api.command.admin.internallb.ListInternalLBVMsCmd; +import org.apache.cloudstack.api.command.admin.internallb.ListInternalLoadBalancerElementsCmd; +import org.apache.cloudstack.api.command.admin.internallb.StartInternalLBVMCmd; +import org.apache.cloudstack.api.command.admin.internallb.StopInternalLBVMCmd; +import org.apache.cloudstack.api.command.admin.ldap.LDAPConfigCmd; +import org.apache.cloudstack.api.command.admin.ldap.LDAPRemoveCmd; +import org.apache.cloudstack.api.command.admin.network.AddNetworkDeviceCmd; +import org.apache.cloudstack.api.command.admin.network.AddNetworkServiceProviderCmd; +import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd; +import org.apache.cloudstack.api.command.admin.network.CreatePhysicalNetworkCmd; +import org.apache.cloudstack.api.command.admin.network.CreateStorageNetworkIpRangeCmd; +import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd; +import org.apache.cloudstack.api.command.admin.network.DeleteNetworkDeviceCmd; +import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd; +import org.apache.cloudstack.api.command.admin.network.DeleteNetworkServiceProviderCmd; +import org.apache.cloudstack.api.command.admin.network.DeletePhysicalNetworkCmd; +import org.apache.cloudstack.api.command.admin.network.DeleteStorageNetworkIpRangeCmd; +import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd; +import org.apache.cloudstack.api.command.admin.network.ListNetworkDeviceCmd; +import org.apache.cloudstack.api.command.admin.network.ListNetworkIsolationMethodsCmd; +import org.apache.cloudstack.api.command.admin.network.ListNetworkServiceProvidersCmd; +import org.apache.cloudstack.api.command.admin.network.ListPhysicalNetworksCmd; +import org.apache.cloudstack.api.command.admin.network.ListStorageNetworkIpRangeCmd; +import org.apache.cloudstack.api.command.admin.network.ListSupportedNetworkServicesCmd; +import org.apache.cloudstack.api.command.admin.network.ReleaseDedicatedGuestVlanRangeCmd; +import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd; +import org.apache.cloudstack.api.command.admin.network.UpdateNetworkServiceProviderCmd; +import org.apache.cloudstack.api.command.admin.network.UpdatePhysicalNetworkCmd; +import org.apache.cloudstack.api.command.admin.network.UpdateStorageNetworkIpRangeCmd; +import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd; +import org.apache.cloudstack.api.command.admin.offering.CreateServiceOfferingCmd; +import org.apache.cloudstack.api.command.admin.offering.DeleteDiskOfferingCmd; +import org.apache.cloudstack.api.command.admin.offering.DeleteServiceOfferingCmd; +import org.apache.cloudstack.api.command.admin.offering.UpdateDiskOfferingCmd; +import org.apache.cloudstack.api.command.admin.offering.UpdateServiceOfferingCmd; +import org.apache.cloudstack.api.command.admin.pod.CreatePodCmd; +import org.apache.cloudstack.api.command.admin.pod.DeletePodCmd; +import org.apache.cloudstack.api.command.admin.pod.ListPodsByCmd; +import org.apache.cloudstack.api.command.admin.pod.UpdatePodCmd; +import org.apache.cloudstack.api.command.admin.region.AddRegionCmd; +import org.apache.cloudstack.api.command.admin.region.RemoveRegionCmd; +import org.apache.cloudstack.api.command.admin.region.UpdateRegionCmd; +import org.apache.cloudstack.api.command.admin.resource.ArchiveAlertsCmd; +import org.apache.cloudstack.api.command.admin.resource.DeleteAlertsCmd; +import org.apache.cloudstack.api.command.admin.resource.ListAlertsCmd; +import org.apache.cloudstack.api.command.admin.resource.ListCapacityCmd; +import org.apache.cloudstack.api.command.admin.resource.UploadCustomCertificateCmd; +import org.apache.cloudstack.api.command.admin.router.ConfigureVirtualRouterElementCmd; +import org.apache.cloudstack.api.command.admin.router.CreateVirtualRouterElementCmd; +import org.apache.cloudstack.api.command.admin.router.DestroyRouterCmd; +import org.apache.cloudstack.api.command.admin.router.ListRoutersCmd; +import org.apache.cloudstack.api.command.admin.router.ListVirtualRouterElementsCmd; +import org.apache.cloudstack.api.command.admin.router.RebootRouterCmd; +import org.apache.cloudstack.api.command.admin.router.StartRouterCmd; +import org.apache.cloudstack.api.command.admin.router.StopRouterCmd; +import org.apache.cloudstack.api.command.admin.router.UpgradeRouterCmd; +import org.apache.cloudstack.api.command.admin.storage.AddS3Cmd; +import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaintenanceCmd; +import org.apache.cloudstack.api.command.admin.storage.CreateStoragePoolCmd; +import org.apache.cloudstack.api.command.admin.storage.DeletePoolCmd; +import org.apache.cloudstack.api.command.admin.storage.FindStoragePoolsForMigrationCmd; +import org.apache.cloudstack.api.command.admin.storage.ListS3sCmd; +import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolsCmd; +import org.apache.cloudstack.api.command.admin.storage.ListStorageProvidersCmd; +import org.apache.cloudstack.api.command.admin.storage.PreparePrimaryStorageForMaintenanceCmd; +import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd; +import org.apache.cloudstack.api.command.admin.swift.AddSwiftCmd; +import org.apache.cloudstack.api.command.admin.swift.ListSwiftsCmd; +import org.apache.cloudstack.api.command.admin.systemvm.DestroySystemVmCmd; +import org.apache.cloudstack.api.command.admin.systemvm.ListSystemVMsCmd; +import org.apache.cloudstack.api.command.admin.systemvm.MigrateSystemVMCmd; +import org.apache.cloudstack.api.command.admin.systemvm.RebootSystemVmCmd; +import org.apache.cloudstack.api.command.admin.systemvm.StartSystemVMCmd; +import org.apache.cloudstack.api.command.admin.systemvm.StopSystemVmCmd; +import org.apache.cloudstack.api.command.admin.systemvm.UpgradeSystemVMCmd; +import org.apache.cloudstack.api.command.admin.template.PrepareTemplateCmd; +import org.apache.cloudstack.api.command.admin.usage.AddTrafficMonitorCmd; +import org.apache.cloudstack.api.command.admin.usage.AddTrafficTypeCmd; +import org.apache.cloudstack.api.command.admin.usage.DeleteTrafficMonitorCmd; +import org.apache.cloudstack.api.command.admin.usage.DeleteTrafficTypeCmd; +import org.apache.cloudstack.api.command.admin.usage.GenerateUsageRecordsCmd; +import org.apache.cloudstack.api.command.admin.usage.GetUsageRecordsCmd; +import org.apache.cloudstack.api.command.admin.usage.ListTrafficMonitorsCmd; +import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; +import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypesCmd; +import org.apache.cloudstack.api.command.admin.usage.ListUsageTypesCmd; +import org.apache.cloudstack.api.command.admin.usage.UpdateTrafficTypeCmd; +import org.apache.cloudstack.api.command.admin.user.CreateUserCmd; +import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd; +import org.apache.cloudstack.api.command.admin.user.DisableUserCmd; +import org.apache.cloudstack.api.command.admin.user.EnableUserCmd; +import org.apache.cloudstack.api.command.admin.user.GetUserCmd; +import org.apache.cloudstack.api.command.admin.user.ListUsersCmd; +import org.apache.cloudstack.api.command.admin.user.LockUserCmd; +import org.apache.cloudstack.api.command.admin.user.RegisterCmd; +import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd; +import org.apache.cloudstack.api.command.admin.vlan.CreateVlanIpRangeCmd; +import org.apache.cloudstack.api.command.admin.vlan.DedicatePublicIpRangeCmd; +import org.apache.cloudstack.api.command.admin.vlan.DeleteVlanIpRangeCmd; +import org.apache.cloudstack.api.command.admin.vlan.ListVlanIpRangesCmd; +import org.apache.cloudstack.api.command.admin.vlan.ReleasePublicIpRangeCmd; +import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; +import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd; +import org.apache.cloudstack.api.command.admin.vm.MigrateVirtualMachineWithVolumeCmd; +import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; +import org.apache.cloudstack.api.command.admin.vpc.CreatePrivateGatewayCmd; +import org.apache.cloudstack.api.command.admin.vpc.CreateVPCOfferingCmd; +import org.apache.cloudstack.api.command.admin.vpc.DeletePrivateGatewayCmd; +import org.apache.cloudstack.api.command.admin.vpc.DeleteVPCOfferingCmd; +import org.apache.cloudstack.api.command.admin.vpc.UpdateVPCOfferingCmd; +import org.apache.cloudstack.api.command.admin.zone.CreateZoneCmd; +import org.apache.cloudstack.api.command.admin.zone.DeleteZoneCmd; +import org.apache.cloudstack.api.command.admin.zone.MarkDefaultZoneForAccountCmd; +import org.apache.cloudstack.api.command.admin.zone.UpdateZoneCmd; +import org.apache.cloudstack.api.command.user.account.AddAccountToProjectCmd; +import org.apache.cloudstack.api.command.user.account.DeleteAccountFromProjectCmd; +import org.apache.cloudstack.api.command.user.account.ListAccountsCmd; +import org.apache.cloudstack.api.command.user.account.ListProjectAccountsCmd; +import org.apache.cloudstack.api.command.user.address.AssociateIPAddrCmd; +import org.apache.cloudstack.api.command.user.address.DisassociateIPAddrCmd; +import org.apache.cloudstack.api.command.user.address.ListPublicIpAddressesCmd; import org.apache.cloudstack.api.command.user.affinitygroup.CreateAffinityGroupCmd; import org.apache.cloudstack.api.command.user.affinitygroup.DeleteAffinityGroupCmd; import org.apache.cloudstack.api.command.user.affinitygroup.ListAffinityGroupTypesCmd; import org.apache.cloudstack.api.command.user.affinitygroup.ListAffinityGroupsCmd; import org.apache.cloudstack.api.command.user.affinitygroup.UpdateVMAffinityGroupCmd; +import org.apache.cloudstack.api.command.user.autoscale.CreateAutoScalePolicyCmd; +import org.apache.cloudstack.api.command.user.autoscale.CreateAutoScaleVmGroupCmd; +import org.apache.cloudstack.api.command.user.autoscale.CreateAutoScaleVmProfileCmd; +import org.apache.cloudstack.api.command.user.autoscale.CreateConditionCmd; +import org.apache.cloudstack.api.command.user.autoscale.DeleteAutoScalePolicyCmd; +import org.apache.cloudstack.api.command.user.autoscale.DeleteAutoScaleVmGroupCmd; +import org.apache.cloudstack.api.command.user.autoscale.DeleteAutoScaleVmProfileCmd; +import org.apache.cloudstack.api.command.user.autoscale.DeleteConditionCmd; +import org.apache.cloudstack.api.command.user.autoscale.DisableAutoScaleVmGroupCmd; +import org.apache.cloudstack.api.command.user.autoscale.EnableAutoScaleVmGroupCmd; +import org.apache.cloudstack.api.command.user.autoscale.ListAutoScalePoliciesCmd; +import org.apache.cloudstack.api.command.user.autoscale.ListAutoScaleVmGroupsCmd; +import org.apache.cloudstack.api.command.user.autoscale.ListAutoScaleVmProfilesCmd; +import org.apache.cloudstack.api.command.user.autoscale.ListConditionsCmd; +import org.apache.cloudstack.api.command.user.autoscale.ListCountersCmd; +import org.apache.cloudstack.api.command.user.autoscale.UpdateAutoScalePolicyCmd; +import org.apache.cloudstack.api.command.user.autoscale.UpdateAutoScaleVmGroupCmd; +import org.apache.cloudstack.api.command.user.autoscale.UpdateAutoScaleVmProfileCmd; +import org.apache.cloudstack.api.command.user.config.ListCapabilitiesCmd; +import org.apache.cloudstack.api.command.user.event.ArchiveEventsCmd; +import org.apache.cloudstack.api.command.user.event.DeleteEventsCmd; +import org.apache.cloudstack.api.command.user.event.ListEventTypesCmd; +import org.apache.cloudstack.api.command.user.event.ListEventsCmd; +import org.apache.cloudstack.api.command.user.firewall.CreateEgressFirewallRuleCmd; +import org.apache.cloudstack.api.command.user.firewall.CreateFirewallRuleCmd; +import org.apache.cloudstack.api.command.user.firewall.CreatePortForwardingRuleCmd; +import org.apache.cloudstack.api.command.user.firewall.DeleteEgressFirewallRuleCmd; +import org.apache.cloudstack.api.command.user.firewall.DeleteFirewallRuleCmd; +import org.apache.cloudstack.api.command.user.firewall.DeletePortForwardingRuleCmd; +import org.apache.cloudstack.api.command.user.firewall.ListEgressFirewallRulesCmd; +import org.apache.cloudstack.api.command.user.firewall.ListFirewallRulesCmd; +import org.apache.cloudstack.api.command.user.firewall.ListPortForwardingRulesCmd; +import org.apache.cloudstack.api.command.user.firewall.UpdatePortForwardingRuleCmd; +import org.apache.cloudstack.api.command.user.guest.ListGuestOsCategoriesCmd; +import org.apache.cloudstack.api.command.user.guest.ListGuestOsCmd; +import org.apache.cloudstack.api.command.user.iso.AttachIsoCmd; +import org.apache.cloudstack.api.command.user.iso.CopyIsoCmd; +import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; +import org.apache.cloudstack.api.command.user.iso.DetachIsoCmd; +import org.apache.cloudstack.api.command.user.iso.ExtractIsoCmd; +import org.apache.cloudstack.api.command.user.iso.ListIsoPermissionsCmd; +import org.apache.cloudstack.api.command.user.iso.ListIsosCmd; +import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; +import org.apache.cloudstack.api.command.user.iso.UpdateIsoCmd; +import org.apache.cloudstack.api.command.user.iso.UpdateIsoPermissionsCmd; +import org.apache.cloudstack.api.command.user.job.ListAsyncJobsCmd; +import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.AssignToLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.CreateApplicationLoadBalancerCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.CreateLBHealthCheckPolicyCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.CreateLBStickinessPolicyCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.CreateLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.DeleteApplicationLoadBalancerCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.DeleteLBHealthCheckPolicyCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.DeleteLBStickinessPolicyCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.DeleteLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListApplicationLoadBalancersCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListLBHealthCheckPoliciesCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListLBStickinessPoliciesCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerRuleInstancesCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerRulesCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.RemoveFromLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.UpdateLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.nat.CreateIpForwardingRuleCmd; +import org.apache.cloudstack.api.command.user.nat.DeleteIpForwardingRuleCmd; +import org.apache.cloudstack.api.command.user.nat.DisableStaticNatCmd; +import org.apache.cloudstack.api.command.user.nat.EnableStaticNatCmd; +import org.apache.cloudstack.api.command.user.nat.ListIpForwardingRulesCmd; +import org.apache.cloudstack.api.command.user.network.*; +import org.apache.cloudstack.api.command.user.offering.ListDiskOfferingsCmd; +import org.apache.cloudstack.api.command.user.offering.ListServiceOfferingsCmd; +import org.apache.cloudstack.api.command.user.project.ActivateProjectCmd; +import org.apache.cloudstack.api.command.user.project.CreateProjectCmd; +import org.apache.cloudstack.api.command.user.project.DeleteProjectCmd; +import org.apache.cloudstack.api.command.user.project.DeleteProjectInvitationCmd; +import org.apache.cloudstack.api.command.user.project.ListProjectInvitationsCmd; +import org.apache.cloudstack.api.command.user.project.ListProjectsCmd; +import org.apache.cloudstack.api.command.user.project.SuspendProjectCmd; +import org.apache.cloudstack.api.command.user.project.UpdateProjectCmd; +import org.apache.cloudstack.api.command.user.project.UpdateProjectInvitationCmd; +import org.apache.cloudstack.api.command.user.region.ListRegionsCmd; +import org.apache.cloudstack.api.command.user.region.ha.gslb.AssignToGlobalLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.region.ha.gslb.CreateGlobalLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.region.ha.gslb.DeleteGlobalLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.region.ha.gslb.ListGlobalLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.region.ha.gslb.RemoveFromGlobalLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.resource.GetCloudIdentifierCmd; +import org.apache.cloudstack.api.command.user.resource.ListHypervisorsCmd; +import org.apache.cloudstack.api.command.user.resource.ListResourceLimitsCmd; +import org.apache.cloudstack.api.command.user.resource.UpdateResourceCountCmd; +import org.apache.cloudstack.api.command.user.resource.UpdateResourceLimitCmd; +import org.apache.cloudstack.api.command.user.securitygroup.AuthorizeSecurityGroupEgressCmd; +import org.apache.cloudstack.api.command.user.securitygroup.AuthorizeSecurityGroupIngressCmd; +import org.apache.cloudstack.api.command.user.securitygroup.CreateSecurityGroupCmd; +import org.apache.cloudstack.api.command.user.securitygroup.DeleteSecurityGroupCmd; +import org.apache.cloudstack.api.command.user.securitygroup.ListSecurityGroupsCmd; +import org.apache.cloudstack.api.command.user.securitygroup.RevokeSecurityGroupEgressCmd; +import org.apache.cloudstack.api.command.user.securitygroup.RevokeSecurityGroupIngressCmd; +import org.apache.cloudstack.api.command.user.snapshot.CreateSnapshotCmd; +import org.apache.cloudstack.api.command.user.snapshot.CreateSnapshotPolicyCmd; +import org.apache.cloudstack.api.command.user.snapshot.DeleteSnapshotCmd; +import org.apache.cloudstack.api.command.user.snapshot.DeleteSnapshotPoliciesCmd; +import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotPoliciesCmd; +import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotsCmd; +import org.apache.cloudstack.api.command.user.ssh.CreateSSHKeyPairCmd; +import org.apache.cloudstack.api.command.user.ssh.DeleteSSHKeyPairCmd; +import org.apache.cloudstack.api.command.user.ssh.ListSSHKeyPairsCmd; +import org.apache.cloudstack.api.command.user.ssh.RegisterSSHKeyPairCmd; +import org.apache.cloudstack.api.command.user.tag.CreateTagsCmd; +import org.apache.cloudstack.api.command.user.tag.DeleteTagsCmd; +import org.apache.cloudstack.api.command.user.tag.ListTagsCmd; +import org.apache.cloudstack.api.command.user.template.CopyTemplateCmd; +import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd; +import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; +import org.apache.cloudstack.api.command.user.template.ExtractTemplateCmd; +import org.apache.cloudstack.api.command.user.template.ListTemplatePermissionsCmd; +import org.apache.cloudstack.api.command.user.template.ListTemplatesCmd; +import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; +import org.apache.cloudstack.api.command.user.template.UpdateTemplateCmd; +import org.apache.cloudstack.api.command.user.template.UpdateTemplatePermissionsCmd; +import org.apache.cloudstack.api.command.user.vm.AddIpToVmNicCmd; +import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd; +import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; +import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd; +import org.apache.cloudstack.api.command.user.vm.GetVMPasswordCmd; +import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; +import org.apache.cloudstack.api.command.user.vm.ListVMsCmd; +import org.apache.cloudstack.api.command.user.vm.RebootVMCmd; +import org.apache.cloudstack.api.command.user.vm.RemoveIpFromVmNicCmd; +import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd; +import org.apache.cloudstack.api.command.user.vm.ResetVMPasswordCmd; +import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd; +import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; +import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd; +import org.apache.cloudstack.api.command.user.vm.StartVMCmd; +import org.apache.cloudstack.api.command.user.vm.StopVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd; +import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; +import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; +import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd; +import org.apache.cloudstack.api.command.user.vmgroup.UpdateVMGroupCmd; +import org.apache.cloudstack.api.command.user.vmsnapshot.CreateVMSnapshotCmd; +import org.apache.cloudstack.api.command.user.vmsnapshot.DeleteVMSnapshotCmd; +import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd; +import org.apache.cloudstack.api.command.user.vmsnapshot.RevertToVMSnapshotCmd; +import org.apache.cloudstack.api.command.user.volume.*; +import org.apache.cloudstack.api.command.user.vpc.CreateStaticRouteCmd; +import org.apache.cloudstack.api.command.user.vpc.CreateVPCCmd; +import org.apache.cloudstack.api.command.user.vpc.DeleteStaticRouteCmd; +import org.apache.cloudstack.api.command.user.vpc.DeleteVPCCmd; +import org.apache.cloudstack.api.command.user.vpc.ListPrivateGatewaysCmd; +import org.apache.cloudstack.api.command.user.vpc.ListStaticRoutesCmd; +import org.apache.cloudstack.api.command.user.vpc.ListVPCOfferingsCmd; +import org.apache.cloudstack.api.command.user.vpc.ListVPCsCmd; +import org.apache.cloudstack.api.command.user.vpc.RestartVPCCmd; +import org.apache.cloudstack.api.command.user.vpc.UpdateVPCCmd; +import org.apache.cloudstack.api.command.user.vpn.AddVpnUserCmd; +import org.apache.cloudstack.api.command.user.vpn.CreateRemoteAccessVpnCmd; +import org.apache.cloudstack.api.command.user.vpn.CreateVpnConnectionCmd; +import org.apache.cloudstack.api.command.user.vpn.CreateVpnCustomerGatewayCmd; +import org.apache.cloudstack.api.command.user.vpn.CreateVpnGatewayCmd; +import org.apache.cloudstack.api.command.user.vpn.DeleteRemoteAccessVpnCmd; +import org.apache.cloudstack.api.command.user.vpn.DeleteVpnConnectionCmd; +import org.apache.cloudstack.api.command.user.vpn.DeleteVpnCustomerGatewayCmd; +import org.apache.cloudstack.api.command.user.vpn.DeleteVpnGatewayCmd; +import org.apache.cloudstack.api.command.user.vpn.ListRemoteAccessVpnsCmd; +import org.apache.cloudstack.api.command.user.vpn.ListVpnConnectionsCmd; +import org.apache.cloudstack.api.command.user.vpn.ListVpnCustomerGatewaysCmd; +import org.apache.cloudstack.api.command.user.vpn.ListVpnGatewaysCmd; +import org.apache.cloudstack.api.command.user.vpn.ListVpnUsersCmd; +import org.apache.cloudstack.api.command.user.vpn.RemoveVpnUserCmd; +import org.apache.cloudstack.api.command.user.vpn.ResetVpnConnectionCmd; +import org.apache.cloudstack.api.command.user.vpn.UpdateVpnCustomerGatewayCmd; +import org.apache.cloudstack.api.command.user.zone.ListZonesByCmd; +import org.apache.cloudstack.api.response.ExtractResponse; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.commons.codec.binary.Base64; +import org.apache.log4j.Logger; + import com.cloud.agent.AgentManager; import com.cloud.agent.api.GetVncPortAnswer; import com.cloud.agent.api.GetVncPortCommand; import com.cloud.agent.api.storage.CopyVolumeAnswer; import com.cloud.agent.api.storage.CopyVolumeCommand; +import com.cloud.agent.api.storage.CreateVolumeOVAAnswer; +import com.cloud.agent.api.storage.CreateVolumeOVACommand; import com.cloud.agent.manager.allocator.HostAllocator; import com.cloud.alert.Alert; import com.cloud.alert.AlertManager; import com.cloud.alert.AlertVO; import com.cloud.alert.dao.AlertDao; import com.cloud.api.ApiDBUtils; -import com.cloud.async.*; +import com.cloud.async.AsyncJobExecutor; +import com.cloud.async.AsyncJobManager; +import com.cloud.async.AsyncJobResult; +import com.cloud.async.AsyncJobVO; +import com.cloud.async.BaseAsyncJobExecutor; import com.cloud.capacity.Capacity; import com.cloud.capacity.CapacityVO; import com.cloud.capacity.dao.CapacityDao; import com.cloud.capacity.dao.CapacityDaoImpl.SummedCapacity; import com.cloud.cluster.ClusterManager; +import com.cloud.configuration.Config; +import com.cloud.configuration.Configuration; +import com.cloud.configuration.ConfigurationManager; +import com.cloud.configuration.ConfigurationVO; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.consoleproxy.ConsoleProxyManagementState; import com.cloud.consoleproxy.ConsoleProxyManager; -import com.cloud.dc.*; +import com.cloud.dc.AccountVlanMapVO; +import com.cloud.dc.ClusterVO; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.HostPodVO; +import com.cloud.dc.Pod; +import com.cloud.dc.PodVlanMapVO; +import com.cloud.dc.Vlan; import com.cloud.dc.Vlan.VlanType; -import com.cloud.dc.dao.*; +import com.cloud.dc.VlanVO; +import com.cloud.dc.dao.AccountVlanMapDao; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.HostPodDao; +import com.cloud.dc.dao.PodVlanMapDao; +import com.cloud.dc.dao.VlanDao; import com.cloud.deploy.DataCenterDeployment; -import com.cloud.deploy.DeploymentPlanner; import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; +import com.cloud.event.ActionEventUtils; import com.cloud.event.EventTypes; import com.cloud.event.EventVO; import com.cloud.event.dao.EventDao; -import com.cloud.exception.*; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.OperationTimedoutException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.exception.StorageUnavailableException; import com.cloud.ha.HighAvailabilityManager; import com.cloud.host.DetailVO; import com.cloud.host.Host; @@ -139,7 +468,12 @@ import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; import com.cloud.info.ConsoleProxyInfo; import com.cloud.keystore.KeystoreManager; import com.cloud.network.IpAddress; -import com.cloud.network.dao.*; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.LoadBalancerDao; +import com.cloud.network.dao.LoadBalancerVO; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; import com.cloud.org.Cluster; import com.cloud.org.Grouping.AllocationState; import com.cloud.projects.Project; @@ -148,11 +482,29 @@ import com.cloud.projects.ProjectManager; import com.cloud.resource.ResourceManager; import com.cloud.server.ResourceTag.TaggedResourceType; import com.cloud.server.auth.UserAuthenticator; -import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; -import com.cloud.storage.*; +import com.cloud.storage.DiskOfferingVO; +import com.cloud.storage.GuestOS; +import com.cloud.storage.GuestOSCategoryVO; +import com.cloud.storage.GuestOSVO; +import com.cloud.storage.GuestOsCategory; +import com.cloud.storage.Storage; import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.StorageManager; +import com.cloud.storage.StoragePool; +import com.cloud.storage.Upload; import com.cloud.storage.Upload.Mode; +import com.cloud.storage.UploadVO; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.Volume; +import com.cloud.storage.VolumeManager; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.storage.dao.GuestOSCategoryDao; +import com.cloud.storage.dao.GuestOSDao; +import com.cloud.storage.dao.UploadDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.s3.S3Manager; import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.storage.snapshot.SnapshotManager; @@ -162,7 +514,13 @@ import com.cloud.tags.ResourceTagVO; import com.cloud.tags.dao.ResourceTagDao; import com.cloud.template.TemplateManager; import com.cloud.template.VirtualMachineTemplate.TemplateFilter; -import com.cloud.user.*; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.SSHKeyPair; +import com.cloud.user.SSHKeyPairVO; +import com.cloud.user.User; +import com.cloud.user.UserContext; +import com.cloud.user.UserVO; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.SSHKeyPairDao; import com.cloud.user.dao.UserDao; @@ -175,91 +533,39 @@ import com.cloud.utils.component.ComponentLifecycle; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.crypt.DBEncryptionUtil; -import com.cloud.utils.db.*; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.GlobalLock; +import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.JoinBuilder.JoinType; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.MacAddress; import com.cloud.utils.net.NetUtils; import com.cloud.utils.ssh.SSHKeysHelper; -import com.cloud.vm.*; +import com.cloud.vm.ConsoleProxyVO; +import com.cloud.vm.DiskProfile; +import com.cloud.vm.InstanceGroupVO; +import com.cloud.vm.SecondaryStorageVmVO; +import com.cloud.vm.UserVmVO; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.State; -import com.cloud.vm.dao.*; +import com.cloud.vm.VirtualMachineManager; +import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.VirtualMachineProfileImpl; +import com.cloud.vm.dao.ConsoleProxyDao; +import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.InstanceGroupDao; +import com.cloud.vm.dao.SecondaryStorageVmDao; +import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.VMInstanceDao; + import edu.emory.mathcs.backport.java.util.Arrays; import edu.emory.mathcs.backport.java.util.Collections; -import org.apache.cloudstack.acl.ControlledEntity; -import org.apache.cloudstack.api.command.admin.autoscale.CreateCounterCmd; -import org.apache.cloudstack.api.command.admin.autoscale.DeleteCounterCmd; -import org.apache.cloudstack.api.command.admin.cluster.AddClusterCmd; -import org.apache.cloudstack.api.command.admin.cluster.DeleteClusterCmd; -import org.apache.cloudstack.api.command.admin.cluster.ListClustersCmd; -import org.apache.cloudstack.api.command.admin.cluster.UpdateClusterCmd; -import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd; -import org.apache.cloudstack.api.command.admin.config.ListHypervisorCapabilitiesCmd; -import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd; -import org.apache.cloudstack.api.command.admin.config.UpdateHypervisorCapabilitiesCmd; -import org.apache.cloudstack.api.command.admin.ldap.LDAPConfigCmd; -import org.apache.cloudstack.api.command.admin.ldap.LDAPRemoveCmd; -import org.apache.cloudstack.api.command.admin.pod.CreatePodCmd; -import org.apache.cloudstack.api.command.admin.pod.DeletePodCmd; -import org.apache.cloudstack.api.command.admin.pod.ListPodsByCmd; -import org.apache.cloudstack.api.command.admin.pod.UpdatePodCmd; -import org.apache.cloudstack.api.command.admin.region.AddRegionCmd; -import org.apache.cloudstack.api.command.admin.region.RemoveRegionCmd; -import org.apache.cloudstack.api.command.admin.region.UpdateRegionCmd; -import org.apache.cloudstack.api.command.admin.swift.AddSwiftCmd; -import org.apache.cloudstack.api.command.admin.swift.ListSwiftsCmd; -import org.apache.cloudstack.api.command.admin.template.PrepareTemplateCmd; -import org.apache.cloudstack.api.command.admin.vlan.CreateVlanIpRangeCmd; -import org.apache.cloudstack.api.command.admin.vlan.DeleteVlanIpRangeCmd; -import org.apache.cloudstack.api.command.admin.vlan.ListVlanIpRangesCmd; -import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; -import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd; -import org.apache.cloudstack.api.command.admin.vm.MigrateVirtualMachineWithVolumeCmd; -import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; -import org.apache.cloudstack.api.command.admin.zone.CreateZoneCmd; -import org.apache.cloudstack.api.command.admin.zone.DeleteZoneCmd; -import org.apache.cloudstack.api.command.admin.zone.MarkDefaultZoneForAccountCmd; -import org.apache.cloudstack.api.command.admin.zone.UpdateZoneCmd; -import org.apache.cloudstack.api.command.user.account.AddAccountToProjectCmd; -import org.apache.cloudstack.api.command.user.account.DeleteAccountFromProjectCmd; -import org.apache.cloudstack.api.command.user.account.ListAccountsCmd; -import org.apache.cloudstack.api.command.user.account.ListProjectAccountsCmd; -import org.apache.cloudstack.api.command.user.address.AssociateIPAddrCmd; -import org.apache.cloudstack.api.command.user.address.DisassociateIPAddrCmd; -import org.apache.cloudstack.api.command.user.address.ListPublicIpAddressesCmd; -import org.apache.cloudstack.api.command.user.config.ListCapabilitiesCmd; -import org.apache.cloudstack.api.command.user.event.ArchiveEventsCmd; -import org.apache.cloudstack.api.command.user.event.DeleteEventsCmd; -import org.apache.cloudstack.api.command.user.event.ListEventTypesCmd; -import org.apache.cloudstack.api.command.user.event.ListEventsCmd; -import org.apache.cloudstack.api.command.user.guest.ListGuestOsCategoriesCmd; -import org.apache.cloudstack.api.command.user.guest.ListGuestOsCmd; -import org.apache.cloudstack.api.command.user.job.ListAsyncJobsCmd; -import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd; -import org.apache.cloudstack.api.command.user.offering.ListDiskOfferingsCmd; -import org.apache.cloudstack.api.command.user.offering.ListServiceOfferingsCmd; -import org.apache.cloudstack.api.command.user.region.ListRegionsCmd; -import org.apache.cloudstack.api.command.user.region.ha.gslb.*; -import org.apache.cloudstack.api.command.user.ssh.CreateSSHKeyPairCmd; -import org.apache.cloudstack.api.command.user.ssh.DeleteSSHKeyPairCmd; -import org.apache.cloudstack.api.command.user.ssh.ListSSHKeyPairsCmd; -import org.apache.cloudstack.api.command.user.ssh.RegisterSSHKeyPairCmd; -import org.apache.cloudstack.api.command.user.tag.CreateTagsCmd; -import org.apache.cloudstack.api.command.user.tag.DeleteTagsCmd; -import org.apache.cloudstack.api.command.user.tag.ListTagsCmd; -import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; -import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; -import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd; -import org.apache.cloudstack.api.command.user.vmgroup.UpdateVMGroupCmd; -import org.apache.cloudstack.api.command.user.vmsnapshot.CreateVMSnapshotCmd; -import org.apache.cloudstack.api.command.user.vmsnapshot.DeleteVMSnapshotCmd; -import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd; -import org.apache.cloudstack.api.command.user.vmsnapshot.RevertToSnapshotCmd; -import org.apache.cloudstack.api.command.user.zone.ListZonesByCmd; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; -import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; + public class ManagementServerImpl extends ManagerBase implements ManagementServer { public static final Logger s_logger = Logger.getLogger(ManagementServerImpl.class.getName()); @@ -616,48 +922,69 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe @Override public Pair, Integer> searchForClusters(ListClustersCmd cmd) { - Filter searchFilter = new Filter(ClusterVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal()); - SearchCriteria sc = _clusterDao.createSearchCriteria(); - - Object id = cmd.getId(); + Object id = cmd.getId(); Object name = cmd.getClusterName(); Object podId = cmd.getPodId(); Long zoneId = cmd.getZoneId(); Object hypervisorType = cmd.getHypervisorType(); Object clusterType = cmd.getClusterType(); Object allocationState = cmd.getAllocationState(); + String zoneType = cmd.getZoneType(); String keyword = cmd.getKeyword(); - zoneId = _accountMgr.checkAccessAndSpecifyAuthority(UserContext.current().getCaller(), zoneId); - + + + Filter searchFilter = new Filter(ClusterVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal()); + + SearchBuilder sb = _clusterDao.createSearchBuilder(); + sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); + sb.and("name", sb.entity().getName(), SearchCriteria.Op.LIKE); + sb.and("podId", sb.entity().getPodId(), SearchCriteria.Op.EQ); + sb.and("dataCenterId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ); + sb.and("hypervisorType", sb.entity().getHypervisorType(), SearchCriteria.Op.EQ); + sb.and("clusterType", sb.entity().getClusterType(), SearchCriteria.Op.EQ); + sb.and("allocationState", sb.entity().getAllocationState(), SearchCriteria.Op.EQ); + + if(zoneType != null) { + SearchBuilder zoneSb = _dcDao.createSearchBuilder(); + zoneSb.and("zoneNetworkType", zoneSb.entity().getNetworkType(), SearchCriteria.Op.EQ); + sb.join("zoneSb", zoneSb, sb.entity().getDataCenterId(), zoneSb.entity().getId(), JoinBuilder.JoinType.INNER); + } + + + SearchCriteria sc = sb.create(); if (id != null) { - sc.addAnd("id", SearchCriteria.Op.EQ, id); + sc.setParameters("id", id); } if (name != null) { - sc.addAnd("name", SearchCriteria.Op.LIKE, "%" + name + "%"); + sc.setParameters("name", "%" + name + "%"); } if (podId != null) { - sc.addAnd("podId", SearchCriteria.Op.EQ, podId); + sc.setParameters("podId", podId); } if (zoneId != null) { - sc.addAnd("dataCenterId", SearchCriteria.Op.EQ, zoneId); + sc.setParameters("dataCenterId", zoneId); } if (hypervisorType != null) { - sc.addAnd("hypervisorType", SearchCriteria.Op.EQ, hypervisorType); + sc.setParameters("hypervisorType", hypervisorType); } if (clusterType != null) { - sc.addAnd("clusterType", SearchCriteria.Op.EQ, clusterType); + sc.setParameters("clusterType", clusterType); } if (allocationState != null) { - sc.addAnd("allocationState", SearchCriteria.Op.EQ, allocationState); + sc.setParameters("allocationState", allocationState); } + if(zoneType != null) { + sc.setJoinParameters("zoneSb", "zoneNetworkType", zoneType); + } + if (keyword != null) { SearchCriteria ssc = _clusterDao.createSearchCriteria(); ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%"); @@ -1068,17 +1395,29 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe @Override public Pair, Integer> searchForPods(ListPodsByCmd cmd) { - Filter searchFilter = new Filter(HostPodVO.class, "dataCenterId", true, cmd.getStartIndex(), cmd.getPageSizeVal()); - SearchCriteria sc = _hostPodDao.createSearchCriteria(); - String podName = cmd.getPodName(); Long id = cmd.getId(); - Long zoneId = cmd.getZoneId(); + Long zoneId = cmd.getZoneId(); Object keyword = cmd.getKeyword(); Object allocationState = cmd.getAllocationState(); - + String zoneType = cmd.getZoneType(); zoneId = _accountMgr.checkAccessAndSpecifyAuthority(UserContext.current().getCaller(), zoneId); + + Filter searchFilter = new Filter(HostPodVO.class, "dataCenterId", true, cmd.getStartIndex(), cmd.getPageSizeVal()); + SearchBuilder sb = _hostPodDao.createSearchBuilder(); + sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); + sb.and("name", sb.entity().getName(), SearchCriteria.Op.LIKE); + sb.and("dataCenterId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ); + sb.and("allocationState", sb.entity().getAllocationState(), SearchCriteria.Op.EQ); + + if(zoneType != null) { + SearchBuilder zoneSb = _dcDao.createSearchBuilder(); + zoneSb.and("zoneNetworkType", zoneSb.entity().getNetworkType(), SearchCriteria.Op.EQ); + sb.join("zoneSb", zoneSb, sb.entity().getDataCenterId(), zoneSb.entity().getId(), JoinBuilder.JoinType.INNER); + } + + SearchCriteria sc = sb.create(); if (keyword != null) { SearchCriteria ssc = _hostPodDao.createSearchCriteria(); ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%"); @@ -1088,21 +1427,25 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe } if (id != null) { - sc.addAnd("id", SearchCriteria.Op.EQ, id); + sc.setParameters("id", id); } - + if (podName != null) { - sc.addAnd("name", SearchCriteria.Op.LIKE, "%" + podName + "%"); + sc.setParameters("name", "%" + podName + "%"); } - + if (zoneId != null) { - sc.addAnd("dataCenterId", SearchCriteria.Op.EQ, zoneId); + sc.setParameters("dataCenterId", zoneId); } - + if (allocationState != null) { - sc.addAnd("allocationState", SearchCriteria.Op.EQ, allocationState); + sc.setParameters("allocationState", allocationState); + } + + if(zoneType != null) { + sc.setJoinParameters("zoneSb", "zoneNetworkType", zoneType); } - + Pair, Integer> result = _hostPodDao.searchAndCount(sc, searchFilter); return new Pair, Integer>(result.first(), result.second()); } @@ -1237,16 +1580,41 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe Object name = cmd.getConfigName(); Object category = cmd.getCategory(); Object keyword = cmd.getKeyword(); - Long id = cmd.getId(); - String scope = cmd.getScope(); + Long zoneId = cmd.getZoneId(); + Long clusterId = cmd.getClusterId(); + Long storagepoolId = cmd.getStoragepoolId(); + Long accountId = cmd.getAccountId(); + String scope = null; + Long id = null; + int paramCountCheck = 0; - if (scope!= null && !scope.isEmpty()) { + if (zoneId != null) { + scope = Config.ConfigurationParameterScope.zone.toString(); + id = zoneId; + paramCountCheck++; + } + if (clusterId != null) { + scope = Config.ConfigurationParameterScope.cluster.toString(); + id = clusterId; + paramCountCheck++; + } + if (accountId != null) { + scope = Config.ConfigurationParameterScope.account.toString(); + id = accountId; + paramCountCheck++; + } + if (storagepoolId != null) { + scope = Config.ConfigurationParameterScope.storagepool.toString(); + id = storagepoolId; + paramCountCheck++; + } + + if (paramCountCheck > 1) { + throw new InvalidParameterValueException("cannot handle multiple IDs, provide only one ID corresponding to the scope"); + } + + if (scope != null && !scope.isEmpty()) { // getting the list of parameters at requested scope - try { - Config.ConfigurationParameterScope.valueOf(scope.toLowerCase()); - } catch (Exception e ) { - throw new InvalidParameterValueException("Invalid scope " + scope + " while listing configuration parameters"); - } if (id == null) { throw new InvalidParameterValueException("Invalid id null, id is needed corresponding to the scope"); } @@ -1309,7 +1677,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe HypervisorType hypervisorType = HypervisorType.getType(cmd.getHypervisor()); return listTemplates(cmd.getId(), cmd.getIsoName(), cmd.getKeyword(), isoFilter, true, cmd.isBootable(), cmd.getPageSizeVal(), cmd.getStartIndex(), cmd.getZoneId(), hypervisorType, true, cmd.listInReadyState(), permittedAccounts, caller, - listProjectResourcesCriteria, tags); + listProjectResourcesCriteria, tags, cmd.getZoneType()); } @Override @@ -1342,12 +1710,12 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe HypervisorType hypervisorType = HypervisorType.getType(cmd.getHypervisor()); return listTemplates(id, cmd.getTemplateName(), cmd.getKeyword(), templateFilter, false, null, cmd.getPageSizeVal(), cmd.getStartIndex(), - cmd.getZoneId(), hypervisorType, showDomr, cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags); + cmd.getZoneId(), hypervisorType, showDomr, cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, cmd.getZoneType()); } private Set> listTemplates(Long templateId, String name, String keyword, TemplateFilter templateFilter, boolean isIso, Boolean bootable, Long pageSize, Long startIndex, Long zoneId, HypervisorType hyperType, boolean showDomr, boolean onlyReady, - List permittedAccounts, Account caller, ListProjectResourcesCriteria listProjectResourcesCriteria, Map tags) { + List permittedAccounts, Account caller, ListProjectResourcesCriteria listProjectResourcesCriteria, Map tags, String zoneType) { VMTemplateVO template = null; if (templateId != null) { @@ -1388,7 +1756,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe startIndex, zoneId, hyperType, onlyReady, showDomr, permittedAccounts, caller, tags); Set> templateZonePairSet2 = new HashSet>(); templateZonePairSet2 = _templateDao.searchTemplates(name, keyword, templateFilter, isIso, hypers, bootable, domain, pageSize, - startIndex, zoneId, hyperType, onlyReady, showDomr, permittedAccounts, caller, listProjectResourcesCriteria, tags); + startIndex, zoneId, hyperType, onlyReady, showDomr, permittedAccounts, caller, listProjectResourcesCriteria, tags, zoneType); for (Pair tmpltPair : templateZonePairSet2) { if (!templateZonePairSet.contains(new Pair(tmpltPair.first(), -1L))) { @@ -1412,7 +1780,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe Set> templateZonePairSet2 = new HashSet>(); templateZonePairSet2 = _templateDao.searchTemplates(name, keyword, templateFilter, isIso, hypers, bootable, domain, pageSize, startIndex, zoneId, hyperType, onlyReady, showDomr, - permittedAccounts, caller, listProjectResourcesCriteria, tags); + permittedAccounts, caller, listProjectResourcesCriteria, tags, zoneType); for (Pair tmpltPair : templateZonePairSet2) { if (!templateZonePairSet.contains(new Pair(tmpltPair.first(), -1L))) { @@ -1430,7 +1798,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe } else { if (template == null) { templateZonePairSet = _templateDao.searchTemplates(name, keyword, templateFilter, isIso, hypers, bootable, domain, pageSize, - startIndex, zoneId, hyperType, onlyReady, showDomr, permittedAccounts, caller, listProjectResourcesCriteria, tags); + startIndex, zoneId, hyperType, onlyReady, showDomr, permittedAccounts, caller, listProjectResourcesCriteria, tags, zoneType); } else { // if template is not public, perform permission check here if (!template.isPublicTemplate() && caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { @@ -2194,6 +2562,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(UpdateNetworkServiceProviderCmd.class); cmdList.add(UpdatePhysicalNetworkCmd.class); cmdList.add(UpdateStorageNetworkIpRangeCmd.class); + cmdList.add(DedicateGuestVlanRangeCmd.class); + cmdList.add(ListDedicatedGuestVlanRangesCmd.class); + cmdList.add(ReleaseDedicatedGuestVlanRangeCmd.class); cmdList.add(CreateDiskOfferingCmd.class); cmdList.add(CreateServiceOfferingCmd.class); cmdList.add(DeleteDiskOfferingCmd.class); @@ -2461,7 +2832,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(ListZonesByCmd.class); cmdList.add(ListVMSnapshotCmd.class); cmdList.add(CreateVMSnapshotCmd.class); - cmdList.add(RevertToSnapshotCmd.class); + cmdList.add(RevertToVMSnapshotCmd.class); cmdList.add(DeleteVMSnapshotCmd.class); cmdList.add(AddIpToVmNicCmd.class); cmdList.add(RemoveIpFromVmNicCmd.class); @@ -2476,6 +2847,12 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(AssignToGlobalLoadBalancerRuleCmd.class); cmdList.add(RemoveFromGlobalLoadBalancerRuleCmd.class); cmdList.add(ListStorageProvidersCmd.class); + cmdList.add(CreateApplicationLoadBalancerCmd.class); + cmdList.add(ListApplicationLoadBalancersCmd.class); + cmdList.add(DeleteApplicationLoadBalancerCmd.class); + cmdList.add(ConfigureInternalLoadBalancerElementCmd.class); + cmdList.add(CreateInternalLoadBalancerElementCmd.class); + cmdList.add(ListInternalLoadBalancerElementsCmd.class); cmdList.add(CreateAffinityGroupCmd.class); cmdList.add(DeleteAffinityGroupCmd.class); cmdList.add(ListAffinityGroupsCmd.class); @@ -2492,6 +2869,11 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(AddResourceDetailCmd.class); cmdList.add(RemoveResourceDetailCmd.class); cmdList.add(ListResourceDetailsCmd.class); + cmdList.add(StopInternalLBVMCmd.class); + cmdList.add(StartInternalLBVMCmd.class); + cmdList.add(ListInternalLBVMsCmd.class); + cmdList.add(ListNetworkIsolationMethodsCmd.class); + cmdList.add(ListNetworkIsolationMethodsCmd.class); return cmdList; } @@ -2652,6 +3034,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe public Pair, Integer> searchForSystemVm(ListSystemVMsCmd cmd) { String type = cmd.getSystemVmType(); Long zoneId = _accountMgr.checkAccessAndSpecifyAuthority(UserContext.current().getCaller(), cmd.getZoneId()); + String zoneType = cmd.getZoneType(); Long id = cmd.getId(); String name = cmd.getSystemVmName(); String state = cmd.getState(); @@ -2678,6 +3061,12 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe sb.join("volumeSearch", volumeSearch, sb.entity().getId(), volumeSearch.entity().getInstanceId(), JoinBuilder.JoinType.INNER); } + if(zoneType != null) { + SearchBuilder zoneSb = _dcDao.createSearchBuilder(); + zoneSb.and("zoneNetworkType", zoneSb.entity().getNetworkType(), SearchCriteria.Op.EQ); + sb.join("zoneSb", zoneSb, sb.entity().getDataCenterId(), zoneSb.entity().getId(), JoinBuilder.JoinType.INNER); + } + SearchCriteria sc = sb.create(); if (keyword != null) { @@ -2718,6 +3107,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe sc.setJoinParameters("volumeSearch", "poolId", storageId); } + if(zoneType != null) { + sc.setJoinParameters("zoneSb", "zoneNetworkType", zoneType); + } + Pair, Integer> result = _vmInstanceDao.searchAndCount(sc, searchFilter); return new Pair, Integer>(result.first(), result.second()); } @@ -3020,7 +3413,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe List extractURLList = _uploadDao.listByTypeUploadStatus(volumeId, Upload.Type.VOLUME, UploadVO.Status.DOWNLOAD_URL_CREATED); if (extractMode == Upload.Mode.HTTP_DOWNLOAD && extractURLList.size() > 0) { - return extractURLList.get(0).getId(); // If download url already + return extractURLList.get(0).getId(); // If download url already Note: volss // exists then return } else { UploadVO uploadJob = _uploadMonitor.createNewUploadEntry(sserver.getId(), volumeId, UploadVO.Status.COPY_IN_PROGRESS, Upload.Type.VOLUME, @@ -3072,6 +3465,19 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe } String volumeLocalPath = "volumes/" + volume.getId() + "/" + cvAnswer.getVolumePath() + "." + getFormatForPool(srcPool); + //Fang: volss, handle the ova special case; + if (getFormatForPool(srcPool) == "ova") { + CreateVolumeOVACommand cvOVACmd = new CreateVolumeOVACommand(secondaryStorageURL, volumeLocalPath, cvAnswer.getVolumePath(), srcPool, copyvolumewait); + CreateVolumeOVAAnswer OVAanswer = null; + + try { + cvOVACmd.setContextParam("hypervisor", HypervisorType.VMware.toString()); + OVAanswer = (CreateVolumeOVAAnswer) _storageMgr.sendToPool(srcPool, cvOVACmd); //Fang: for extract volume, create the ova file here; + + } catch (StorageUnavailableException e) { + s_logger.debug("Storage unavailable"); + } + } // Update the DB that volume is copied and volumePath uploadJob.setUploadState(UploadVO.Status.COPY_COMPLETE); uploadJob.setLastUpdated(new Date()); diff --git a/server/src/com/cloud/servlet/ConsoleProxyServlet.java b/server/src/com/cloud/servlet/ConsoleProxyServlet.java index ebb91746268..097986bda62 100644 --- a/server/src/com/cloud/servlet/ConsoleProxyServlet.java +++ b/server/src/com/cloud/servlet/ConsoleProxyServlet.java @@ -73,7 +73,7 @@ public class ConsoleProxyServlet extends HttpServlet { @Inject AccountManager _accountMgr; @Inject VirtualMachineManager _vmMgr; @Inject ManagementServer _ms; - @Inject IdentityService _identityService; + @Inject IdentityService _identityService; static ManagementServer s_ms; @@ -81,13 +81,13 @@ public class ConsoleProxyServlet extends HttpServlet { public ConsoleProxyServlet() { } - + @Override public void init(ServletConfig config) throws ServletException { - SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, config.getServletContext()); + SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, config.getServletContext()); s_ms = _ms; } - + @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) { doGet(req, resp); @@ -274,7 +274,7 @@ public class ConsoleProxyServlet extends HttpServlet { private void handleAuthRequest(HttpServletRequest req, HttpServletResponse resp, long vmId) { - // TODO authentication channel between console proxy VM and management server needs to be secured, + // TODO authentication channel between console proxy VM and management server needs to be secured, // the data is now being sent through private network, but this is apparently not enough VMInstanceVO vm = _vmMgr.findById(vmId); if(vm == null) { @@ -334,11 +334,11 @@ public class ConsoleProxyServlet extends HttpServlet { private String getEncryptorPassword() { String key = _ms.getEncryptionKey(); String iv = _ms.getEncryptionIV(); - + ConsoleProxyPasswordBasedEncryptor.KeyIVPair keyIvPair = new ConsoleProxyPasswordBasedEncryptor.KeyIVPair(key, iv); return _gson.toJson(keyIvPair); } - + private String composeThumbnailUrl(String rootUrl, VMInstanceVO vm, HostVO hostVo, int w, int h) { StringBuffer sb = new StringBuffer(rootUrl); @@ -385,8 +385,7 @@ public class ConsoleProxyServlet extends HttpServlet { Ternary parsedHostInfo = parseHostInfo(portInfo.first()); String sid = vm.getVncPassword(); - String tag = String.valueOf(vm.getId()); - tag = _identityService.getIdentityUuid("vm_instance", tag); + String tag = vm.getUuid(); String ticket = genAccessTicket(host, String.valueOf(portInfo.second()), sid, tag); ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(getEncryptorPassword()); ConsoleProxyClientParam param = new ConsoleProxyClientParam(); @@ -473,12 +472,12 @@ public class ConsoleProxyServlet extends HttpServlet { } catch (PermissionDeniedException ex) { if (accountObj.getType() == Account.ACCOUNT_TYPE_NORMAL) { if (s_logger.isDebugEnabled()) { - s_logger.debug("VM access is denied. VM owner account " + vm.getAccountId() + s_logger.debug("VM access is denied. VM owner account " + vm.getAccountId() + " does not match the account id in session " + accountObj.getId() + " and caller is a normal user"); } } else if(accountObj.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN || accountObj.getType() == Account.ACCOUNT_TYPE_READ_ONLY_ADMIN) { if(s_logger.isDebugEnabled()) { - s_logger.debug("VM access is denied. VM owner account " + vm.getAccountId() + s_logger.debug("VM access is denied. VM owner account " + vm.getAccountId() + " does not match the account id in session " + accountObj.getId() + " and the domain-admin caller does not manage the target domain"); } } @@ -515,7 +514,7 @@ public class ConsoleProxyServlet extends HttpServlet { account = _accountMgr.getAccount(user.getAccountId()); } - if ((user == null) || (user.getRemoved() != null) || !user.getState().equals(Account.State.enabled) + if ((user == null) || (user.getRemoved() != null) || !user.getState().equals(Account.State.enabled) || (account == null) || !account.getState().equals(Account.State.enabled)) { s_logger.warn("Deleted/Disabled/Locked user with id=" + userId + " attempting to access public API"); return false; @@ -586,7 +585,7 @@ public class ConsoleProxyServlet extends HttpServlet { if (!user.getState().equals(Account.State.enabled) || !account.getState().equals(Account.State.enabled)) { s_logger.debug("disabled or locked user accessing the api, userid = " + user.getId() + "; name = " + user.getUsername() + "; state: " + user.getState() + "; accountState: " + account.getState()); return false; - } + } // verify secret key exists secretKey = user.getSecretKey(); @@ -632,10 +631,10 @@ public class ConsoleProxyServlet extends HttpServlet { case '>': sb.append(">"); break; case '&': sb.append("&"); break; case '"': sb.append("""); break; - case ' ': sb.append(" ");break; + case ' ': sb.append(" ");break; default: sb.append(c); break; } } return sb.toString(); - } + } } diff --git a/server/src/com/cloud/storage/OCFS2ManagerImpl.java b/server/src/com/cloud/storage/OCFS2ManagerImpl.java index 476bf04cae9..5eb9a4a5c44 100755 --- a/server/src/com/cloud/storage/OCFS2ManagerImpl.java +++ b/server/src/com/cloud/storage/OCFS2ManagerImpl.java @@ -56,7 +56,7 @@ import com.cloud.utils.exception.CloudRuntimeException; @Local(value ={OCFS2Manager.class}) public class OCFS2ManagerImpl extends ManagerBase implements OCFS2Manager, ResourceListener { private static final Logger s_logger = Logger.getLogger(OCFS2ManagerImpl.class); - + @Inject ClusterDetailsDao _clusterDetailsDao; @Inject AgentManager _agentMgr; @Inject HostDao _hostDao; @@ -64,7 +64,7 @@ public class OCFS2ManagerImpl extends ManagerBase implements OCFS2Manager, Resou @Inject ResourceManager _resourceMgr; @Inject StoragePoolHostDao _poolHostDao; @Inject PrimaryDataStoreDao _poolDao; - + @Override public boolean configure(String name, Map params) throws ConfigurationException { return true; @@ -96,8 +96,8 @@ public class OCFS2ManagerImpl extends ManagerBase implements OCFS2Manager, Resou } return lst; } - - + + private boolean prepareNodes(String clusterName, List hosts) { PrepareOCFS2NodesCommand cmd = new PrepareOCFS2NodesCommand(clusterName, marshalNodes(hosts)); for (HostVO h : hosts) { @@ -111,36 +111,36 @@ public class OCFS2ManagerImpl extends ManagerBase implements OCFS2Manager, Resou return false; } } - + return true; } - + private String getClusterName(Long clusterId) { ClusterVO cluster = _clusterDao.findById(clusterId); if (cluster == null) { throw new CloudRuntimeException("Cannot get cluster for id " + clusterId); } - - String clusterName = "OvmCluster" + cluster.getId(); + + String clusterName = "OvmCluster" + cluster.getId(); return clusterName; } - + @Override public boolean prepareNodes(List hosts, StoragePool pool) { if (pool.getPoolType() != StoragePoolType.OCFS2) { throw new CloudRuntimeException("None OCFS2 storage pool is getting into OCFS2 manager!"); } - + return prepareNodes(getClusterName(pool.getClusterId()), hosts); } @Override - public boolean prepareNodes(Long clusterId) { + public boolean prepareNodes(Long clusterId) { ClusterVO cluster = _clusterDao.findById(clusterId); if (cluster == null) { throw new CloudRuntimeException("Cannot find cluster for ID " + clusterId); } - + SearchCriteriaService sc = SearchCriteria2.create(HostVO.class); sc.addAnd(sc.getEntity().getClusterId(), Op.EQ, clusterId); sc.addAnd(sc.getEntity().getPodId(), Op.EQ, cluster.getPodId()); @@ -151,36 +151,36 @@ public class OCFS2ManagerImpl extends ManagerBase implements OCFS2Manager, Resou s_logger.debug("There is no host in cluster " + clusterId + ", no need to prepare OCFS2 nodes"); return true; } - + return prepareNodes(getClusterName(clusterId), hosts); } @Override public void processDiscoverEventBefore(Long dcid, Long podId, Long clusterId, URI uri, String username, String password, List hostTags) { // TODO Auto-generated method stub - + } @Override public void processDiscoverEventAfter(Map> resources) { // TODO Auto-generated method stub - + } @Override - public void processDeleteHostEventBefore(HostVO host) { + public void processDeleteHostEventBefore(Host host) { // TODO Auto-generated method stub - + } @Override - public void processDeletHostEventAfter(HostVO host) { + public void processDeletHostEventAfter(Host host) { String errMsg = String.format("Prepare OCFS2 nodes failed after delete host %1$s (zone:%2$s, pod:%3$s, cluster:%4$s", host.getId(), host.getDataCenterId(), host.getPodId(), host.getClusterId()); - + if (host.getHypervisorType() != HypervisorType.Ovm) { return; } - + boolean hasOcfs2 = false; List poolRefs = _poolHostDao.listByHostId(host.getId()); for (StoragePoolHostVO poolRef : poolRefs) { @@ -205,24 +205,24 @@ public class OCFS2ManagerImpl extends ManagerBase implements OCFS2Manager, Resou @Override public void processCancelMaintenaceEventBefore(Long hostId) { // TODO Auto-generated method stub - + } @Override public void processCancelMaintenaceEventAfter(Long hostId) { // TODO Auto-generated method stub - + } @Override public void processPrepareMaintenaceEventBefore(Long hostId) { // TODO Auto-generated method stub - + } @Override public void processPrepareMaintenaceEventAfter(Long hostId) { // TODO Auto-generated method stub - + } } diff --git a/server/src/com/cloud/storage/StorageManager.java b/server/src/com/cloud/storage/StorageManager.java index 6026cd9c0fc..d49a7f86e94 100755 --- a/server/src/com/cloud/storage/StorageManager.java +++ b/server/src/com/cloud/storage/StorageManager.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.storage; +import java.math.BigDecimal; import java.util.List; import java.util.Set; @@ -120,4 +121,5 @@ public interface StorageManager extends StorageService { DataStore createLocalStorage(Host host, StoragePoolInfo poolInfo) throws ConnectionException; + BigDecimal getStorageOverProvisioningFactor(Long dcId); } diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index a182e39dd86..1d4dcefad92 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -40,6 +40,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.server.ConfigurationServer; import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaintenanceCmd; import org.apache.cloudstack.api.command.admin.storage.CreateStoragePoolCmd; import org.apache.cloudstack.api.command.admin.storage.DeletePoolCmd; @@ -292,9 +293,13 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C SnapshotDataFactory snapshotFactory; @Inject protected HypervisorCapabilitiesDao _hypervisorCapabilitiesDao; + @Inject + ConfigurationServer _configServer; @Inject protected ResourceTagDao _resourceTagDao; + + protected List _storagePoolAllocators; public List getStoragePoolAllocators() { return _storagePoolAllocators; @@ -327,15 +332,12 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C protected int _retry = 2; protected int _pingInterval = 60; // seconds protected int _hostRetry; - protected BigDecimal _overProvisioningFactor = new BigDecimal(1); + //protected BigDecimal _overProvisioningFactor = new BigDecimal(1); private long _maxVolumeSizeInGb; private long _serverId; private int _customDiskOfferingMinSize = 1; private int _customDiskOfferingMaxSize = 1024; - private double _storageUsedThreshold = 1.0d; - private double _storageAllocatedThreshold = 1.0d; - protected BigDecimal _storageOverprovisioningFactor = new BigDecimal(1); private Map hostListeners = new HashMap(); private boolean _recreateSystemVmEnabled; @@ -535,12 +537,6 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C Map configs = _configDao.getConfiguration( "management-server", params); - String overProvisioningFactorStr = configs - .get("storage.overprovisioning.factor"); - if (overProvisioningFactorStr != null) { - _overProvisioningFactor = new BigDecimal(overProvisioningFactorStr); - } - _retry = NumbersUtil.parseInt(configs.get(Config.StartRetry.key()), 10); _pingInterval = NumbersUtil.parseInt(configs.get("ping.interval"), 60); _hostRetry = NumbersUtil.parseInt(configs.get("host.retry"), 2); @@ -576,24 +572,6 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C String time = configs.get("storage.cleanup.interval"); _storageCleanupInterval = NumbersUtil.parseInt(time, 86400); - String storageUsedThreshold = _configDao - .getValue(Config.StorageCapacityDisableThreshold.key()); - if (storageUsedThreshold != null) { - _storageUsedThreshold = Double.parseDouble(storageUsedThreshold); - } - - String storageAllocatedThreshold = _configDao - .getValue(Config.StorageAllocatedCapacityDisableThreshold.key()); - if (storageAllocatedThreshold != null) { - _storageAllocatedThreshold = Double - .parseDouble(storageAllocatedThreshold); - } - - String globalStorageOverprovisioningFactor = configs - .get("storage.overprovisioning.factor"); - _storageOverprovisioningFactor = new BigDecimal(NumbersUtil.parseFloat( - globalStorageOverprovisioningFactor, 2.0f)); - s_logger.info("Storage cleanup enabled: " + _storageCleanupEnabled + ", interval: " + _storageCleanupInterval + ", template cleanup enabled: " + _templateCleanupEnabled); @@ -979,6 +957,11 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C listener.hostConnect(hostId, pool.getId()); } + @Override + public BigDecimal getStorageOverProvisioningFactor(Long dcId){ + return new BigDecimal(_configServer.getConfigValue(Config.StorageOverprovisioningFactor.key(), Config.ConfigurationParameterScope.zone.toString(), dcId)); + } + @Override public void createCapacityEntry(StoragePoolVO storagePool, short capacityType, long allocated) { SearchCriteria capacitySC = _capacityDao.createSearchCriteria(); @@ -990,7 +973,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C long totalOverProvCapacity; if (storagePool.getPoolType() == StoragePoolType.NetworkFilesystem) { - totalOverProvCapacity = _overProvisioningFactor.multiply(new BigDecimal(storagePool.getCapacityBytes())).longValue();// All this for the inaccuracy of floats for big number multiplication. + BigDecimal overProvFactor = getStorageOverProvisioningFactor(storagePool.getDataCenterId()); + totalOverProvCapacity = overProvFactor.multiply(new BigDecimal(storagePool.getCapacityBytes())).longValue();// All this for the inaccuracy of floats for big number multiplication. } else { totalOverProvCapacity = storagePool.getCapacityBytes(); } @@ -1731,6 +1715,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C private boolean checkUsagedSpace(StoragePool pool) { StatsCollector sc = StatsCollector.getInstance(); + double storageUsedThreshold = Double.parseDouble(_configServer.getConfigValue(Config.StorageCapacityDisableThreshold.key(), Config.ConfigurationParameterScope.zone.toString(), pool.getDataCenterId())); if (sc != null) { long totalSize = pool.getCapacityBytes(); StorageStats stats = sc.getStoragePoolStats(pool.getId()); @@ -1745,16 +1730,16 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C + pool.getCapacityBytes() + ", usedBytes: " + stats.getByteUsed() + ", usedPct: " + usedPercentage + ", disable threshold: " - + _storageUsedThreshold); + + storageUsedThreshold); } - if (usedPercentage >= _storageUsedThreshold) { + if (usedPercentage >= storageUsedThreshold) { if (s_logger.isDebugEnabled()) { s_logger.debug("Insufficient space on pool: " + pool.getId() + " since its usage percentage: " + usedPercentage + " has crossed the pool.storage.capacity.disablethreshold: " - + _storageUsedThreshold); + + storageUsedThreshold); } return false; } @@ -1793,12 +1778,13 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C long totalOverProvCapacity; if (pool.getPoolType() == StoragePoolType.NetworkFilesystem) { - totalOverProvCapacity = _storageOverprovisioningFactor.multiply( + totalOverProvCapacity = getStorageOverProvisioningFactor(pool.getDataCenterId()).multiply( new BigDecimal(pool.getCapacityBytes())).longValue(); } else { totalOverProvCapacity = pool.getCapacityBytes(); } + double storageAllocatedThreshold = Double.parseDouble(_configServer.getConfigValue(Config.StorageAllocatedCapacityDisableThreshold.key(), Config.ConfigurationParameterScope.zone.toString(), pool.getDataCenterId())); if (s_logger.isDebugEnabled()) { s_logger.debug("Checking pool: " + pool.getId() + " for volume allocation " + volumes.toString() @@ -1806,12 +1792,12 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C + ", totalAllocatedSize : " + allocatedSizeWithtemplate + ", askingSize : " + totalAskingSize + ", allocated disable threshold: " - + _storageAllocatedThreshold); + + storageAllocatedThreshold); } double usedPercentage = (allocatedSizeWithtemplate + totalAskingSize) / (double) (totalOverProvCapacity); - if (usedPercentage > _storageAllocatedThreshold) { + if (usedPercentage > storageAllocatedThreshold) { if (s_logger.isDebugEnabled()) { s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() @@ -1820,7 +1806,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C + " since its allocated percentage: " + usedPercentage + " has crossed the allocated pool.storage.allocated.capacity.disablethreshold: " - + _storageAllocatedThreshold + ", skipping this pool"); + + storageAllocatedThreshold + ", skipping this pool"); } return false; } diff --git a/server/src/com/cloud/storage/download/DownloadMonitorImpl.java b/server/src/com/cloud/storage/download/DownloadMonitorImpl.java index 5d7a2106e6a..220cbffd5a3 100755 --- a/server/src/com/cloud/storage/download/DownloadMonitorImpl.java +++ b/server/src/com/cloud/storage/download/DownloadMonitorImpl.java @@ -875,7 +875,9 @@ public class DownloadMonitorImpl extends ManagerBase implements DownloadMonitor tmpltHost.setPhysicalSize(tmpltInfo.getPhysicalSize()); tmpltHost.setLastUpdated(new Date()); - if (tmpltInfo.getSize() > 0) { + // Skipping limit checks for SYSTEM Account and for the templates created from volumes or snapshots + // which already got checked and incremented during createTemplate API call. + if (tmpltInfo.getSize() > 0 && tmplt.getAccountId() != Account.ACCOUNT_ID_SYSTEM && tmplt.getUrl() != null) { long accountId = tmplt.getAccountId(); try { _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(accountId), diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java index 490948ba5ae..26aae48ba38 100755 --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -48,7 +48,7 @@ import com.cloud.agent.api.Command; import com.cloud.agent.api.DeleteSnapshotBackupCommand; import com.cloud.agent.api.DeleteSnapshotsDirCommand; import com.cloud.agent.api.DownloadSnapshotFromS3Command; -import com.cloud.agent.api.downloadSnapshotFromSwiftCommand; +import com.cloud.agent.api.DownloadSnapshotFromSwiftCommand; import com.cloud.agent.api.to.S3TO; import com.cloud.agent.api.to.SwiftTO; import com.cloud.alert.AlertManager; @@ -58,6 +58,7 @@ import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterVO; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.domain.dao.DomainDao; @@ -383,7 +384,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, String parent = null; try { for (String backupUuid : BackupUuids) { - downloadSnapshotFromSwiftCommand cmd = new downloadSnapshotFromSwiftCommand(swift, secondaryStoragePoolUrl, dcId, accountId, volumeId, parent, backupUuid, _backupsnapshotwait); + DownloadSnapshotFromSwiftCommand cmd = new DownloadSnapshotFromSwiftCommand(swift, secondaryStoragePoolUrl, dcId, accountId, volumeId, parent, backupUuid, _backupsnapshotwait); Answer answer = _agentMgr.sendToSSVM(dcId, cmd); if ((answer == null) || !answer.getResult()) { throw new CloudRuntimeException("downloadSnapshotsFromSwift failed "); @@ -571,6 +572,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, String keyword = cmd.getKeyword(); String snapshotTypeStr = cmd.getSnapshotType(); String intervalTypeStr = cmd.getIntervalType(); + String zoneType = cmd.getZoneType(); Map tags = cmd.getTags(); Account caller = UserContext.current().getCaller(); @@ -602,17 +604,23 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, sb.and("snapshotTypeNEQ", sb.entity().getsnapshotType(), SearchCriteria.Op.NEQ); if (tags != null && !tags.isEmpty()) { - SearchBuilder tagSearch = _resourceTagDao.createSearchBuilder(); - for (int count=0; count < tags.size(); count++) { - tagSearch.or().op("key" + String.valueOf(count), tagSearch.entity().getKey(), SearchCriteria.Op.EQ); - tagSearch.and("value" + String.valueOf(count), tagSearch.entity().getValue(), SearchCriteria.Op.EQ); - tagSearch.cp(); + SearchBuilder tagSearch = _resourceTagDao.createSearchBuilder(); + for (int count=0; count < tags.size(); count++) { + tagSearch.or().op("key" + String.valueOf(count), tagSearch.entity().getKey(), SearchCriteria.Op.EQ); + tagSearch.and("value" + String.valueOf(count), tagSearch.entity().getValue(), SearchCriteria.Op.EQ); + tagSearch.cp(); + } + tagSearch.and("resourceType", tagSearch.entity().getResourceType(), SearchCriteria.Op.EQ); + sb.groupBy(sb.entity().getId()); + sb.join("tagSearch", tagSearch, sb.entity().getId(), tagSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER); } - tagSearch.and("resourceType", tagSearch.entity().getResourceType(), SearchCriteria.Op.EQ); - sb.groupBy(sb.entity().getId()); - sb.join("tagSearch", tagSearch, sb.entity().getId(), tagSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER); - } + if(zoneType != null) { + SearchBuilder zoneSb = _dcDao.createSearchBuilder(); + zoneSb.and("zoneNetworkType", zoneSb.entity().getNetworkType(), SearchCriteria.Op.EQ); + sb.join("zoneSb", zoneSb, sb.entity().getDataCenterId(), zoneSb.entity().getId(), JoinBuilder.JoinType.INNER); + } + SearchCriteria sc = sb.create(); _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); @@ -630,6 +638,10 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, } } + if(zoneType != null) { + sc.setJoinParameters("zoneSb", "zoneNetworkType", zoneType); + } + if (name != null) { sc.setParameters("name", "%" + name + "%"); } diff --git a/server/src/com/cloud/template/HypervisorTemplateAdapter.java b/server/src/com/cloud/template/HypervisorTemplateAdapter.java index 491900b44e6..322f32eacdf 100755 --- a/server/src/com/cloud/template/HypervisorTemplateAdapter.java +++ b/server/src/com/cloud/template/HypervisorTemplateAdapter.java @@ -30,6 +30,9 @@ import javax.inject.Inject; import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; +import org.apache.cloudstack.api.command.user.template.ExtractTemplateCmd; +import com.cloud.agent.api.storage.PrepareOVAPackingCommand; +import com.cloud.agent.api.storage.PrepareOVAPackingAnswer; import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; @@ -64,6 +67,10 @@ import com.cloud.utils.UriUtils; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.UserVmVO; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.exception.AgentUnavailableException; +import com.cloud.exception.OperationTimedoutException; + @Local(value=TemplateAdapter.class) public class HypervisorTemplateAdapter extends TemplateAdapterBase implements TemplateAdapter { @@ -188,6 +195,77 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase implements Te return template; } + @Override + public TemplateProfile prepareExtractTemplate(ExtractTemplateCmd extractcmd) { + TemplateProfile profile = super.prepareExtractTemplate(extractcmd); + VMTemplateVO template = (VMTemplateVO)profile.getTemplate(); + Long zoneId = profile.getZoneId(); + Long templateId = template.getId(); + + if (template.getHypervisorType() == HypervisorType.VMware) { + PrepareOVAPackingCommand cmd = null; + String zoneName=""; + List secondaryStorageHosts; + if (!template.isCrossZones() && zoneId != null) { + DataCenterVO zone = _dcDao.findById(zoneId); + zoneName = zone.getName(); + secondaryStorageHosts = _ssvmMgr.listSecondaryStorageHostsInOneZone(zoneId); + + s_logger.debug("Attempting to mark template host refs for template: " + template.getName() + " as destroyed in zone: " + zoneName); + + // Make sure the template is downloaded to all the necessary secondary storage hosts + + for (HostVO secondaryStorageHost : secondaryStorageHosts) { + long hostId = secondaryStorageHost.getId(); + List templateHostVOs = _tmpltHostDao.listByHostTemplate(hostId, templateId); + for (VMTemplateHostVO templateHostVO : templateHostVOs) { + if (templateHostVO.getDownloadState() == Status.DOWNLOAD_IN_PROGRESS) { + String errorMsg = "Please specify a template that is not currently being downloaded."; + s_logger.debug("Template: " + template.getName() + " is currently being downloaded to secondary storage host: " + secondaryStorageHost.getName() + "."); + throw new CloudRuntimeException(errorMsg); + } + String installPath = templateHostVO.getInstallPath(); + if (installPath != null) { + HostVO ssvmhost = _ssvmMgr.pickSsvmHost(secondaryStorageHost); + if( ssvmhost == null ) { + s_logger.warn("prepareOVAPacking (hyervisorTemplateAdapter): There is no secondary storage VM for secondary storage host " + secondaryStorageHost.getName()); + throw new CloudRuntimeException("PrepareExtractTemplate: can't locate ssvm for SecStorage Host."); + } + //Answer answer = _agentMgr.sendToSecStorage(secondaryStorageHost, new PrepareOVAPackingCommand(secondaryStorageHost.getStorageUrl(), installPath)); + cmd = new PrepareOVAPackingCommand(secondaryStorageHost.getStorageUrl(), installPath); + + if (cmd == null) { + s_logger.debug("Fang: PrepareOVAPacking cmd can't created. cmd is null ."); + throw new CloudRuntimeException("PrepareExtractTemplate: can't create a new cmd to packing ova."); + } else { + cmd.setContextParam("hypervisor", HypervisorType.VMware.toString()); + } + Answer answer = null; + s_logger.debug("Fang: PrepareOVAPAcking cmd, before send out. cmd: " + cmd.toString()); + try { + answer = _agentMgr.send(ssvmhost.getId(), cmd); + } catch (AgentUnavailableException e) { + s_logger.warn("Unable to packOVA for template: id: " + templateId + ", name " + ssvmhost.getName(), e); + } catch (OperationTimedoutException e) { + s_logger.warn("Unable to packOVA for template timeout. template id: " + templateId); + e.printStackTrace(); + } + + if (answer == null || !answer.getResult()) { + s_logger.debug("Failed to create OVA for template " + templateHostVO + " due to " + ((answer == null) ? "answer is null" : answer.getDetails())); + throw new CloudRuntimeException("PrepareExtractTemplate: Failed to create OVA for template extraction. "); + } + } + } + } + } else { + s_logger.debug("Failed to create OVA for template " + template + " due to zone non-existing."); + throw new CloudRuntimeException("PrepareExtractTemplate: Failed to create OVA for template extraction. "); + } + } + return profile; + } + @Override @DB public boolean delete(TemplateProfile profile) { boolean success = true; diff --git a/server/src/com/cloud/template/TemplateAdapter.java b/server/src/com/cloud/template/TemplateAdapter.java index 1f8f491cb25..9a2d877926d 100755 --- a/server/src/com/cloud/template/TemplateAdapter.java +++ b/server/src/com/cloud/template/TemplateAdapter.java @@ -22,6 +22,7 @@ import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; +import org.apache.cloudstack.api.command.user.template.ExtractTemplateCmd; import com.cloud.exception.ResourceAllocationException; import com.cloud.hypervisor.Hypervisor.HypervisorType; @@ -56,6 +57,8 @@ public interface TemplateAdapter extends Adapter { public TemplateProfile prepareDelete(DeleteIsoCmd cmd); + public TemplateProfile prepareExtractTemplate(ExtractTemplateCmd cmd); + public boolean delete(TemplateProfile profile); public TemplateProfile prepare(boolean isIso, Long userId, String name, String displayText, Integer bits, diff --git a/server/src/com/cloud/template/TemplateAdapterBase.java b/server/src/com/cloud/template/TemplateAdapterBase.java index 1b114250621..0940d3e2af1 100755 --- a/server/src/com/cloud/template/TemplateAdapterBase.java +++ b/server/src/com/cloud/template/TemplateAdapterBase.java @@ -26,12 +26,14 @@ import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; +import org.apache.cloudstack.api.command.user.template.ExtractTemplateCmd; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; import org.apache.log4j.Logger; import com.cloud.api.ApiDBUtils; +import com.cloud.configuration.Config; import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.DataCenterVO; @@ -44,6 +46,7 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.org.Grouping; +import com.cloud.server.ConfigurationServer; import com.cloud.storage.GuestOS; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; @@ -82,6 +85,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat protected @Inject ResourceLimitService _resourceLimitMgr; protected @Inject DataStoreManager storeMgr; @Inject TemplateManager templateMgr; + @Inject ConfigurationServer _configServer; @Override public boolean stop() { @@ -167,8 +171,8 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat if (url.toLowerCase().contains("file://")) { throw new InvalidParameterValueException("File:// type urls are currently unsupported"); } - - boolean allowPublicUserTemplates = Boolean.parseBoolean(_configDao.getValue("allow.public.user.templates")); + // check whether owner can create public templates + boolean allowPublicUserTemplates = Boolean.parseBoolean(_configServer.getConfigValue(Config.AllowPublicUserTemplates.key(), Config.ConfigurationParameterScope.account.toString(), templateOwner.getId())); if (!isAdmin && !allowPublicUserTemplates && isPublic) { throw new InvalidParameterValueException("Only private templates/ISO can be created."); } @@ -337,6 +341,18 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat return new TemplateProfile(userId, template, zoneId); } + public TemplateProfile prepareExtractTemplate(ExtractTemplateCmd cmd) { + Long templateId = cmd.getId(); + Long userId = UserContext.current().getCallerUserId(); + Long zoneId = cmd.getZoneId(); + + VMTemplateVO template = _tmpltDao.findById(templateId.longValue()); + if (template == null) { + throw new InvalidParameterValueException("unable to find template with id " + templateId); + } + return new TemplateProfile(userId, template, zoneId); + } + public TemplateProfile prepareDelete(DeleteIsoCmd cmd) { Long templateId = cmd.getId(); Long userId = UserContext.current().getCallerUserId(); diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index c7eaa64335e..a8729e1490a 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -75,8 +75,8 @@ import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.AttachIsoCommand; import com.cloud.agent.api.ComputeChecksumCommand; -import com.cloud.agent.api.downloadTemplateFromSwiftToSecondaryStorageCommand; -import com.cloud.agent.api.uploadTemplateToSwiftFromSecondaryStorageCommand; +import com.cloud.agent.api.DownloadTemplateFromSwiftToSecondaryStorageCommand; +import com.cloud.agent.api.UploadTemplateToSwiftFromSecondaryStorageCommand; import com.cloud.agent.api.storage.DestroyCommand; import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer; import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; @@ -113,6 +113,7 @@ import com.cloud.projects.Project; import com.cloud.projects.ProjectManager; import com.cloud.resource.ResourceManager; +import com.cloud.server.ConfigurationServer; import com.cloud.storage.GuestOSVO; import com.cloud.storage.LaunchPermissionVO; import com.cloud.storage.Snapshot; @@ -253,6 +254,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, protected ResourceManager _resourceMgr; @Inject VolumeManager volumeMgr; @Inject VMTemplateHostDao templateHostDao; + @Inject + ConfigurationServer _configServer; int _primaryStorageDownloadWait; @@ -364,6 +367,13 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, String mode = cmd.getMode(); Long eventId = cmd.getStartEventId(); + VirtualMachineTemplate template = getTemplate(templateId); + if (template == null) { + throw new InvalidParameterValueException("unable to find template with id " + templateId); + } + TemplateAdapter adapter = getAdapter(template.getHypervisorType()); + TemplateProfile profile = adapter.prepareExtractTemplate(cmd); + // FIXME: async job needs fixing Long uploadId = extract(caller, templateId, url, zoneId, mode, eventId, false, null, _asyncMgr); if (uploadId != null){ @@ -569,7 +579,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, return errMsg; } - downloadTemplateFromSwiftToSecondaryStorageCommand cmd = new downloadTemplateFromSwiftToSecondaryStorageCommand(swift, secHost.getName(), dcId, template.getAccountId(), templateId, + DownloadTemplateFromSwiftToSecondaryStorageCommand cmd = new DownloadTemplateFromSwiftToSecondaryStorageCommand(swift, secHost.getName(), dcId, template.getAccountId(), templateId, tmpltSwift.getPath(), _primaryStorageDownloadWait); try { Answer answer = _agentMgr.sendToSSVM(dcId, cmd); @@ -618,7 +628,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, return errMsg; } - uploadTemplateToSwiftFromSecondaryStorageCommand cmd = new uploadTemplateToSwiftFromSecondaryStorageCommand(swift, secHost.getName(), secHost.getDataCenterId(), template.getAccountId(), + UploadTemplateToSwiftFromSecondaryStorageCommand cmd = new UploadTemplateToSwiftFromSecondaryStorageCommand(swift, secHost.getName(), secHost.getDataCenterId(), template.getAccountId(), templateId, _primaryStorageDownloadWait); Answer answer = null; try { @@ -1609,7 +1619,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } boolean isAdmin = _accountMgr.isAdmin(caller.getType()); - boolean allowPublicUserTemplates = Boolean.valueOf(_configDao.getValue("allow.public.user.templates")); + // check configuration parameter(allow.public.user.templates) value for the template owner + boolean allowPublicUserTemplates = Boolean.valueOf(_configServer.getConfigValue(Config.AllowPublicUserTemplates.key(), Config.ConfigurationParameterScope.account.toString(), template.getAccountId())); if (!isAdmin && !allowPublicUserTemplates && isPublic != null && isPublic) { throw new InvalidParameterValueException("Only private " + mediaType + "s can be created."); } @@ -1842,8 +1853,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if (isPublic == null) { isPublic = Boolean.FALSE; } - boolean allowPublicUserTemplates = Boolean.parseBoolean(_configDao - .getValue("allow.public.user.templates")); + // check whether template owner can create public templates + boolean allowPublicUserTemplates = Boolean.parseBoolean(_configServer.getConfigValue(Config.AllowPublicUserTemplates.key(), Config.ConfigurationParameterScope.account.toString(), templateOwner.getId())); if (!isAdmin && !allowPublicUserTemplates && isPublic) { throw new PermissionDeniedException("Failed to create template " + name + ", only private templates can be created."); diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index 8de73fbd582..4088f64f58b 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -59,6 +59,7 @@ import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.configuration.dao.ResourceCountDao; import com.cloud.dc.DataCenterVO; import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.DataCenterVnetDao; import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; @@ -76,6 +77,8 @@ import com.cloud.network.IpAddress; import com.cloud.network.NetworkManager; import com.cloud.network.VpnUserVO; import com.cloud.network.as.AutoScaleManager; +import com.cloud.network.dao.AccountGuestVlanMapDao; +import com.cloud.network.dao.AccountGuestVlanMapVO; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.NetworkDao; @@ -222,6 +225,10 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M @Inject VolumeManager volumeMgr; @Inject private AffinityGroupDao _affinityGroupDao; + @Inject + private AccountGuestVlanMapDao _accountGuestVlanMapDao; + @Inject + private DataCenterVnetDao _dataCenterVnetDao; private List _userAuthenticators; List _userPasswordEncoders; @@ -699,6 +706,14 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M } } + // release account specific guest vlans + List maps = _accountGuestVlanMapDao.listAccountGuestVlanMapsByAccount(accountId); + for (AccountGuestVlanMapVO map : maps) { + _dataCenterVnetDao.releaseDedicatedGuestVlans(map.getId()); + } + int vlansReleased = _accountGuestVlanMapDao.removeByAccountId(accountId); + s_logger.info("deleteAccount: Released " + vlansReleased + " dedicated guest vlan ranges from account " + accountId); + return true; } catch (Exception ex) { s_logger.warn("Failed to cleanup account " + account + " due to ", ex); diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 3e62282e9eb..e6cea77f712 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -485,7 +485,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use _accountMgr.checkAccess(caller, null, true, userVm); - boolean result = resetVMPasswordInternal(cmd, password); + boolean result = resetVMPasswordInternal(vmId, password); if (result) { userVm.setPassword(password); @@ -512,10 +512,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use return userVm; } - private boolean resetVMPasswordInternal(ResetVMPasswordCmd cmd, + private boolean resetVMPasswordInternal(Long vmId, String password) throws ResourceUnavailableException, InsufficientCapacityException { - Long vmId = cmd.getId(); Long userId = UserContext.current().getCallerUserId(); VMInstanceVO vmInstance = _vmDao.findById(vmId); @@ -838,6 +837,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use if(network == null) { throw new InvalidParameterValueException("unable to find a network with id " + networkId); } + List allNics = _nicDao.listByVmId(vmInstance.getId()); + for(NicVO nic : allNics){ + if(nic.getNetworkId() == network.getId()) + throw new CloudRuntimeException("A NIC already exists for VM:" + vmInstance.getInstanceName() + " in network: " + network.getUuid()); + } + NicProfile profile = new NicProfile(null, null); if(ipAddress != null) { profile = new NicProfile(ipAddress, null); @@ -1059,13 +1064,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use @ActionEvent(eventType = EventTypes.EVENT_VM_SCALE, eventDescription = "scaling Vm") public UserVm upgradeVirtualMachine(ScaleVMCmd cmd) throws InvalidParameterValueException, ResourceAllocationException { + Long vmId = cmd.getId(); Long newServiceOfferingId = cmd.getServiceOfferingId(); Account caller = UserContext.current().getCaller(); // Verify input parameters VMInstanceVO vmInstance = _vmInstanceDao.findById(vmId); - if(vmInstance.getHypervisorType() != HypervisorType.XenServer){ + if(vmInstance.getHypervisorType() != HypervisorType.XenServer && vmInstance.getHypervisorType() != HypervisorType.VMware){ throw new InvalidParameterValueException("This operation not permitted for this hypervisor of the vm"); } @@ -1087,8 +1093,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } // Dynamically upgrade the running vms + boolean success = false; if(vmInstance.getState().equals(State.Running)){ - boolean success = false; int retry = _scaleRetry; while (retry-- != 0) { // It's != so that it can match -1. try{ @@ -1106,7 +1112,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use vmInstance = _vmInstanceDao.findById(vmId); vmInstance = _itMgr.reConfigureVm(vmInstance, oldServiceOffering, existingHostHasCapacity); success = true; - return _vmDao.findById(vmInstance.getId()); + return success; }catch(InsufficientCapacityException e ){ s_logger.warn("Received exception while scaling ",e); } catch (ResourceUnavailableException e) { @@ -1123,11 +1129,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } } } - if (!success) - return null; } - return _vmDao.findById(vmInstance.getId()); + return success; } @@ -2933,10 +2937,15 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } UserVO user = _userDao.findById(userId); - + boolean status = false; try { VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid()); - vmEntity.stop(new Long(userId).toString()); + status = vmEntity.stop(new Long(userId).toString()); + if (status) { + return _vmDao.findById(vmId); + } else { + return null; + } } catch (ResourceUnavailableException e) { throw new CloudRuntimeException( "Unable to contact the agent to stop the virtual machine " @@ -2946,8 +2955,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use "Unable to contact the agent to stop the virtual machine " + vm, e); } - - return _vmDao.findById(vmId); } @Override @@ -3750,19 +3757,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use + cmd.getAccountName() + " is disabled."); } - // make sure the accounts are under same domain - if (oldAccount.getDomainId() != newAccount.getDomainId()) { - throw new InvalidParameterValueException( - "The account should be under same domain for moving VM between two accounts. Old owner domain =" - + oldAccount.getDomainId() - + " New owner domain=" - + newAccount.getDomainId()); - } + //check caller has access to both the old and new account + _accountMgr.checkAccess(caller, null, true, oldAccount); + _accountMgr.checkAccess(caller, null, true, newAccount); // make sure the accounts are not same if (oldAccount.getAccountId() == newAccount.getAccountId()) { throw new InvalidParameterValueException( - "The account should be same domain for moving VM between two accounts. Account id =" + "The new account is the same as the old account. Account id =" + oldAccount.getAccountId()); } @@ -3854,6 +3856,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use _resourceLimitMgr.decrementResourceCount(oldAccount.getAccountId(), ResourceType.primary_storage, new Long(volume.getSize())); volume.setAccountId(newAccount.getAccountId()); + volume.setDomainId(newAccount.getDomainId()); _volsDao.persist(volume); _resourceLimitMgr.incrementResourceCount(newAccount.getAccountId(), ResourceType.volume); _resourceLimitMgr.incrementResourceCount(newAccount.getAccountId(), ResourceType.primary_storage, @@ -4106,7 +4109,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } @Override - public UserVm restoreVM(RestoreVMCmd cmd) { + public UserVm restoreVM(RestoreVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException { // Input validation Account caller = UserContext.current().getCaller(); @@ -4124,7 +4127,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use return restoreVMInternal(caller, vm, newTemplateId); } - public UserVm restoreVMInternal(Account caller, UserVmVO vm, Long newTemplateId){ + public UserVm restoreVMInternal(Account caller, UserVmVO vm, Long newTemplateId) throws InsufficientCapacityException, ResourceUnavailableException { Long userId = caller.getId(); Account owner = _accountDao.findById(vm.getAccountId()); @@ -4218,6 +4221,29 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use _volsDao.detachVolume(root.getId()); this.volumeMgr.destroyVolume(root); + if (template.getEnablePassword()) { + String password = generateRandomPassword(); + boolean result = resetVMPasswordInternal(vmId, password); + if (result) { + vm.setPassword(password); + _vmDao.loadDetails(vm); + // update the password in vm_details table too + // Check if an SSH key pair was selected for the instance and if so + // use it to encrypt & save the vm password + String sshPublicKey = vm.getDetail("SSH.PublicKey"); + if (sshPublicKey != null && !sshPublicKey.equals("") && password != null && !password.equals("saved_password")) { + String encryptedPasswd = RSAHelper.encryptWithSSHPublicKey(sshPublicKey, password); + if (encryptedPasswd == null) { + throw new CloudRuntimeException("VM reset is completed but error occurred when encrypting newly created password"); + } + vm.setDetail("Encrypted.Password", encryptedPasswd); + _vmDao.saveDetails(vm); + } + } else { + throw new CloudRuntimeException("VM reset is completed but failed to reset password for the virtual machine "); + } + } + if (needRestart) { try { _itMgr.start(vm, null, user, caller); @@ -4250,7 +4276,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use _agentMgr.send(dest.getHost().getId(),cmds); PlugNicAnswer plugNicAnswer = cmds.getAnswer(PlugNicAnswer.class); if (!(plugNicAnswer != null && plugNicAnswer.getResult())) { - s_logger.warn("Unable to plug nic for " + vmVO); + s_logger.warn("Unable to plug nic for " + vmVO + " due to: " + " due to: " + plugNicAnswer.getDetails()); return false; } } catch (OperationTimedoutException e) { @@ -4278,7 +4304,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use _agentMgr.send(dest.getHost().getId(),cmds); UnPlugNicAnswer unplugNicAnswer = cmds.getAnswer(UnPlugNicAnswer.class); if (!(unplugNicAnswer != null && unplugNicAnswer.getResult())) { - s_logger.warn("Unable to unplug nic for " + vmVO); + s_logger.warn("Unable to unplug nic for " + vmVO + " due to: " + unplugNicAnswer.getDetails()); return false; } } catch (OperationTimedoutException e) { diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index 252fc99ca0d..521b5e0c582 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -24,7 +24,6 @@ import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -37,39 +36,56 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.capacity.CapacityManager; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; -import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; - -import com.cloud.dc.*; -import com.cloud.agent.api.*; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.AgentManager.OnError; import com.cloud.agent.Listener; +import com.cloud.agent.api.AgentControlAnswer; +import com.cloud.agent.api.AgentControlCommand; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.CheckVirtualMachineAnswer; +import com.cloud.agent.api.CheckVirtualMachineCommand; +import com.cloud.agent.api.ClusterSyncAnswer; +import com.cloud.agent.api.ClusterSyncCommand; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.MigrateAnswer; +import com.cloud.agent.api.MigrateCommand; +import com.cloud.agent.api.PingRoutingCommand; +import com.cloud.agent.api.PrepareForMigrationAnswer; +import com.cloud.agent.api.PrepareForMigrationCommand; +import com.cloud.agent.api.RebootAnswer; +import com.cloud.agent.api.RebootCommand; +import com.cloud.agent.api.ScaleVmCommand; +import com.cloud.agent.api.StartAnswer; +import com.cloud.agent.api.StartCommand; +import com.cloud.agent.api.StartupCommand; +import com.cloud.agent.api.StartupRoutingCommand; import com.cloud.agent.api.StartupRoutingCommand.VmState; +import com.cloud.agent.api.StopAnswer; +import com.cloud.agent.api.StopCommand; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; -import com.cloud.agent.api.to.StorageFilerTO; -import com.cloud.agent.api.to.VolumeTO; import com.cloud.agent.manager.Commands; import com.cloud.agent.manager.allocator.HostAllocator; import com.cloud.alert.AlertManager; +import com.cloud.capacity.CapacityManager; import com.cloud.cluster.ClusterManager; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; +import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.dc.dao.ClusterDao; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.ClusterDetailsVO; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; -import com.cloud.consoleproxy.ConsoleProxyManager; +import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; import com.cloud.deploy.DataCenterDeployment; @@ -108,6 +124,7 @@ import com.cloud.network.NetworkManager; import com.cloud.network.NetworkModel; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; +import com.cloud.network.rules.RulesManager; import com.cloud.offering.ServiceOffering; import com.cloud.org.Cluster; import com.cloud.resource.ResourceManager; @@ -125,12 +142,13 @@ import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.GuestOSCategoryDao; import com.cloud.storage.dao.GuestOSDao; +import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VolumeDao; -import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.storage.snapshot.SnapshotManager; import com.cloud.user.Account; import com.cloud.user.AccountManager; +import com.cloud.user.ResourceLimitService; import com.cloud.user.User; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; @@ -152,12 +170,12 @@ import com.cloud.vm.VirtualMachine.Event; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.VMInstanceDao; import com.cloud.vm.snapshot.VMSnapshot; import com.cloud.vm.snapshot.VMSnapshotManager; import com.cloud.vm.snapshot.VMSnapshotVO; import com.cloud.vm.snapshot.dao.VMSnapshotDao; -import com.cloud.vm.dao.UserVmDetailsDao; @Local(value = VirtualMachineManager.class) public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMachineManager, Listener { @@ -231,6 +249,10 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac protected VMSnapshotDao _vmSnapshotDao; @Inject protected VolumeDataFactory volFactory; + @Inject + protected ResourceLimitService _resourceLimitMgr; + @Inject + protected RulesManager rulesMgr; protected List _planners; public List getPlanners() { @@ -428,6 +450,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac s_logger.debug("Cleaning up NICS"); _networkMgr.cleanupNics(profile); // Clean up volumes based on the vm's instance id + List rootVol = _volsDao.findByInstanceAndType(vm.getId(), Volume.Type.ROOT); this.volumeMgr.cleanupVolumes(vm.getId()); VirtualMachineGuru guru = getVmGuru(vm); @@ -462,6 +485,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac s_logger.debug("Expunged " + vm); } + // Update Resource count + if (vm.getAccountId() != Account.ACCOUNT_ID_SYSTEM && !rootVol.isEmpty()) { + _resourceLimitMgr.decrementResourceCount(vm.getAccountId(), ResourceType.volume); + _resourceLimitMgr.decrementResourceCount(vm.getAccountId(), ResourceType.primary_storage, + new Long(rootVol.get(0).getSize())); + } return true; } @@ -1136,7 +1165,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac vmGuru.finalizeStop(profile, answer); } catch (AgentUnavailableException e) { + s_logger.warn("Unable to stop vm, agent unavailable: " + e.toString()); } catch (OperationTimedoutException e) { + s_logger.warn("Unable to stop vm, operation timed out: " + e.toString()); } finally { if (!stopped) { if (!forced) { @@ -2832,6 +2863,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac s_logger.warn("Failed to remove nic from " + vm + " in " + network + ", nic is default."); throw new CloudRuntimeException("Failed to remove nic from " + vm + " in " + network + ", nic is default."); } + + // if specified nic is associated with PF/LB/Static NAT + if(rulesMgr.listAssociatedRulesForGuestNic(nic).size() > 0){ + throw new CloudRuntimeException("Failed to remove nic from " + vm + " in " + network + + ", nic has associated Port forwarding or Load balancer or Static NAT rules."); + } NicProfile nicProfile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), _networkModel.getNetworkRate(network.getId(), vm.getId()), diff --git a/server/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerManagerImpl.java b/server/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerManagerImpl.java new file mode 100644 index 00000000000..ec0be8c9d96 --- /dev/null +++ b/server/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerManagerImpl.java @@ -0,0 +1,524 @@ +// 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. + +package org.apache.cloudstack.network.lb; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; +import javax.inject.Inject; + +import org.apache.cloudstack.acl.SecurityChecker.AccessType; +import org.apache.cloudstack.api.command.user.loadbalancer.ListApplicationLoadBalancersCmd; +import org.apache.cloudstack.lb.ApplicationLoadBalancerRuleVO; +import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.event.ActionEvent; +import com.cloud.event.EventTypes; +import com.cloud.event.UsageEventUtils; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapcityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.UnsupportedServiceException; +import com.cloud.network.Network; +import com.cloud.network.Network.Capability; +import com.cloud.network.Network.Service; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkModel; +import com.cloud.network.Networks.TrafficType; +import com.cloud.network.dao.FirewallRulesDao; +import com.cloud.network.lb.LoadBalancingRule; +import com.cloud.network.lb.LoadBalancingRule.LbDestination; +import com.cloud.network.lb.LoadBalancingRule.LbHealthCheckPolicy; +import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; +import com.cloud.network.lb.LoadBalancingRulesManager; +import com.cloud.network.rules.FirewallRule.State; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.projects.Project.ListProjectResourcesCriteria; +import com.cloud.server.ResourceTag.TaggedResourceType; +import com.cloud.tags.ResourceTagVO; +import com.cloud.tags.dao.ResourceTagDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.UserContext; +import com.cloud.utils.Pair; +import com.cloud.utils.Ternary; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.JoinBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; +import com.cloud.utils.net.NetUtils; + +@Component +@Local(value = { ApplicationLoadBalancerService.class }) +public class ApplicationLoadBalancerManagerImpl extends ManagerBase implements ApplicationLoadBalancerService { + private static final Logger s_logger = Logger.getLogger(ApplicationLoadBalancerManagerImpl.class); + + @Inject NetworkModel _networkModel; + @Inject ApplicationLoadBalancerRuleDao _lbDao; + @Inject AccountManager _accountMgr; + @Inject LoadBalancingRulesManager _lbMgr; + @Inject FirewallRulesDao _firewallDao; + @Inject ResourceTagDao _resourceTagDao; + @Inject NetworkManager _ntwkMgr; + + + @Override + @ActionEvent(eventType = EventTypes.EVENT_LOAD_BALANCER_CREATE, eventDescription = "creating load balancer") + public ApplicationLoadBalancerRule createApplicationLoadBalancer(String name, String description, Scheme scheme, long sourceIpNetworkId, String sourceIp, + int sourcePort, int instancePort, String algorithm, long networkId, long lbOwnerId) throws InsufficientAddressCapacityException, + NetworkRuleConflictException, InsufficientVirtualNetworkCapcityException { + + //Validate LB rule guest network + Network guestNtwk = _networkModel.getNetwork(networkId); + if (guestNtwk == null || guestNtwk.getTrafficType() != TrafficType.Guest) { + throw new InvalidParameterValueException("Can't find guest network by id"); + } + + Account caller = UserContext.current().getCaller(); + _accountMgr.checkAccess(caller, AccessType.UseNetwork, false, guestNtwk); + + Network sourceIpNtwk = _networkModel.getNetwork(sourceIpNetworkId); + if (sourceIpNtwk == null) { + throw new InvalidParameterValueException("Can't find source ip network by id"); + } + + Account lbOwner = _accountMgr.getAccount(lbOwnerId); + if (lbOwner == null) { + throw new InvalidParameterValueException("Can't find the lb owner account"); + } + + return createApplicationLoadBalancer(name, description, scheme, sourceIpNtwk, sourceIp, sourcePort, instancePort, algorithm, lbOwner, guestNtwk); + } + + + protected ApplicationLoadBalancerRule createApplicationLoadBalancer(String name, String description, Scheme scheme, Network sourceIpNtwk, String sourceIp, int sourcePort, int instancePort, String algorithm, + Account lbOwner, Network guestNtwk) throws NetworkRuleConflictException, InsufficientVirtualNetworkCapcityException { + + //Only Internal scheme is supported in this release + if (scheme != Scheme.Internal) { + throw new UnsupportedServiceException("Only scheme of type " + Scheme.Internal + " is supported"); + } + + //1) Validate LB rule's parameters + validateLbRule(sourcePort, instancePort, algorithm, guestNtwk, scheme); + + //2) Validate source network + validateSourceIpNtwkForLbRule(sourceIpNtwk, scheme); + + //3) Get source ip address + Ip sourceIpAddr = getSourceIp(scheme, sourceIpNtwk, sourceIp); + + ApplicationLoadBalancerRuleVO newRule = new ApplicationLoadBalancerRuleVO(name, description, sourcePort, instancePort, algorithm, guestNtwk.getId(), + lbOwner.getId(), lbOwner.getDomainId(), sourceIpAddr, sourceIpNtwk.getId(), scheme); + + //4) Validate Load Balancing rule on the providers + LoadBalancingRule loadBalancing = new LoadBalancingRule(newRule, new ArrayList(), + new ArrayList(), new ArrayList(), sourceIpAddr); + if (!_lbMgr.validateLbRule(loadBalancing)) { + throw new InvalidParameterValueException("LB service provider cannot support this rule"); + } + + //5) Persist Load Balancer rule + return persistLbRule(newRule); + } + + + @DB + protected ApplicationLoadBalancerRule persistLbRule(ApplicationLoadBalancerRuleVO newRule) throws NetworkRuleConflictException { + + Transaction txn = Transaction.currentTxn(); + txn.start(); + + //1) Persist the rule + newRule = _lbDao.persist(newRule); + boolean success = true; + + try { + //2) Detect conflicts + detectLbRulesConflicts(newRule); + if (!_firewallDao.setStateToAdd(newRule)) { + throw new CloudRuntimeException("Unable to update the state to add for " + newRule); + } + s_logger.debug("Load balancer " + newRule.getId() + " for Ip address " + newRule.getSourceIp().addr() + ", source port " + + newRule.getSourcePortStart() + ", instance port " + newRule.getDefaultPortStart() + " is added successfully."); + UserContext.current().setEventDetails("Load balancer Id: " + newRule.getId()); + Network ntwk = _networkModel.getNetwork(newRule.getNetworkId()); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_LOAD_BALANCER_CREATE, newRule.getAccountId(), + ntwk.getDataCenterId(), newRule.getId(), null, LoadBalancingRule.class.getName(), + newRule.getUuid()); + txn.commit(); + + return newRule; + } catch (Exception e) { + success = false; + if (e instanceof NetworkRuleConflictException) { + throw (NetworkRuleConflictException) e; + } + throw new CloudRuntimeException("Unable to add lb rule for ip address " + newRule.getSourceIpAddressId(), e); + } finally { + if (!success && newRule != null) { + _lbMgr.removeLBRule(newRule); + } + } + } + + /** + * Validates Lb rule parameters + * @param sourcePort + * @param instancePort + * @param algorithm + * @param network + * @param scheme TODO + * @param networkId + */ + protected void validateLbRule(int sourcePort, int instancePort, String algorithm, Network network, Scheme scheme) { + //1) verify that lb service is supported by the network + if (!_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Lb)) { + InvalidParameterValueException ex = new InvalidParameterValueException( + "LB service is not supported in specified network id"); + ex.addProxyObject(network, network.getId(), "networkId"); + throw ex; + } + + //2) verify that lb service is supported by the network + _lbMgr.isLbServiceSupportedInNetwork(network.getId(), scheme); + + Map caps = _networkModel.getNetworkServiceCapabilities(network.getId(), Service.Lb); + String supportedProtocols = caps.get(Capability.SupportedProtocols).toLowerCase(); + if (!supportedProtocols.contains(NetUtils.TCP_PROTO.toLowerCase())) { + throw new InvalidParameterValueException("Protocol " + NetUtils.TCP_PROTO.toLowerCase() + " is not supported in zone " + network.getDataCenterId()); + } + + //3) Validate rule parameters + if (!NetUtils.isValidPort(instancePort)) { + throw new InvalidParameterValueException("Invalid value for instance port: " + instancePort); + } + + if (!NetUtils.isValidPort(sourcePort)) { + throw new InvalidParameterValueException("Invalid value for source port: " + sourcePort); + } + + if ((algorithm == null) || !NetUtils.isValidAlgorithm(algorithm)) { + throw new InvalidParameterValueException("Invalid algorithm: " + algorithm); + } + } + + + /** + * Gets source ip address based on the LB rule scheme/source IP network/requested IP address + * @param scheme + * @param sourceIpNtwk + * @param requestedIp + * @return + * @throws InsufficientVirtualNetworkCapcityException + */ + protected Ip getSourceIp(Scheme scheme, Network sourceIpNtwk, String requestedIp) throws InsufficientVirtualNetworkCapcityException { + + if (requestedIp != null) { + if (_lbDao.countBySourceIp(new Ip(requestedIp), sourceIpNtwk.getId()) > 0) { + s_logger.debug("IP address " + requestedIp + " is already used by existing LB rule, returning it"); + return new Ip(requestedIp); + } + + validateRequestedSourceIpForLbRule(sourceIpNtwk, new Ip(requestedIp), scheme); + } + + requestedIp = allocateSourceIpForLbRule(scheme, sourceIpNtwk, requestedIp); + + if (requestedIp == null) { + throw new InsufficientVirtualNetworkCapcityException("Unable to acquire IP address for network " + sourceIpNtwk, Network.class, sourceIpNtwk.getId()); + } + return new Ip(requestedIp); + } + + + /** + * Allocates new Source IP address for the Load Balancer rule based on LB rule scheme/sourceNetwork + * @param scheme + * @param sourceIpNtwk + * @param requestedIp TODO + * @param sourceIp + * @return + */ + protected String allocateSourceIpForLbRule(Scheme scheme, Network sourceIpNtwk, String requestedIp) { + String sourceIp = null; + if (scheme != Scheme.Internal) { + throw new InvalidParameterValueException("Only scheme " + Scheme.Internal + " is supported"); + } else { + sourceIp = allocateSourceIpForInternalLbRule(sourceIpNtwk, requestedIp); + } + return sourceIp; + } + + + /** + * Allocates sourceIp for the Internal LB rule + * @param sourceIpNtwk + * @param requestedIp TODO + * @return + */ + protected String allocateSourceIpForInternalLbRule(Network sourceIpNtwk, String requestedIp) { + return _ntwkMgr.acquireGuestIpAddress(sourceIpNtwk, requestedIp); + } + + + /** + * Validates requested source ip address of the LB rule based on Lb rule scheme/sourceNetwork + * @param sourceIpNtwk + * @param requestedSourceIp + * @param scheme + */ + void validateRequestedSourceIpForLbRule(Network sourceIpNtwk, Ip requestedSourceIp, Scheme scheme) { + //only Internal scheme is supported in this release + if (scheme != Scheme.Internal) { + throw new UnsupportedServiceException("Only scheme of type " + Scheme.Internal + " is supported"); + } else { + //validate guest source ip + validateRequestedSourceIpForInternalLbRule(sourceIpNtwk, requestedSourceIp); + } + } + + + /** + * Validates requested source IP address of Internal Lb rule against sourceNetworkId + * @param sourceIpNtwk + * @param requestedSourceIp + */ + protected void validateRequestedSourceIpForInternalLbRule(Network sourceIpNtwk, Ip requestedSourceIp) { + //Check if the IP is within the network cidr + Pair cidr = NetUtils.getCidr(sourceIpNtwk.getCidr()); + if (!NetUtils.getCidrSubNet(requestedSourceIp.addr(), cidr.second()).equalsIgnoreCase(NetUtils.getCidrSubNet(cidr.first(), cidr.second()))) { + throw new InvalidParameterValueException("The requested IP is not in the network's CIDR subnet."); + } + } + + + /** + * Validates source IP network for the LB rule + * @param sourceNtwk + * @param scheme + * @return + */ + protected Network validateSourceIpNtwkForLbRule(Network sourceNtwk, Scheme scheme) { + //only Internal scheme is supported in this release + if (scheme != Scheme.Internal) { + throw new UnsupportedServiceException("Only scheme of type " + Scheme.Internal + " is supported"); + } else { + //validate source ip network + return validateSourceIpNtwkForInternalLbRule(sourceNtwk); + } + + } + + /** + * Validates source IP network for the Internal LB rule + * @param sourceIpNtwk + * @return + */ + protected Network validateSourceIpNtwkForInternalLbRule(Network sourceIpNtwk) { + if (sourceIpNtwk.getTrafficType() != TrafficType.Guest) { + throw new InvalidParameterValueException("Only traffic type " + TrafficType.Guest + " is supported"); + } + + //Can't create the LB rule if the network's cidr is NULL + String ntwkCidr = sourceIpNtwk.getCidr(); + if (ntwkCidr == null) { + throw new InvalidParameterValueException("Can't create the application load balancer rule for the network having NULL cidr"); + } + + //check if the requested ip address is within the cidr + return sourceIpNtwk; + } + + + @Override + public boolean deleteApplicationLoadBalancer(long id) { + return _lbMgr.deleteLoadBalancerRule(id, true); + } + + @Override + public Pair, Integer> listApplicationLoadBalancers(ListApplicationLoadBalancersCmd cmd) { + Long id = cmd.getId(); + String name = cmd.getLoadBalancerRuleName(); + String ip = cmd.getSourceIp(); + Long ipNtwkId = cmd.getSourceIpNetworkId(); + String keyword = cmd.getKeyword(); + Scheme scheme = cmd.getScheme(); + Long networkId = cmd.getNetworkId(); + + Map tags = cmd.getTags(); + + Account caller = UserContext.current().getCaller(); + List permittedAccounts = new ArrayList(); + + Ternary domainIdRecursiveListProject = new Ternary( + cmd.getDomainId(), cmd.isRecursive(), null); + _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, + domainIdRecursiveListProject, cmd.listAll(), false); + Long domainId = domainIdRecursiveListProject.first(); + Boolean isRecursive = domainIdRecursiveListProject.second(); + ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); + + Filter searchFilter = new Filter(ApplicationLoadBalancerRuleVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal()); + SearchBuilder sb = _lbDao.createSearchBuilder(); + _accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); + + sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); + sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ); + sb.and("sourceIpAddress", sb.entity().getSourceIp(), SearchCriteria.Op.EQ); + sb.and("sourceIpAddressNetworkId", sb.entity().getSourceIpNetworkId(), SearchCriteria.Op.EQ); + sb.and("scheme", sb.entity().getScheme(), SearchCriteria.Op.EQ); + sb.and("networkId", sb.entity().getNetworkId(), SearchCriteria.Op.EQ); + + //list only load balancers having not null sourceIp/sourceIpNtwkId + sb.and("sourceIpAddress", sb.entity().getSourceIp(), SearchCriteria.Op.NNULL); + sb.and("sourceIpAddressNetworkId", sb.entity().getSourceIpNetworkId(), SearchCriteria.Op.NNULL); + + if (tags != null && !tags.isEmpty()) { + SearchBuilder tagSearch = _resourceTagDao.createSearchBuilder(); + for (int count = 0; count < tags.size(); count++) { + tagSearch.or().op("key" + String.valueOf(count), tagSearch.entity().getKey(), SearchCriteria.Op.EQ); + tagSearch.and("value" + String.valueOf(count), tagSearch.entity().getValue(), SearchCriteria.Op.EQ); + tagSearch.cp(); + } + tagSearch.and("resourceType", tagSearch.entity().getResourceType(), SearchCriteria.Op.EQ); + sb.groupBy(sb.entity().getId()); + sb.join("tagSearch", tagSearch, sb.entity().getId(), tagSearch.entity().getResourceId(), + JoinBuilder.JoinType.INNER); + } + + SearchCriteria sc = sb.create(); + _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); + + if (keyword != null) { + SearchCriteria ssc = _lbDao.createSearchCriteria(); + ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%"); + ssc.addOr("description", SearchCriteria.Op.LIKE, "%" + keyword + "%"); + sc.addAnd("name", SearchCriteria.Op.SC, ssc); + } + + if (name != null) { + sc.setParameters("name", name); + } + + if (id != null) { + sc.setParameters("id", id); + } + + if (ip != null) { + sc.setParameters("sourceIpAddress", ip); + } + + if (ipNtwkId != null) { + sc.setParameters("sourceIpAddressNetworkId", ipNtwkId); + } + + if (scheme != null) { + sc.setParameters("scheme", scheme); + } + + if (networkId != null) { + sc.setParameters("networkId", networkId); + } + + if (tags != null && !tags.isEmpty()) { + int count = 0; + sc.setJoinParameters("tagSearch", "resourceType", TaggedResourceType.LoadBalancer.toString()); + for (String key : tags.keySet()) { + sc.setJoinParameters("tagSearch", "key" + String.valueOf(count), key); + sc.setJoinParameters("tagSearch", "value" + String.valueOf(count), tags.get(key)); + count++; + } + } + + Pair, Integer> result = _lbDao.searchAndCount(sc, searchFilter); + return new Pair, Integer>(result.first(), result.second()); + } + + @Override + public ApplicationLoadBalancerRule getApplicationLoadBalancer(long ruleId) { + ApplicationLoadBalancerRule lbRule = _lbDao.findById(ruleId); + if (lbRule == null) { + throw new InvalidParameterValueException("Can't find the load balancer by id"); + } + return lbRule; + } + + + /** + * Detects lb rule conflicts against other rules + * @param newLbRule + * @throws NetworkRuleConflictException + */ + protected void detectLbRulesConflicts(ApplicationLoadBalancerRule newLbRule) throws NetworkRuleConflictException { + if (newLbRule.getScheme() != Scheme.Internal) { + throw new UnsupportedServiceException("Only scheme of type " + Scheme.Internal + " is supported"); + } else { + detectInternalLbRulesConflict(newLbRule); + } + } + + + /** + * Detects Internal Lb Rules conflicts + * @param newLbRule + * @throws NetworkRuleConflictException + */ + protected void detectInternalLbRulesConflict(ApplicationLoadBalancerRule newLbRule) throws NetworkRuleConflictException { + List lbRules = _lbDao.listBySourceIpAndNotRevoked(newLbRule.getSourceIp(), newLbRule.getSourceIpNetworkId()); + + for (ApplicationLoadBalancerRuleVO lbRule : lbRules) { + if (lbRule.getId() == newLbRule.getId()) { + continue; // Skips my own rule. + } + + if (lbRule.getNetworkId() != newLbRule.getNetworkId() && lbRule.getState() != State.Revoke) { + throw new NetworkRuleConflictException("New rule is for a different network than what's specified in rule " + + lbRule.getXid()); + } + + if ((lbRule.getSourcePortStart().intValue() <= newLbRule.getSourcePortStart().intValue() + && lbRule.getSourcePortEnd().intValue() >= newLbRule.getSourcePortStart().intValue()) + || (lbRule.getSourcePortStart().intValue() <= newLbRule.getSourcePortEnd().intValue() + && lbRule.getSourcePortEnd().intValue() >= newLbRule.getSourcePortEnd().intValue()) + || (newLbRule.getSourcePortStart().intValue() <= lbRule.getSourcePortStart().intValue() + && newLbRule.getSourcePortEnd().intValue() >= lbRule.getSourcePortStart().intValue()) + || (newLbRule.getSourcePortStart().intValue() <= lbRule.getSourcePortEnd().intValue() + && newLbRule.getSourcePortEnd().intValue() >= lbRule.getSourcePortEnd().intValue())) { + + + throw new NetworkRuleConflictException("The range specified, " + newLbRule.getSourcePortStart() + "-" + newLbRule.getSourcePortEnd() + ", conflicts with rule " + lbRule.getId() + + " which has " + lbRule.getSourcePortStart() + "-" + lbRule.getSourcePortEnd()); + } + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("No network rule conflicts detected for " + newLbRule + " against " + (lbRules.size() - 1) + " existing rules"); + } + } +} diff --git a/server/test/com/cloud/network/DedicateGuestVlanRangesTest.java b/server/test/com/cloud/network/DedicateGuestVlanRangesTest.java new file mode 100644 index 00000000000..e81d7222a60 --- /dev/null +++ b/server/test/com/cloud/network/DedicateGuestVlanRangesTest.java @@ -0,0 +1,378 @@ +// 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. + +package com.cloud.network; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.lang.reflect.Field; + +import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd; +import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd; +import org.apache.cloudstack.api.command.admin.network.ReleaseDedicatedGuestVlanRangeCmd; + +import org.apache.log4j.Logger; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import com.cloud.dc.DataCenterVnetVO; +import com.cloud.dc.dao.DataCenterVnetDao; +import com.cloud.network.dao.AccountGuestVlanMapDao; +import com.cloud.network.dao.AccountGuestVlanMapVO; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.projects.ProjectManager; +import com.cloud.user.Account; +import com.cloud.user.dao.AccountDao; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.UserContext; +import com.cloud.utils.db.Transaction; + +import junit.framework.Assert; + +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.doNothing; + +public class DedicateGuestVlanRangesTest { + + private static final Logger s_logger = Logger.getLogger(DedicateGuestVlanRangesTest.class); + + NetworkServiceImpl networkService = new NetworkServiceImpl(); + + DedicateGuestVlanRangeCmd dedicateGuestVlanRangesCmd = new DedicateGuestVlanRangeCmdExtn(); + Class _dedicateGuestVlanRangeClass = dedicateGuestVlanRangesCmd.getClass().getSuperclass(); + + ReleaseDedicatedGuestVlanRangeCmd releaseDedicatedGuestVlanRangesCmd = new ReleaseDedicatedGuestVlanRangeCmdExtn(); + Class _releaseGuestVlanRangeClass = releaseDedicatedGuestVlanRangesCmd.getClass().getSuperclass(); + + ListDedicatedGuestVlanRangesCmd listDedicatedGuestVlanRangesCmd = new ListDedicatedGuestVlanRangesCmdExtn(); + Class _listDedicatedGuestVlanRangeClass = listDedicatedGuestVlanRangesCmd.getClass().getSuperclass(); + + + @Mock AccountManager _accountMgr; + @Mock AccountDao _accountDao; + @Mock ProjectManager _projectMgr; + @Mock PhysicalNetworkDao _physicalNetworkDao; + @Mock DataCenterVnetDao _dataCenterVnetDao; + @Mock AccountGuestVlanMapDao _accountGuestVlanMapDao; + + @Before + public void setup() throws Exception { + MockitoAnnotations.initMocks(this); + + networkService._accountMgr = _accountMgr; + networkService._accountDao = _accountDao; + networkService._projectMgr = _projectMgr; + networkService._physicalNetworkDao = _physicalNetworkDao; + networkService._datacneter_vnet = _dataCenterVnetDao; + networkService._accountGuestVlanMapDao = _accountGuestVlanMapDao; + + Account account = (Account) new AccountVO("testaccount", 1, "networkdomain", (short) 0, UUID.randomUUID().toString()); + when(networkService._accountMgr.getAccount(anyLong())).thenReturn(account); + when(networkService._accountDao.findActiveAccount(anyString(), anyLong())).thenReturn(account); + + UserContext.registerContext(1, account, null, true); + + Field accountNameField = _dedicateGuestVlanRangeClass.getDeclaredField("accountName"); + accountNameField.setAccessible(true); + accountNameField.set(dedicateGuestVlanRangesCmd, "accountname"); + + Field projectIdField = _dedicateGuestVlanRangeClass.getDeclaredField("projectId"); + projectIdField.setAccessible(true); + projectIdField.set(dedicateGuestVlanRangesCmd, null); + + Field domainIdField = _dedicateGuestVlanRangeClass.getDeclaredField("domainId"); + domainIdField.setAccessible(true); + domainIdField.set(dedicateGuestVlanRangesCmd, 1L); + + Field physicalNetworkIdField = _dedicateGuestVlanRangeClass.getDeclaredField("physicalNetworkId"); + physicalNetworkIdField.setAccessible(true); + physicalNetworkIdField.set(dedicateGuestVlanRangesCmd, 1L); + + Field releaseIdField = _releaseGuestVlanRangeClass.getDeclaredField("id"); + releaseIdField.setAccessible(true); + releaseIdField.set(releaseDedicatedGuestVlanRangesCmd, 1L); + } + + @Test + public void testDedicateGuestVlanRange() throws Exception { + s_logger.info("Running tests for DedicateGuestVlanRange API"); + + /* + * TEST 1: given valid parameters DedicateGuestVlanRange should succeed + */ + runDedicateGuestVlanRangePostiveTest(); + + /* + * TEST 2: given invalid format for vlan range DedicateGuestVlanRange should fail + */ + runDedicateGuestVlanRangeInvalidFormat(); + + /* + * TEST 3: given vlan range that doesn't exist in the system request should fail + */ + runDedicateGuestVlanRangeInvalidRangeValue(); + + /* + * TEST 4: given vlan range has vlans that are allocated to a different account request should fail + */ + runDedicateGuestVlanRangeAllocatedVlans(); + + /* + * TEST 5: given vlan range is already dedicated to another account request should fail + */ + runDedicateGuestVlanRangeDedicatedRange(); + + /* + * TEST 6: given vlan range is partially dedicated to a different account request should fail + */ + runDedicateGuestVlanRangePartiallyDedicated(); + } + + @Test + public void testReleaseDedicatedGuestVlanRange() throws Exception { + + s_logger.info("Running tests for ReleaseDedicatedGuestVlanRange API"); + + /* + * TEST 1: given valid parameters ReleaseDedicatedGuestVlanRange should succeed + */ + runReleaseDedicatedGuestVlanRangePostiveTest(); + + /* + * TEST 2: given range doesn't exist request should fail + */ + runReleaseDedicatedGuestVlanRangeInvalidRange(); + } + + void runDedicateGuestVlanRangePostiveTest() throws Exception { + Transaction txn = Transaction.open("runDedicateGuestVlanRangePostiveTest"); + + Field dedicateVlanField = _dedicateGuestVlanRangeClass.getDeclaredField("vlan"); + dedicateVlanField.setAccessible(true); + dedicateVlanField.set(dedicateGuestVlanRangesCmd, "2-5"); + + PhysicalNetworkVO physicalNetwork = new PhysicalNetworkVO(1L, 1L, "2-5", "200", 1L, null, "testphysicalnetwork"); + physicalNetwork.addIsolationMethod("VLAN"); + AccountGuestVlanMapVO accountGuestVlanMapVO = new AccountGuestVlanMapVO(1L,1L); + + when(networkService._physicalNetworkDao.findById(anyLong())).thenReturn(physicalNetwork); + + when(networkService._datacneter_vnet.listAllocatedVnetsInRange(anyLong(), anyLong(), anyInt(), anyInt())).thenReturn(null); + + when(networkService._accountGuestVlanMapDao.listAccountGuestVlanMapsByPhysicalNetwork(anyLong())).thenReturn(null); + + when(networkService._accountGuestVlanMapDao.persist(any(AccountGuestVlanMapVO.class))).thenReturn(accountGuestVlanMapVO); + + when(networkService._datacneter_vnet.update(anyLong(), any(DataCenterVnetVO.class))).thenReturn(true); + + List dataCenterVnetList = new ArrayList(); + DataCenterVnetVO dataCenterVnetVO = new DataCenterVnetVO("2-5", 1L, 1L); + dataCenterVnetList.add(dataCenterVnetVO); + when(networkService._datacneter_vnet.findVnet(anyLong(), anyString())).thenReturn(dataCenterVnetList); + + try { + GuestVlan result = networkService.dedicateGuestVlanRange(dedicateGuestVlanRangesCmd); + Assert.assertNotNull(result); + } catch (Exception e) { + s_logger.info("exception in testing runDedicateGuestVlanRangePostiveTest message: " + e.toString()); + } finally { + txn.close("runDedicateGuestRangePostiveTest"); + } + } + + void runDedicateGuestVlanRangeInvalidFormat() throws Exception { + Transaction txn = Transaction.open("runDedicateGuestVlanRangeInvalidFormat"); + + Field dedicateVlanField = _dedicateGuestVlanRangeClass.getDeclaredField("vlan"); + dedicateVlanField.setAccessible(true); + dedicateVlanField.set(dedicateGuestVlanRangesCmd, "2"); + + PhysicalNetworkVO physicalNetwork = new PhysicalNetworkVO(1L, 1L, "2-5", "200", 1L, null, "testphysicalnetwork"); + physicalNetwork.addIsolationMethod("VLAN"); + + when(networkService._physicalNetworkDao.findById(anyLong())).thenReturn(physicalNetwork); + + try { + networkService.dedicateGuestVlanRange(dedicateGuestVlanRangesCmd); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("Invalid format for parameter value vlan")); + } finally { + txn.close("runDedicateGuestVlanRangeInvalidFormat"); + } + } + + void runDedicateGuestVlanRangeInvalidRangeValue() throws Exception { + Transaction txn = Transaction.open("runDedicateGuestVlanRangeInvalidRangeValue"); + + Field dedicateVlanField = _dedicateGuestVlanRangeClass.getDeclaredField("vlan"); + dedicateVlanField.setAccessible(true); + dedicateVlanField.set(dedicateGuestVlanRangesCmd, "2-5"); + + PhysicalNetworkVO physicalNetwork = new PhysicalNetworkVO(1L, 1L, "6-10", "200", 1L, null, "testphysicalnetwork"); + physicalNetwork.addIsolationMethod("VLAN"); + + when(networkService._physicalNetworkDao.findById(anyLong())).thenReturn(physicalNetwork); + + try { + networkService.dedicateGuestVlanRange(dedicateGuestVlanRangesCmd); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("Unable to find guest vlan by range")); + } finally { + txn.close("runDedicateGuestVlanRangeInvalidRangeValue"); + } + } + + void runDedicateGuestVlanRangeAllocatedVlans() throws Exception { + Transaction txn = Transaction.open("runDedicateGuestVlanRangeAllocatedVlans"); + + Field dedicateVlanField = _dedicateGuestVlanRangeClass.getDeclaredField("vlan"); + dedicateVlanField.setAccessible(true); + dedicateVlanField.set(dedicateGuestVlanRangesCmd, "2-5"); + + PhysicalNetworkVO physicalNetwork = new PhysicalNetworkVO(1L, 1L, "2-5", "200", 1L, null, "testphysicalnetwork"); + physicalNetwork.addIsolationMethod("VLAN"); + when(networkService._physicalNetworkDao.findById(anyLong())).thenReturn(physicalNetwork); + + List dataCenterList = new ArrayList(); + DataCenterVnetVO dataCenter = new DataCenterVnetVO("2-5", 1L, 1L); + dataCenter.setAccountId(1L); + dataCenterList.add(dataCenter); + when(networkService._datacneter_vnet.listAllocatedVnetsInRange(anyLong(), anyLong(), anyInt(), anyInt())).thenReturn(dataCenterList); + + try { + networkService.dedicateGuestVlanRange(dedicateGuestVlanRangesCmd); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("is allocated to a different account")); + } finally { + txn.close("runDedicateGuestVlanRangeAllocatedVlans"); + } + } + + void runDedicateGuestVlanRangeDedicatedRange() throws Exception { + Transaction txn = Transaction.open("runDedicateGuestVlanRangeDedicatedRange"); + + Field dedicateVlanField = _dedicateGuestVlanRangeClass.getDeclaredField("vlan"); + dedicateVlanField.setAccessible(true); + dedicateVlanField.set(dedicateGuestVlanRangesCmd, "2-5"); + + PhysicalNetworkVO physicalNetwork = new PhysicalNetworkVO(1L, 1L, "2-5", "200", 1L, null, "testphysicalnetwork"); + physicalNetwork.addIsolationMethod("VLAN"); + + when(networkService._physicalNetworkDao.findById(anyLong())).thenReturn(physicalNetwork); + + when(networkService._datacneter_vnet.listAllocatedVnetsInRange(anyLong(), anyLong(), anyInt(), anyInt())).thenReturn(null); + + List guestVlanMaps = new ArrayList(); + AccountGuestVlanMapVO accountGuestVlanMap = new AccountGuestVlanMapVO(1L, 1L); + accountGuestVlanMap.setGuestVlanRange("2-5"); + guestVlanMaps.add(accountGuestVlanMap); + when(networkService._accountGuestVlanMapDao.listAccountGuestVlanMapsByPhysicalNetwork(anyLong())).thenReturn(guestVlanMaps); + + try { + networkService.dedicateGuestVlanRange(dedicateGuestVlanRangesCmd); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("Vlan range is already dedicated to another account")); + } finally { + txn.close("runDedicateGuestVlanRangeDedicatedRange"); + } + } + + void runDedicateGuestVlanRangePartiallyDedicated() throws Exception { + Transaction txn = Transaction.open("runDedicateGuestVlanRangePartiallyDedicated"); + + Field dedicateVlanField = _dedicateGuestVlanRangeClass.getDeclaredField("vlan"); + dedicateVlanField.setAccessible(true); + dedicateVlanField.set(dedicateGuestVlanRangesCmd, "2-5"); + + PhysicalNetworkVO physicalNetwork = new PhysicalNetworkVO(1L, 1L, "2-5", "200", 1L, null, "testphysicalnetwork"); + physicalNetwork.addIsolationMethod("VLAN"); + + when(networkService._physicalNetworkDao.findById(anyLong())).thenReturn(physicalNetwork); + + when(networkService._datacneter_vnet.listAllocatedVnetsInRange(anyLong(), anyLong(), anyInt(), anyInt())).thenReturn(null); + + List guestVlanMaps = new ArrayList(); + AccountGuestVlanMapVO accountGuestVlanMap = new AccountGuestVlanMapVO(2L, 1L); + accountGuestVlanMap.setGuestVlanRange("4-8"); + guestVlanMaps.add(accountGuestVlanMap); + when(networkService._accountGuestVlanMapDao.listAccountGuestVlanMapsByPhysicalNetwork(anyLong())).thenReturn(guestVlanMaps); + + try { + networkService.dedicateGuestVlanRange(dedicateGuestVlanRangesCmd); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("Vlan range is partially dedicated to another account")); + } finally { + txn.close("runDedicateGuestVlanRangePartiallyDedicated"); + } + } + + void runReleaseDedicatedGuestVlanRangePostiveTest() throws Exception { + Transaction txn = Transaction.open("runReleaseDedicatedGuestVlanRangePostiveTest"); + + AccountGuestVlanMapVO accountGuestVlanMap = new AccountGuestVlanMapVO(1L, 1L); + when(networkService._accountGuestVlanMapDao.findById(anyLong())).thenReturn(accountGuestVlanMap); + doNothing().when(networkService._datacneter_vnet).releaseDedicatedGuestVlans(anyLong()); + when(networkService._accountGuestVlanMapDao.remove(anyLong())).thenReturn(true); + + try { + Boolean result = networkService.releaseDedicatedGuestVlanRange(releaseDedicatedGuestVlanRangesCmd.getId()); + Assert.assertTrue(result); + } catch (Exception e) { + s_logger.info("exception in testing runReleaseGuestVlanRangePostiveTest1 message: " + e.toString()); + } finally { + txn.close("runReleaseDedicatedGuestVlanRangePostiveTest"); + } + } + + void runReleaseDedicatedGuestVlanRangeInvalidRange() throws Exception { + Transaction txn = Transaction.open("runReleaseDedicatedGuestVlanRangeInvalidRange"); + + when(networkService._accountGuestVlanMapDao.findById(anyLong())).thenReturn(null); + + try { + networkService.releaseDedicatedGuestVlanRange(releaseDedicatedGuestVlanRangesCmd.getId()); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("Dedicated guest vlan with specified id doesn't exist in the system")); + } finally { + txn.close("runReleaseDedicatedGuestVlanRangeInvalidRange"); + } + } + + public class DedicateGuestVlanRangeCmdExtn extends DedicateGuestVlanRangeCmd { + public long getEntityOwnerId() { + return 1; + } + } + + public class ReleaseDedicatedGuestVlanRangeCmdExtn extends ReleaseDedicatedGuestVlanRangeCmd { + public long getEntityOwnerId() { + return 1; + } + } + + public class ListDedicatedGuestVlanRangesCmdExtn extends ListDedicatedGuestVlanRangesCmd { + public long getEntityOwnerId() { + return 1; + } + } +} diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index 3dd060bf018..698c5530472 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -16,19 +16,40 @@ // under the License. package com.cloud.network; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; +import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; +import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; +import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; +import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; +import org.springframework.stereotype.Component; + import com.cloud.dc.DataCenter; import com.cloud.dc.Pod; import com.cloud.dc.Vlan.VlanType; import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; -import com.cloud.exception.*; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapcityException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.Networks.TrafficType; import com.cloud.network.addr.PublicIp; import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.NetworkVO; +import com.cloud.network.GuestVlan; import com.cloud.network.element.LoadBalancingServiceProvider; import com.cloud.network.element.StaticNatServiceProvider; import com.cloud.network.element.UserDataServiceProvider; @@ -36,6 +57,7 @@ import com.cloud.network.guru.NetworkGuru; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRule.State; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.rules.StaticNat; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.NetworkOfferingVO; @@ -49,9 +71,12 @@ import com.cloud.vm.NicVO; import com.cloud.vm.ReservationContext; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; +import com.cloud.vm.*; import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.VirtualMachineProfile; import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd; +import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd; import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; import org.apache.cloudstack.api.command.user.network.*; import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; @@ -63,6 +88,7 @@ import java.util.List; import java.util.Map; import java.util.Set; + @Component @Local(value = { NetworkManager.class, NetworkService.class }) public class MockNetworkManagerImpl extends ManagerBase implements NetworkManager, NetworkService { @@ -330,6 +356,24 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage } @Override + public GuestVlan dedicateGuestVlanRange(DedicateGuestVlanRangeCmd cmd) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Pair, Integer> listDedicatedGuestVlanRanges(ListDedicatedGuestVlanRangesCmd cmd) { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean releaseDedicatedGuestVlanRange(Long dedicatedGuestVlanRangeId) { + // TODO Auto-generated method stub + return true; + } + + @Override public List listNetworkServices(String providerName) { // TODO Auto-generated method stub return null; @@ -595,15 +639,9 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage return null; } - /* (non-Javadoc) - * @see com.cloud.network.NetworkService#createPrivateNetwork(java.lang.String, java.lang.String, long, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, long, java.lang.Long) - */ @Override - public Network createPrivateNetwork(String networkName, String displayText, long physicalNetworkId, String vlan, - String startIp, String endIP, String gateway, String netmask, long networkOwnerId, Long vpcId) - throws ResourceAllocationException, ConcurrentOperationException, InsufficientCapacityException { - // TODO Auto-generated method stub - return null; + public Network createPrivateNetwork(String s, String s2, long l, String s3, String s4, String s5, String s6, String s7, long l2, Long aLong) throws ResourceAllocationException, ConcurrentOperationException, InsufficientCapacityException { + return null; //To change body of implemented methods use File | Settings | File Templates. } /* (non-Javadoc) @@ -803,7 +841,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage } @Override - public LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network) { + public LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network, Scheme lbScheme) { // TODO Auto-generated method stub return null; } @@ -831,7 +869,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage } @Override - public String allocateSecondaryGuestIP(Account account, long zoneId, + public NicSecondaryIp allocateSecondaryGuestIP(Account account, long zoneId, Long nicId, Long networkId, String ipaddress) { // TODO Auto-generated method stub return null; diff --git a/server/test/com/cloud/network/MockNetworkModelImpl.java b/server/test/com/cloud/network/MockNetworkModelImpl.java index 511249fff5a..c3a0d6c5ae9 100644 --- a/server/test/com/cloud/network/MockNetworkModelImpl.java +++ b/server/test/com/cloud/network/MockNetworkModelImpl.java @@ -33,12 +33,14 @@ import com.cloud.network.Network.Capability; import com.cloud.network.Network.GuestType; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; +import com.cloud.network.Networks.IsolationType; import com.cloud.network.Networks.TrafficType; import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.NetworkVO; import com.cloud.network.element.NetworkElement; import com.cloud.network.element.UserDataServiceProvider; import com.cloud.offering.NetworkOffering; +import com.cloud.offering.NetworkOffering.Detail; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.user.Account; import com.cloud.utils.component.ManagerBase; @@ -566,7 +568,7 @@ public class MockNetworkModelImpl extends ManagerBase implements NetworkModel { * @see com.cloud.network.NetworkModel#getDefaultNetworkDomain() */ @Override - public String getDefaultNetworkDomain() { + public String getDefaultNetworkDomain(long zoneId) { // TODO Auto-generated method stub return null; } @@ -850,4 +852,26 @@ public class MockNetworkModelImpl extends ManagerBase implements NetworkModel { // TODO Auto-generated method stub return null; } + + @Override + public IpAddress getPublicIpAddress(String ipAddress, long zoneId) { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getUsedIpsInNetwork(Network network) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Map getNtwkOffDetails(long offId) { + return null; + } + + public IsolationType[] listNetworkIsolationMethods() { + // TODO Auto-generated method stub + return null; + } } diff --git a/server/test/com/cloud/network/MockRulesManagerImpl.java b/server/test/com/cloud/network/MockRulesManagerImpl.java index e5a6894d76d..82a3e9346e3 100644 --- a/server/test/com/cloud/network/MockRulesManagerImpl.java +++ b/server/test/com/cloud/network/MockRulesManagerImpl.java @@ -28,6 +28,7 @@ import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.PortForwardingRuleVO; import com.cloud.network.rules.RulesManager; @@ -40,6 +41,7 @@ import com.cloud.utils.Pair; import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.net.Ip; +import com.cloud.vm.Nic; import com.cloud.vm.VirtualMachine; @Local(value = {RulesManager.class, RulesService.class}) @@ -76,8 +78,7 @@ public class MockRulesManagerImpl extends ManagerBase implements RulesManager, R @Override public boolean enableStaticNat(long ipAddressId, long vmId, long networkId, - boolean isSystemVm, String ipAddr) throws NetworkRuleConflictException, - ResourceUnavailableException { + String ipAddr) throws NetworkRuleConflictException, ResourceUnavailableException { // TODO Auto-generated method stub return false; } @@ -311,4 +312,10 @@ public class MockRulesManagerImpl extends ManagerBase implements RulesManager, R return null; } + @Override + public List listAssociatedRulesForGuestNic(Nic nic) { + // TODO Auto-generated method stub + return null; + } + } diff --git a/server/test/com/cloud/network/security/SecurityGroupManagerTestConfiguration.java b/server/test/com/cloud/network/security/SecurityGroupManagerTestConfiguration.java index b3a9ff12dab..e2e9d68c013 100644 --- a/server/test/com/cloud/network/security/SecurityGroupManagerTestConfiguration.java +++ b/server/test/com/cloud/network/security/SecurityGroupManagerTestConfiguration.java @@ -19,6 +19,7 @@ package com.cloud.network.security; import java.io.IOException; +import org.apache.cloudstack.test.utils.SpringUtils; import org.mockito.Mockito; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; @@ -60,7 +61,6 @@ import com.cloud.tags.dao.ResourceTagsDaoImpl; import com.cloud.user.AccountManager; import com.cloud.user.DomainManager; import com.cloud.user.dao.AccountDaoImpl; -import com.cloud.utils.component.SpringComponentScanUtils; import com.cloud.vm.UserVmManager; import com.cloud.vm.VirtualMachineManager; import com.cloud.vm.dao.NicDaoImpl; @@ -151,7 +151,7 @@ public class SecurityGroupManagerTestConfiguration { public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { mdr.getClassMetadata().getClassName(); ComponentScan cs = SecurityGroupManagerTestConfiguration.class.getAnnotation(ComponentScan.class); - return SpringComponentScanUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); } } diff --git a/server/test/com/cloud/snapshot/SnapshotDaoTestConfiguration.java b/server/test/com/cloud/snapshot/SnapshotDaoTestConfiguration.java index cc410dbc4ca..6695edc0225 100644 --- a/server/test/com/cloud/snapshot/SnapshotDaoTestConfiguration.java +++ b/server/test/com/cloud/snapshot/SnapshotDaoTestConfiguration.java @@ -19,6 +19,7 @@ package com.cloud.snapshot; import java.io.IOException; +import org.apache.cloudstack.test.utils.SpringUtils; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.Configuration; @@ -36,7 +37,6 @@ import com.cloud.host.dao.HostTagsDaoImpl; import com.cloud.storage.dao.SnapshotDaoImpl; import com.cloud.storage.dao.VolumeDaoImpl; import com.cloud.tags.dao.ResourceTagsDaoImpl; -import com.cloud.utils.component.SpringComponentScanUtils; import com.cloud.vm.dao.NicDaoImpl; import com.cloud.vm.dao.VMInstanceDaoImpl; @@ -65,7 +65,7 @@ public class SnapshotDaoTestConfiguration { public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { mdr.getClassMetadata().getClassName(); ComponentScan cs = SnapshotDaoTestConfiguration.class.getAnnotation(ComponentScan.class); - return SpringComponentScanUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); } } diff --git a/server/test/com/cloud/storage/dao/StoragePoolDaoTestConfiguration.java b/server/test/com/cloud/storage/dao/StoragePoolDaoTestConfiguration.java index 58de4d2730b..2f79ff04258 100644 --- a/server/test/com/cloud/storage/dao/StoragePoolDaoTestConfiguration.java +++ b/server/test/com/cloud/storage/dao/StoragePoolDaoTestConfiguration.java @@ -20,6 +20,7 @@ package com.cloud.storage.dao; import java.io.IOException; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl; +import org.apache.cloudstack.test.utils.SpringUtils; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.Configuration; @@ -28,7 +29,6 @@ import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.TypeFilter; -import com.cloud.utils.component.SpringComponentScanUtils; @Configuration @ComponentScan(basePackageClasses={ @@ -46,7 +46,7 @@ public class StoragePoolDaoTestConfiguration { public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { mdr.getClassMetadata().getClassName(); ComponentScan cs = StoragePoolDaoTestConfiguration.class.getAnnotation(ComponentScan.class); - return SpringComponentScanUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); } } diff --git a/server/test/com/cloud/vm/MockUserVmManagerImpl.java b/server/test/com/cloud/vm/MockUserVmManagerImpl.java index 46eb6eb15f6..a88625a42fa 100644 --- a/server/test/com/cloud/vm/MockUserVmManagerImpl.java +++ b/server/test/com/cloud/vm/MockUserVmManagerImpl.java @@ -403,14 +403,14 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager, } @Override - public UserVm restoreVM(RestoreVMCmd cmd) { + public UserVm restoreVM(RestoreVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException{ // TODO Auto-generated method stub return null; } @Override - public UserVm upgradeVirtualMachine(ScaleVMCmd scaleVMCmd) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException { - return null; //To change body of implemented methods use File | Settings | File Templates. + public boolean upgradeVirtualMachine(ScaleVMCmd scaleVMCmd) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException { + return false; //To change body of implemented methods use File | Settings | File Templates. } diff --git a/server/test/com/cloud/vm/UserVmManagerTest.java b/server/test/com/cloud/vm/UserVmManagerTest.java index 075c79a81c0..f84a67a5d4f 100755 --- a/server/test/com/cloud/vm/UserVmManagerTest.java +++ b/server/test/com/cloud/vm/UserVmManagerTest.java @@ -17,19 +17,26 @@ package com.cloud.vm; +import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyFloat; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.when; import java.lang.reflect.Field; import java.util.List; +import java.util.UUID; +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd; import org.junit.Before; @@ -44,9 +51,11 @@ import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.hypervisor.Hypervisor; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.offering.ServiceOffering; import com.cloud.service.ServiceOfferingVO; import com.cloud.storage.VMTemplateVO; @@ -57,6 +66,7 @@ import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.user.Account; import com.cloud.user.AccountManager; +import com.cloud.user.AccountService; import com.cloud.user.AccountVO; import com.cloud.user.UserContext; import com.cloud.user.UserVO; @@ -73,6 +83,7 @@ public class UserVmManagerTest { @Mock VolumeManager _storageMgr; @Mock Account _account; @Mock AccountManager _accountMgr; + @Mock AccountService _accountService; @Mock ConfigurationManager _configMgr; @Mock CapacityManager _capacityMgr; @Mock AccountDao _accountDao; @@ -91,6 +102,7 @@ public class UserVmManagerTest { @Mock VMTemplateVO _templateMock; @Mock VolumeVO _volumeMock; @Mock List _rootVols; + @Mock Account _accountMock2; @Before public void setup(){ MockitoAnnotations.initMocks(this); @@ -102,6 +114,7 @@ public class UserVmManagerTest { _userVmMgr._itMgr = _itMgr; _userVmMgr.volumeMgr = _storageMgr; _userVmMgr._accountDao = _accountDao; + _userVmMgr._accountService = _accountService; _userVmMgr._userDao = _userDao; _userVmMgr._accountMgr = _accountMgr; _userVmMgr._configMgr = _configMgr; @@ -121,7 +134,7 @@ public class UserVmManagerTest { // Test restoreVm when VM state not in running/stopped case @Test(expected=CloudRuntimeException.class) - public void testRestoreVMF1() throws ResourceAllocationException { + public void testRestoreVMF1() throws ResourceAllocationException, InsufficientCapacityException, ResourceUnavailableException { when(_vmDao.findById(anyLong())).thenReturn(_vmMock); when(_templateDao.findById(anyLong())).thenReturn(_templateMock); @@ -370,6 +383,74 @@ public class UserVmManagerTest { return serviceOffering; } - + // Test Move VM b/w accounts where caller is not ROOT/Domain admin + @Test(expected=InvalidParameterValueException.class) + public void testMoveVmToUser1() throws Exception { + AssignVMCmd cmd = new AssignVMCmd(); + Class _class = cmd.getClass(); + + Field virtualmachineIdField = _class.getDeclaredField("virtualMachineId"); + virtualmachineIdField.setAccessible(true); + virtualmachineIdField.set(cmd, 1L); + + Field accountNameField = _class.getDeclaredField("accountName"); + accountNameField.setAccessible(true); + accountNameField.set(cmd, "account"); + + Field domainIdField = _class.getDeclaredField("domainId"); + domainIdField.setAccessible(true); + domainIdField.set(cmd, 1L); + + // caller is of type 0 + Account caller = (Account) new AccountVO("testaccount", 1, "networkdomain", (short) 0, + UUID.randomUUID().toString()); + UserContext.registerContext(1, caller, null, true); + + _userVmMgr.moveVMToUser(cmd); + } + + + // Test Move VM b/w accounts where caller doesn't have access to the old or new account + @Test(expected=PermissionDeniedException.class) + public void testMoveVmToUser2() throws Exception { + AssignVMCmd cmd = new AssignVMCmd(); + Class _class = cmd.getClass(); + + Field virtualmachineIdField = _class.getDeclaredField("virtualMachineId"); + virtualmachineIdField.setAccessible(true); + virtualmachineIdField.set(cmd, 1L); + + Field accountNameField = _class.getDeclaredField("accountName"); + accountNameField.setAccessible(true); + accountNameField.set(cmd, "account"); + + Field domainIdField = _class.getDeclaredField("domainId"); + domainIdField.setAccessible(true); + domainIdField.set(cmd, 1L); + + // caller is of type 0 + Account caller = (Account) new AccountVO("testaccount", 1, "networkdomain", (short) 1, + UUID.randomUUID().toString()); + UserContext.registerContext(1, caller, null, true); + + Account oldAccount = (Account) new AccountVO("testaccount", 1, "networkdomain", (short) 0, + UUID.randomUUID().toString()); + Account newAccount = (Account) new AccountVO("testaccount", 1, "networkdomain", (short) 1, + UUID.randomUUID().toString()); + + UserVmVO vm = new UserVmVO(10L, "test", "test", 1L, HypervisorType.Any, 1L, false, false, 1L, 1L, + 5L, "test", "test", 1L); + vm.setState(VirtualMachine.State.Stopped); + when(_vmDao.findById(anyLong())).thenReturn(vm); + + when(_accountService.getActiveAccountById(anyLong())).thenReturn(oldAccount); + + when(_accountService.getActiveAccountByName(anyString(), anyLong())).thenReturn(newAccount); + + doThrow(new PermissionDeniedException("Access check failed")).when(_accountMgr).checkAccess(any(Account.class), any(AccessType.class), + any(Boolean.class), any(ControlledEntity.class)); + + _userVmMgr.moveVMToUser(cmd); + } } \ No newline at end of file diff --git a/server/test/com/cloud/vm/dao/UserVmCloneSettingDaoTestConfiguration.java b/server/test/com/cloud/vm/dao/UserVmCloneSettingDaoTestConfiguration.java index 6e22e174f58..3bd4df8543f 100644 --- a/server/test/com/cloud/vm/dao/UserVmCloneSettingDaoTestConfiguration.java +++ b/server/test/com/cloud/vm/dao/UserVmCloneSettingDaoTestConfiguration.java @@ -19,6 +19,7 @@ package com.cloud.vm.dao; import java.io.IOException; +import org.apache.cloudstack.test.utils.SpringUtils; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.Configuration; @@ -27,7 +28,6 @@ import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.TypeFilter; -import com.cloud.utils.component.SpringComponentScanUtils; import com.cloud.vm.dao.UserVmCloneSettingDaoImpl; @Configuration @@ -45,7 +45,7 @@ public class UserVmCloneSettingDaoTestConfiguration { public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { mdr.getClassMetadata().getClassName(); ComponentScan cs = UserVmCloneSettingDaoTestConfiguration.class.getAnnotation(ComponentScan.class); - return SpringComponentScanUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); } } diff --git a/server/test/com/cloud/vm/dao/UserVmDaoTestConfiguration.java b/server/test/com/cloud/vm/dao/UserVmDaoTestConfiguration.java index 6a63fabd44b..7af772c1b17 100644 --- a/server/test/com/cloud/vm/dao/UserVmDaoTestConfiguration.java +++ b/server/test/com/cloud/vm/dao/UserVmDaoTestConfiguration.java @@ -19,6 +19,7 @@ package com.cloud.vm.dao; import java.io.IOException; +import org.apache.cloudstack.test.utils.SpringUtils; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.Configuration; @@ -27,7 +28,6 @@ import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.TypeFilter; -import com.cloud.utils.component.SpringComponentScanUtils; @Configuration @ComponentScan(basePackageClasses={ @@ -43,7 +43,7 @@ public class UserVmDaoTestConfiguration { public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { mdr.getClassMetadata().getClassName(); ComponentScan cs = UserVmDaoTestConfiguration.class.getAnnotation(ComponentScan.class); - return SpringComponentScanUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); } } diff --git a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java index 46568603ec4..7ca02d42745 100755 --- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -281,7 +281,7 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu * @see com.cloud.configuration.ConfigurationService#getNetworkOfferingNetworkRate(long) */ @Override - public Integer getNetworkOfferingNetworkRate(long networkOfferingId) { + public Integer getNetworkOfferingNetworkRate(long networkOfferingId, Long dataCenterId) { // TODO Auto-generated method stub return null; } @@ -334,7 +334,7 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu * @see com.cloud.configuration.ConfigurationService#getServiceOfferingNetworkRate(long) */ @Override - public Integer getServiceOfferingNetworkRate(long serviceOfferingId) { + public Integer getServiceOfferingNetworkRate(long serviceOfferingId, Long dataCenterId) { // TODO Auto-generated method stub return null; } @@ -424,9 +424,9 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu * @see com.cloud.configuration.ConfigurationManager#updateConfiguration(long, java.lang.String, java.lang.String, java.lang.String) */ @Override - public void updateConfiguration(long userId, String name, String category, String value, String scope, Long resourceId) { + public String updateConfiguration(long userId, String name, String category, String value, String scope, Long resourceId) { // TODO Auto-generated method stub - + return null; } /* (non-Javadoc) @@ -499,7 +499,7 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu @Override public NetworkOfferingVO createNetworkOffering(String name, String displayText, TrafficType trafficType, String tags, boolean specifyVlan, Availability availability, Integer networkRate, Map> serviceProviderMap, boolean isDefault, GuestType type, boolean systemOnly, Long serviceOfferingId, boolean conserveMode, - Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent) { + Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent, Map details) { // TODO Auto-generated method stub return null; } diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index 7640af08a32..7ba4b59ca19 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -16,18 +16,53 @@ // under the License. package com.cloud.vpc; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd; +import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd; +import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; +import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; +import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; +import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; +import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + import com.cloud.dc.DataCenter; import com.cloud.dc.Pod; import com.cloud.dc.Vlan.VlanType; import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; -import com.cloud.exception.*; -import com.cloud.network.*; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapcityException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.GuestVlan; +import com.cloud.network.IpAddress; +import com.cloud.network.Network; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkProfile; +import com.cloud.network.NetworkRuleApplier; +import com.cloud.network.NetworkService; import com.cloud.network.Networks.TrafficType; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.PhysicalNetworkTrafficType; +import com.cloud.network.PublicIpAddress; import com.cloud.network.addr.PublicIp; +import com.cloud.network.dao.AccountGuestVlanMapVO; import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.NetworkServiceMapDao; import com.cloud.network.dao.NetworkVO; @@ -39,6 +74,7 @@ import com.cloud.network.guru.NetworkGuru; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRule.State; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.rules.StaticNat; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.NetworkOfferingVO; @@ -56,18 +92,14 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.VirtualMachineProfile; import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd; +import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd; import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; import org.apache.cloudstack.api.command.user.network.*; import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; @Component @Local(value = { NetworkManager.class, NetworkService.class }) @@ -342,9 +374,24 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage return false; } + @Override + public GuestVlan dedicateGuestVlanRange(DedicateGuestVlanRangeCmd cmd) { + // TODO Auto-generated method stub + return null; + } + @Override + public Pair, Integer> listDedicatedGuestVlanRanges(ListDedicatedGuestVlanRangesCmd cmd) { + // TODO Auto-generated method stub + return null; + } + @Override + public boolean releaseDedicatedGuestVlanRange(Long dedicatedGuestVlanRangeId) { + // TODO Auto-generated method stub + return true; + } /* (non-Javadoc) * @see com.cloud.network.NetworkService#listNetworkServices(java.lang.String) @@ -605,7 +652,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage */ @Override public Network createPrivateNetwork(String networkName, String displayText, long physicalNetworkId, String vlan, - String startIp, String endIP, String gateway, String netmask, long networkOwnerId, Long vpcId) + String startIp, String endIP, String gateway, String netmask, long networkOwnerId, Long vpcId, Boolean sourceNat) throws ResourceAllocationException, ConcurrentOperationException, InsufficientCapacityException { // TODO Auto-generated method stub return null; @@ -1287,7 +1334,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage } @Override - public LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network) { + public LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network, Scheme lbScheme) { // TODO Auto-generated method stub return null; } @@ -1312,7 +1359,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage } @Override - public String allocateSecondaryGuestIP(Account account, long zoneId, + public NicSecondaryIp allocateSecondaryGuestIP(Account account, long zoneId, Long nicId, Long networkId, String ipaddress) { // TODO Auto-generated method stub return null; diff --git a/server/test/com/cloud/vpc/MockNetworkModelImpl.java b/server/test/com/cloud/vpc/MockNetworkModelImpl.java index 9857964d911..d9e33b75616 100644 --- a/server/test/com/cloud/vpc/MockNetworkModelImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkModelImpl.java @@ -37,6 +37,7 @@ import com.cloud.network.Network.GuestType; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.NetworkModel; +import com.cloud.network.Networks.IsolationType; import com.cloud.network.Networks.TrafficType; import com.cloud.network.PhysicalNetwork; import com.cloud.network.PhysicalNetworkSetupInfo; @@ -46,6 +47,7 @@ import com.cloud.network.dao.NetworkVO; import com.cloud.network.element.NetworkElement; import com.cloud.network.element.UserDataServiceProvider; import com.cloud.offering.NetworkOffering; +import com.cloud.offering.NetworkOffering.Detail; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.user.Account; @@ -581,7 +583,7 @@ public class MockNetworkModelImpl extends ManagerBase implements NetworkModel { * @see com.cloud.network.NetworkModel#getDefaultNetworkDomain() */ @Override - public String getDefaultNetworkDomain() { + public String getDefaultNetworkDomain(long zoneId) { // TODO Auto-generated method stub return null; } @@ -863,4 +865,26 @@ public class MockNetworkModelImpl extends ManagerBase implements NetworkModel { return null; } + @Override + public IpAddress getPublicIpAddress(String ipAddress, long zoneId) { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getUsedIpsInNetwork(Network network) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Map getNtwkOffDetails(long offId) { + return null; + } + + public IsolationType[] listNetworkIsolationMethods() { + // TODO Auto-generated method stub + return null; + } + } diff --git a/server/test/com/cloud/vpc/MockVpcManagerImpl.java b/server/test/com/cloud/vpc/MockVpcManagerImpl.java index feda7f398bd..de4169c9525 100644 --- a/server/test/com/cloud/vpc/MockVpcManagerImpl.java +++ b/server/test/com/cloud/vpc/MockVpcManagerImpl.java @@ -164,7 +164,7 @@ public class MockVpcManagerImpl extends ManagerBase implements VpcManager { * @see com.cloud.network.vpc.VpcService#createVpcPrivateGateway(long, java.lang.Long, java.lang.String, java.lang.String, java.lang.String, java.lang.String, long) */ @Override - public PrivateGateway createVpcPrivateGateway(long vpcId, Long physicalNetworkId, String vlan, String ipAddress, String gateway, String netmask, long gatewayOwnerId) throws ResourceAllocationException, + public PrivateGateway createVpcPrivateGateway(long vpcId, Long physicalNetworkId, String vlan, String ipAddress, String gateway, String netmask, long gatewayOwnerId, Boolean isSourceNat) throws ResourceAllocationException, ConcurrentOperationException, InsufficientCapacityException { // TODO Auto-generated method stub return null; diff --git a/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java b/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java index ef5478bb1f8..9010f1f5acb 100644 --- a/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java +++ b/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java @@ -36,6 +36,7 @@ import com.cloud.network.RemoteAccessVpn; import com.cloud.network.Site2SiteVpnConnection; import com.cloud.network.VpcVirtualNetworkApplianceService; import com.cloud.network.VpnUser; +import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.router.VirtualRouter; import com.cloud.network.router.VpcVirtualNetworkApplianceManager; import com.cloud.network.rules.FirewallRule; @@ -46,7 +47,6 @@ import com.cloud.network.vpc.Vpc; import com.cloud.user.Account; import com.cloud.user.User; import com.cloud.uservm.UserVm; -import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.vm.DomainRouterVO; import com.cloud.vm.NicProfile; @@ -402,4 +402,16 @@ VpcVirtualNetworkApplianceService { return null; } + @Override + public boolean applyLoadBalancingRules(Network network, List rules, List routers) throws ResourceUnavailableException { + // TODO Auto-generated method stub + return false; + } + + @Override + public VirtualRouter findRouter(long routerId) { + // TODO Auto-generated method stub + return null; + } + } diff --git a/server/test/com/cloud/vpc/VpcTest.java b/server/test/com/cloud/vpc/VpcTest.java new file mode 100644 index 00000000000..52e837ec5ca --- /dev/null +++ b/server/test/com/cloud/vpc/VpcTest.java @@ -0,0 +1,269 @@ +// 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. + +package com.cloud.vpc; + +import com.cloud.configuration.ConfigurationManager; +import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.VlanDao; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkModel; +import com.cloud.network.NetworkService; +import com.cloud.network.dao.FirewallRulesDao; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.Site2SiteVpnGatewayDao; +import com.cloud.network.vpc.*; +import com.cloud.network.vpc.dao.PrivateIpDao; +import com.cloud.network.vpc.dao.StaticRouteDao; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.network.vpc.dao.VpcGatewayDao; +import com.cloud.network.vpc.dao.VpcOfferingDao; +import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; +import com.cloud.network.vpc.dao.VpcServiceMapDao; +import com.cloud.network.vpn.Site2SiteVpnManager; +import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; +import com.cloud.server.ConfigurationServer; +import com.cloud.tags.dao.ResourceTagDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.ResourceLimitService; +import com.cloud.user.UserContext; +import com.cloud.utils.component.ComponentContext; +import com.cloud.vm.dao.DomainRouterDao; + +import junit.framework.TestCase; +import org.apache.cloudstack.api.command.user.network.CreateNetworkACLCmd; +import org.apache.cloudstack.api.command.user.vpc.CreateVPCCmd; +import org.apache.cloudstack.test.utils.SpringUtils; +import org.apache.log4j.Logger; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.filter.TypeFilter; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; + +import javax.inject.Inject; +import java.io.IOException; +import java.util.UUID; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(loader = AnnotationConfigContextLoader.class) +public class VpcTest extends TestCase { + + @Inject + VpcService _vpcService; + + @Inject + AccountManager _accountMgr; + + @Inject + VpcManager _vpcMgr; + + @Inject + VpcDao _vpcDao; + + @Inject + VpcOfferingDao _vpcOfferinDao; + + private VpcVO vpc; + private static final Logger s_logger = Logger.getLogger(VpcTest.class); + + @Before + public void setUp() { + ComponentContext.initComponentsLifeCycle(); + Account account = new AccountVO("testaccount", 1, "testdomain", (short) 0, UUID.randomUUID().toString()); + UserContext.registerContext(1, account, null, true); + vpc = new VpcVO(1, "myvpc", "myvpc", 2, 1, 1, "10.0.1.0/16", "mydomain"); + } + + @Test + public void testCreateVpc() throws Exception { + Mockito.when( + _vpcMgr.createVpc(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString(), + Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenReturn(vpc); + Mockito.when(_vpcOfferinDao.persist(Mockito.any(VpcOfferingVO.class))).thenReturn( + new VpcOfferingVO("test", "test", 1L)); + Vpc vpc1 = _vpcMgr.createVpc(1, 1, 1, "myVpc", "my Vpc", "10.0.0.0/16", "test"); + assertNotNull("Vpc is created", vpc1); + } + + @Configuration + @ComponentScan(basePackageClasses = { VpcManager.class }, includeFilters = { @ComponentScan.Filter(value = VpcTestConfiguration.Library.class, type = FilterType.CUSTOM) }, useDefaultFilters = false) + public static class VpcTestConfiguration extends SpringUtils.CloudStackTestConfiguration { + + @Bean + public AccountManager accountManager() { + return Mockito.mock(AccountManager.class); + } + + @Bean + public NetworkManager networkManager() { + return Mockito.mock(NetworkManager.class); + } + + @Bean + public NetworkModel networkModel() { + return Mockito.mock(NetworkModel.class); + } + + @Bean + public VpcManager vpcManager() { + return Mockito.mock(VpcManager.class); + } + + @Bean + public ResourceTagDao resourceTagDao() { + return Mockito.mock(ResourceTagDao.class); + } + + @Bean + public VpcDao VpcDao() { + return Mockito.mock(VpcDao.class); + } + + @Bean + public VpcOfferingDao vpcOfferingDao() { + return Mockito.mock(VpcOfferingDao.class); + } + + @Bean + public VpcOfferingServiceMapDao vpcOfferingServiceMapDao() { + return Mockito.mock(VpcOfferingServiceMapDao.class); + } + + @Bean + public ConfigurationDao configurationDao() { + return Mockito.mock(ConfigurationDao.class); + } + + @Bean + public ConfigurationManager configurationManager() { + return Mockito.mock(ConfigurationManager.class); + } + + @Bean + public NetworkDao networkDao() { + return Mockito.mock(NetworkDao.class); + } + + @Bean + public NetworkACLManager networkACLManager() { + return Mockito.mock(NetworkACLManager.class); + } + + @Bean + public IPAddressDao ipAddressDao() { + return Mockito.mock(IPAddressDao.class); + } + + @Bean + public DomainRouterDao domainRouterDao() { + return Mockito.mock(DomainRouterDao.class); + } + + @Bean + public VpcGatewayDao vpcGatewayDao() { + return Mockito.mock(VpcGatewayDao.class); + } + + @Bean + public PrivateIpDao privateIpDao() { + return Mockito.mock(PrivateIpDao.class); + } + + @Bean + public StaticRouteDao staticRouteDao() { + return Mockito.mock(StaticRouteDao.class); + } + + @Bean + public NetworkOfferingServiceMapDao networkOfferingServiceMapDao() { + return Mockito.mock(NetworkOfferingServiceMapDao.class); + } + + @Bean + public PhysicalNetworkDao physicalNetworkDao() { + return Mockito.mock(PhysicalNetworkDao.class); + } + + @Bean + public FirewallRulesDao firewallRulesDao() { + return Mockito.mock(FirewallRulesDao.class); + } + + @Bean + public Site2SiteVpnGatewayDao site2SiteVpnGatewayDao() { + return Mockito.mock(Site2SiteVpnGatewayDao.class); + } + + @Bean + public Site2SiteVpnManager site2SiteVpnManager() { + return Mockito.mock(Site2SiteVpnManager.class); + } + + @Bean + public VlanDao vlanDao() { + return Mockito.mock(VlanDao.class); + } + + @Bean + public ResourceLimitService resourceLimitService() { + return Mockito.mock(ResourceLimitService.class); + } + + @Bean + public VpcServiceMapDao vpcServiceMapDao() { + return Mockito.mock(VpcServiceMapDao.class); + } + + @Bean + public NetworkService networkService() { + return Mockito.mock(NetworkService.class); + } + + @Bean + public DataCenterDao dataCenterDao() { + return Mockito.mock(DataCenterDao.class); + } + + @Bean + public ConfigurationServer configurationServer() { + return Mockito.mock(ConfigurationServer.class); + } + + public static class Library implements TypeFilter { + @Override + public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { + mdr.getClassMetadata().getClassName(); + ComponentScan cs = VpcTestConfiguration.class.getAnnotation(ComponentScan.class); + return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + } + } + } + +} diff --git a/server/test/com/cloud/vpc/VpcTestConfiguration.java b/server/test/com/cloud/vpc/VpcTestConfiguration.java index b1f2f80c076..7ae83f3a9c9 100644 --- a/server/test/com/cloud/vpc/VpcTestConfiguration.java +++ b/server/test/com/cloud/vpc/VpcTestConfiguration.java @@ -19,6 +19,7 @@ package com.cloud.vpc; import java.io.IOException; +import org.apache.cloudstack.test.utils.SpringUtils; import org.mockito.Mockito; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; @@ -91,7 +92,6 @@ import com.cloud.tags.dao.ResourceTagsDaoImpl; import com.cloud.user.AccountManager; import com.cloud.user.dao.AccountDaoImpl; import com.cloud.user.dao.UserStatisticsDaoImpl; -import com.cloud.utils.component.SpringComponentScanUtils; import com.cloud.vm.UserVmManager; import com.cloud.vm.dao.DomainRouterDaoImpl; import com.cloud.vm.dao.NicDaoImpl; @@ -236,7 +236,7 @@ public class VpcTestConfiguration { public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { mdr.getClassMetadata().getClassName(); ComponentScan cs = VpcTestConfiguration.class.getAnnotation(ComponentScan.class); - return SpringComponentScanUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); } } } diff --git a/server/test/com/cloud/vpc/dao/MockNetworkOfferingDaoImpl.java b/server/test/com/cloud/vpc/dao/MockNetworkOfferingDaoImpl.java index dbf14113de4..a8208dd7d9c 100644 --- a/server/test/com/cloud/vpc/dao/MockNetworkOfferingDaoImpl.java +++ b/server/test/com/cloud/vpc/dao/MockNetworkOfferingDaoImpl.java @@ -101,28 +101,28 @@ public class MockNetworkOfferingDaoImpl extends NetworkOfferingDaoImpl implement if (id.longValue() == 1) { //network offering valid for vpc vo = new NetworkOfferingVO("vpc", "vpc", TrafficType.Guest, false, true, null, null, false, - Availability.Optional, null, Network.GuestType.Isolated, false, false, false); + Availability.Optional, null, Network.GuestType.Isolated, false, false, false, false, false); } else if (id.longValue() == 2) { //invalid offering - source nat is not included vo = new NetworkOfferingVO("vpc", "vpc", TrafficType.Guest, false, true, null, null, false, - Availability.Optional, null, Network.GuestType.Isolated, false, false, false); + Availability.Optional, null, Network.GuestType.Isolated, false, false, false, false, false); } else if (id.longValue() == 3) { //network offering invalid for vpc (conserve mode off) vo = new NetworkOfferingVO("non vpc", "non vpc", TrafficType.Guest, false, true, null, null, false, - Availability.Optional, null, Network.GuestType.Isolated, true, false, false); + Availability.Optional, null, Network.GuestType.Isolated, true, false, false, false, false); } else if (id.longValue() == 4) { //network offering invalid for vpc (Shared) vo = new NetworkOfferingVO("non vpc", "non vpc", TrafficType.Guest, false, true, null, null, false, - Availability.Optional, null, Network.GuestType.Shared, false, false, false); + Availability.Optional, null, Network.GuestType.Shared, false, false, false, false, false); } else if (id.longValue() == 5) { //network offering invalid for vpc (has redundant router) vo = new NetworkOfferingVO("vpc", "vpc", TrafficType.Guest, false, true, null, null, false, - Availability.Optional, null, Network.GuestType.Isolated, false, false, false); + Availability.Optional, null, Network.GuestType.Isolated, false, false, false, false, false); vo.setRedundantRouter(true); } else if (id.longValue() == 6) { //network offering invalid for vpc (has lb service) vo = new NetworkOfferingVO("vpc", "vpc", TrafficType.Guest, false, true, null, null, false, - Availability.Optional, null, Network.GuestType.Isolated, false, false, false); + Availability.Optional, null, Network.GuestType.Isolated, false, false, false, false, false); } if (vo != null) { diff --git a/server/test/com/cloud/vpc/dao/MockNetworkServiceMapDaoImpl.java b/server/test/com/cloud/vpc/dao/MockNetworkServiceMapDaoImpl.java index 002b61dcbc4..103f04ea8b9 100644 --- a/server/test/com/cloud/vpc/dao/MockNetworkServiceMapDaoImpl.java +++ b/server/test/com/cloud/vpc/dao/MockNetworkServiceMapDaoImpl.java @@ -95,4 +95,10 @@ public class MockNetworkServiceMapDaoImpl extends GenericDaoBase getProvidersForServiceInNetwork(long networkId, Service service) { + // TODO Auto-generated method stub + return null; + } } diff --git a/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java b/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java deleted file mode 100644 index fb294697cc6..00000000000 --- a/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java +++ /dev/null @@ -1,344 +0,0 @@ -// 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. -package org.apache.cloudstack.affinity; - -import java.io.IOException; - -import org.apache.cloudstack.acl.SecurityChecker; -import org.apache.cloudstack.affinity.dao.AffinityGroupDao; -import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl; -import org.mockito.Mockito; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.FilterType; -import org.springframework.context.annotation.ComponentScan.Filter; -import org.springframework.core.type.classreading.MetadataReader; -import org.springframework.core.type.classreading.MetadataReaderFactory; -import org.springframework.core.type.filter.TypeFilter; -import com.cloud.utils.component.ComponentContext; -import com.cloud.agent.AgentManager; -import com.cloud.alert.AlertManager; -import com.cloud.api.query.dao.UserAccountJoinDaoImpl; -import com.cloud.capacity.dao.CapacityDaoImpl; -import com.cloud.cluster.agentlb.dao.HostTransferMapDaoImpl; -import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.dc.dao.AccountVlanMapDaoImpl; -import com.cloud.dc.dao.ClusterDaoImpl; -import com.cloud.dc.dao.DataCenterDaoImpl; -import com.cloud.dc.dao.DataCenterIpAddressDaoImpl; -import com.cloud.dc.dao.DataCenterLinkLocalIpAddressDao; -import com.cloud.dc.dao.DataCenterLinkLocalIpAddressDaoImpl; -import com.cloud.dc.dao.DataCenterVnetDaoImpl; -import com.cloud.dc.dao.DcDetailsDaoImpl; -import com.cloud.dc.dao.HostPodDaoImpl; -import com.cloud.dc.dao.PodVlanDaoImpl; -import com.cloud.dc.dao.PodVlanMapDaoImpl; -import com.cloud.dc.dao.VlanDaoImpl; -import com.cloud.domain.dao.DomainDaoImpl; -import com.cloud.event.EventUtils; -import com.cloud.event.dao.EventDao; -import com.cloud.event.dao.EventDaoImpl; -import com.cloud.event.dao.UsageEventDaoImpl; -import com.cloud.host.dao.HostDaoImpl; -import com.cloud.host.dao.HostDetailsDaoImpl; -import com.cloud.host.dao.HostTagsDaoImpl; -import com.cloud.network.Ipv6AddressManager; -import com.cloud.network.NetworkManager; -import com.cloud.network.NetworkModel; -import com.cloud.network.NetworkService; -import com.cloud.network.StorageNetworkManager; -import com.cloud.network.dao.FirewallRulesCidrsDaoImpl; -import com.cloud.network.dao.FirewallRulesDaoImpl; -import com.cloud.network.dao.IPAddressDaoImpl; -import com.cloud.network.dao.LoadBalancerDaoImpl; -import com.cloud.network.dao.NetworkDao; -import com.cloud.network.dao.NetworkDomainDaoImpl; -import com.cloud.network.dao.NetworkServiceMapDaoImpl; -import com.cloud.network.dao.PhysicalNetworkDaoImpl; -import com.cloud.network.dao.PhysicalNetworkServiceProviderDaoImpl; -import com.cloud.network.dao.PhysicalNetworkTrafficTypeDaoImpl; -import com.cloud.network.dao.UserIpv6AddressDaoImpl; -import com.cloud.network.element.DhcpServiceProvider; -import com.cloud.network.element.IpDeployer; -import com.cloud.network.element.NetworkElement; -import com.cloud.network.guru.NetworkGuru; -import com.cloud.network.lb.LoadBalancingRulesManager; -import com.cloud.network.rules.FirewallManager; -import com.cloud.network.rules.RulesManager; -import com.cloud.network.rules.dao.PortForwardingRulesDaoImpl; -import com.cloud.network.vpc.NetworkACLManager; -import com.cloud.network.vpc.VpcManager; -import com.cloud.network.vpc.dao.PrivateIpDaoImpl; -import com.cloud.network.vpn.RemoteAccessVpnService; -import com.cloud.offerings.dao.NetworkOfferingDao; -import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; -import com.cloud.projects.ProjectManager; -import com.cloud.service.dao.ServiceOfferingDaoImpl; -import com.cloud.storage.dao.DiskOfferingDaoImpl; -import com.cloud.storage.dao.S3DaoImpl; -import com.cloud.storage.dao.SnapshotDaoImpl; -import com.cloud.storage.dao.StoragePoolDetailsDaoImpl; -import com.cloud.storage.dao.SwiftDaoImpl; -import com.cloud.storage.dao.VolumeDaoImpl; -import com.cloud.storage.s3.S3Manager; -import com.cloud.storage.secondary.SecondaryStorageVmManager; -import com.cloud.storage.swift.SwiftManager; -import com.cloud.tags.dao.ResourceTagsDaoImpl; -import com.cloud.user.AccountManager; -import com.cloud.user.ResourceLimitService; -import com.cloud.user.UserContext; -import com.cloud.user.UserContextInitializer; -import com.cloud.user.dao.AccountDao; -import com.cloud.user.dao.AccountDaoImpl; -import com.cloud.user.dao.UserDaoImpl; -import com.cloud.utils.component.SpringComponentScanUtils; -import com.cloud.utils.db.GenericDao; -import com.cloud.utils.db.GenericDaoBase; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.dao.InstanceGroupDaoImpl; -import com.cloud.vm.dao.NicDaoImpl; -import com.cloud.vm.dao.NicSecondaryIpDaoImpl; -import com.cloud.vm.dao.UserVmDao; -import com.cloud.vm.dao.VMInstanceDaoImpl; - -@Configuration -@ComponentScan(basePackageClasses = { AccountVlanMapDaoImpl.class, VolumeDaoImpl.class, HostPodDaoImpl.class, - DomainDaoImpl.class, SwiftDaoImpl.class, ServiceOfferingDaoImpl.class, VlanDaoImpl.class, - IPAddressDaoImpl.class, ResourceTagsDaoImpl.class, InstanceGroupDaoImpl.class, - UserAccountJoinDaoImpl.class, CapacityDaoImpl.class, SnapshotDaoImpl.class, HostDaoImpl.class, - VMInstanceDaoImpl.class, HostTransferMapDaoImpl.class, PortForwardingRulesDaoImpl.class, - PrivateIpDaoImpl.class, UsageEventDaoImpl.class, PodVlanMapDaoImpl.class, DiskOfferingDaoImpl.class, - DataCenterDaoImpl.class, DataCenterIpAddressDaoImpl.class, - DataCenterVnetDaoImpl.class, PodVlanDaoImpl.class, DcDetailsDaoImpl.class, NicSecondaryIpDaoImpl.class, - UserIpv6AddressDaoImpl.class, S3DaoImpl.class, UserDaoImpl.class, NicDaoImpl.class, NetworkDomainDaoImpl.class, - HostDetailsDaoImpl.class, HostTagsDaoImpl.class, ClusterDaoImpl.class, FirewallRulesDaoImpl.class, - FirewallRulesCidrsDaoImpl.class, PhysicalNetworkDaoImpl.class, PhysicalNetworkTrafficTypeDaoImpl.class, - PhysicalNetworkServiceProviderDaoImpl.class, LoadBalancerDaoImpl.class, NetworkServiceMapDaoImpl.class, - PrimaryDataStoreDaoImpl.class, StoragePoolDetailsDaoImpl.class, AffinityGroupServiceImpl.class, - ComponentContext.class, AffinityGroupProcessor.class, UserVmVO.class, EventUtils.class, UserVmVO.class - }, includeFilters = { @Filter(value = AffinityApiTestConfiguration.Library.class, type = FilterType.CUSTOM) }, useDefaultFilters = false) -public class AffinityApiTestConfiguration { - - @Bean - public AccountDao accountDao() { - return Mockito.mock(AccountDao.class); - } - - @Bean - public EventUtils eventUtils() { - return Mockito.mock(EventUtils.class); - } - - @Bean - public AffinityGroupProcessor affinityGroupProcessor() { - return Mockito.mock(AffinityGroupProcessor.class); - } - - @Bean - public ComponentContext componentContext() { - return Mockito.mock(ComponentContext.class); - } - - - @Bean - public UserContextInitializer userContextInitializer() { - return Mockito.mock(UserContextInitializer.class); - } - - @Bean - public UserVmVO userVmVO() { - return Mockito.mock(UserVmVO.class); - } - - @Bean - public AffinityGroupDao affinityGroupDao() { - return Mockito.mock(AffinityGroupDao.class); - } - - @Bean - public AffinityGroupVMMapDao affinityGroupVMMapDao() { - return Mockito.mock(AffinityGroupVMMapDao.class); - } - - @Bean - public AccountManager acctMgr() { - return Mockito.mock(AccountManager.class); - } - - @Bean - public NetworkService ntwkSvc() { - return Mockito.mock(NetworkService.class); - } - - @Bean - public NetworkModel ntwkMdl() { - return Mockito.mock(NetworkModel.class); - } - - @Bean - public AlertManager alertMgr() { - return Mockito.mock(AlertManager.class); - } - - @Bean - public SecurityChecker securityChkr() { - return Mockito.mock(SecurityChecker.class); - } - - @Bean - public ResourceLimitService resourceSvc() { - return Mockito.mock(ResourceLimitService.class); - } - - @Bean - public ProjectManager projectMgr() { - return Mockito.mock(ProjectManager.class); - } - - @Bean - public SecondaryStorageVmManager ssvmMgr() { - return Mockito.mock(SecondaryStorageVmManager.class); - } - - @Bean - public SwiftManager swiftMgr() { - return Mockito.mock(SwiftManager.class); - } - - @Bean - public S3Manager s3Mgr() { - return Mockito.mock(S3Manager.class); - } - - @Bean - public VpcManager vpcMgr() { - return Mockito.mock(VpcManager.class); - } - - @Bean - public UserVmDao userVMDao() { - return Mockito.mock(UserVmDao.class); - } - - @Bean - public RulesManager rulesMgr() { - return Mockito.mock(RulesManager.class); - } - - @Bean - public LoadBalancingRulesManager lbRulesMgr() { - return Mockito.mock(LoadBalancingRulesManager.class); - } - - @Bean - public RemoteAccessVpnService vpnMgr() { - return Mockito.mock(RemoteAccessVpnService.class); - } - - @Bean - public NetworkGuru ntwkGuru() { - return Mockito.mock(NetworkGuru.class); - } - - @Bean - public NetworkElement ntwkElement() { - return Mockito.mock(NetworkElement.class); - } - - @Bean - public IpDeployer ipDeployer() { - return Mockito.mock(IpDeployer.class); - } - - @Bean - public DhcpServiceProvider dhcpProvider() { - return Mockito.mock(DhcpServiceProvider.class); - } - - @Bean - public FirewallManager firewallMgr() { - return Mockito.mock(FirewallManager.class); - } - - @Bean - public AgentManager agentMgr() { - return Mockito.mock(AgentManager.class); - } - - @Bean - public StorageNetworkManager storageNtwkMgr() { - return Mockito.mock(StorageNetworkManager.class); - } - - @Bean - public NetworkACLManager ntwkAclMgr() { - return Mockito.mock(NetworkACLManager.class); - } - - @Bean - public Ipv6AddressManager ipv6Mgr() { - return Mockito.mock(Ipv6AddressManager.class); - } - - @Bean - public ConfigurationDao configDao() { - return Mockito.mock(ConfigurationDao.class); - } - - @Bean - public NetworkManager networkManager() { - return Mockito.mock(NetworkManager.class); - } - - @Bean - public NetworkOfferingDao networkOfferingDao() { - return Mockito.mock(NetworkOfferingDao.class); - } - - @Bean - public EventDao eventDao() { - return Mockito.mock(EventDao.class); - } - - @Bean - public NetworkDao networkDao() { - return Mockito.mock(NetworkDao.class); - } - - @Bean - public NetworkOfferingServiceMapDao networkOfferingServiceMapDao() { - return Mockito.mock(NetworkOfferingServiceMapDao.class); - } - - @Bean - public DataCenterLinkLocalIpAddressDao datacenterLinkLocalIpAddressDao() { - return Mockito.mock(DataCenterLinkLocalIpAddressDao.class); - } - - public static class Library implements TypeFilter { - - @Override - public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { - mdr.getClassMetadata().getClassName(); - ComponentScan cs = AffinityApiTestConfiguration.class.getAnnotation(ComponentScan.class); - return SpringComponentScanUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); - } - - } -} diff --git a/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java b/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java index a5e6d15bf0b..484b044e28e 100644 --- a/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java +++ b/server/test/org/apache/cloudstack/affinity/AffinityApiUnitTest.java @@ -16,22 +16,40 @@ // under the License. package org.apache.cloudstack.affinity; -import static org.junit.Assert.*; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyLong; -import static org.mockito.Mockito.*; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.when; +import java.io.IOException; import java.util.ArrayList; import java.util.List; +import javax.inject.Inject; +import javax.naming.ConfigurationException; + import org.apache.cloudstack.affinity.dao.AffinityGroupDao; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; +import org.apache.cloudstack.test.utils.SpringUtils; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.filter.TypeFilter; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; import com.cloud.event.EventUtils; import com.cloud.event.EventVO; @@ -41,6 +59,7 @@ import com.cloud.exception.ResourceInUseException; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.user.Account; import com.cloud.user.AccountManager; +import com.cloud.user.AccountService; import com.cloud.user.AccountVO; import com.cloud.user.UserContext; import com.cloud.user.dao.AccountDao; @@ -49,15 +68,12 @@ import com.cloud.vm.UserVmVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.dao.UserVmDao; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations = "classpath:/affinityContext.xml") +@ContextConfiguration(loader = AnnotationConfigContextLoader.class) public class AffinityApiUnitTest { @Inject - AffinityGroupServiceImpl _affinityService; + AffinityGroupService _affinityService; @Inject AccountManager _acctMgr; @@ -82,7 +98,7 @@ public class AffinityApiUnitTest { @Inject AccountDao _accountDao; - + @Inject EventDao _eventDao; @@ -91,7 +107,6 @@ public class AffinityApiUnitTest { @BeforeClass public static void setUp() throws ConfigurationException { - } @Before @@ -119,6 +134,7 @@ public class AffinityApiUnitTest { @Test public void createAffinityGroupTest() { + when(_groupDao.isNameInUse(anyLong(), anyLong(), eq("group1"))).thenReturn(false); AffinityGroup group = _affinityService.createAffinityGroup("user", domainId, "group1", "mock", "affinity group one"); assertNotNull("Affinity group 'group1' of type 'mock' failed to create ", group); @@ -184,4 +200,57 @@ public class AffinityApiUnitTest { _affinityService.updateVMAffinityGroups(10L, affinityGroupIds); } + @Configuration + @ComponentScan(basePackageClasses = {AffinityGroupServiceImpl.class, EventUtils.class}, includeFilters = {@Filter(value = TestConfiguration.Library.class, type = FilterType.CUSTOM)}, useDefaultFilters = false) + public static class TestConfiguration extends SpringUtils.CloudStackTestConfiguration { + + @Bean + public AccountDao accountDao() { + return Mockito.mock(AccountDao.class); + } + + @Bean + public AccountService accountService() { + return Mockito.mock(AccountService.class); + } + + @Bean + public AffinityGroupProcessor affinityGroupProcessor() { + return Mockito.mock(AffinityGroupProcessor.class); + } + + @Bean + public AffinityGroupDao affinityGroupDao() { + return Mockito.mock(AffinityGroupDao.class); + } + + @Bean + public AffinityGroupVMMapDao affinityGroupVMMapDao() { + return Mockito.mock(AffinityGroupVMMapDao.class); + } + + @Bean + public AccountManager accountManager() { + return Mockito.mock(AccountManager.class); + } + + @Bean + public EventDao eventDao() { + return Mockito.mock(EventDao.class); + } + + @Bean + public UserVmDao userVMDao() { + return Mockito.mock(UserVmDao.class); + } + + public static class Library implements TypeFilter { + + @Override + public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { + ComponentScan cs = TestConfiguration.class.getAnnotation(ComponentScan.class); + return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + } + } + } } diff --git a/server/test/org/apache/cloudstack/lb/ApplicationLoadBalancerTest.java b/server/test/org/apache/cloudstack/lb/ApplicationLoadBalancerTest.java new file mode 100644 index 00000000000..461cbbdf012 --- /dev/null +++ b/server/test/org/apache/cloudstack/lb/ApplicationLoadBalancerTest.java @@ -0,0 +1,292 @@ +// 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. +package org.apache.cloudstack.lb; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +import javax.inject.Inject; + +import junit.framework.TestCase; + +import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; +import org.apache.cloudstack.network.lb.ApplicationLoadBalancerManagerImpl; +import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.cloud.event.dao.UsageEventDao; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapcityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.UnsupportedServiceException; +import com.cloud.network.Network; +import com.cloud.network.Network.Capability; +import com.cloud.network.Network.Service; +import com.cloud.network.NetworkModel; +import com.cloud.network.Networks.TrafficType; +import com.cloud.network.dao.FirewallRulesDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.lb.LoadBalancingRule; +import com.cloud.network.lb.LoadBalancingRulesManager; +import com.cloud.network.rules.FirewallRuleVO; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.UserContext; +import com.cloud.user.UserVO; +import com.cloud.utils.component.ComponentContext; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; +import com.cloud.utils.net.NetUtils; + +/** + * This class is responsible for unittesting the methods defined in ApplicationLoadBalancerService + * + */ + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations="classpath:/appLoadBalancer.xml") +public class ApplicationLoadBalancerTest extends TestCase{ + //The interface to test + @Inject ApplicationLoadBalancerManagerImpl _appLbSvc; + + //The interfaces below are mocked + @Inject ApplicationLoadBalancerRuleDao _lbDao; + @Inject LoadBalancingRulesManager _lbMgr; + @Inject NetworkModel _ntwkModel; + @Inject AccountManager _accountMgr; + @Inject FirewallRulesDao _firewallDao; + @Inject UsageEventDao _usageEventDao; + + + public static long existingLbId = 1L; + public static long nonExistingLbId = 2L; + + public static long validGuestNetworkId = 1L; + public static long invalidGuestNetworkId = 2L; + public static long validPublicNetworkId = 3L; + + public static long validAccountId = 1L; + public static long invalidAccountId = 2L; + + public String validRequestedIp = "10.1.1.1"; + + + + @Before + public void setUp() { + ComponentContext.initComponentsLifeCycle(); + //mockito for .getApplicationLoadBalancer tests + Mockito.when(_lbDao.findById(1L)).thenReturn(new ApplicationLoadBalancerRuleVO()); + Mockito.when(_lbDao.findById(2L)).thenReturn(null); + + //mockito for .deleteApplicationLoadBalancer tests + Mockito.when(_lbMgr.deleteLoadBalancerRule(existingLbId, true)).thenReturn(true); + Mockito.when(_lbMgr.deleteLoadBalancerRule(nonExistingLbId, true)).thenReturn(false); + + //mockito for .createApplicationLoadBalancer tests + NetworkVO guestNetwork = new NetworkVO(TrafficType.Guest, null, null, 1, + null, 1, 1L); + setId(guestNetwork, validGuestNetworkId); + guestNetwork.setCidr("10.1.1.1/24"); + + NetworkVO publicNetwork = new NetworkVO(TrafficType.Public, null, null, 1, + null, 1, 1L); + + Mockito.when(_ntwkModel.getNetwork(validGuestNetworkId)).thenReturn(guestNetwork); + Mockito.when(_ntwkModel.getNetwork(invalidGuestNetworkId)).thenReturn(null); + Mockito.when(_ntwkModel.getNetwork(validPublicNetworkId)).thenReturn(publicNetwork); + + Mockito.when(_accountMgr.getAccount(validAccountId)).thenReturn(new AccountVO()); + Mockito.when(_accountMgr.getAccount(invalidAccountId)).thenReturn(null); + Mockito.when(_ntwkModel.areServicesSupportedInNetwork(validGuestNetworkId, Service.Lb)).thenReturn(true); + Mockito.when(_ntwkModel.areServicesSupportedInNetwork(invalidGuestNetworkId, Service.Lb)).thenReturn(false); + + ApplicationLoadBalancerRuleVO lbRule = new ApplicationLoadBalancerRuleVO("new", "new", 22, 22, "roundrobin", + validGuestNetworkId, validAccountId, 1L, new Ip(validRequestedIp), validGuestNetworkId, Scheme.Internal); + Mockito.when(_lbDao.persist(Mockito.any(ApplicationLoadBalancerRuleVO.class))).thenReturn(lbRule); + + Mockito.when(_lbMgr.validateLbRule(Mockito.any(LoadBalancingRule.class))).thenReturn(true); + + Mockito.when(_firewallDao.setStateToAdd(Mockito.any(FirewallRuleVO.class))).thenReturn(true); + + Mockito.when(_accountMgr.getSystemUser()).thenReturn(new UserVO(1)); + Mockito.when(_accountMgr.getSystemAccount()).thenReturn(new AccountVO(2)); + UserContext.registerContext(_accountMgr.getSystemUser().getId(), _accountMgr.getSystemAccount(), null, false); + + Mockito.when(_ntwkModel.areServicesSupportedInNetwork(Mockito.anyLong(), Mockito.any(Network.Service.class))).thenReturn(true); + + Map caps = new HashMap(); + caps.put(Capability.SupportedProtocols, NetUtils.TCP_PROTO); + Mockito.when(_ntwkModel.getNetworkServiceCapabilities(Mockito.anyLong(), Mockito.any(Network.Service.class))).thenReturn(caps); + + + Mockito.when(_lbDao.countBySourceIp(new Ip(validRequestedIp), validGuestNetworkId)).thenReturn(1L); + + } + + /** + * TESTS FOR .getApplicationLoadBalancer + */ + + @Test + //Positive test - retrieve existing lb + public void searchForExistingLoadBalancer() { + ApplicationLoadBalancerRule rule = _appLbSvc.getApplicationLoadBalancer(existingLbId); + assertNotNull("Couldn't find existing application load balancer", rule); + } + + @Test + //Negative test - try to retrieve non-existing lb + public void searchForNonExistingLoadBalancer() { + boolean notFound = false; + ApplicationLoadBalancerRule rule = null; + try { + rule = _appLbSvc.getApplicationLoadBalancer(nonExistingLbId); + if (rule != null) { + notFound = false; + } + } catch (InvalidParameterValueException ex) { + notFound = true; + } + + assertTrue("Found non-existing load balancer; no invalid parameter value exception was thrown", notFound); + } + + /** + * TESTS FOR .deleteApplicationLoadBalancer + */ + + + @Test + //Positive test - delete existing lb + public void deleteExistingLoadBalancer() { + boolean result = false; + try { + result = _appLbSvc.deleteApplicationLoadBalancer(existingLbId); + } finally { + assertTrue("Couldn't delete existing application load balancer", result); + } + } + + + @Test + //Negative test - try to delete non-existing lb + public void deleteNonExistingLoadBalancer() { + boolean result = true; + try { + result = _appLbSvc.deleteApplicationLoadBalancer(nonExistingLbId); + } finally { + assertFalse("Didn't fail when try to delete non-existing load balancer", result); + } + } + + /** + * TESTS FOR .createApplicationLoadBalancer + * @throws NetworkRuleConflictException + * @throws InsufficientVirtualNetworkCapcityException + * @throws InsufficientAddressCapacityException + */ + + @Test (expected = CloudRuntimeException.class) + //Positive test + public void createValidLoadBalancer() throws InsufficientAddressCapacityException, + InsufficientVirtualNetworkCapcityException, NetworkRuleConflictException { + _appLbSvc.createApplicationLoadBalancer("alena", "alena", Scheme.Internal, validGuestNetworkId, validRequestedIp, + 22, 22, "roundrobin", validGuestNetworkId, validAccountId); + } + + + @Test(expected = UnsupportedServiceException.class) + //Negative test - only internal scheme value is supported in the current release + public void createPublicLoadBalancer() throws InsufficientAddressCapacityException, + InsufficientVirtualNetworkCapcityException, NetworkRuleConflictException { + _appLbSvc.createApplicationLoadBalancer("alena", "alena", Scheme.Public, validGuestNetworkId, validRequestedIp, + 22, 22, "roundrobin", validGuestNetworkId, validAccountId); + } + + + @Test(expected = InvalidParameterValueException.class) + //Negative test - invalid SourcePort + public void createWithInvalidSourcePort() throws InsufficientAddressCapacityException, + InsufficientVirtualNetworkCapcityException, NetworkRuleConflictException { + _appLbSvc.createApplicationLoadBalancer("alena", "alena", Scheme.Internal, validGuestNetworkId, validRequestedIp, + 65536, 22, "roundrobin", validGuestNetworkId, validAccountId); + } + + @Test(expected = InvalidParameterValueException.class) + //Negative test - invalid instancePort + public void createWithInvalidInstandePort() throws InsufficientAddressCapacityException, + InsufficientVirtualNetworkCapcityException, NetworkRuleConflictException { + _appLbSvc.createApplicationLoadBalancer("alena", "alena", Scheme.Internal, validGuestNetworkId, validRequestedIp, + 22, 65536, "roundrobin", validGuestNetworkId, validAccountId); + + } + + + @Test(expected = InvalidParameterValueException.class) + //Negative test - invalid algorithm + public void createWithInvalidAlgorithm() throws InsufficientAddressCapacityException, InsufficientVirtualNetworkCapcityException, NetworkRuleConflictException { + String expectedExcText = null; + _appLbSvc.createApplicationLoadBalancer("alena", "alena", Scheme.Internal, validGuestNetworkId, validRequestedIp, + 22, 22, "invalidalgorithm", validGuestNetworkId, validAccountId); + + } + + @Test(expected = InvalidParameterValueException.class) + //Negative test - invalid sourceNetworkId (of Public type, which is not supported) + public void createWithInvalidSourceIpNtwk() throws InsufficientAddressCapacityException, + InsufficientVirtualNetworkCapcityException, NetworkRuleConflictException { + _appLbSvc.createApplicationLoadBalancer("alena", "alena", Scheme.Internal, validPublicNetworkId, validRequestedIp, + 22, 22, "roundrobin", validGuestNetworkId, validAccountId); + + } + + + @Test(expected = InvalidParameterValueException.class) + //Negative test - invalid requested IP (outside of guest network cidr range) + public void createWithInvalidRequestedIp() throws InsufficientAddressCapacityException, + InsufficientVirtualNetworkCapcityException, NetworkRuleConflictException { + + _appLbSvc.createApplicationLoadBalancer("alena", "alena", Scheme.Internal, validGuestNetworkId, "10.2.1.1", + 22, 22, "roundrobin", validGuestNetworkId, validAccountId); + } + + + private static NetworkVO setId(NetworkVO vo, long id) { + NetworkVO voToReturn = vo; + Class c = voToReturn.getClass(); + try { + Field f = c.getDeclaredField("id"); + f.setAccessible(true); + f.setLong(voToReturn, id); + } catch (NoSuchFieldException ex) { + return null; + } catch (IllegalAccessException ex) { + return null; + } + + return voToReturn; + } +} diff --git a/server/test/org/apache/cloudstack/lb/ChildTestConfiguration.java b/server/test/org/apache/cloudstack/lb/ChildTestConfiguration.java new file mode 100644 index 00000000000..a5b84ed6206 --- /dev/null +++ b/server/test/org/apache/cloudstack/lb/ChildTestConfiguration.java @@ -0,0 +1,105 @@ +// 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. +package org.apache.cloudstack.lb; + +import java.io.IOException; + +import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; +import org.apache.cloudstack.test.utils.SpringUtils; +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.filter.TypeFilter; + +import com.cloud.dc.dao.AccountVlanMapDaoImpl; +import com.cloud.event.dao.UsageEventDao; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkModel; +import com.cloud.network.dao.FirewallRulesDao; +import com.cloud.network.lb.LoadBalancingRulesManager; +import com.cloud.tags.dao.ResourceTagDao; +import com.cloud.user.AccountManager; +import com.cloud.utils.net.NetUtils; + + +@Configuration +@ComponentScan( + basePackageClasses={ + NetUtils.class + }, + includeFilters={@Filter(value=ChildTestConfiguration.Library.class, type=FilterType.CUSTOM)}, + useDefaultFilters=false + ) + + public class ChildTestConfiguration { + + public static class Library implements TypeFilter { + + @Bean + public ApplicationLoadBalancerRuleDao applicationLoadBalancerDao() { + return Mockito.mock(ApplicationLoadBalancerRuleDao.class); + } + + @Bean + public NetworkModel networkModel() { + return Mockito.mock(NetworkModel.class); + } + + @Bean + public AccountManager accountManager() { + return Mockito.mock(AccountManager.class); + } + + @Bean + public LoadBalancingRulesManager loadBalancingRulesManager() { + return Mockito.mock(LoadBalancingRulesManager.class); + } + + @Bean + public FirewallRulesDao firewallRulesDao() { + return Mockito.mock(FirewallRulesDao.class); + } + + @Bean + public ResourceTagDao resourceTagDao() { + return Mockito.mock(ResourceTagDao.class); + } + + @Bean + public NetworkManager networkManager() { + return Mockito.mock(NetworkManager.class); + } + + @Bean + public UsageEventDao UsageEventDao() { + return Mockito.mock(UsageEventDao.class); + } + + @Override + public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { + mdr.getClassMetadata().getClassName(); + ComponentScan cs = ChildTestConfiguration.class.getAnnotation(ComponentScan.class); + return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + } + + } +} diff --git a/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java b/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java index f1163ef35ee..6f52397251b 100644 --- a/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java +++ b/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java @@ -19,8 +19,15 @@ package org.apache.cloudstack.networkoffering; import java.io.IOException; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.dao.*; +import com.cloud.server.ConfigurationServer; +import com.cloud.user.*; import org.apache.cloudstack.acl.SecurityChecker; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; +import org.apache.cloudstack.test.utils.SpringUtils; import org.mockito.Mockito; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; @@ -37,18 +44,6 @@ import com.cloud.api.query.dao.UserAccountJoinDaoImpl; import com.cloud.capacity.dao.CapacityDaoImpl; import com.cloud.cluster.agentlb.dao.HostTransferMapDaoImpl; import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.dc.dao.AccountVlanMapDaoImpl; -import com.cloud.dc.dao.ClusterDaoImpl; -import com.cloud.dc.dao.DataCenterDaoImpl; -import com.cloud.dc.dao.DataCenterIpAddressDaoImpl; -import com.cloud.dc.dao.DataCenterLinkLocalIpAddressDao; -import com.cloud.dc.dao.DataCenterLinkLocalIpAddressDaoImpl; -import com.cloud.dc.dao.DataCenterVnetDaoImpl; -import com.cloud.dc.dao.DcDetailsDaoImpl; -import com.cloud.dc.dao.HostPodDaoImpl; -import com.cloud.dc.dao.PodVlanDaoImpl; -import com.cloud.dc.dao.PodVlanMapDaoImpl; -import com.cloud.dc.dao.VlanDaoImpl; import com.cloud.domain.dao.DomainDaoImpl; import com.cloud.event.dao.UsageEventDaoImpl; import com.cloud.host.dao.HostDaoImpl; @@ -59,6 +54,7 @@ import com.cloud.network.NetworkManager; import com.cloud.network.NetworkModel; import com.cloud.network.NetworkService; import com.cloud.network.StorageNetworkManager; +import com.cloud.network.dao.AccountGuestVlanMapDaoImpl; import com.cloud.network.dao.FirewallRulesCidrsDaoImpl; import com.cloud.network.dao.FirewallRulesDaoImpl; import com.cloud.network.dao.IPAddressDaoImpl; @@ -97,13 +93,8 @@ import com.cloud.storage.s3.S3Manager; import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.storage.swift.SwiftManager; import com.cloud.tags.dao.ResourceTagsDaoImpl; -import com.cloud.user.AccountManager; -import com.cloud.user.ResourceLimitService; -import com.cloud.user.UserContext; -import com.cloud.user.UserContextInitializer; import com.cloud.user.dao.AccountDaoImpl; import com.cloud.user.dao.UserDaoImpl; -import com.cloud.utils.component.SpringComponentScanUtils; import com.cloud.vm.dao.InstanceGroupDaoImpl; import com.cloud.vm.dao.NicDaoImpl; import com.cloud.vm.dao.NicSecondaryIpDaoImpl; @@ -156,7 +147,8 @@ import com.cloud.vm.dao.VMInstanceDaoImpl; LoadBalancerDaoImpl.class, NetworkServiceMapDaoImpl.class, PrimaryDataStoreDaoImpl.class, - StoragePoolDetailsDaoImpl.class + StoragePoolDetailsDaoImpl.class, + AccountGuestVlanMapDaoImpl.class }, includeFilters={@Filter(value=ChildTestConfiguration.Library.class, type=FilterType.CUSTOM)}, useDefaultFilters=false @@ -323,6 +315,22 @@ public class ChildTestConfiguration { public DataCenterLinkLocalIpAddressDao datacenterLinkLocalIpAddressDao() { return Mockito.mock(DataCenterLinkLocalIpAddressDao.class); } + + @Bean + public ConfigurationServer configurationServer() { + return Mockito.mock(ConfigurationServer.class); + } + + @Bean + public ClusterDetailsDao clusterDetailsDao() { + return Mockito.mock(ClusterDetailsDao.class); + } + + @Bean + public AccountDetailsDao accountDetailsDao() { + return Mockito.mock(AccountDetailsDao.class); + } + public static class Library implements TypeFilter { @@ -330,7 +338,7 @@ public class ChildTestConfiguration { public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { mdr.getClassMetadata().getClassName(); ComponentScan cs = ChildTestConfiguration.class.getAnnotation(ComponentScan.class); - return SpringComponentScanUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); } } diff --git a/server/test/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java b/server/test/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java index cbb6c00e397..92aa2a2c8ff 100644 --- a/server/test/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java +++ b/server/test/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java @@ -41,6 +41,7 @@ import com.cloud.network.Network; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.Networks.TrafficType; +import com.cloud.network.vpc.VpcManager; import com.cloud.offering.NetworkOffering.Availability; import com.cloud.offerings.NetworkOfferingServiceMapVO; import com.cloud.offerings.NetworkOfferingVO; @@ -72,6 +73,9 @@ public class CreateNetworkOfferingTest extends TestCase{ @Inject AccountManager accountMgr; + @Inject + VpcManager vpcMgr; + @Before public void setUp() { ComponentContext.initComponentsLifeCycle(); @@ -80,6 +84,7 @@ public class CreateNetworkOfferingTest extends TestCase{ Mockito.when(configDao.findByName(Mockito.anyString())).thenReturn(configVO); Mockito.when(offDao.persist(Mockito.any(NetworkOfferingVO.class))).thenReturn(new NetworkOfferingVO()); + Mockito.when(offDao.persist(Mockito.any(NetworkOfferingVO.class), Mockito.anyMap())).thenReturn(new NetworkOfferingVO()); Mockito.when(mapDao.persist(Mockito.any(NetworkOfferingServiceMapVO.class))).thenReturn(new NetworkOfferingServiceMapVO()); Mockito.when(accountMgr.getSystemUser()).thenReturn(new UserVO(1)); Mockito.when(accountMgr.getSystemAccount()).thenReturn(new AccountVO(2)); @@ -92,7 +97,7 @@ public class CreateNetworkOfferingTest extends TestCase{ public void createSharedNtwkOffWithVlan() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, - null, false, null, true, false); + null, false, null, true, false, null); assertNotNull("Shared network offering with specifyVlan=true failed to create ", off); } @@ -101,7 +106,7 @@ public class CreateNetworkOfferingTest extends TestCase{ try { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, false, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, - null, false, null, true, false); + null, false, null, true, false, null); assertNull("Shared network offering with specifyVlan=false was created", off); } catch (InvalidParameterValueException ex) { } @@ -111,7 +116,7 @@ public class CreateNetworkOfferingTest extends TestCase{ public void createSharedNtwkOffWithSpecifyIpRanges() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, - null, false, null, true, false); + null, false, null, true, false, null); assertNotNull("Shared network offering with specifyIpRanges=true failed to create ", off); } @@ -121,7 +126,7 @@ public class CreateNetworkOfferingTest extends TestCase{ try { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, - null, false, null, false, false); + null, false, null, false, false, null); assertNull("Shared network offering with specifyIpRanges=false was created", off); } catch (InvalidParameterValueException ex) { } @@ -136,7 +141,7 @@ public class CreateNetworkOfferingTest extends TestCase{ serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, Network.GuestType.Isolated, false, - null, false, null, false, false); + null, false, null, false, false, null); assertNotNull("Isolated network offering with specifyIpRanges=false failed to create ", off); } @@ -149,7 +154,7 @@ public class CreateNetworkOfferingTest extends TestCase{ serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, Network.GuestType.Isolated, false, - null, false, null, false, false); + null, false, null, false, false, null); assertNotNull("Isolated network offering with specifyVlan=true wasn't created", off); } @@ -163,7 +168,7 @@ public class CreateNetworkOfferingTest extends TestCase{ serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, Network.GuestType.Isolated, false, - null, false, null, true, false); + null, false, null, true, false, null); assertNull("Isolated network offering with specifyIpRanges=true and source nat service enabled, was created", off); } catch (InvalidParameterValueException ex) { } @@ -176,8 +181,47 @@ public class CreateNetworkOfferingTest extends TestCase{ Set vrProvider = new HashSet(); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, Network.GuestType.Isolated, false, - null, false, null, true, false); + null, false, null, true, false, null); assertNotNull("Isolated network offering with specifyIpRanges=true and with no sourceNatService, failed to create", off); } + + @Test + public void createVpcNtwkOff() { + Map> serviceProviderMap = new HashMap>(); + Set vrProvider = new HashSet(); + vrProvider.add(Provider.VPCVirtualRouter); + serviceProviderMap.put(Network.Service.Dhcp , vrProvider); + serviceProviderMap.put(Network.Service.Dns , vrProvider); + serviceProviderMap.put(Network.Service.Lb , vrProvider); + serviceProviderMap.put(Network.Service.SourceNat , vrProvider); + serviceProviderMap.put(Network.Service.Gateway , vrProvider); + serviceProviderMap.put(Network.Service.Lb , vrProvider); + NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, + Availability.Optional, 200, serviceProviderMap, false, Network.GuestType.Isolated, false, + null, false, null, false, false, null); + // System.out.println("Creating Vpc Network Offering"); + assertNotNull("Vpc Isolated network offering with Vpc provider ", off); + } + + @Test + public void createVpcNtwkOffWithNetscaler() { + Map> serviceProviderMap = new HashMap>(); + Set vrProvider = new HashSet(); + Set lbProvider = new HashSet(); + vrProvider.add(Provider.VPCVirtualRouter); + lbProvider.add(Provider.Netscaler); + serviceProviderMap.put(Network.Service.Dhcp, vrProvider); + serviceProviderMap.put(Network.Service.Dns, vrProvider); + serviceProviderMap.put(Network.Service.Lb, vrProvider); + serviceProviderMap.put(Network.Service.SourceNat, vrProvider); + serviceProviderMap.put(Network.Service.Gateway, vrProvider); + serviceProviderMap.put(Network.Service.Lb, lbProvider); + NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, + Availability.Optional, 200, serviceProviderMap, false, Network.GuestType.Isolated, false, null, false, + null, false, false, null); + // System.out.println("Creating Vpc Network Offering"); + assertNotNull("Vpc Isolated network offering with Vpc and Netscaler provider ", off); + } + } diff --git a/server/test/resources/affinityContext.xml b/server/test/resources/appLoadBalancer.xml similarity index 67% rename from server/test/resources/affinityContext.xml rename to server/test/resources/appLoadBalancer.xml index 15476c1a1b3..d7c1502a715 100644 --- a/server/test/resources/affinityContext.xml +++ b/server/test/resources/appLoadBalancer.xml @@ -23,25 +23,21 @@ - - - - - - - - - - - - - + + - - + + + + + + + + + + - + - - \ No newline at end of file + diff --git a/services/console-proxy/plugin/pom.xml b/services/console-proxy/plugin/pom.xml index 4cbe6d1c8f4..55db33bd951 100644 --- a/services/console-proxy/plugin/pom.xml +++ b/services/console-proxy/plugin/pom.xml @@ -20,16 +20,10 @@ 4.0.0 cloud-plugin-console-proxy Apache CloudStack Console Proxy Plugin - pom org.apache.cloudstack - cloud-service-console-proxy + cloudstack-service-console-proxy 4.2.0-SNAPSHOT ../pom.xml - - install - src - test - diff --git a/services/console-proxy/pom.xml b/services/console-proxy/pom.xml index 1453e8cc264..3aac7b25a80 100644 --- a/services/console-proxy/pom.xml +++ b/services/console-proxy/pom.xml @@ -18,12 +18,12 @@ --> 4.0.0 - cloud-service-console-proxy + cloudstack-service-console-proxy Apache CloudStack Console Proxy Service pom org.apache.cloudstack - cloud-services + cloudstack-services 4.2.0-SNAPSHOT ../pom.xml diff --git a/services/console-proxy/server/css/ajaxviewer.css b/services/console-proxy/server/css/ajaxviewer.css index 5ea552b176f..fd2fb3c44e9 100644 --- a/services/console-proxy/server/css/ajaxviewer.css +++ b/services/console-proxy/server/css/ajaxviewer.css @@ -91,12 +91,12 @@ body { position: absolute; top:32; width: 260; - height: 65; + height: 95; display: block; display: none; border-top: 1px solid black; - background-image:url(/resource/images/back.gif); - background-repeat:repeat-x repeat-y; + background-image:url(/resource/images/back.gif); + background-repeat:repeat-x repeat-y; } #toolbar ul li ul li { diff --git a/services/console-proxy/server/js/ajaxkeys.js b/services/console-proxy/server/js/ajaxkeys.js index 2ecf5b561e0..5f497bbb785 100644 --- a/services/console-proxy/server/js/ajaxkeys.js +++ b/services/console-proxy/server/js/ajaxkeys.js @@ -23,55 +23,306 @@ under the License. * They are used by the ajaxviewer.js */ -//client event type. corresponds to events in ajaxviewer. -X11_KEY_CIRCUMFLEX_ACCENT = 0x5e; // ^ -X11_KEY_YEN_MARK = 0xa5; +//client event type. corresponds to events in ajaxviewer. + + +//use java AWT key modifier masks +JS_KEY_BACKSPACE = 8; +JS_KEY_TAB = 9; +JS_KEY_ENTER = 13; +JS_KEY_SHIFT = 16; +JS_KEY_CTRL = 17; +JS_KEY_ALT = 18; +JS_KEY_CAPSLOCK = 20; +JS_KEY_ESCAPE = 27; +JS_KEY_PAGEUP = 33; +JS_KEY_PAGEDOWN = 34; +JS_KEY_END = 35; +JS_KEY_HOME = 36; +JS_KEY_LEFT = 37; +JS_KEY_UP = 38; +JS_KEY_RIGHT = 39; +JS_KEY_DOWN = 40; +JS_KEY_INSERT = 45; +JS_KEY_DELETE = 46; +JS_KEY_SELECT_KEY = 93; +JS_KEY_NUMPAD0 = 96; +JS_KEY_NUMPAD1 = 97; +JS_KEY_NUMPAD2 = 98; +JS_KEY_NUMPAD3 = 99; +JS_KEY_NUMPAD4 = 100; +JS_KEY_NUMPAD5 = 101; +JS_KEY_NUMPAD6 = 102; +JS_KEY_NUMPAD7 = 103; +JS_KEY_NUMPAD8 = 104; +JS_KEY_NUMPAD9 = 105; +JS_KEY_MULTIPLY = 106; +JS_KEY_ADD = 107; +JS_KEY_SUBSTRACT = 109; +JS_KEY_DECIMAL_POINT = 110; +JS_KEY_DIVIDE = 111; +JS_KEY_F1 = 112; +JS_KEY_F2 = 113; +JS_KEY_F3 = 114; +JS_KEY_F4 = 115; +JS_KEY_F5 = 116; +JS_KEY_F6 = 117; +JS_KEY_F7 = 118; +JS_KEY_F8 = 119; +JS_KEY_F9 = 120; +JS_KEY_F10 = 121; +JS_KEY_F11 = 122; +JS_KEY_F12 = 123; +JS_KEY_SEMI_COLON = 186; // ; +JS_KEY_COMMA = 188; // , +JS_KEY_DASH = 189; // - +JS_KEY_PERIOD = 190; // . +JS_KEY_FORWARD_SLASH = 191; // / +JS_KEY_GRAVE_ACCENT = 192; // ` +JS_KEY_OPEN_BRACKET = 219; // [ +JS_KEY_BACK_SLASH = 220; // \ +JS_KEY_CLOSE_BRACKET = 221; // ] +JS_KEY_SINGLE_QUOTE = 222; // ' + + +//X11 keysym definitions +X11_KEY_CAPSLOCK = 0xffe5; +X11_KEY_BACKSPACE = 0xff08; +X11_KEY_TAB = 0xff09; +X11_KEY_ENTER = 0xff0d; +X11_KEY_ESCAPE = 0xff1b; +X11_KEY_INSERT = 0xff63; +X11_KEY_DELETE = 0xffff; +X11_KEY_HOME = 0xff50; +X11_KEY_END = 0xff57; +X11_KEY_PAGEUP = 0xff55; +X11_KEY_PAGEDOWN = 0xff56; +X11_KEY_LEFT = 0xff51; +X11_KEY_UP = 0xff52; +X11_KEY_RIGHT = 0xff53; +X11_KEY_DOWN = 0xff54; +X11_KEY_F1 = 0xffbe; +X11_KEY_F2 = 0xffbf; +X11_KEY_F3 = 0xffc0; +X11_KEY_F4 = 0xffc1; +X11_KEY_F5 = 0xffc2; +X11_KEY_F6 = 0xffc3; +X11_KEY_F7 = 0xffc4; +X11_KEY_F8 = 0xffc5; +X11_KEY_F9 = 0xffc6; +X11_KEY_F10 = 0xffc7; +X11_KEY_F11 = 0xffc8; +X11_KEY_F12 = 0xffc9; +X11_KEY_SHIFT = 0xffe1; +X11_KEY_CTRL = 0xffe3; +X11_KEY_ALT = 0xffe9; +X11_KEY_GRAVE_ACCENT = 0x60; +X11_KEY_SUBSTRACT = 0x2d; +X11_KEY_ADD = 0x2b; X11_KEY_OPEN_BRACKET = 0x5b; X11_KEY_CLOSE_BRACKET = 0x5d; +X11_KEY_BACK_SLASH = 0x7c; +X11_KEY_REVERSE_SOLIUS = 0x5c; // another back slash (back slash on JP keyboard) +X11_KEY_SINGLE_QUOTE = 0x22; +X11_KEY_COMMA = 0x3c; +X11_KEY_PERIOD = 0x3e; +X11_KEY_FORWARD_SLASH = 0x3f; +X11_KEY_DASH = 0x2d; X11_KEY_COLON = 0x3a; -X11_KEY_REVERSE_SOLIUS = 0x5c; // another back slash (back slash on JP keyboard) -X11_KEY_CAPSLOCK = 0xffe5; X11_KEY_SEMI_COLON = 0x3b; -X11_KEY_SHIFT = 0xffe1; -X11_KEY_ADD = 0x2b; +X11_KEY_NUMPAD0 = 0x30; +X11_KEY_NUMPAD1 = 0x31; +X11_KEY_NUMPAD2 = 0x32; +X11_KEY_NUMPAD3 = 0x33; +X11_KEY_NUMPAD4 = 0x34; +X11_KEY_NUMPAD5 = 0x35; +X11_KEY_NUMPAD6 = 0x36; +X11_KEY_NUMPAD7 = 0x37; +X11_KEY_NUMPAD8 = 0x38; +X11_KEY_NUMPAD9 = 0x39; +X11_KEY_DECIMAL_POINT = 0x2e; +X11_KEY_DIVIDE = 0x3f; +X11_KEY_TILDE = 0x7e; // ~ +X11_KEY_CIRCUMFLEX_ACCENT = 0x5e; // ^ +X11_KEY_YEN_MARK = 0xa5; // Japanese YEN mark +X11_KEY_ASTERISK = 0x2a; KEY_DOWN = 5; KEY_UP = 6; +KEYBOARD_TYPE_COOKED = "us"; +KEYBOARD_TYPE_JP = "jp"; +KEYBOARD_TYPE_UK = "uk"; + //JP keyboard type -// + var keyboardTables = [ - {tindex: 0, keyboardType: "EN-Cooked", mappingTable: - {X11: [ {keycode: 222, entry: X11_KEY_CIRCUMFLEX_ACCENT}, + {tindex: 0, keyboardType: KEYBOARD_TYPE_COOKED, mappingTable: + {X11: [ {keycode: 222, entry: X11_KEY_CIRCUMFLEX_ACCENT}, {keycode: 220, entry: X11_KEY_YEN_MARK}, - {keycode: 219, entry: X11_KEY_OPEN_BRACKET}, - {keycode: 221, entry: X11_KEY_CLOSE_BRACKET}, - {keycode: 59, entry: X11_KEY_COLON, browser: "Firefox"}, {keycode: 186, entry: X11_KEY_COLON, browser: "Chrome"}, {keycode: 9, entry: 9, guestos: "XenServer"}, {keycode: 226, entry: X11_KEY_REVERSE_SOLIUS}, + {keycode: 240, entry: [ {type: KEY_DOWN, code: X11_KEY_CAPSLOCK, modifiers: 0 }, {type: KEY_UP, code: X11_KEY_CAPSLOCK, modifiers: 0 }, ] + } + ], + keyPress: [ + {keycode: 59, entry: [ + {type: KEY_DOWN, code: X11_KEY_SEMI_COLON, modifiers: 0 }, + {type: KEY_UP, code: X11_KEY_SEMI_COLON, modifiers: 0 }, + ] }, - ], - keyPress: [ - {keycode: 59, entry: [ - {type: KEY_DOWN, code: X11_KEY_SEMI_COLON, modifiers: 0 }, - {type: KEY_UP, code: X11_KEY_SEMI_COLON, modifiers: 0 }, - ] - }, - {keycode: 43, entry: [ - {type: KEY_DOWN, code: X11_KEY_SHIFT, modifiers: 0, shift: false }, - {type: KEY_DOWN, code: X11_KEY_ADD, modifiers: 0, shift: false }, - {type: KEY_UP, code: X11_KEY_ADD, modifiers: 0, shift: false }, - {type: KEY_UP, code: X11_KEY_SHIFT, modifiers: 0, shift: false }, - {type: KEY_DOWN, code: X11_KEY_ADD, modifiers: 0, shift: true }, - {type: KEY_UP, code: X11_KEY_ADD, modifiers: 0, shift: true }, - ] - }, - ] - } - } ] - + {keycode: 43, entry: [ + {type: KEY_DOWN, code: X11_KEY_SHIFT, modifiers: 0, shift: false }, + {type: KEY_DOWN, code: X11_KEY_ADD, modifiers: 0, shift: false }, + {type: KEY_UP, code: X11_KEY_ADD, modifiers: 0, shift: false }, + {type: KEY_UP, code: X11_KEY_SHIFT, modifiers: 0, shift: false }, + {type: KEY_DOWN, code: X11_KEY_ADD, modifiers: 0, shift: true }, + {type: KEY_UP, code: X11_KEY_ADD, modifiers: 0, shift: true }, + ] + } + ] + } + }, {tindex: 1, keyboardType: KEYBOARD_TYPE_JP, mappingTable: + // intialize keyboard mapping for RAW keyboard + {X11: [ + {keycode: JS_KEY_CAPSLOCK, entry : X11_KEY_CAPSLOCK}, + {keycode: JS_KEY_BACKSPACE, entry : X11_KEY_BACKSPACE}, + {keycode: JS_KEY_TAB, entry : X11_KEY_TAB}, + {keycode: JS_KEY_ENTER, entry : X11_KEY_ENTER}, + {keycode: JS_KEY_ESCAPE, entry : X11_KEY_ESCAPE}, + {keycode: JS_KEY_INSERT, entry : X11_KEY_INSERT}, + {keycode: JS_KEY_DELETE, entry : X11_KEY_DELETE}, + {keycode: JS_KEY_HOME, entry : X11_KEY_HOME}, + {keycode: JS_KEY_END, entry : X11_KEY_END}, + {keycode: JS_KEY_PAGEUP, entry : X11_KEY_PAGEUP}, + {keycode: JS_KEY_PAGEDOWN, entry : X11_KEY_PAGEDOWN}, + {keycode: JS_KEY_LEFT, entry : X11_KEY_LEFT}, + {keycode: JS_KEY_UP, entry : X11_KEY_UP}, + {keycode: JS_KEY_RIGHT, entry : X11_KEY_RIGHT}, + {keycode: JS_KEY_DOWN, entry : X11_KEY_DOWN}, + {keycode: JS_KEY_F1, entry : X11_KEY_F1}, + {keycode: JS_KEY_F2, entry : X11_KEY_F2}, + {keycode: JS_KEY_F3, entry : X11_KEY_F3}, + {keycode: JS_KEY_F4, entry : X11_KEY_F4}, + {keycode: JS_KEY_F5, entry : X11_KEY_F5}, + {keycode: JS_KEY_F6, entry : X11_KEY_F6}, + {keycode: JS_KEY_F7, entry : X11_KEY_F7}, + {keycode: JS_KEY_F8, entry : X11_KEY_F8}, + {keycode: JS_KEY_F9, entry : X11_KEY_F9}, + {keycode: JS_KEY_F10, entry : X11_KEY_F10}, + {keycode: JS_KEY_F11, entry : X11_KEY_F11}, + {keycode: JS_KEY_F12, entry : X11_KEY_F12}, + {keycode: JS_KEY_SHIFT, entry : X11_KEY_SHIFT}, + {keycode: JS_KEY_CTRL, entry : X11_KEY_CTRL}, + {keycode: JS_KEY_ALT, entry : X11_KEY_ALT}, + //{keycode: JS_KEY_GRAVE_ACCENT, entry : X11_KEY_GRAVE_ACCENT}, + //[192 / 64 = "' @"] + {keycode: 192, entry : 0x5b, browser: "IE"}, + {keycode: 64, entry : 0x5b, browser: "Firefox"}, + //{keycode: JS_KEY_ADD, entry : X11_KEY_ADD}, + //[187 / 59 = "; +"] + {keycode: 187, entry : 0x3a, browser: "IE"}, + {keycode: 59, entry : 0x3b, browser: "Firefox"}, + //{keycode: JS_KEY_OPEN_BRACKET, entry : X11_KEY_OPEN_BRACKET}, + //[219 = "[{"] + {keycode: 219, entry : 0x5d, browser: "IE"}, + {keycode: 219, entry : 0x5d, browser: "Firefox"}, + //{keycode: JS_KEY_CLOSE_BRACKET, entry : X11_KEY_CLOSE_BRACKET}, + //[221 = "]}"] + {keycode: 221, entry : 0x5c, browser: "IE"}, + {keycode: 221, entry : 0x5c, browser: "Firefox"}, + {keycode: JS_KEY_BACK_SLASH, entry : X11_KEY_BACK_SLASH}, + //{keycode: JS_KEY_SINGLE_QUOTE, entry : X11_KEY_SINGLE_QUOTE}, + //[222 / 160 = "~^"] + {keycode: 222, entry : 0x3d, browser: "IE"}, + {keycode: 160, entry : 0x3d, browser: "Firefox"}, + //[173 = "-=" ] specific to Firefox browser + {keycode: 173, entry : 0x2d, browser: "Firefox"}, + {keycode: JS_KEY_COMMA, entry : X11_KEY_COMMA}, + {keycode: JS_KEY_PERIOD, entry : X11_KEY_PERIOD}, + {keycode: JS_KEY_FORWARD_SLASH, entry : X11_KEY_FORWARD_SLASH}, + {keycode: JS_KEY_DASH, entry : X11_KEY_DASH}, + {keycode: JS_KEY_SEMI_COLON, entry : X11_KEY_SEMI_COLON}, + {keycode: JS_KEY_NUMPAD0, entry : X11_KEY_NUMPAD0}, + {keycode: JS_KEY_NUMPAD1, entry : X11_KEY_NUMPAD1}, + {keycode: JS_KEY_NUMPAD2, entry : X11_KEY_NUMPAD2}, + {keycode: JS_KEY_NUMPAD3, entry : X11_KEY_NUMPAD3}, + {keycode: JS_KEY_NUMPAD4, entry : X11_KEY_NUMPAD4}, + {keycode: JS_KEY_NUMPAD5, entry : X11_KEY_NUMPAD5}, + {keycode: JS_KEY_NUMPAD6, entry : X11_KEY_NUMPAD6}, + {keycode: JS_KEY_NUMPAD7, entry : X11_KEY_NUMPAD7}, + {keycode: JS_KEY_NUMPAD8, entry : X11_KEY_NUMPAD8}, + {keycode: JS_KEY_NUMPAD9, entry : X11_KEY_NUMPAD9}, + {keycode: JS_KEY_DECIMAL_POINT, entry : X11_KEY_DECIMAL_POINT}, + {keycode: JS_KEY_DIVIDE, entry : 0xffaf}, + {keycode: JS_KEY_MULTIPLY, entry : 0xffaa}, + {keycode: JS_KEY_ADD, entry : 0xffab}, + {keycode: JS_KEY_SUBSTRACT, entry : 0xffad}, + //Kanji Key = 243 / 244 + {keycode: 243, entry : 0x7e, browser: "IE"}, + {keycode: 244, entry : 0x7e, browser: "IE"}, + //Caps Lock = 240 + {keycode: 240, entry : 0xffe5}, + /* + {keycode: JS_KEY_MULTIPLY, entry : [ + {type: KEY_DOWN, code: X11_KEY_SHIFT, modifiers: 0 }, + {type: KEY_DOWN, code: X11_KEY_ASTERISK, modifiers: 0 }, + {type: KEY_UP, code: X11_KEY_ASTERISK, modifiers: 0 }, + {type: KEY_UP, code: X11_KEY_SHIFT, modifiers: 0 } + ]}, + {keycode: JS_KEY_ADD, entry : false} + */ + //[186 / 58 = "~^"] + {keycode: 186, entry : 0x22, browser: "IE"}, + {keycode: 58, entry : 0x22, browser: "Firefox"}, + ], + keyPress: [ + {keycode: 61, entry: [ + {type: KEY_DOWN, code: X11_KEY_ADD, modifiers: 0, shift: false }, + {type: KEY_UP, code: X11_KEY_ADD, modifiers: 0, shift: false } + ]}, + ] + } + }, {tindex: 2, keyboardType: KEYBOARD_TYPE_UK, mappingTable: + {X11: [], + keyPress: [ + //[34 = "] + {keycode: 34, entry: + [{type : KEY_DOWN, code : 0x40, modifiers : 64, shift : true}] + }, + //[35 = #] + {keycode: 35, entry: + [{type : KEY_DOWN, code : 0x5c, modifiers : 0, shift : false}] + }, + // [64 = @] + {keycode: 64, entry: + [{type : KEY_DOWN, code : 0x22, modifiers : 64, shift : true}] + }, + // [92 = \] + {keycode: 92, entry: + [{type : KEY_DOWN, code : 0xa6, modifiers : 0, shift : false}] + }, + // [126 = ~] + {keycode: 126, entry: + [{type : KEY_DOWN, code : 0x7c, modifiers : 64, shift : true}] + }, + // [163 = £] + {keycode: 163, entry: + [{type : KEY_DOWN, code : 0x23, modifiers : 64, shift : true}] + }, + // [172 = ¬] + {keycode: 172, entry: + [{type : KEY_DOWN, code : 0x7e, modifiers : 64, shift : true}] + }, + // [166 = ¦] + {keycode: 166, entry: + [{type : KEY_DOWN, code : 0x60, modifiers : 896, shift : false}] + } + ] + } + }] diff --git a/services/console-proxy/server/js/ajaxviewer.js b/services/console-proxy/server/js/ajaxviewer.js index e95615d8946..a6e1edafaea 100644 --- a/services/console-proxy/server/js/ajaxviewer.js +++ b/services/console-proxy/server/js/ajaxviewer.js @@ -99,92 +99,13 @@ function KeyboardMapper() { // KeyboardMapper.KEYBOARD_TYPE_RAW = 0; KeyboardMapper.KEYBOARD_TYPE_COOKED = 1; +KeyboardMapper.KEYBOARD_TYPE_UK = 2; KeyboardMapper.prototype = { - + setKeyboardType : function(keyboardType) { this.keyboardType = keyboardType; - - if(keyboardType == KeyboardMapper.KEYBOARD_TYPE_RAW) { - // intialize keyboard mapping for RAW keyboard - this.jsX11KeysymMap[AjaxViewer.JS_KEY_CAPSLOCK] = AjaxViewer.X11_KEY_CAPSLOCK; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_BACKSPACE] = AjaxViewer.X11_KEY_BACKSPACE; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_TAB] = AjaxViewer.X11_KEY_TAB; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_ENTER] = AjaxViewer.X11_KEY_ENTER; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_ESCAPE] = AjaxViewer.X11_KEY_ESCAPE; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_INSERT] = AjaxViewer.X11_KEY_INSERT; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_DELETE] = AjaxViewer.X11_KEY_DELETE; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_HOME] = AjaxViewer.X11_KEY_HOME; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_END] = AjaxViewer.X11_KEY_END; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_PAGEUP] = AjaxViewer.X11_KEY_PAGEUP; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_PAGEDOWN] = AjaxViewer.X11_KEY_PAGEDOWN; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_LEFT] = AjaxViewer.X11_KEY_LEFT; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_UP] = AjaxViewer.X11_KEY_UP; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_RIGHT] = AjaxViewer.X11_KEY_RIGHT; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_DOWN] = AjaxViewer.X11_KEY_DOWN; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_F1] = AjaxViewer.X11_KEY_F1; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_F2] = AjaxViewer.X11_KEY_F2; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_F3] = AjaxViewer.X11_KEY_F3; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_F4] = AjaxViewer.X11_KEY_F4; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_F5] = AjaxViewer.X11_KEY_F5; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_F6] = AjaxViewer.X11_KEY_F6; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_F7] = AjaxViewer.X11_KEY_F7; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_F8] = AjaxViewer.X11_KEY_F8; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_F9] = AjaxViewer.X11_KEY_F9; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_F10] = AjaxViewer.X11_KEY_F10; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_F11] = AjaxViewer.X11_KEY_F11; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_F12] = AjaxViewer.X11_KEY_F12; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_SHIFT] = AjaxViewer.X11_KEY_SHIFT; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_CTRL] = AjaxViewer.X11_KEY_CTRL; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_ALT] = AjaxViewer.X11_KEY_ALT; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_GRAVE_ACCENT] = AjaxViewer.X11_KEY_GRAVE_ACCENT; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_SUBSTRACT] = AjaxViewer.X11_KEY_SUBSTRACT; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_ADD] = AjaxViewer.X11_KEY_ADD; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_OPEN_BRACKET] = AjaxViewer.X11_KEY_OPEN_BRACKET; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_CLOSE_BRACKET] = AjaxViewer.X11_KEY_CLOSE_BRACKET; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_BACK_SLASH] = AjaxViewer.X11_KEY_BACK_SLASH; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_SINGLE_QUOTE] = AjaxViewer.X11_KEY_SINGLE_QUOTE; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_COMMA] = AjaxViewer.X11_KEY_COMMA; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_PERIOD] = AjaxViewer.X11_KEY_PERIOD; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_FORWARD_SLASH] = AjaxViewer.X11_KEY_FORWARD_SLASH; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_DASH] = AjaxViewer.X11_KEY_DASH; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_SEMI_COLON] = AjaxViewer.X11_KEY_SEMI_COLON; - - this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD0] = AjaxViewer.X11_KEY_NUMPAD0; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD1] = AjaxViewer.X11_KEY_NUMPAD1; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD2] = AjaxViewer.X11_KEY_NUMPAD2; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD3] = AjaxViewer.X11_KEY_NUMPAD3; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD4] = AjaxViewer.X11_KEY_NUMPAD4; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD5] = AjaxViewer.X11_KEY_NUMPAD5; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD6] = AjaxViewer.X11_KEY_NUMPAD6; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD7] = AjaxViewer.X11_KEY_NUMPAD7; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD8] = AjaxViewer.X11_KEY_NUMPAD8; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD9] = AjaxViewer.X11_KEY_NUMPAD9; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_DECIMAL_POINT] = AjaxViewer.X11_KEY_DECIMAL_POINT; - this.jsX11KeysymMap[AjaxViewer.JS_KEY_DIVIDE] = AjaxViewer.X11_KEY_DIVIDE; - - this.jsX11KeysymMap[AjaxViewer.JS_KEY_MULTIPLY] = [ - {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_SHIFT, modifiers: 0 }, - {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_ASTERISK, modifiers: 0 }, - {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_ASTERISK, modifiers: 0 }, - {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_SHIFT, modifiers: 0 } - ]; - - this.jsX11KeysymMap[AjaxViewer.JS_KEY_ADD] = false; - this.jsKeyPressX11KeysymMap = []; - this.jsKeyPressX11KeysymMap[61] = [ - {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: false }, - {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: false } - ]; - this.jsKeyPressX11KeysymMap[43] = [ - {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_SHIFT, modifiers: 0, shift: false }, - {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: false }, - {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: false }, - {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_SHIFT, modifiers: 0, shift: false }, - {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: true }, - {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: true } - ]; - } else { + if(keyboardType == KeyboardMapper.KEYBOARD_TYPE_COOKED || keyboardType == KeyboardMapper.KEYBOARD_TYPE_UK) { // initialize mapping for COOKED keyboard this.jsX11KeysymMap[AjaxViewer.JS_KEY_CAPSLOCK] = AjaxViewer.X11_KEY_CAPSLOCK; this.jsX11KeysymMap[AjaxViewer.JS_KEY_BACKSPACE] = AjaxViewer.X11_KEY_BACKSPACE; @@ -325,7 +246,6 @@ KeyboardMapper.prototype = { // ENTER/BACKSPACE key should already have been sent through KEY DOWN/KEY UP event if(code == AjaxViewer.JS_KEY_ENTER || code == AjaxViewer.JS_KEY_BACKSPACE) return; - if(code > 0) { var X11Keysym = code; X11Keysym = this.jsKeyPressX11KeysymMap[code]; @@ -475,6 +395,7 @@ AjaxViewer.STATUS_SENDING = 3; AjaxViewer.STATUS_SENT = 4; AjaxViewer.KEYBOARD_TYPE_ENGLISH = "us"; +AjaxViewer.KEYBOARD_TYPE_UK_ENGLISH = "uk"; AjaxViewer.KEYBOARD_TYPE_JAPANESE = "jp"; AjaxViewer.JS_KEY_BACKSPACE = 8; @@ -736,6 +657,10 @@ AjaxViewer.prototype = { this.keyboardMappers[AjaxViewer.KEYBOARD_TYPE_ENGLISH] = mapper; mapper.setKeyboardType(KeyboardMapper.KEYBOARD_TYPE_COOKED); + var mapper = new KeyboardMapper(); + this.keyboardMappers[AjaxViewer.KEYBOARD_TYPE_UK_ENGLISH] = mapper; + mapper.setKeyboardType(KeyboardMapper.KEYBOARD_TYPE_UK); + mapper = new KeyboardMapper(); this.keyboardMappers[AjaxViewer.KEYBOARD_TYPE_JAPANESE] = mapper; mapper.setKeyboardType(KeyboardMapper.KEYBOARD_TYPE_RAW); @@ -795,25 +720,25 @@ AjaxViewer.prototype = { */ // create the mapping table based on the tables input - if (keyboardTables != undefined ) { + if (keyboardTables != undefined ) { - for(var i = 0; i < keyboardTables.length; i++) { - var mappingTbl = keyboardTables[i]; - var mappings = mappingTbl.mappingTable; - var x11Maps = mappings.X11; - for (var j = 0; j < x11Maps.length; j++) { - var code = x11Maps[j].keycode; - var mappedEntry = x11Maps[j].entry; - mapper.jsX11KeysymMap[code] = mappedEntry; + for(var i = 0; i < keyboardTables.length; i++) { + var mappingTbl = keyboardTables[i]; + var keyboardType = mappingTbl.keyboardType; + var mappings = mappingTbl.mappingTable; + var x11Maps = mappings.X11; + for (var j = 0; j < x11Maps.length; j++) { + var code = x11Maps[j].keycode; + var mappedEntry = x11Maps[j].entry; + this.keyboardMappers[keyboardType].jsX11KeysymMap[code] = mappedEntry; + } + var keyPressMaps = mappings.keyPress; + for (var j = 0; j < keyPressMaps.length; j++) { + var code = keyPressMaps[j].keycode; + var mappedEntry = keyPressMaps[j].entry; + this.keyboardMappers[keyboardType].jsKeyPressX11KeysymMap[code] = mappedEntry; + } } - var keyPressMaps = mappings.keyPress; - for (var j = 0; j < keyPressMaps.length; j++) { - var code = keyPressMaps[j].keycode; - var mappedEntry = keyPressMaps[j].entry; - mapper.jsKeyPressX11KeysymMap[code] = mappedEntry; - } - - } } }, // end of the setupKeyboardTranslationTable function @@ -867,6 +792,9 @@ AjaxViewer.prototype = { } else if(cmd == "keyboard_us") { $("#toolbar").find(".pulldown").find("ul").hide(); this.currentKeyboard = AjaxViewer.KEYBOARD_TYPE_ENGLISH; + } else if(cmd == "keyboard_uk") { + $("#toolbar").find(".pulldown").find("ul").hide(); + this.currentKeyboard = AjaxViewer.KEYBOARD_TYPE_UK_ENGLISH; } else if(cmd == "sendCtrlAltDel") { this.sendKeyboardEvent(AjaxViewer.KEY_DOWN, 0xffe9, 0); // X11 Alt this.sendKeyboardEvent(AjaxViewer.KEY_DOWN, 0xffe3, 0); // X11 Ctrl diff --git a/services/console-proxy/server/pom.xml b/services/console-proxy/server/pom.xml index 3ac5d5957f7..c3e360b079f 100644 --- a/services/console-proxy/server/pom.xml +++ b/services/console-proxy/server/pom.xml @@ -22,7 +22,7 @@ Apache CloudStack Console Proxy org.apache.cloudstack - cloud-service-console-proxy + cloudstack-service-console-proxy 4.2.0-SNAPSHOT ../pom.xml diff --git a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyClientBase.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyClientBase.java index 289bdab2f8a..f4c912a9e53 100644 --- a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyClientBase.java +++ b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyClientBase.java @@ -329,6 +329,7 @@ public abstract class ConsoleProxyClientBase implements ConsoleProxyClient, Cons "", "", "", diff --git a/services/pom.xml b/services/pom.xml index 54b22bbbf62..805bcdb5e6d 100644 --- a/services/pom.xml +++ b/services/pom.xml @@ -18,7 +18,7 @@ --> 4.0.0 - cloud-services + cloudstack-services Apache CloudStack Cloud Services pom diff --git a/services/secondary-storage/pom.xml b/services/secondary-storage/pom.xml index 2c8a1d0b9b8..eb6c0ee9b50 100644 --- a/services/secondary-storage/pom.xml +++ b/services/secondary-storage/pom.xml @@ -22,7 +22,7 @@ Apache CloudStack Secondary Storage Service org.apache.cloudstack - cloud-services + cloudstack-services 4.2.0-SNAPSHOT ../pom.xml diff --git a/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java index 638d5cad99d..e7fa5b2f1bc 100755 --- a/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java +++ b/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java @@ -80,9 +80,9 @@ import com.cloud.agent.api.SecStorageVMSetupCommand; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupSecondaryStorageCommand; import com.cloud.agent.api.UploadTemplateToS3FromSecondaryStorageCommand; -import com.cloud.agent.api.downloadSnapshotFromSwiftCommand; -import com.cloud.agent.api.downloadTemplateFromSwiftToSecondaryStorageCommand; -import com.cloud.agent.api.uploadTemplateToSwiftFromSecondaryStorageCommand; +import com.cloud.agent.api.DownloadSnapshotFromSwiftCommand; +import com.cloud.agent.api.DownloadTemplateFromSwiftToSecondaryStorageCommand; +import com.cloud.agent.api.UploadTemplateToSwiftFromSecondaryStorageCommand; import com.cloud.agent.api.storage.CreateEntityDownloadURLCommand; import com.cloud.agent.api.storage.DeleteEntityDownloadURLCommand; import com.cloud.agent.api.storage.DeleteTemplateCommand; @@ -190,20 +190,20 @@ SecondaryStorageResource { return execute((ListTemplateCommand)cmd); } else if (cmd instanceof ListVolumeCommand){ return execute((ListVolumeCommand)cmd); - }else if (cmd instanceof downloadSnapshotFromSwiftCommand){ - return execute((downloadSnapshotFromSwiftCommand)cmd); + }else if (cmd instanceof DownloadSnapshotFromSwiftCommand){ + return execute((DownloadSnapshotFromSwiftCommand)cmd); } else if (cmd instanceof DownloadSnapshotFromS3Command) { return execute((DownloadSnapshotFromS3Command) cmd); } else if (cmd instanceof DeleteSnapshotBackupCommand){ return execute((DeleteSnapshotBackupCommand)cmd); } else if (cmd instanceof DeleteSnapshotsDirCommand){ return execute((DeleteSnapshotsDirCommand)cmd); - } else if (cmd instanceof downloadTemplateFromSwiftToSecondaryStorageCommand) { - return execute((downloadTemplateFromSwiftToSecondaryStorageCommand) cmd); + } else if (cmd instanceof DownloadTemplateFromSwiftToSecondaryStorageCommand) { + return execute((DownloadTemplateFromSwiftToSecondaryStorageCommand) cmd); } else if (cmd instanceof DownloadTemplateFromS3ToSecondaryStorageCommand) { return execute((DownloadTemplateFromS3ToSecondaryStorageCommand) cmd); - } else if (cmd instanceof uploadTemplateToSwiftFromSecondaryStorageCommand) { - return execute((uploadTemplateToSwiftFromSecondaryStorageCommand) cmd); + } else if (cmd instanceof UploadTemplateToSwiftFromSecondaryStorageCommand) { + return execute((UploadTemplateToSwiftFromSecondaryStorageCommand) cmd); } else if (cmd instanceof UploadTemplateToS3FromSecondaryStorageCommand) { return execute((UploadTemplateToS3FromSecondaryStorageCommand) cmd); } else if (cmd instanceof DeleteObjectFromSwiftCommand) { @@ -281,7 +281,7 @@ SecondaryStorageResource { } - private Answer execute(downloadTemplateFromSwiftToSecondaryStorageCommand cmd) { + private Answer execute(DownloadTemplateFromSwiftToSecondaryStorageCommand cmd) { SwiftTO swift = cmd.getSwift(); String secondaryStorageUrl = cmd.getSecondaryStorageUrl(); Long accountId = cmd.getAccountId(); @@ -324,7 +324,7 @@ SecondaryStorageResource { } } - private Answer execute(uploadTemplateToSwiftFromSecondaryStorageCommand cmd) { + private Answer execute(UploadTemplateToSwiftFromSecondaryStorageCommand cmd) { SwiftTO swift = cmd.getSwift(); String secondaryStorageUrl = cmd.getSecondaryStorageUrl(); Long accountId = cmd.getAccountId(); @@ -769,7 +769,7 @@ SecondaryStorageResource { SNAPSHOT_ROOT_DIR, accountId, volumeId); } - public Answer execute(downloadSnapshotFromSwiftCommand cmd){ + public Answer execute(DownloadSnapshotFromSwiftCommand cmd){ SwiftTO swift = cmd.getSwift(); String secondaryStorageUrl = cmd.getSecondaryStorageUrl(); Long accountId = cmd.getAccountId(); diff --git a/setup/db/db/schema-2214to30.sql b/setup/db/db/schema-2214to30.sql index 60eceea447d..e288b0fd4f9 100755 --- a/setup/db/db/schema-2214to30.sql +++ b/setup/db/db/schema-2214to30.sql @@ -664,6 +664,7 @@ ALTER TABLE `cloud`.`dc_storage_network_ip_range` ADD COLUMN `gateway` varchar(1 ALTER TABLE `cloud`.`volumes` ADD COLUMN `last_pool_id` bigint unsigned; UPDATE `cloud`.`volumes` SET `last_pool_id` = `pool_id`; +UPDATE `cloud`.`volumes` SET `path` = SUBSTRING_INDEX(`path`, '/', -1); ALTER TABLE `cloud`.`user_ip_address` ADD COLUMN `is_system` int(1) unsigned NOT NULL default '0'; ALTER TABLE `cloud`.`volumes` ADD COLUMN `update_count` bigint unsigned NOT NULL DEFAULT 0; diff --git a/setup/db/db/schema-40to410.sql b/setup/db/db/schema-40to410.sql index ff1d9085329..b7b1c7a91dd 100644 --- a/setup/db/db/schema-40to410.sql +++ b/setup/db/db/schema-40to410.sql @@ -443,6 +443,10 @@ ALTER TABLE `cloud`.`vlan` ADD COLUMN `ip6_range` varchar(255); ALTER TABLE `cloud`.`data_center` ADD COLUMN `ip6_dns1` varchar(255); ALTER TABLE `cloud`.`data_center` ADD COLUMN `ip6_dns2` varchar(255); +UPDATE `cloud`.`networks` INNER JOIN `cloud`.`vlan` ON networks.id = vlan.network_id +SET networks.gateway = vlan.vlan_gateway, networks.ip6_gateway = vlan.ip6_gateway, networks.ip6_cidr = vlan.ip6_cidr +WHERE networks.data_center_id = vlan.data_center_id AND networks.physical_network_id = vlan.physical_network_id; + -- DB views for list api DROP VIEW IF EXISTS `cloud`.`user_vm_view`; @@ -640,6 +644,7 @@ CREATE VIEW `cloud`.`domain_router_view` AS data_center.id data_center_id, data_center.uuid data_center_uuid, data_center.name data_center_name, + data_center.networktype data_center_type, data_center.dns1 dns1, data_center.dns2 dns2, data_center.ip6_dns1 ip6_dns1, @@ -680,7 +685,8 @@ CREATE VIEW `cloud`.`domain_router_view` AS domain_router.scripts_version scripts_version, domain_router.is_redundant_router is_redundant_router, domain_router.redundant_state redundant_state, - domain_router.stop_pending stop_pending + domain_router.stop_pending stop_pending, + domain_router.role role from `cloud`.`domain_router` inner join diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index 1317d303c5c..5bb1eaad530 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -119,21 +119,27 @@ CREATE TABLE `cloud`.`load_balancer_healthcheck_policies` ( INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'vm.instancename.flag', 'false', 'Append guest VM display Name (if set) to the internal name of the VM'); -INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (208, UUID(), 6, 'Windows 8'); -INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (209, UUID(), 6, 'Windows 8 (64 bit)'); -INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (210, UUID(), 6, 'Windows 8 Server (64 bit)'); -INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Windows 8', 208); -INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Windows 8 (64 bit)', 209); -INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Windows 8 Server (64 bit)', 210); +INSERT IGNORE INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (165, UUID(), 6, 'Windows 8 (32-bit)'); +INSERT IGNORE INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (166, UUID(), 6, 'Windows 8 (64-bit)'); +INSERT IGNORE INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (167, UUID(), 6, 'Windows Server 2012 (64-bit)'); +INSERT IGNORE INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (168, UUID(), 6, 'Windows Server 8 (64-bit)'); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Windows 8 (32-bit)', 165); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Windows 8 (64-bit)', 166); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Windows Server 2012 (64-bit)', 167); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Windows Server 8 (64-bit)', 168); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("XenServer", 'Windows 8 (32-bit)', 165); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("XenServer", 'Windows 8 (64-bit)', 166); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("XenServer", 'Windows Server 2012 (64-bit)', 167); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("XenServer", 'Windows Server 8 (64-bit)', 168); -INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (211, UUID(), 7, 'Apple Mac OS X 10.6 (32 bits)'); -INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (212, UUID(), 7, 'Apple Mac OS X 10.6 (64 bits)'); -INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (213, UUID(), 7, 'Apple Mac OS X 10.7 (32 bits)'); -INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (214, UUID(), 7, 'Apple Mac OS X 10.7 (64 bits)'); -INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Apple Mac OS X 10.6 (32 bits)', 211); -INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Apple Mac OS X 10.6 (64 bits)', 212); -INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Apple Mac OS X 10.7 (32 bits)', 213); -INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Apple Mac OS X 10.7 (64 bits)', 214); +INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (211, UUID(), 7, 'Apple Mac OS X 10.6 (32-bit)'); +INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (212, UUID(), 7, 'Apple Mac OS X 10.6 (64-bit)'); +INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (213, UUID(), 7, 'Apple Mac OS X 10.7 (32-bit)'); +INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (214, UUID(), 7, 'Apple Mac OS X 10.7 (64-bit)'); +INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Apple Mac OS X 10.6 (32-bit)', 211); +INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Apple Mac OS X 10.6 (64-bit)', 212); +INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Apple Mac OS X 10.7 (32-bit)', 213); +INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Apple Mac OS X 10.7 (64-bit)', 214); CREATE TABLE `cloud`.`user_vm_clone_setting` ( `vm_id` bigint unsigned NOT NULL COMMENT 'guest VM id', @@ -385,7 +391,7 @@ CREATE TABLE `cloud`.`vm_snapshots` ( ALTER TABLE `cloud`.`hypervisor_capabilities` ADD COLUMN `vm_snapshot_enabled` tinyint(1) DEFAULT 0 NOT NULL COMMENT 'Whether VM snapshot is supported by hypervisor'; UPDATE `cloud`.`hypervisor_capabilities` SET `vm_snapshot_enabled`=1 WHERE `hypervisor_type` in ('VMware', 'XenServer'); - + DROP VIEW IF EXISTS `cloud`.`user_vm_view`; CREATE VIEW `cloud`.`user_vm_view` AS select @@ -496,7 +502,7 @@ CREATE VIEW `cloud`.`user_vm_view` AS async_job.uuid job_uuid, async_job.job_status job_status, async_job.account_id job_account_id, - affinity_group.id affinity_group_id, + affinity_group.id affinity_group_id, affinity_group.uuid affinity_group_uuid, affinity_group.name affinity_group_name, affinity_group.description affinity_group_description @@ -561,7 +567,7 @@ CREATE VIEW `cloud`.`user_vm_view` AS and async_job.job_status = 0 left join `cloud`.`affinity_group_vm_map` ON vm_instance.id = affinity_group_vm_map.instance_id - left join + left join `cloud`.`affinity_group` ON affinity_group_vm_map.affinity_group_id = affinity_group.id; DROP VIEW IF EXISTS `cloud`.`affinity_group_view`; @@ -890,7 +896,8 @@ CREATE VIEW `cloud`.`domain_router_view` AS domain_router.scripts_version scripts_version, domain_router.is_redundant_router is_redundant_router, domain_router.redundant_state redundant_state, - domain_router.stop_pending stop_pending + domain_router.stop_pending stop_pending, + domain_router.role role from `cloud`.`domain_router` inner join @@ -965,7 +972,7 @@ CREATE TABLE `cloud`.`network_asa1000v_map` ( ALTER TABLE `cloud`.`network_offerings` ADD COLUMN `eip_associate_public_ip` int(1) unsigned NOT NULL DEFAULT 0 COMMENT 'true if public IP is associated with user VM creation by default when EIP service is enabled.' AFTER `elastic_ip_service`; -- Re-enable foreign key checking, at the end of the upgrade path -SET foreign_key_checks = 1; +SET foreign_key_checks = 1; -- Add "default" field to account/user tables @@ -1161,7 +1168,43 @@ CREATE VIEW `cloud`.`account_view` AS and async_job.instance_type = 'Account' and async_job.job_status = 0; + + +ALTER TABLE `cloud`.`load_balancing_rules` ADD COLUMN `source_ip_address` varchar(40) COMMENT 'source ip address for the load balancer rule'; +ALTER TABLE `cloud`.`load_balancing_rules` ADD COLUMN `source_ip_address_network_id` bigint unsigned COMMENT 'the id of the network where source ip belongs to'; +ALTER TABLE `cloud`.`load_balancing_rules` ADD COLUMN `scheme` varchar(40) NOT NULL COMMENT 'load balancer scheme; can be Internal or Public'; +UPDATE `cloud`.`load_balancing_rules` SET `scheme`='Public'; + + + +-- Add details talbe for the network offering +CREATE TABLE `cloud`.`network_offering_details` ( + `id` bigint unsigned NOT NULL auto_increment, + `network_offering_id` bigint unsigned NOT NULL COMMENT 'network offering id', + `name` varchar(255) NOT NULL, + `value` varchar(1024) NOT NULL, + PRIMARY KEY (`id`), + CONSTRAINT `fk_network_offering_details__network_offering_id` FOREIGN KEY `fk_network_offering_details__network_offering_id`(`network_offering_id`) REFERENCES `network_offerings`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- Change the constraint for the network service map table. Now we support multiple provider for the same service +ALTER TABLE `cloud`.`ntwk_service_map` DROP FOREIGN KEY `fk_ntwk_service_map__network_id`; +ALTER TABLE `cloud`.`ntwk_service_map` DROP INDEX `network_id`; + +ALTER TABLE `cloud`.`ntwk_service_map` ADD UNIQUE `network_id` (`network_id`,`service`,`provider`); +ALTER TABLE `cloud`.`ntwk_service_map` ADD CONSTRAINT `fk_ntwk_service_map__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks` (`id`) ON DELETE CASCADE; + + +ALTER TABLE `cloud`.`network_offerings` ADD COLUMN `internal_lb` int(1) unsigned NOT NULL DEFAULT '0' COMMENT 'true if the network offering supports Internal lb service'; +ALTER TABLE `cloud`.`network_offerings` ADD COLUMN `public_lb` int(1) unsigned NOT NULL DEFAULT '0' COMMENT 'true if the network offering supports Public lb service'; +UPDATE `cloud`.`network_offerings` SET public_lb=1 where id IN (SELECT DISTINCT network_offering_id FROM `cloud`.`ntwk_offering_service_map` WHERE service='Lb'); + + +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'NetworkManager', 'internallbvm.service.offering', null, 'Uuid of the service offering used by internal lb vm; if NULL - default system internal lb offering will be used'); + + alter table `cloud_usage`.`usage_network_offering` add column nic_id bigint(20) unsigned NOT NULL; +<<<<<<< HEAD DROP VIEW IF EXISTS `cloud`.`disk_offering_view`; CREATE VIEW `cloud`.`disk_offering_view` AS select @@ -1471,3 +1514,31 @@ CREATE VIEW `cloud`.`volume_view` AS and async_job.instance_type = 'Volume' and async_job.job_status = 0; +======= +ALTER TABLE `cloud`.`data_center_details` MODIFY value varchar(1024); +ALTER TABLE `cloud`.`cluster_details` MODIFY value varchar(255); +ALTER TABLE `cloud`.`storage_pool_details` MODIFY value varchar(255); +ALTER TABLE `cloud`.`account_details` MODIFY value varchar(255); + +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Network', 'DEFAULT', 'management-server', 'midonet.apiserver.address', 'http://localhost:8081', 'Specify the address at which the Midonet API server can be contacted (if using Midonet)'); +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Network', 'DEFAULT', 'management-server', 'midonet.providerrouter.id', 'd7c5e6a3-e2f4-426b-b728-b7ce6a0448e5', 'Specifies the UUID of the Midonet provider router (if using Midonet)'); + +alter table cloud.vpc_gateways add column source_nat boolean default false; +alter table cloud.private_ip_address add column source_nat boolean default false; + +CREATE TABLE `cloud`.`account_vnet_map` ( + `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT, + `uuid` varchar(255) UNIQUE, + `vnet_range` varchar(255) NOT NULL COMMENT 'dedicated guest vlan range', + `account_id` bigint unsigned NOT NULL COMMENT 'account id. foreign key to account table', + `physical_network_id` bigint unsigned NOT NULL COMMENT 'physical network id. foreign key to the the physical network table', + PRIMARY KEY (`id`), + CONSTRAINT `fk_account_vnet_map__physical_network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network` (`id`) ON DELETE CASCADE, + INDEX `i_account_vnet_map__physical_network_id`(`physical_network_id`), + CONSTRAINT `fk_account_vnet_map__account_id` FOREIGN KEY (`account_id`) REFERENCES `account` (`id`) ON DELETE CASCADE, + INDEX `i_account_vnet_map__account_id`(`account_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +ALTER TABLE `cloud`.`op_dc_vnet_alloc` ADD COLUMN account_vnet_map_id bigint unsigned; +ALTER TABLE `cloud`.`op_dc_vnet_alloc` ADD CONSTRAINT `fk_op_dc_vnet_alloc__account_vnet_map_id` FOREIGN KEY `fk_op_dc_vnet_alloc__account_vnet_map_id` (`account_vnet_map_id`) REFERENCES `account_vnet_map` (`id`); +>>>>>>> master diff --git a/setup/db/templates.sql b/setup/db/templates.sql index 2f95f1e00f8..1685dce385c 100755 --- a/setup/db/templates.sql +++ b/setup/db/templates.sql @@ -214,6 +214,10 @@ INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (161 INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (162, UUID(), 1, 'CentOS 5.7 (64-bit)'); INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (163, UUID(), 10, 'Ubuntu 12.04 (32-bit)'); INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (164, UUID(), 10, 'Ubuntu 12.04 (64-bit)'); +INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (165, UUID(), 6, 'Windows 8 (32-bit)'); +INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (166, UUID(), 6, 'Windows 8 (64-bit)'); +INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (167, UUID(), 6, 'Windows Server 2012 (64-bit)'); +INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (168, UUID(), 6, 'Windows Server 8 (64-bit)'); INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (200, UUID(), 1, 'Other CentOS (32-bit)'); INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name) VALUES (201, UUID(), 1, 'Other CentOS (64-bit)'); @@ -294,6 +298,10 @@ INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ('XenServer', 'Other install media', 130); INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ('XenServer', 'Other PV (32-bit)', 139); INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ('XenServer', 'Other PV (64-bit)', 140); +INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("XenServer", 'Windows 8 (32-bit)', 165); +INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("XenServer", 'Windows 8 (64-bit)', 166); +INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("XenServer", 'Windows Server 2012 (64-bit)', 167); +INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("XenServer", 'Windows Server 8 (64-bit)', 168); INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Microsoft Windows 7(32-bit)', 48); @@ -323,6 +331,10 @@ INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Microsoft Windows 95', 63); INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Microsoft Windows NT 4', 64); INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Microsoft Windows 3.1', 65); +INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Windows 8 (32-bit)', 165); +INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Windows 8 (64-bit)', 166); +INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Windows Server 2012 (64-bit)', 167); +INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Windows Server 8 (64-bit)', 168); INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Red Hat Enterprise Linux 5.0(32-bit)', 30); INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ("VmWare", 'Red Hat Enterprise Linux 5.1(32-bit)', 32); diff --git a/setup/dev/advanced.cfg b/setup/dev/advanced.cfg index c031c2a4f84..83357866ca7 100644 --- a/setup/dev/advanced.cfg +++ b/setup/dev/advanced.cfg @@ -45,7 +45,14 @@ { "broadcastdomainrange": "ZONE", "name": "VpcVirtualRouter" + }, + { + "broadcastdomainrange": "ZONE", + "name": "InternalLbVm" } + ], + "isolationmethods": [ + "VLAN" ] } ], @@ -84,8 +91,12 @@ "clustertype": "CloudManaged", "primaryStorages": [ { - "url": "nfs://10.147.28.6:/export/home/sandbox/primary", + "url": "nfs://10.147.28.6:/export/home/sandbox/primary0", "name": "PS0" + }, + { + "url": "nfs://10.147.28.6:/export/home/sandbox/primary1", + "name": "PS1" } ] } diff --git a/setup/dev/basic.cfg b/setup/dev/basic.cfg index 3f56a3ce980..326874d1f19 100644 --- a/setup/dev/basic.cfg +++ b/setup/dev/basic.cfg @@ -42,6 +42,9 @@ "broadcastdomainrange": "Pod", "name": "SecurityGroupProvider" } + ], + "isolationmethods": [ + "L3" ] } ], diff --git a/test/integration/component/test_accounts.py b/test/integration/component/test_accounts.py index 459cfb3a251..9cbefe55fdb 100644 --- a/test/integration/component/test_accounts.py +++ b/test/integration/component/test_accounts.py @@ -60,7 +60,7 @@ class Services: "cpunumber": 1, "cpuspeed": 100, # in MHz - "memory": 64, + "memory": 128, # In MBs }, "virtual_machine": { @@ -162,11 +162,11 @@ class TestAccounts(cloudstackTestCase): self.apiclient, self.services["account"] ) - self.debug("Created account: %s" % account.account.name) + self.debug("Created account: %s" % account.name) self.cleanup.append(account) list_accounts_response = list_accounts( self.apiclient, - id=account.account.id + id=account.id ) self.assertEqual( isinstance(list_accounts_response, list), @@ -181,12 +181,12 @@ class TestAccounts(cloudstackTestCase): account_response = list_accounts_response[0] self.assertEqual( - account.account.accounttype, + account.accounttype, account_response.accounttype, "Check Account Type of Created account" ) self.assertEqual( - account.account.name, + account.name, account_response.name, "Check Account Name of Created account" ) @@ -194,8 +194,8 @@ class TestAccounts(cloudstackTestCase): user = User.create( self.apiclient, self.services["user"], - account=account.account.name, - domainid=account.account.domainid + account=account.name, + domainid=account.domainid ) self.debug("Created user: %s" % user.id) list_users_response = list_users( @@ -301,15 +301,15 @@ class TestRemoveUserFromAccount(cloudstackTestCase): user_1 = User.create( self.apiclient, self.services["user"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created user: %s" % user_1.id) user_2 = User.create( self.apiclient, self.services["user"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created user: %s" % user_2.id) self.cleanup.append(user_2) @@ -317,12 +317,12 @@ class TestRemoveUserFromAccount(cloudstackTestCase): vm_1 = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) self.debug("Deployed VM in account: %s, ID: %s" % ( - self.account.account.name, + self.account.name, vm_1.id )) self.cleanup.append(vm_1) @@ -330,12 +330,12 @@ class TestRemoveUserFromAccount(cloudstackTestCase): vm_2 = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) self.debug("Deployed VM in account: %s, ID: %s" % ( - self.account.account.name, + self.account.name, vm_2.id )) self.cleanup.append(vm_2) @@ -347,7 +347,7 @@ class TestRemoveUserFromAccount(cloudstackTestCase): # Account should exist after deleting user accounts_response = list_accounts( self.apiclient, - id=self.account.account.id + id=self.account.id ) self.assertEqual( isinstance(accounts_response, list), @@ -362,8 +362,8 @@ class TestRemoveUserFromAccount(cloudstackTestCase): ) vm_response = list_virtual_machines( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(vm_response, list), @@ -401,43 +401,43 @@ class TestRemoveUserFromAccount(cloudstackTestCase): user_1 = User.create( self.apiclient, self.services["user"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created user: %s" % user_1.id) user_2 = User.create( self.apiclient, self.services["user"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created user: %s" % user_2.id) vm_1 = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, + accountid=self.account.name, serviceofferingid=self.service_offering.id ) self.debug("Deployed VM in account: %s, ID: %s" % ( - self.account.account.name, + self.account.name, vm_1.id )) vm_2 = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, + accountid=self.account.name, serviceofferingid=self.service_offering.id ) self.debug("Deployed VM in account: %s, ID: %s" % ( - self.account.account.name, + self.account.name, vm_2.id )) # Get users associated with an account # (Total 3: 2 - Created & 1 default generated while account creation) users = list_users( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(users, list), @@ -468,7 +468,7 @@ class TestRemoveUserFromAccount(cloudstackTestCase): # Account is removed after last user is deleted account_response = list_accounts( self.apiclient, - id=self.account.account.id + id=self.account.id ) self.assertEqual( account_response, @@ -478,8 +478,8 @@ class TestRemoveUserFromAccount(cloudstackTestCase): # All VMs associated with account are removed. vm_response = list_virtual_machines( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( vm_response, @@ -490,8 +490,8 @@ class TestRemoveUserFromAccount(cloudstackTestCase): with self.assertRaises(Exception): list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) return @@ -1217,11 +1217,11 @@ class TestUserDetails(cloudstackTestCase): # Fetching the user details of account self.debug( "Fetching user details for account: %s" % - self.account.account.name) + self.account.name) users = User.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(users, list), @@ -1304,11 +1304,11 @@ class TestUserDetails(cloudstackTestCase): # Fetching the user details of account self.debug( "Fetching user details for account: %s" % - self.account.account.name) + self.account.name) users = User.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(users, list), @@ -1391,11 +1391,11 @@ class TestUserDetails(cloudstackTestCase): # Fetching the user details of account self.debug( "Fetching user details for account: %s" % - self.account.account.name) + self.account.name) users = User.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(users, list), @@ -1515,7 +1515,7 @@ class TestUserLogin(cloudstackTestCase): self.debug("Logging into the cloudstack with login API") respose = User.login( self.apiclient, - username=self.account.account.name, + username=self.account.name, password=self.services["account"]["password"] ) self.assertEqual(respose, None, "Login response should not be none") @@ -1572,8 +1572,8 @@ class TestUserLogin(cloudstackTestCase): accounts = Account.list( self.apiclient, - name=self.account.account.name, - domainid=self.account.account.domainid, + name=self.account.name, + domainid=self.account.domainid, listall=True ) @@ -1586,7 +1586,7 @@ class TestUserLogin(cloudstackTestCase): self.debug("Logging into the cloudstack with login API") respose = User.login( self.apiclient, - username=self.account.account.name, + username=self.account.name, password=self.services["account"]["password"] ) self.assertEqual(respose, None, "Login response should not be none") diff --git a/test/integration/component/test_allocation_states.py b/test/integration/component/test_allocation_states.py index fe4c35f3b9f..5ce0b21124b 100644 --- a/test/integration/component/test_allocation_states.py +++ b/test/integration/component/test_allocation_states.py @@ -49,7 +49,7 @@ class Services: "displaytext": "Tiny Instance", "cpunumber": 1, "cpuspeed": 100, # in MHz - "memory": 64, # In MBs + "memory": 128, # In MBs }, "disk_offering": { "displaytext": "Small", diff --git a/test/integration/component/test_blocker_bugs.py b/test/integration/component/test_blocker_bugs.py index bfd1c13cb19..d099bf1a448 100644 --- a/test/integration/component/test_blocker_bugs.py +++ b/test/integration/component/test_blocker_bugs.py @@ -51,7 +51,7 @@ class Services: "displaytext": "Tiny Instance", "cpunumber": 1, "cpuspeed": 100, # in MHz - "memory": 64, # In MBs + "memory": 128, # In MBs }, "disk_offering": { "displaytext": "Small", @@ -136,7 +136,7 @@ class TestSnapshots(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, @@ -146,8 +146,8 @@ class TestSnapshots(cloudstackTestCase): cls.api_client, cls.services["virtual_machine"], templateid=cls.template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, mode=cls.services["mode"] ) @@ -204,8 +204,8 @@ class TestSnapshots(cloudstackTestCase): self.apiclient, self.services["volume"], zoneid=self.zone.id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, diskofferingid=self.disk_offering.id ) self.debug("Created volume with ID: %s" % volume.id) @@ -283,8 +283,8 @@ class TestSnapshots(cloudstackTestCase): snapshot = Snapshot.create( self.apiclient, volume_response.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created snapshot: %s" % snapshot.id) #Create volume from snapshot @@ -292,8 +292,8 @@ class TestSnapshots(cloudstackTestCase): self.apiclient, snapshot.id, self.services["volume"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created Volume: %s from Snapshot: %s" % ( volume_from_snapshot.id, @@ -323,12 +323,12 @@ class TestSnapshots(cloudstackTestCase): self.apiclient, self.services["virtual_machine"], templateid=self.template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, mode=self.services["mode"] ) - self.debug("Deployed new VM for account: %s" % self.account.account.name) + self.debug("Deployed new VM for account: %s" % self.account.name) self.cleanup.append(new_virtual_machine) self.debug("Attaching volume: %s to VM: %s" % ( @@ -434,7 +434,7 @@ class TestTemplate(cloudstackTestCase): cls.services["account"], domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls._cleanup = [ cls.account, @@ -471,8 +471,8 @@ class TestTemplate(cloudstackTestCase): self.apiclient, self.services["templates"], zoneid=self.zone.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Registering template with ID: %s" % template.id) try: @@ -519,8 +519,8 @@ class TestTemplate(cloudstackTestCase): self.apiclient, self.services["virtual_machine"], templateid=template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, ) self.debug("Deployed VM with ID: %s " % virtual_machine.id) @@ -565,15 +565,15 @@ class TestNATRules(cloudstackTestCase): cls.api_client, cls.services["virtual_machine"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) cls.public_ip = PublicIPAddress.create( cls.api_client, - accountid=cls.account.account.name, + accountid=cls.account.name, zoneid=cls.zone.id, - domainid=cls.account.account.domainid, + domainid=cls.account.domainid, services=cls.services["virtual_machine"] ) cls._cleanup = [ @@ -817,23 +817,23 @@ class TestRouters(cloudstackTestCase): vm_1 = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.admin_account.account.name, - domainid=self.admin_account.account.domainid, + accountid=self.admin_account.name, + domainid=self.admin_account.domainid, serviceofferingid=self.service_offering.id ) self.debug("Deployed VM with ID: %s" % vm_1.id) vm_2 = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.user_account.account.name, - domainid=self.user_account.account.domainid, + accountid=self.user_account.name, + domainid=self.user_account.domainid, serviceofferingid=self.service_offering.id ) self.debug("Deployed VM with ID: %s" % vm_2.id) routers = list_routers( self.apiclient, - account=self.admin_account.account.name, - domainid=self.admin_account.account.domainid, + account=self.admin_account.name, + domainid=self.admin_account.domainid, ) self.assertEqual( isinstance(routers, list), @@ -887,8 +887,8 @@ class TestRouterRestart(cloudstackTestCase): cls.api_client, cls.services["virtual_machine"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) cls.cleanup = [ @@ -927,8 +927,8 @@ class TestRouterRestart(cloudstackTestCase): # Find router associated with user account list_router_response = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(list_router_response, list), @@ -945,8 +945,8 @@ class TestRouterRestart(cloudstackTestCase): while True: networks = Network.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) network = networks[0] if network.state in ["Implemented", "Setup"]: @@ -966,8 +966,8 @@ class TestRouterRestart(cloudstackTestCase): # Get router details after restart list_router_response = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(list_router_response, list), @@ -1009,7 +1009,7 @@ class TestTemplates(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, cls.services["service_offering"] @@ -1020,8 +1020,8 @@ class TestTemplates(cloudstackTestCase): cls.api_client, cls.services["virtual_machine"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, ) #Stop virtual machine @@ -1091,8 +1091,8 @@ class TestTemplates(cloudstackTestCase): self.apiclient, self.services["templates"], self.volume.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Creating template with ID: %s" % template.id) # Volume and Template Size should be same @@ -1121,8 +1121,8 @@ class TestTemplates(cloudstackTestCase): snapshot = Snapshot.create( self.apiclient, self.volume.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created snapshot with ID: %s" % snapshot.id) snapshots = Snapshot.list( @@ -1203,8 +1203,8 @@ class TestTemplates(cloudstackTestCase): snapshot = Snapshot.create( self.apiclient, self.volume.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created snapshot with ID: %s" % snapshot.id) snapshots = Snapshot.list( diff --git a/test/integration/component/test_egress_rules.py b/test/integration/component/test_egress_rules.py index 7972aa50639..872ca2c7b5d 100644 --- a/test/integration/component/test_egress_rules.py +++ b/test/integration/component/test_egress_rules.py @@ -69,7 +69,7 @@ class Services: "displaytext": "Tiny Instance", "cpunumber": 1, "cpuspeed": 100, # in MHz - "memory": 64, # In MBs + "memory": 128, # In MBs }, "security_group": { "name": 'SSH', @@ -175,7 +175,7 @@ class TestDefaultSecurityGroupEgress(cloudstackTestCase): admin=True, domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls._cleanup = [ cls.account, @@ -208,12 +208,12 @@ class TestDefaultSecurityGroupEgress(cloudstackTestCase): # 4. listVirtualMachines should show that the VM belongs to default # security group - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) self.virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) self.debug("Deployed VM with ID: %s" % self.virtual_machine.id) @@ -260,8 +260,8 @@ class TestDefaultSecurityGroupEgress(cloudstackTestCase): # Verify listSecurity groups response security_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(security_groups, list), @@ -333,7 +333,7 @@ class TestAuthorizeIngressRule(cloudstackTestCase): cls.services["account"], domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls._cleanup = [ cls.account, cls.service_offering @@ -371,15 +371,15 @@ class TestAuthorizeIngressRule(cloudstackTestCase): security_group = SecurityGroup.create( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created security group with ID: %s" % security_group.id) # Default Security group should not have any ingress rule sercurity_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(sercurity_groups, list), @@ -396,8 +396,8 @@ class TestAuthorizeIngressRule(cloudstackTestCase): ingress_rule = security_group.authorize( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(ingress_rule, dict), @@ -410,12 +410,12 @@ class TestAuthorizeIngressRule(cloudstackTestCase): self.virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, securitygroupids=[security_group.id] ) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) # Should be able to SSH VM try: self.debug("SSH into VM: %s" % self.virtual_machine.ssh_ip) @@ -491,7 +491,7 @@ class TestDefaultGroupEgress(cloudstackTestCase): cls.services["account"], domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls._cleanup = [ cls.account, cls.service_offering @@ -529,16 +529,16 @@ class TestDefaultGroupEgress(cloudstackTestCase): security_group = SecurityGroup.create( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created security group with ID: %s" % security_group.id) # Default Security group should not have any ingress rule sercurity_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(sercurity_groups, list), @@ -557,8 +557,8 @@ class TestDefaultGroupEgress(cloudstackTestCase): ingress_rule = security_group.authorize( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( @@ -575,8 +575,8 @@ class TestDefaultGroupEgress(cloudstackTestCase): egress_rule = security_group.authorizeEgress( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( @@ -589,12 +589,12 @@ class TestDefaultGroupEgress(cloudstackTestCase): self.virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, securitygroupids=[security_group.id] ) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) # Should be able to SSH VM try: @@ -692,7 +692,7 @@ class TestDefaultGroupEgressAfterDeploy(cloudstackTestCase): cls.services["account"], domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls._cleanup = [ cls.account, cls.service_offering @@ -730,16 +730,16 @@ class TestDefaultGroupEgressAfterDeploy(cloudstackTestCase): security_group = SecurityGroup.create( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created security group with ID: %s" % security_group.id) # Default Security group should not have any ingress rule sercurity_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(sercurity_groups, list), @@ -758,8 +758,8 @@ class TestDefaultGroupEgressAfterDeploy(cloudstackTestCase): ingress_rule = security_group.authorize( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( @@ -773,12 +773,12 @@ class TestDefaultGroupEgressAfterDeploy(cloudstackTestCase): self.virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, securitygroupids=[security_group.id] ) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) # Authorize Security group to SSH to VM self.debug( @@ -787,8 +787,8 @@ class TestDefaultGroupEgressAfterDeploy(cloudstackTestCase): egress_rule = security_group.authorizeEgress( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( @@ -875,7 +875,7 @@ class TestRevokeEgressRule(cloudstackTestCase): cls.services["account"], domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls._cleanup = [ cls.account, cls.service_offering @@ -915,16 +915,16 @@ class TestRevokeEgressRule(cloudstackTestCase): security_group = SecurityGroup.create( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created security group with ID: %s" % security_group.id) # Default Security group should not have any ingress rule sercurity_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(sercurity_groups, list), @@ -944,8 +944,8 @@ class TestRevokeEgressRule(cloudstackTestCase): ingress_rule = security_group.authorize( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( @@ -963,8 +963,8 @@ class TestRevokeEgressRule(cloudstackTestCase): egress_rule = security_group.authorizeEgress( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( @@ -977,12 +977,12 @@ class TestRevokeEgressRule(cloudstackTestCase): self.virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, securitygroupids=[security_group.id] ) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) # Should be able to SSH VM try: @@ -1033,7 +1033,7 @@ class TestRevokeEgressRule(cloudstackTestCase): "Revoke Egress Rule for Security Group %s for account: %s" \ % ( security_group.id, - self.account.account.name + self.account.name )) result = security_group.revokeEgress( @@ -1137,7 +1137,7 @@ class TestInvalidAccountAuthroize(cloudstackTestCase): cls.services["account"], domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls._cleanup = [ cls.account, cls.service_offering @@ -1173,16 +1173,16 @@ class TestInvalidAccountAuthroize(cloudstackTestCase): security_group = SecurityGroup.create( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created security group with ID: %s" % security_group.id) # Default Security group should not have any ingress rule sercurity_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(sercurity_groups, list), @@ -1205,7 +1205,7 @@ class TestInvalidAccountAuthroize(cloudstackTestCase): self.apiclient, self.services["security_group"], account=random_gen(), - domainid=self.account.account.domainid + domainid=self.account.domainid ) return @@ -1804,7 +1804,7 @@ class TestStartStopVMWithEgressRule(cloudstackTestCase): cls.services["account"], domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls._cleanup = [ cls.account, cls.service_offering @@ -1842,16 +1842,16 @@ class TestStartStopVMWithEgressRule(cloudstackTestCase): security_group = SecurityGroup.create( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created security group with ID: %s" % security_group.id) # Default Security group should not have any ingress rule sercurity_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(sercurity_groups, list), @@ -1871,8 +1871,8 @@ class TestStartStopVMWithEgressRule(cloudstackTestCase): ingress_rule = security_group.authorize( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( @@ -1886,12 +1886,12 @@ class TestStartStopVMWithEgressRule(cloudstackTestCase): self.virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, securitygroupids=[security_group.id] ) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) # Authorize Security group to SSH to VM self.debug( @@ -1900,8 +1900,8 @@ class TestStartStopVMWithEgressRule(cloudstackTestCase): egress_rule = security_group.authorizeEgress( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( @@ -2016,7 +2016,7 @@ class TestInvalidParametersForEgress(cloudstackTestCase): cls.services["account"], domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls._cleanup = [ cls.account, cls.service_offering @@ -2054,16 +2054,16 @@ class TestInvalidParametersForEgress(cloudstackTestCase): security_group = SecurityGroup.create( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created security group with ID: %s" % security_group.id) # Default Security group should not have any ingress rule sercurity_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(sercurity_groups, list), @@ -2085,8 +2085,8 @@ class TestInvalidParametersForEgress(cloudstackTestCase): egress_rule = security_group.authorizeEgress( self.apiclient, self.services["sg_invalid_port"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug( "Authorizing egress rule for sec group ID: %s with invalid cidr" @@ -2095,8 +2095,8 @@ class TestInvalidParametersForEgress(cloudstackTestCase): egress_rule = security_group.authorizeEgress( self.apiclient, self.services["sg_invalid_cidr"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug( "Authorizing egress rule for sec group ID: %s with invalid account" @@ -2106,7 +2106,7 @@ class TestInvalidParametersForEgress(cloudstackTestCase): self.apiclient, self.services["security_group"], account=random_gen(), - domainid=self.account.account.domainid + domainid=self.account.domainid ) self.debug( "Authorizing egress rule for sec group ID: %s with cidr: anywhere and port: 22" @@ -2114,8 +2114,8 @@ class TestInvalidParametersForEgress(cloudstackTestCase): egress_rule_A = security_group.authorizeEgress( self.apiclient, self.services["sg_cidr_anywhere"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( @@ -2127,8 +2127,8 @@ class TestInvalidParametersForEgress(cloudstackTestCase): egress_rule_R = security_group.authorizeEgress( self.apiclient, self.services["sg_cidr_restricted"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( @@ -2144,8 +2144,8 @@ class TestInvalidParametersForEgress(cloudstackTestCase): security_group.authorizeEgress( self.apiclient, self.services["sg_cidr_restricted"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) return @@ -2203,7 +2203,7 @@ class TestEgressAfterHostMaintainance(cloudstackTestCase): cls.services["account"], domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls._cleanup = [ cls.account, cls.service_offering @@ -2241,16 +2241,16 @@ class TestEgressAfterHostMaintainance(cloudstackTestCase): security_group = SecurityGroup.create( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created security group with ID: %s" % security_group.id) # Default Security group should not have any ingress rule sercurity_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(sercurity_groups, list), @@ -2270,8 +2270,8 @@ class TestEgressAfterHostMaintainance(cloudstackTestCase): ingress_rule = security_group.authorize( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( @@ -2289,8 +2289,8 @@ class TestEgressAfterHostMaintainance(cloudstackTestCase): egress_rule = security_group.authorizeEgress( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( @@ -2303,12 +2303,12 @@ class TestEgressAfterHostMaintainance(cloudstackTestCase): self.virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, securitygroupids=[security_group.id] ) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) # Should be able to SSH VM try: diff --git a/test/integration/component/test_eip_elb.py b/test/integration/component/test_eip_elb.py index c1ad50530b5..b01371b7643 100644 --- a/test/integration/component/test_eip_elb.py +++ b/test/integration/component/test_eip_elb.py @@ -49,7 +49,7 @@ class Services: "displaytext": "Tiny Instance", "cpunumber": 1, "cpuspeed": 100, # in MHz - "memory": 64, # In MBs + "memory": 128, # In MBs }, "lbrule": { "name": "SSH", @@ -119,8 +119,8 @@ class TestEIP(cloudstackTestCase): cls.virtual_machine = VirtualMachine.create( cls.api_client, cls.services["virtual_machine"], - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) networks = Network.list( @@ -140,8 +140,8 @@ class TestEIP(cloudstackTestCase): cls.api_client, associatednetworkid=cls.guest_network.id, isstaticnat=True, - account=cls.account.account.name, - domainid=cls.account.account.domainid, + account=cls.account.name, + domainid=cls.account.domainid, listall=True ) if isinstance(ip_addrs, list): @@ -240,8 +240,8 @@ class TestEIP(cloudstackTestCase): # Verify listSecurity groups response security_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(security_groups, list), @@ -262,8 +262,8 @@ class TestEIP(cloudstackTestCase): "Creating Ingress rule to allow SSH on default security group") cmd = authorizeSecurityGroupIngress.authorizeSecurityGroupIngressCmd() - cmd.domainid = self.account.account.domainid - cmd.account = self.account.account.name + cmd.domainid = self.account.domainid + cmd.account = self.account.name cmd.securitygroupid = security_group.id cmd.protocol = 'TCP' cmd.startport = 22 @@ -370,16 +370,16 @@ class TestEIP(cloudstackTestCase): public_ip = PublicIPAddress.create( self.apiclient, - accountid=self.account.account.name, + accountid=self.account.name, zoneid=self.zone.id, - domainid=self.account.account.domainid, + domainid=self.account.domainid, services=self.services["virtual_machine"] ) self.debug("IP address: %s is acquired by network: %s" % ( - public_ip.ipaddress.ipaddress, + public_ip.ipaddress, self.guest_network.id)) self.debug("Enabling static NAT for IP Address: %s" % - public_ip.ipaddress.ipaddress) + public_ip.ipaddress) StaticNATRule.enable( self.apiclient, @@ -390,11 +390,11 @@ class TestEIP(cloudstackTestCase): # Fetch details from user_ip_address table in database self.debug( "select is_system, one_to_one_nat from user_ip_address where public_ip_address='%s';" \ - % public_ip.ipaddress.ipaddress) + % public_ip.ipaddress) qresultset = self.dbclient.execute( "select is_system, one_to_one_nat from user_ip_address where public_ip_address='%s';" \ - % public_ip.ipaddress.ipaddress + % public_ip.ipaddress ) self.assertEqual( isinstance(qresultset, list), @@ -449,12 +449,12 @@ class TestEIP(cloudstackTestCase): ) # try: -# self.debug("SSH into VM: %s" % public_ip.ipaddress.ipaddress) +# self.debug("SSH into VM: %s" % public_ip.ipaddress) # ssh = self.virtual_machine.get_ssh_client( -# ipaddress=public_ip.ipaddress.ipaddress) +# ipaddress=public_ip.ipaddress) # except Exception as e: # self.fail("SSH Access failed for %s: %s" % \ -# (public_ip.ipaddress.ipaddress, e) +# (public_ip.ipaddress, e) # ) self.debug("SSH into netscaler: %s" % @@ -472,7 +472,7 @@ class TestEIP(cloudstackTestCase): self.debug("Output: %s" % result) self.assertEqual( - result.count(public_ip.ipaddress.ipaddress), + result.count(public_ip.ipaddress), 1, "One IP from EIP pool should be taken and configured on NS" ) @@ -484,7 +484,7 @@ class TestEIP(cloudstackTestCase): self.debug("Output: %s" % result) self.assertEqual( - result.count("NAME: Cloud-Inat-%s" % public_ip.ipaddress.ipaddress), + result.count("NAME: Cloud-Inat-%s" % public_ip.ipaddress), 1, "User source IP should be enabled for INAT service" ) @@ -517,8 +517,8 @@ class TestEIP(cloudstackTestCase): self.api_client, associatednetworkid=self.guest_network.id, isstaticnat=True, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, listall=True ) self.assertEqual( @@ -602,8 +602,8 @@ class TestEIP(cloudstackTestCase): self.api_client, associatednetworkid=self.guest_network.id, isstaticnat=True, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, listall=True ) self.assertEqual( @@ -711,8 +711,8 @@ class TestEIP(cloudstackTestCase): self.api_client, associatednetworkid=self.guest_network.id, isstaticnat=True, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, listall=True ) self.assertEqual( @@ -784,8 +784,8 @@ class TestEIP(cloudstackTestCase): self.api_client, associatednetworkid=self.guest_network.id, isstaticnat=True, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, listall=True ) self.assertEqual( @@ -942,15 +942,15 @@ class TestELB(cloudstackTestCase): cls.vm_1 = VirtualMachine.create( cls.api_client, cls.services["virtual_machine"], - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) cls.vm_2 = VirtualMachine.create( cls.api_client, cls.services["virtual_machine"], - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) networks = Network.list( @@ -968,9 +968,9 @@ class TestELB(cloudstackTestCase): cls.lb_rule = LoadBalancerRule.create( cls.api_client, cls.services["lbrule"], - accountid=cls.account.account.name, + accountid=cls.account.name, networkid=cls.guest_network.id, - domainid=cls.account.account.domainid + domainid=cls.account.domainid ) cls.lb_rule.assign(cls.api_client, [cls.vm_1, cls.vm_2]) @@ -1024,8 +1024,8 @@ class TestELB(cloudstackTestCase): # Verify listSecurity groups response security_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(security_groups, list), @@ -1046,8 +1046,8 @@ class TestELB(cloudstackTestCase): "Creating Ingress rule to allow SSH on default security group") cmd = authorizeSecurityGroupIngress.authorizeSecurityGroupIngressCmd() - cmd.domainid = self.account.account.domainid - cmd.account = self.account.account.name + cmd.domainid = self.account.domainid + cmd.account = self.account.name cmd.securitygroupid = security_group.id cmd.protocol = 'TCP' cmd.startport = 22 @@ -1056,12 +1056,12 @@ class TestELB(cloudstackTestCase): self.apiclient.authorizeSecurityGroupIngress(cmd) self.debug( - "Fetching LB IP for account: %s" % self.account.account.name) + "Fetching LB IP for account: %s" % self.account.name) ip_addrs = PublicIPAddress.list( self.api_client, associatednetworkid=self.guest_network.id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, forloadbalancing=True, listall=True ) @@ -1073,7 +1073,7 @@ class TestELB(cloudstackTestCase): lb_ip = ip_addrs[0] self.debug("LB IP generated for account: %s is: %s" % ( - self.account.account.name, + self.account.name, lb_ip.ipaddress )) #TODO: uncomment this after ssh issue is resolved @@ -1199,24 +1199,24 @@ class TestELB(cloudstackTestCase): public_ip = PublicIPAddress.create( self.apiclient, - accountid=self.account.account.name, + accountid=self.account.name, zoneid=self.zone.id, - domainid=self.account.account.domainid, + domainid=self.account.domainid, services=self.services["virtual_machine"] ) self.debug("IP address: %s is acquired by network: %s" % ( - public_ip.ipaddress.ipaddress, + public_ip.ipaddress, self.guest_network.id)) self.debug("Creating LB rule for public IP: %s" % - public_ip.ipaddress.ipaddress) + public_ip.ipaddress) lb_rule = LoadBalancerRule.create( self.apiclient, self.services["lbrule"], - accountid=self.account.account.name, + accountid=self.account.name, ipaddressid=public_ip.ipaddress.id, networkid=self.guest_network.id, - domainid=self.account.account.domaind + domainid=self.account.domaind ) self.debug("Assigning VMs (%s, %s) to LB rule: %s" % (self.vm_1.name, self.vm_2.name, @@ -1225,10 +1225,10 @@ class TestELB(cloudstackTestCase): #TODO: workaround : add route in the guest VM for SNIP # # self.debug("SSHing into VMs using ELB IP: %s" % -# public_ip.ipaddress.ipaddress) +# public_ip.ipaddress) # try: # ssh_1 = self.vm_1.get_ssh_client( -# ipaddress=public_ip.ipaddress.ipaddress) +# ipaddress=public_ip.ipaddress) # self.debug("Command: hostname") # result = ssh_1.execute("hostname") # self.debug("Result: %s" % result) @@ -1244,7 +1244,7 @@ class TestELB(cloudstackTestCase): # ) # # ssh_2 = self.vm_2.get_ssh_client( -# ipaddress=public_ip.ipaddress.ipaddress) +# ipaddress=public_ip.ipaddress) # self.debug("Command: hostname") # result = ssh_2.execute("hostname") # self.debug("Result: %s" % result) @@ -1265,11 +1265,11 @@ class TestELB(cloudstackTestCase): ## Fetch details from user_ip_address table in database self.debug( "select is_system from user_ip_address where public_ip_address='%s';" \ - % public_ip.ipaddress.ipaddress) + % public_ip.ipaddress) qresultset = self.dbclient.execute( "select is_system from user_ip_address where public_ip_address='%s';" \ - % public_ip.ipaddress.ipaddress) + % public_ip.ipaddress) self.assertEqual( isinstance(qresultset, list), @@ -1304,7 +1304,7 @@ class TestELB(cloudstackTestCase): self.debug("Output: %s" % result) self.assertEqual( - result.count(public_ip.ipaddress.ipaddress), + result.count(public_ip.ipaddress), 1, "One IP from EIP pool should be taken and configured on NS" ) @@ -1316,7 +1316,7 @@ class TestELB(cloudstackTestCase): self.debug("Output: %s" % result) self.assertEqual( - result.count("Cloud-VirtualServer-%s-22 (%s:22) - TCP" % (public_ip.ipaddress.ipaddress, public_ip.ipaddress.ipaddress)), + result.count("Cloud-VirtualServer-%s-22 (%s:22) - TCP" % (public_ip.ipaddress, public_ip.ipaddress)), 1, "User subnet IP should be enabled for LB service" ) @@ -1342,12 +1342,12 @@ class TestELB(cloudstackTestCase): # running and USNIP : ON self.debug( - "Fetching LB IP for account: %s" % self.account.account.name) + "Fetching LB IP for account: %s" % self.account.name) ip_addrs = PublicIPAddress.list( self.api_client, associatednetworkid=self.guest_network.id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, forloadbalancing=True, listall=True ) @@ -1359,7 +1359,7 @@ class TestELB(cloudstackTestCase): lb_ip = ip_addrs[0] self.debug("LB IP generated for account: %s is: %s" % ( - self.account.account.name, + self.account.name, lb_ip.ipaddress )) @@ -1424,11 +1424,11 @@ class TestELB(cloudstackTestCase): # Fetch details from account_id table in database self.debug( "select id from account where account_name='%s';" \ - % self.account.account.name) + % self.account.name) qresultset = self.dbclient.execute( "select id from account where account_name='%s';" \ - % self.account.account.name) + % self.account.name) self.assertEqual( isinstance(qresultset, list), @@ -1467,7 +1467,7 @@ class TestELB(cloudstackTestCase): public_ip = qresult[0] self.debug( - "Fetching public IP for account: %s" % self.account.account.name) + "Fetching public IP for account: %s" % self.account.name) ip_addrs = PublicIPAddress.list( self.api_client, ipaddress=public_ip, diff --git a/test/integration/component/test_multiple_ip_ranges.py b/test/integration/component/test_multiple_ip_ranges.py new file mode 100644 index 00000000000..7e9e712aef0 --- /dev/null +++ b/test/integration/component/test_multiple_ip_ranges.py @@ -0,0 +1,429 @@ +# 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. +""" Tests for Multiple IP Ranges feature +""" +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.cloudstackException import cloudstackAPIException +from marvin.integration.lib.utils import * +from marvin.integration.lib.base import * +from marvin.integration.lib.common import * +from netaddr import * + +from nose.plugins.attrib import attr + +class Services: + """Test Multiple IP Ranges + """ + def __init__(self): + self.services = { + "account": { + "email": "test@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + # Random characters are appended for unique + # username + "password": "password", + }, + "service_offering": { + "name": "Tiny Instance", + "displaytext": "Tiny Instance", + "cpunumber": 1, + "cpuspeed": 200, # in MHz + "memory": 256, # In MBs + }, + "disk_offering": { + "displaytext": "Small Disk", + "name": "Small Disk", + "disksize": 1 + }, + "templates": { + "displaytext": 'Template', + "name": 'Template', + "ostype": "CentOS 5.3 (64-bit)", + "templatefilter": 'self', + }, + "vlan_ip_range": { + "startip": "", + "endip": "", + "netmask": "", + "gateway": "", + "forvirtualnetwork": "false", + "vlan": "untagged", + } + } + +class TestMultipleIpRanges(cloudstackTestCase): + """Test Multiple IP Ranges for guest network + """ + + + @classmethod + def setUpClass(cls): + cls.api_client = super(TestMultipleIpRanges, cls).getClsTestClient().getApiClient() + cls.services = Services().services + # Get Zone, Domain and templates + cls.domain = get_domain(cls.api_client, cls.services) + cls.zone = get_zone(cls.api_client, cls.services) + cls.pod = get_pod(cls.api_client, cls.zone.id, cls.services) + cls.services['mode'] = cls.zone.networktype + cls.services["domainid"] = cls.domain.id + cls.services["zoneid"] = cls.zone.id + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=cls.domain.id + ) + cls.services["account"] = cls.account.name + cls._cleanup = [ + cls.account, + ] + return + + @classmethod + def tearDownClass(cls): + try: + #Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [ ] + return + + def tearDown(self): + try: + #Clean up, terminate the resources created + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def increment_cidr(self): + """Takes CIDR as input and will increment by one and returns the new CIDR + """ + publicIpRange = PublicIpRange.list(self.apiclient) + self.startIp = publicIpRange[0].startip + self.endIp = publicIpRange[0].endip + self.gateway = publicIpRange[0].gateway + self.netmask = publicIpRange[0].netmask + #Pass ip address and mask length to IPNetwork to findout the CIDR + ip = IPNetwork(self.startIp+"/"+self.netmask) + new_cidr = ip.__iadd__(1) + ip2 = IPNetwork(new_cidr) + return ip2 + + def verify_vlan_range(self,vlan,services): + #compare vlan_list response with configured values + self.assertEqual( + isinstance(vlan, list), + True, + "Check list response returned a valid list" + ) + self.assertNotEqual( + len(vlan), + 0, + "check list vlan response" + ) + self.assertEqual( + str(vlan[0].startip), + str(services["startip"]), + "Start IP in vlan ip range is not matched with the configured start ip" + ) + self.assertEqual( + str(vlan[0].endip), + str(services["endip"]), + "End IP in vlan ip range is not matched with the configured end ip" + ) + self.assertEqual( + str(vlan[0].gateway), + str(services["gateway"]), + "gateway in vlan ip range is not matched with the configured gateway" + ) + self.assertEqual( + str(vlan[0].netmask), + str(services["netmask"]), + "netmask in vlan ip range is not matched with the configured netmask" + ) + return + + @attr(tags=["advanced_sg", "sg"]) + def test_01_add_ip_same_cidr(self): + """Test add guest ip range in the existing cidr + """ + #call increment_cidr function to get exiting cidr from the setup and increment it + ip2 = self.increment_cidr() + test_nw = ip2.network + ip = IPAddress(test_nw) + #Add IP range(5 IPs) in the new CIDR + test_gateway = ip.__add__(1) + test_startIp = ip.__add__(3) + test_endIp = ip.__add__(10) + test_startIp2= ip.__add__(11) + test_endIp2 = ip.__add__(15) + #Populating services with new IP range + self.services["vlan_ip_range"]["startip"] = test_startIp + self.services["vlan_ip_range"]["endip"] = test_endIp + self.services["vlan_ip_range"]["gateway"] = test_gateway + self.services["vlan_ip_range"]["netmask"] = self.netmask + self.services["vlan_ip_range"]["zoneid"] = self.zone.id + self.services["vlan_ip_range"]["podid"] = self.pod.id + #create new vlan ip range + new_vlan = PublicIpRange.create(self.apiclient, self.services["vlan_ip_range"]) + self.debug("Created new vlan range with startip:%s and endip:%s" %(test_startIp,test_endIp)) + self.cleanup.append(new_vlan) + new_vlan_res = new_vlan.list(self.apiclient,id=new_vlan.vlan.id) + #Compare list output with configured values + self.verify_vlan_range(new_vlan_res,self.services["vlan_ip_range"]) + #Add few more ips in the same CIDR + self.services["vlan_ip_range"]["startip"] = test_startIp2 + self.services["vlan_ip_range"]["endip"] = test_endIp2 + new_vlan2 = PublicIpRange.create(self.apiclient, self.services["vlan_ip_range"]) + self.debug("Created new vlan range with startip:%s and endip:%s" %(test_startIp2,test_endIp2)) + self.cleanup.append(new_vlan2) + #list new vlan ip range + new_vlan2_res = new_vlan2.list(self.apiclient,id=new_vlan2.vlan.id) + #Compare list output with configured values + self.verify_vlan_range(new_vlan2_res,self.services["vlan_ip_range"]) + return + + @attr(tags=["advanced_sg", "sg"]) + def test_02_add_ip_diff_cidr(self): + """Test add ip range in a new cidr + + Steps: + 1.Get public vlan range (guest cidr) from the setup + 2.Add IP range to a new cidr + """ + #call increment_cidr function to get exiting cidr from the setup and increment it + ip2 = self.increment_cidr() + test_nw = ip2.network + ip = IPAddress(test_nw) + #Add IP range(5 IPs) in the new CIDR + test_gateway = ip.__add__(1) + test_startIp = ip.__add__(3) + test_endIp = ip.__add__(10) + #Populating services with new IP range + self.services["vlan_ip_range"]["startip"] = test_startIp + self.services["vlan_ip_range"]["endip"] = test_endIp + self.services["vlan_ip_range"]["gateway"] = test_gateway + self.services["vlan_ip_range"]["netmask"] = self.netmask + self.services["vlan_ip_range"]["zoneid"] = self.zone.id + self.services["vlan_ip_range"]["podid"] = self.pod.id + #create new vlan ip range + new_vlan = PublicIpRange.create(self.apiclient, self.services["vlan_ip_range"]) + self.debug("Created new vlan range with startip:%s and endip:%s" %(test_startIp,test_endIp)) + self.cleanup.append(new_vlan) + new_vlan_res = new_vlan.list(self.apiclient,id=new_vlan.vlan.id) + #Compare list output with configured values + self.verify_vlan_range(new_vlan_res,self.services["vlan_ip_range"]) + return + + @attr(tags=["advanced-sg", "sg"]) + def test_03_del_ip_range(self): + """Test delete ip range + + Steps: + 1.Add ip range in same/new cidr + 2.delete the ip range added at step1 + 3.Verify the ip range deletion using list APIs + """ + #call increment_cidr function to get exiting cidr from the setup and increment it + ip2 = self.increment_cidr() + test_nw = ip2.network + ip = IPAddress(test_nw) + #Add IP range(5 IPs) in the new CIDR + test_gateway = ip.__add__(1) + test_startIp = ip.__add__(3) + test_endIp = ip.__add__(10) + #Populating services with new IP range + self.services["vlan_ip_range"]["startip"] = test_startIp + self.services["vlan_ip_range"]["endip"] = test_endIp + self.services["vlan_ip_range"]["gateway"] = test_gateway + self.services["vlan_ip_range"]["netmask"] = self.netmask + self.services["vlan_ip_range"]["zoneid"] = self.zone.id + self.services["vlan_ip_range"]["podid"] = self.pod.id + #create new vlan ip range + new_vlan = PublicIpRange.create(self.apiclient, self.services["vlan_ip_range"]) + self.debug("Created new vlan range with startip:%s and endip:%s" %(test_startIp,test_endIp)) + new_vlan_res = new_vlan.list(self.apiclient,id=new_vlan.vlan.id) + #Compare list output with configured values + self.verify_vlan_range(new_vlan_res,self.services["vlan_ip_range"]) + #Delete the above IP range + new_vlan.delete(self.apiclient) + #listing vlan ip ranges with the id should through exception , if not mark the test case as failed + try: + new_vlan.list(self.apiclient, id=new_vlan.vlan.id) + except cloudstackAPIException as cs: + self.debug(cs.errorMsg) + self.assertTrue(cs.errorMsg.find("entity does not exist")>0, msg="Failed to delete IP range") + return + + @attr(tags=["advanced-sg", "sg"]) + def test_04_add_noncontiguous_ip_range(self): + """Test adding non-contiguous ip range in existing cidr + + 1.Add ip range in new cidr + 1.Add non-contigous ip range in cidr added at step1 + 2.Verify the ip range using list APIs + """ + #call increment_cidr function to get exiting cidr from the setup and increment it + ip2 = self.increment_cidr() + test_nw = ip2.network + ip = IPAddress(test_nw) + #Add IP range(5 IPs) in the new CIDR + test_gateway = ip.__add__(1) + test_startIp = ip.__add__(50) + test_endIp = ip.__add__(60) + #Populating services with new IP range + self.services["vlan_ip_range"]["startip"] = test_startIp + self.services["vlan_ip_range"]["endip"] = test_endIp + self.services["vlan_ip_range"]["gateway"] = test_gateway + self.services["vlan_ip_range"]["netmask"] = self.netmask + self.services["vlan_ip_range"]["zoneid"] = self.zone.id + self.services["vlan_ip_range"]["podid"] = self.pod.id + #create new vlan ip range + new_vlan = PublicIpRange.create(self.apiclient, self.services["vlan_ip_range"]) + self.debug("Created new vlan range with startip:%s and endip:%s" %(test_startIp,test_endIp)) + self.cleanup.append(new_vlan) + new_vlan_res = new_vlan.list(self.apiclient,id=new_vlan.vlan.id) + #Compare list output with configured values + self.verify_vlan_range(new_vlan_res,self.services["vlan_ip_range"]) + #Add non-contiguous ip range in exiting cidr + test_startIp2 = ip.__add__(10) + test_endIp2 = ip.__add__(20) + #Populating services with new IP range + self.services["vlan_ip_range"]["startip"] = test_startIp2 + self.services["vlan_ip_range"]["endip"] = test_endIp2 + #create new vlan ip range + new_vlan = PublicIpRange.create(self.apiclient, self.services["vlan_ip_range"]) + self.debug("Created new vlan range with startip:%s and endip:%s" %(test_startIp,test_endIp)) + self.cleanup.append(new_vlan) + new_vlan_res = new_vlan.list(self.apiclient,id=new_vlan.vlan.id) + #Compare list output with configured values + self.verify_vlan_range(new_vlan_res,self.services["vlan_ip_range"]) + return + + @attr(tags=["advanced-sg", "sg"]) + def test_05_add_overlapped_ip_range(self): + """Test adding overlapped ip range in existing cidr + + 1.Add ip range in new cidr e.g:10.147.40.10-10.147.40.100 + 2.Add ip range overlapped with the ip range in step1 e.g.10.147.40.90-150 + """ + #call increment_cidr function to get exiting cidr from the setup and increment it + ip2 = self.increment_cidr() + test_nw = ip2.network + ip = IPAddress(test_nw) + #Add IP range in the new CIDR + test_gateway = ip.__add__(1) + test_startIp = ip.__add__(10) + test_endIp = ip.__add__(100) + test_startIp2 = ip.__add__(90) + test_endIp2 = ip.__add__(150) + #Populating services with new IP range + self.services["vlan_ip_range"]["startip"] = test_startIp + self.services["vlan_ip_range"]["endip"] = test_endIp + self.services["vlan_ip_range"]["gateway"] = test_gateway + self.services["vlan_ip_range"]["netmask"] = self.netmask + self.services["vlan_ip_range"]["zoneid"] = self.zone.id + self.services["vlan_ip_range"]["podid"] = self.pod.id + #create new vlan ip range + new_vlan = PublicIpRange.create(self.apiclient, self.services["vlan_ip_range"]) + self.debug("Created new vlan range with startip:%s and endip:%s" %(test_startIp,test_endIp)) + self.cleanup.append(new_vlan) + new_vlan_res = new_vlan.list(self.apiclient,id=new_vlan.vlan.id) + #Compare list output with configured values + self.verify_vlan_range(new_vlan_res,self.services["vlan_ip_range"]) + #Add overlapped ip range + #Populating services with new IP range + self.services["vlan_ip_range"]["startip"] = test_startIp2 + self.services["vlan_ip_range"]["endip"] = test_endIp2 + #Try to create ip range overlapped with exiting ip range + try: + PublicIpRange.create(self.apiclient, self.services["vlan_ip_range"]) + except cloudstackAPIException as cs: + self.debug(cs.errorMsg) + self.assertTrue(cs.errorMsg.find("already has IPs that overlap with the new range")>0, msg="Fail:CS allowed adding overlapped ip ranges in guest cidr") + return + #Test will reach here there is a bug in overlap ip range checking + self.fail("CS should not accept overlapped ip ranges in guest traffic, but it allowed") + return + + + @attr(tags=["advanced_sg", "sg"]) + def test_06_add_ip_range_overlapped_with_two_ranges(self): + """Test adding overlapped ip range in existing cidr + + 1.Add ip range in new cidr e.g:10.147.40.2-10.147.40.10 + 2.Add another ip range in the same cidr e.g:10.147.40.20-10.147.40.30 + 2.Add ip range overlapped with both the ip ranges e.g.10.147.40.10-20 + """ + #call increment_cidr function to get exiting cidr from the setup and increment it + ip2 = self.increment_cidr() + test_nw = ip2.network + ip = IPAddress(test_nw) + #Add IP range in the new CIDR + test_gateway = ip.__add__(1) + test_startIp = ip.__add__(2) + test_endIp = ip.__add__(10) + test_startIp2 = ip.__add__(20) + test_endIp2 = ip.__add__(30) + test_startIp3 = ip.__add__(10) + test_endIp3 = ip.__add__(20) + #Populating services with new IP range + self.services["vlan_ip_range"]["startip"] = test_startIp + self.services["vlan_ip_range"]["endip"] = test_endIp + self.services["vlan_ip_range"]["gateway"] = test_gateway + self.services["vlan_ip_range"]["netmask"] = self.netmask + self.services["vlan_ip_range"]["zoneid"] = self.zone.id + self.services["vlan_ip_range"]["podid"] = self.pod.id + #create new vlan ip range + new_vlan = PublicIpRange.create(self.apiclient, self.services["vlan_ip_range"]) + self.debug("Created new vlan range with startip:%s and endip:%s" %(test_startIp,test_endIp)) + self.cleanup.append(new_vlan) + new_vlan_res = new_vlan.list(self.apiclient,id=new_vlan.vlan.id) + #Compare list output with configured values + self.verify_vlan_range(new_vlan_res,self.services["vlan_ip_range"]) + #Add 2nd IP range in the same CIDR + self.services["vlan_ip_range"]["startip"] = test_startIp2 + self.services["vlan_ip_range"]["endip"] = test_endIp2 + new_vlan = PublicIpRange.create(self.apiclient, self.services["vlan_ip_range"]) + self.debug("Created new vlan range with startip:%s and endip:%s" %(test_startIp2,test_endIp2)) + self.cleanup.append(new_vlan) + new_vlan_res = new_vlan.list(self.apiclient,id=new_vlan.vlan.id) + #Compare list output with configured values + self.verify_vlan_range(new_vlan_res,self.services["vlan_ip_range"]) + #Add ip range which will overlap with two existing ip ranges in the same CIDR + #Populating services with new IP range + self.services["vlan_ip_range"]["startip"] = test_startIp3 + self.services["vlan_ip_range"]["endip"] = test_endIp3 + #Try to create ip range overlapped with exiting ip range + try: + PublicIpRange.create(self.apiclient, self.services["vlan_ip_range"]) + except cloudstackAPIException as cs: + self.debug(cs.errorMsg) + self.assertTrue(cs.errorMsg.find("already has IPs that overlap with the new range")>0, msg="Fail:CS allowed adding overlapped ip ranges in guest cidr") + return + #Test will reach here there is a bug in overlap ip range checking + self.fail("CS should not accept overlapped ip ranges in guest traffic, but it allowed") + return diff --git a/test/integration/component/test_network_offering.py b/test/integration/component/test_network_offering.py index 8b12525103a..e33c3765642 100644 --- a/test/integration/component/test_network_offering.py +++ b/test/integration/component/test_network_offering.py @@ -49,7 +49,7 @@ class Services: "displaytext": "Tiny Instance", "cpunumber": 1, "cpuspeed": 100, # in MHz - "memory": 64, # In MBs + "memory": 128, # In MBs }, "network_offering": { "name": 'Network offering-VR services', @@ -256,21 +256,21 @@ class TestNOVirtualRouter(cloudstackTestCase): self.network = Network.create( self.apiclient, self.services["network"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, networkofferingid=self.network_offering.id, zoneid=self.zone.id ) self.debug("Created network with ID: %s" % self.network.id) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) # Spawn an instance in that network virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, networkids=[str(self.network.id)] ) @@ -279,8 +279,8 @@ class TestNOVirtualRouter(cloudstackTestCase): src_nat_list = PublicIPAddress.list( self.apiclient, associatednetworkid=self.network.id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, listall=True, issourcenat=True, ) @@ -305,7 +305,7 @@ class TestNOVirtualRouter(cloudstackTestCase): self.apiclient, self.services["lbrule"], ipaddressid=src_nat.id, - accountid=self.account.account.name + accountid=self.account.name ) self.debug( "Trying to create a port forwarding rule in source NAT: %s" % @@ -322,18 +322,18 @@ class TestNOVirtualRouter(cloudstackTestCase): self.debug("Associating public IP for network: %s" % self.network.id) ip_with_nat_rule = PublicIPAddress.create( self.apiclient, - accountid=self.account.account.name, + accountid=self.account.name, zoneid=self.zone.id, - domainid=self.account.account.domainid, + domainid=self.account.domainid, networkid=self.network.id ) self.debug("Associated %s with network %s" % ( - ip_with_nat_rule.ipaddress.ipaddress, + ip_with_nat_rule.ipaddress, self.network.id )) self.debug("Creating PF rule for IP address: %s" % - ip_with_nat_rule.ipaddress.ipaddress) + ip_with_nat_rule.ipaddress) NATRule.create( self.apiclient, virtual_machine, @@ -342,7 +342,7 @@ class TestNOVirtualRouter(cloudstackTestCase): ) self.debug("Trying to create LB rule on IP with NAT: %s" % - ip_with_nat_rule.ipaddress.ipaddress) + ip_with_nat_rule.ipaddress) # Create Load Balancer rule on IP already having NAT rule with self.assertRaises(Exception): @@ -350,7 +350,7 @@ class TestNOVirtualRouter(cloudstackTestCase): self.apiclient, self.services["lbrule"], ipaddressid=ip_with_nat_rule.ipaddress.id, - accountid=self.account.account.name + accountid=self.account.name ) self.debug("Creating PF rule with public port: 66") @@ -376,27 +376,27 @@ class TestNOVirtualRouter(cloudstackTestCase): self.debug("Associating public IP for network: %s" % self.network.id) ip_with_lb_rule = PublicIPAddress.create( self.apiclient, - accountid=self.account.account.name, + accountid=self.account.name, zoneid=self.zone.id, - domainid=self.account.account.domainid, + domainid=self.account.domainid, networkid=self.network.id ) self.debug("Associated %s with network %s" % ( - ip_with_lb_rule.ipaddress.ipaddress, + ip_with_lb_rule.ipaddress, self.network.id )) self.debug("Creating LB rule for IP address: %s" % - ip_with_lb_rule.ipaddress.ipaddress) + ip_with_lb_rule.ipaddress) LoadBalancerRule.create( self.apiclient, self.services["lbrule"], ipaddressid=ip_with_lb_rule.ipaddress.id, - accountid=self.account.account.name + accountid=self.account.name ) self.debug("Trying to create PF rule on IP with LB rule: %s" % - ip_with_nat_rule.ipaddress.ipaddress) + ip_with_nat_rule.ipaddress) with self.assertRaises(Exception): NATRule.create( @@ -411,7 +411,7 @@ class TestNOVirtualRouter(cloudstackTestCase): self.apiclient, self.services["lbrule_port_2221"], ipaddressid=ip_with_lb_rule.ipaddress.id, - accountid=self.account.account.name + accountid=self.account.name ) # Check if NAT rule created successfully @@ -499,21 +499,21 @@ class TestNOVirtualRouter(cloudstackTestCase): self.network = Network.create( self.apiclient, self.services["network"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, networkofferingid=self.network_offering.id, zoneid=self.zone.id ) self.debug("Created network with ID: %s" % self.network.id) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) # Spawn an instance in that network virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, networkids=[str(self.network.id)] ) @@ -522,8 +522,8 @@ class TestNOVirtualRouter(cloudstackTestCase): src_nat_list = PublicIPAddress.list( self.apiclient, associatednetworkid=self.network.id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, listall=True, issourcenat=True, ) @@ -547,7 +547,7 @@ class TestNOVirtualRouter(cloudstackTestCase): self.apiclient, self.services["lbrule"], ipaddressid=src_nat.id, - accountid=self.account.account.name + accountid=self.account.name ) self.debug("Created LB rule on source NAT: %s" % src_nat.ipaddress) @@ -624,18 +624,18 @@ class TestNOVirtualRouter(cloudstackTestCase): self.debug("Associating public IP for network: %s" % self.network.id) public_ip = PublicIPAddress.create( self.apiclient, - accountid=self.account.account.name, + accountid=self.account.name, zoneid=self.zone.id, - domainid=self.account.account.domainid, + domainid=self.account.domainid, networkid=self.network.id ) self.debug("Associated %s with network %s" % ( - public_ip.ipaddress.ipaddress, + public_ip.ipaddress, self.network.id )) self.debug("Creating PF rule for IP address: %s" % - public_ip.ipaddress.ipaddress) + public_ip.ipaddress) NATRule.create( self.apiclient, virtual_machine, @@ -644,14 +644,14 @@ class TestNOVirtualRouter(cloudstackTestCase): ) self.debug("Trying to create LB rule on IP with NAT: %s" % - public_ip.ipaddress.ipaddress) + public_ip.ipaddress) # Create Load Balancer rule on IP already having NAT rule lb_rule = LoadBalancerRule.create( self.apiclient, self.services["lbrule"], ipaddressid=public_ip.ipaddress.id, - accountid=self.account.account.name + accountid=self.account.name ) self.debug("Creating PF rule with public port: 66") @@ -679,7 +679,7 @@ class TestNOVirtualRouter(cloudstackTestCase): self.apiclient, self.services["lbrule_port_2221"], ipaddressid=public_ip.ipaddress.id, - accountid=self.account.account.name + accountid=self.account.name ) # Check if NAT rule created successfully @@ -700,8 +700,8 @@ class TestNOVirtualRouter(cloudstackTestCase): vpn = Vpn.create( self.apiclient, src_nat.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) vpns = Vpn.list( @@ -834,21 +834,21 @@ class TestNOWithNetscaler(cloudstackTestCase): self.network = Network.create( self.apiclient, self.services["network"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, networkofferingid=self.network_offering.id, zoneid=self.zone.id ) self.debug("Created network with ID: %s" % self.network.id) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) # Spawn an instance in that network virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, networkids=[str(self.network.id)] ) @@ -857,8 +857,8 @@ class TestNOWithNetscaler(cloudstackTestCase): src_nat_list = PublicIPAddress.list( self.apiclient, associatednetworkid=self.network.id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, listall=True, issourcenat=True, ) @@ -883,7 +883,7 @@ class TestNOWithNetscaler(cloudstackTestCase): self.apiclient, self.services["lbrule"], ipaddressid=src_nat.id, - accountid=self.account.account.name + accountid=self.account.name ) self.debug( @@ -930,18 +930,18 @@ class TestNOWithNetscaler(cloudstackTestCase): self.debug("Associating public IP for network: %s" % self.network.id) ip_with_nat_rule = PublicIPAddress.create( self.apiclient, - accountid=self.account.account.name, + accountid=self.account.name, zoneid=self.zone.id, - domainid=self.account.account.domainid, + domainid=self.account.domainid, networkid=self.network.id ) self.debug("Associated %s with network %s" % ( - ip_with_nat_rule.ipaddress.ipaddress, + ip_with_nat_rule.ipaddress, self.network.id )) self.debug("Creating PF rule for IP address: %s" % - ip_with_nat_rule.ipaddress.ipaddress) + ip_with_nat_rule.ipaddress) NATRule.create( self.apiclient, virtual_machine, @@ -950,7 +950,7 @@ class TestNOWithNetscaler(cloudstackTestCase): ) self.debug("Trying to create LB rule on IP with NAT: %s" % - ip_with_nat_rule.ipaddress.ipaddress) + ip_with_nat_rule.ipaddress) # Create Load Balancer rule on IP already having NAT rule with self.assertRaises(Exception): @@ -958,7 +958,7 @@ class TestNOWithNetscaler(cloudstackTestCase): self.apiclient, self.services["lbrule"], ipaddressid=ip_with_nat_rule.ipaddress.id, - accountid=self.account.account.name + accountid=self.account.name ) self.debug("Creating PF rule with public port: 66") @@ -984,28 +984,28 @@ class TestNOWithNetscaler(cloudstackTestCase): self.debug("Associating public IP for network: %s" % self.network.id) ip_with_lb_rule = PublicIPAddress.create( self.apiclient, - accountid=self.account.account.name, + accountid=self.account.name, zoneid=self.zone.id, - domainid=self.account.account.domainid, + domainid=self.account.domainid, networkid=self.network.id ) self.debug("Associated %s with network %s" % ( - ip_with_lb_rule.ipaddress.ipaddress, + ip_with_lb_rule.ipaddress, self.network.id )) self.debug("Creating LB rule for IP address: %s" % - ip_with_lb_rule.ipaddress.ipaddress) + ip_with_lb_rule.ipaddress) LoadBalancerRule.create( self.apiclient, self.services["lbrule"], ipaddressid=ip_with_lb_rule.ipaddress.id, - accountid=self.account.account.name, + accountid=self.account.name, networkid=self.network.id ) self.debug("Trying to create PF rule on IP with LB rule: %s" % - ip_with_nat_rule.ipaddress.ipaddress) + ip_with_nat_rule.ipaddress) with self.assertRaises(Exception): NATRule.create( @@ -1031,7 +1031,7 @@ class TestNOWithNetscaler(cloudstackTestCase): self.apiclient, self.services["lbrule_port_2221"], ipaddressid=ip_with_lb_rule.ipaddress.id, - accountid=self.account.account.name, + accountid=self.account.name, networkid=self.network.id ) @@ -1054,8 +1054,8 @@ class TestNOWithNetscaler(cloudstackTestCase): Vpn.create( self.apiclient, src_nat.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) return @@ -1104,21 +1104,21 @@ class TestNOWithNetscaler(cloudstackTestCase): self.network = Network.create( self.apiclient, self.services["network"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, networkofferingid=self.network_offering.id, zoneid=self.zone.id ) self.debug("Created network with ID: %s" % self.network.id) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) # Spawn an instance in that network virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, networkids=[str(self.network.id)] ) @@ -1127,8 +1127,8 @@ class TestNOWithNetscaler(cloudstackTestCase): src_nat_list = PublicIPAddress.list( self.apiclient, associatednetworkid=self.network.id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, listall=True, issourcenat=True, ) @@ -1153,7 +1153,7 @@ class TestNOWithNetscaler(cloudstackTestCase): self.apiclient, self.services["lbrule"], ipaddressid=src_nat.id, - accountid=self.account.account.name + accountid=self.account.name ) self.debug( @@ -1213,18 +1213,18 @@ class TestNOWithNetscaler(cloudstackTestCase): self.debug("Associating public IP for network: %s" % self.network.id) ip_with_nat_rule = PublicIPAddress.create( self.apiclient, - accountid=self.account.account.name, + accountid=self.account.name, zoneid=self.zone.id, - domainid=self.account.account.domainid, + domainid=self.account.domainid, networkid=self.network.id ) self.debug("Associated %s with network %s" % ( - ip_with_nat_rule.ipaddress.ipaddress, + ip_with_nat_rule.ipaddress, self.network.id )) self.debug("Creating PF rule for IP address: %s" % - ip_with_nat_rule.ipaddress.ipaddress) + ip_with_nat_rule.ipaddress) NATRule.create( self.apiclient, virtual_machine, @@ -1233,7 +1233,7 @@ class TestNOWithNetscaler(cloudstackTestCase): ) self.debug("Trying to create LB rule on IP with NAT: %s" % - ip_with_nat_rule.ipaddress.ipaddress) + ip_with_nat_rule.ipaddress) # Create Load Balancer rule on IP already having NAT rule with self.assertRaises(Exception): @@ -1241,7 +1241,7 @@ class TestNOWithNetscaler(cloudstackTestCase): self.apiclient, self.services["lbrule"], ipaddressid=ip_with_nat_rule.ipaddress.id, - accountid=self.account.account.name + accountid=self.account.name ) self.debug("Creating PF rule with public port: 66") @@ -1267,28 +1267,28 @@ class TestNOWithNetscaler(cloudstackTestCase): self.debug("Associating public IP for network: %s" % self.network.id) ip_with_lb_rule = PublicIPAddress.create( self.apiclient, - accountid=self.account.account.name, + accountid=self.account.name, zoneid=self.zone.id, - domainid=self.account.account.domainid, + domainid=self.account.domainid, networkid=self.network.id ) self.debug("Associated %s with network %s" % ( - ip_with_lb_rule.ipaddress.ipaddress, + ip_with_lb_rule.ipaddress, self.network.id )) self.debug("Creating LB rule for IP address: %s" % - ip_with_lb_rule.ipaddress.ipaddress) + ip_with_lb_rule.ipaddress) LoadBalancerRule.create( self.apiclient, self.services["lbrule"], ipaddressid=ip_with_lb_rule.ipaddress.id, - accountid=self.account.account.name, + accountid=self.account.name, networkid=self.network.id ) self.debug("Trying to create PF rule on IP with LB rule: %s" % - ip_with_nat_rule.ipaddress.ipaddress) + ip_with_nat_rule.ipaddress) with self.assertRaises(Exception): NATRule.create( @@ -1314,7 +1314,7 @@ class TestNOWithNetscaler(cloudstackTestCase): self.apiclient, self.services["lbrule_port_2221"], ipaddressid=ip_with_lb_rule.ipaddress.id, - accountid=self.account.account.name, + accountid=self.account.name, networkid=self.network.id ) @@ -1336,8 +1336,8 @@ class TestNOWithNetscaler(cloudstackTestCase): vpn = Vpn.create( self.apiclient, src_nat.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) vpns = Vpn.list( @@ -1457,21 +1457,21 @@ class TestNetworkUpgrade(cloudstackTestCase): self.network = Network.create( self.apiclient, self.services["network"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, networkofferingid=self.network_offering.id, zoneid=self.zone.id ) self.debug("Created network with ID: %s" % self.network.id) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) # Spawn an instance in that network virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, networkids=[str(self.network.id)] ) @@ -1480,8 +1480,8 @@ class TestNetworkUpgrade(cloudstackTestCase): src_nat_list = PublicIPAddress.list( self.apiclient, associatednetworkid=self.network.id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, listall=True, issourcenat=True, ) @@ -1504,7 +1504,7 @@ class TestNetworkUpgrade(cloudstackTestCase): self.apiclient, self.services["lbrule"], ipaddressid=src_nat.id, - accountid=self.account.account.name + accountid=self.account.name ) self.debug("Created LB rule on source NAT: %s" % src_nat.ipaddress) @@ -1585,8 +1585,8 @@ class TestNetworkUpgrade(cloudstackTestCase): vpn = Vpn.create( self.apiclient, src_nat.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) vpns = Vpn.list( @@ -1657,21 +1657,21 @@ class TestNetworkUpgrade(cloudstackTestCase): self.network = Network.create( self.apiclient, self.services["network"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, networkofferingid=self.network_offering.id, zoneid=self.zone.id ) self.debug("Created network with ID: %s" % self.network.id) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) # Spawn an instance in that network virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, networkids=[str(self.network.id)] ) @@ -1680,8 +1680,8 @@ class TestNetworkUpgrade(cloudstackTestCase): src_nat_list = PublicIPAddress.list( self.apiclient, associatednetworkid=self.network.id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, listall=True, issourcenat=True, ) @@ -1704,7 +1704,7 @@ class TestNetworkUpgrade(cloudstackTestCase): self.apiclient, self.services["lbrule"], ipaddressid=src_nat.id, - accountid=self.account.account.name + accountid=self.account.name ) self.debug("Created LB rule on source NAT: %s" % src_nat.ipaddress) @@ -1785,8 +1785,8 @@ class TestNetworkUpgrade(cloudstackTestCase): vpn = Vpn.create( self.apiclient, src_nat.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) vpns = Vpn.list( @@ -1921,21 +1921,21 @@ class TestSharedNetworkWithoutIp(cloudstackTestCase): self.network = Network.create( self.apiclient, self.services["network"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, networkofferingid=shared_nw_off.id, zoneid=self.zone.id ) self.debug("Created network with ID: %s" % self.network.id) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) try: # Spawn an instance in that network VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, networkids=[str(self.network.id)] ) diff --git a/test/integration/component/test_project_configs.py b/test/integration/component/test_project_configs.py index f1469f22e52..1eef123b2ee 100644 --- a/test/integration/component/test_project_configs.py +++ b/test/integration/component/test_project_configs.py @@ -70,7 +70,7 @@ class Services: "displaytext": "Tiny Instance", "cpunumber": 1, "cpuspeed": 100, # in MHz - "memory": 64, # In MBs + "memory": 128, # In MBs }, "virtual_machine": { "displayname": "Test VM", @@ -206,8 +206,8 @@ class TestUserProjectCreation(cloudstackTestCase): project = Project.create( self.apiclient, self.services["project"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Cleanup created project at end of test self.cleanup.append(project) @@ -242,8 +242,8 @@ class TestUserProjectCreation(cloudstackTestCase): project = Project.create( self.apiclient, self.services["project"], - account=self.user.account.name, - domainid=self.user.account.domainid + account=self.user.name, + domainid=self.user.domainid ) # Cleanup created project at end of test self.cleanup.append(project) @@ -373,8 +373,8 @@ class TestProjectCreationNegative(cloudstackTestCase): project = Project.create( self.apiclient, self.services["project"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Cleanup created project at end of test self.cleanup.append(project) @@ -409,11 +409,11 @@ class TestProjectCreationNegative(cloudstackTestCase): project = Project.create( self.apiclient, self.services["project"], - account=self.user.account.name, - domainid=self.user.account.domainid + account=self.user.name, + domainid=self.user.domainid ) self.debug("Project creation with domain user: %s failed" % - self.user.account.name) + self.user.name) return @@ -498,8 +498,8 @@ class TestProjectInviteRequired(cloudstackTestCase): project = Project.create( self.apiclient, self.services["project"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Cleanup created project at end of test self.cleanup.append(project) @@ -531,21 +531,21 @@ class TestProjectInviteRequired(cloudstackTestCase): "Check project name from list response" ) self.debug("Adding %s user to project: %s" % ( - self.user.account.name, + self.user.name, project.name )) # Add user to the project project.addAccount( self.apiclient, - self.user.account.name, - self.user.account.email + self.user.name, + self.user.email ) # listProjectAccount to verify the user is added to project or not accounts_reponse = Project.listAccounts( self.apiclient, projectid=project.id, - account=self.user.account.name, + account=self.user.name, ) self.debug(accounts_reponse) self.assertEqual( @@ -650,8 +650,8 @@ class TestProjectInviteRequiredTrue(cloudstackTestCase): project = Project.create( self.apiclient, self.services["project"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Cleanup created project at end of test self.cleanup.append(project) @@ -684,22 +684,22 @@ class TestProjectInviteRequiredTrue(cloudstackTestCase): "Check project name from list response" ) self.debug("Adding %s user to project: %s" % ( - self.user.account.name, + self.user.name, project.name )) # Add user to the project project.addAccount( self.apiclient, - self.user.account.name, - self.user.account.email + self.user.name, + self.user.email ) # listProjectAccount to verify the user is added to project or not accounts_reponse = ProjectInvitation.list( self.apiclient, state='Pending', - account=self.user.account.name, - domainid=self.user.account.domainid + account=self.user.name, + domainid=self.user.domainid ) self.assertEqual( isinstance(accounts_reponse, list), @@ -819,8 +819,8 @@ class TestProjectInviteTimeout(cloudstackTestCase): project = Project.create( self.apiclient, self.services["project"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Cleanup created project at end of test self.cleanup.append(project) @@ -853,22 +853,22 @@ class TestProjectInviteTimeout(cloudstackTestCase): "Check project name from list response" ) self.debug("Adding %s user to project: %s" % ( - self.user.account.name, + self.user.name, project.name )) # Add user to the project project.addAccount( self.apiclient, - self.user.account.name, - self.user.account.email + self.user.name, + self.user.email ) # listProjectAccount to verify the user is added to project or not accounts_reponse = ProjectInvitation.list( self.apiclient, state='Pending', - account=self.user.account.name, - domainid=self.user.account.domainid + account=self.user.name, + domainid=self.user.domainid ) self.assertEqual( isinstance(accounts_reponse, list), @@ -894,18 +894,18 @@ class TestProjectInviteTimeout(cloudstackTestCase): self.apiclient, projectid=project.id, accept=True, - account=self.user.account.name + account=self.user.name ) self.debug( "Accepting project invitation for project: %s user: %s" % ( project.name, - self.user.account.name + self.user.name )) # listProjectAccount to verify the user is added to project or not accounts_reponse = Project.listAccounts( self.apiclient, projectid=project.id, - account=self.user.account.name, + account=self.user.name, ) self.assertEqual( @@ -945,8 +945,8 @@ class TestProjectInviteTimeout(cloudstackTestCase): project = Project.create( self.apiclient, self.services["project"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Cleanup created project at end of test self.cleanup.append(project) @@ -979,22 +979,22 @@ class TestProjectInviteTimeout(cloudstackTestCase): "Check project name from list response" ) self.debug("Adding %s user to project: %s" % ( - self.user.account.name, + self.user.name, project.name )) # Add user to the project project.addAccount( self.apiclient, - self.user.account.name, - self.user.account.email + self.user.name, + self.user.email ) # listProjectAccount to verify the user is added to project or not accounts_reponse = ProjectInvitation.list( self.apiclient, state='Pending', - account=self.user.account.name, - domainid=self.user.account.domainid + account=self.user.name, + domainid=self.user.domainid ) self.assertEqual( isinstance(accounts_reponse, list), @@ -1025,18 +1025,18 @@ class TestProjectInviteTimeout(cloudstackTestCase): self.apiclient, projectid=project.id, accept=True, - account=self.user.account.name + account=self.user.name ) self.debug( "Accepting invitation after expiry project: %s user: %s" % ( project.name, - self.user.account.name + self.user.name )) # listProjectAccount to verify the user is added to project or not accounts_reponse = ProjectInvitation.list( self.apiclient, - account=self.user.account.name, - domainid=self.user.account.domainid + account=self.user.name, + domainid=self.user.domainid ) self.assertEqual( @@ -1076,8 +1076,8 @@ class TestProjectInviteTimeout(cloudstackTestCase): project = Project.create( self.apiclient, self.services["project"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Cleanup created project at end of test self.cleanup.append(project) @@ -1110,22 +1110,22 @@ class TestProjectInviteTimeout(cloudstackTestCase): "Check project name from list response" ) self.debug("Adding %s user to project: %s" % ( - self.user.account.name, + self.user.name, project.name )) # Add user to the project project.addAccount( self.apiclient, - self.user.account.name, - self.user.account.email + self.user.name, + self.user.email ) # listProjectAccount to verify the user is added to project or not accounts_reponse = ProjectInvitation.list( self.apiclient, state='Pending', - account=self.user.account.name, - domainid=self.user.account.domainid + account=self.user.name, + domainid=self.user.domainid ) self.assertEqual( isinstance(accounts_reponse, list), @@ -1151,22 +1151,22 @@ class TestProjectInviteTimeout(cloudstackTestCase): time.sleep(int(self.config.value) * 2) self.debug("Adding %s user again to project: %s" % ( - self.user.account.name, + self.user.name, project.name )) # Add user to the project project.addAccount( self.apiclient, - self.user.account.name, - self.user.account.email + self.user.name, + self.user.email ) # listProjectAccount to verify the user is added to project or not accounts_reponse = ProjectInvitation.list( self.apiclient, state='Pending', - account=self.user.account.name, - domainid=self.user.account.domainid + account=self.user.name, + domainid=self.user.domainid ) self.assertEqual( isinstance(accounts_reponse, list), @@ -1205,8 +1205,8 @@ class TestProjectInviteTimeout(cloudstackTestCase): project = Project.create( self.apiclient, self.services["project"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Cleanup created project at end of test self.cleanup.append(project) @@ -1239,22 +1239,22 @@ class TestProjectInviteTimeout(cloudstackTestCase): "Check project name from list response" ) self.debug("Adding %s user to project: %s" % ( - self.user.account.name, + self.user.name, project.name )) # Add user to the project project.addAccount( self.apiclient, - self.user.account.name, - self.user.account.email + self.user.name, + self.user.email ) # listProjectAccount to verify the user is added to project or not accounts_reponse = ProjectInvitation.list( self.apiclient, state='Pending', - account=self.user.account.name, - domainid=self.user.account.domainid + account=self.user.name, + domainid=self.user.domainid ) self.assertEqual( isinstance(accounts_reponse, list), @@ -1279,18 +1279,18 @@ class TestProjectInviteTimeout(cloudstackTestCase): self.apiclient, projectid=project.id, accept=False, - account=self.user.account.name + account=self.user.name ) self.debug( "Declining invitation for project: %s user: %s" % ( project.name, - self.user.account.name + self.user.name )) # listProjectAccount to verify the user is added to project or not accounts_reponse = Project.listAccounts( self.apiclient, projectid=project.id, - account=self.user.account.name, + account=self.user.name, ) self.assertEqual( accounts_reponse, @@ -1333,8 +1333,8 @@ class TestProjectInviteTimeout(cloudstackTestCase): project = Project.create( self.apiclient, self.services["project"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Cleanup created project at end of test self.cleanup.append(project) @@ -1367,19 +1367,19 @@ class TestProjectInviteTimeout(cloudstackTestCase): "Check project name from list response" ) self.debug("Adding user with email: %s to project: %s" % ( - self.user.account.email, + self.user.email, project.name )) # Add user to the project project.addAccount( self.apiclient, - email=self.user.account.user[0].email + email=self.user.user[0].email ) # Fetch the latest mail sent to user mail_content = fetch_latest_mail( self.services["mail_account"], - from_mail=self.user.account.user[0].email + from_mail=self.user.user[0].email ) return diff --git a/test/integration/component/test_project_limits.py b/test/integration/component/test_project_limits.py index ab13238e187..17ddfc67da5 100644 --- a/test/integration/component/test_project_limits.py +++ b/test/integration/component/test_project_limits.py @@ -63,7 +63,7 @@ class Services: "displaytext": "Tiny Instance", "cpunumber": 1, "cpuspeed": 100, # in MHz - "memory": 64, # In MBs + "memory": 128, # In MBs }, "disk_offering": { "displaytext": "Tiny Disk Offering", @@ -429,14 +429,14 @@ class TestProjectLimits(cloudstackTestCase): ) self.debug("Adding %s user to project: %s" % ( - self.user.account.name, + self.user.name, project.name )) # Add user to the project project.addAccount( self.apiclient, - self.user.account.name, + self.user.name, ) # Get the resource limits for domain @@ -459,14 +459,14 @@ class TestProjectLimits(cloudstackTestCase): #with self.assertRaises(Exception): self.debug( "Attempting to update resource limit by user: %s" % ( - self.user.account.name + self.user.name )) # Update project resource limits to 3 update_resource_limit( self.apiclient, resource.resourcetype, - account=self.user.account.name, - domainid=self.user.account.domainid, + account=self.user.name, + domainid=self.user.domainid, max=3, projectid=project.id ) @@ -505,10 +505,10 @@ class TestResourceLimitsProject(cloudstackTestCase): cls.project = Project.create( cls.api_client, cls.services["project"], - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name # Create Service offering and disk offerings etc cls.service_offering = ServiceOffering.create( @@ -720,7 +720,7 @@ class TestResourceLimitsProject(cloudstackTestCase): projectid=self.project.id ) - self.debug("Deploying VM for account: %s" % self.account.account.name) + self.debug("Deploying VM for account: %s" % self.account.name) virtual_machine_1 = VirtualMachine.create( self.apiclient, self.services["server"], @@ -843,7 +843,7 @@ class TestResourceLimitsProject(cloudstackTestCase): ) self.debug( "Updating template resource limits for domain: %s" % - self.account.account.domainid) + self.account.domainid) # Set usage_vm=1 for Account 1 update_resource_limit( self.apiclient, @@ -852,7 +852,7 @@ class TestResourceLimitsProject(cloudstackTestCase): projectid=self.project.id ) - self.debug("Deploying VM for account: %s" % self.account.account.name) + self.debug("Deploying VM for account: %s" % self.account.name) virtual_machine_1 = VirtualMachine.create( self.apiclient, self.services["server"], @@ -994,13 +994,13 @@ class TestMaxProjectNetworks(cloudstackTestCase): # 3. Create network should fail self.debug("Creating project with '%s' as admin" % - self.account.account.name) + self.account.name) # Create project as a domain admin project = Project.create( self.apiclient, self.services["project"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Cleanup created project at end of test self.cleanup.append(project) diff --git a/test/integration/component/test_project_resources.py b/test/integration/component/test_project_resources.py index 191ceb54cb6..84141889f3f 100644 --- a/test/integration/component/test_project_resources.py +++ b/test/integration/component/test_project_resources.py @@ -64,7 +64,7 @@ class Services: "displaytext": "Tiny Instance", "cpunumber": 1, "cpuspeed": 100, # in MHz - "memory": 64, # In MBs + "memory": 128, # In MBs }, "disk_offering": { "displaytext": "Tiny Disk Offering", @@ -220,8 +220,8 @@ class TestOfferings(cloudstackTestCase): project = Project.create( self.apiclient, self.services["project"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Cleanup created project at end of test self.cleanup.append(project) @@ -263,8 +263,8 @@ class TestOfferings(cloudstackTestCase): project = Project.create( self.apiclient, self.services["project"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Cleanup created project at end of test self.cleanup.append(project) @@ -400,8 +400,8 @@ class TestNetwork(cloudstackTestCase): project = Project.create( self.apiclient, self.services["project"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Cleanup created project at end of test self.cleanup.append(project) @@ -546,10 +546,10 @@ class TestTemplates(cloudstackTestCase): cls.project = Project.create( cls.api_client, cls.services["project"], - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name # Create Service offering and disk offerings etc cls.service_offering = ServiceOffering.create( @@ -771,10 +771,10 @@ class TestSnapshots(cloudstackTestCase): cls.project = Project.create( cls.api_client, cls.services["project"], - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name # Create Service offering and disk offerings etc cls.service_offering = ServiceOffering.create( @@ -872,8 +872,8 @@ class TestSnapshots(cloudstackTestCase): snapshots = Snapshot.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( snapshots, @@ -918,10 +918,10 @@ class TestPublicIpAddress(cloudstackTestCase): cls.project = Project.create( cls.api_client, cls.services["project"], - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name # Create Service offering and disk offerings etc cls.service_offering = ServiceOffering.create( @@ -1037,7 +1037,7 @@ class TestPublicIpAddress(cloudstackTestCase): #Create Load Balancer rule and assign VMs to rule self.debug("Created LB rule for public IP: %s" % - public_ip.ipaddress.ipaddress) + public_ip.ipaddress) lb_rule = LoadBalancerRule.create( self.apiclient, self.services["lbrule"], @@ -1112,13 +1112,13 @@ class TestPublicIpAddress(cloudstackTestCase): "Check end port of firewall rule" ) - self.debug("Deploying VM for account: %s" % self.account.account.name) + self.debug("Deploying VM for account: %s" % self.account.name) virtual_machine_1 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, ) self.cleanup.append(virtual_machine_1) @@ -1142,17 +1142,17 @@ class TestPublicIpAddress(cloudstackTestCase): ) self.debug("Creating LB rule for public IP: %s outside project" % - public_ip.ipaddress.ipaddress) + public_ip.ipaddress) with self.assertRaises(Exception): LoadBalancerRule.create( self.apiclient, self.services["lbrule"], public_ip.ipaddress.id, - accountid=self.account.account.name + accountid=self.account.name ) self.debug( "Creating firewall rule for public IP: %s outside project" % - public_ip.ipaddress.ipaddress) + public_ip.ipaddress) with self.assertRaises(Exception): FireWallRule.create( self.apiclient, @@ -1219,10 +1219,10 @@ class TestSecurityGroup(cloudstackTestCase): cls.project = Project.create( cls.api_client, cls.services["project"], - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls._cleanup = [ cls.project, @@ -1317,8 +1317,8 @@ class TestSecurityGroup(cloudstackTestCase): self.apiclient, self.services["server"], serviceofferingid=self.service_offering.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, securitygroupids=[security_group.id], ) return diff --git a/test/integration/component/test_project_usage.py b/test/integration/component/test_project_usage.py index 03c42fd196f..ab789e1c13d 100644 --- a/test/integration/component/test_project_usage.py +++ b/test/integration/component/test_project_usage.py @@ -52,7 +52,7 @@ class Services: "displaytext": "Tiny Instance", "cpunumber": 1, "cpuspeed": 100, # in MHz - "memory": 64, # In MBs + "memory": 128, # In MBs }, "disk_offering": { "displaytext": "Small", @@ -142,13 +142,13 @@ class TestVmUsage(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.project = Project.create( cls.api_client, cls.services["project"], - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) cls.service_offering = ServiceOffering.create( @@ -337,13 +337,13 @@ class TestPublicIPUsage(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.project = Project.create( cls.api_client, cls.services["project"], - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) cls.service_offering = ServiceOffering.create( @@ -416,7 +416,7 @@ class TestPublicIPUsage(cloudstackTestCase): # 3. Delete the newly created account self.debug("Deleting public IP: %s" % - self.public_ip.ipaddress.ipaddress) + self.public_ip.ipaddress) # Release one of the IP self.public_ip.delete(self.apiclient) @@ -512,13 +512,13 @@ class TestVolumeUsage(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.project = Project.create( cls.api_client, cls.services["project"], - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) cls.service_offering = ServiceOffering.create( @@ -689,13 +689,13 @@ class TestTemplateUsage(cloudstackTestCase): cls.services["account"], domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.project = Project.create( cls.api_client, cls.services["project"], - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) cls.service_offering = ServiceOffering.create( @@ -858,12 +858,12 @@ class TestISOUsage(cloudstackTestCase): cls.services["account"], domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.project = Project.create( cls.api_client, cls.services["project"], - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) cls.iso = Iso.create( @@ -1014,13 +1014,13 @@ class TestLBRuleUsage(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.project = Project.create( cls.api_client, cls.services["project"], - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) cls.service_offering = ServiceOffering.create( @@ -1198,13 +1198,13 @@ class TestSnapshotUsage(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.project = Project.create( cls.api_client, cls.services["project"], - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) cls.service_offering = ServiceOffering.create( @@ -1375,13 +1375,13 @@ class TestNatRuleUsage(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.project = Project.create( cls.api_client, cls.services["project"], - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) cls.service_offering = ServiceOffering.create( @@ -1559,13 +1559,13 @@ class TestVpnUsage(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.project = Project.create( cls.api_client, cls.services["project"], - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) cls.service_offering = ServiceOffering.create( @@ -1648,7 +1648,7 @@ class TestVpnUsage(cloudstackTestCase): ) self.debug("Created VPN user for account: %s" % - self.account.account.name) + self.account.name) vpnuser = VpnUser.create( self.apiclient, diff --git a/test/integration/component/test_projects.py b/test/integration/component/test_projects.py index 95df5bf8c30..f013e99a0dd 100644 --- a/test/integration/component/test_projects.py +++ b/test/integration/component/test_projects.py @@ -78,7 +78,7 @@ class Services: "displaytext": "Tiny Instance", "cpunumber": 1, "cpuspeed": 100, # in MHz - "memory": 64, # In MBs + "memory": 128, # In MBs }, "virtual_machine": { "displayname": "Test VM", @@ -183,8 +183,8 @@ class TestMultipleProjectCreation(cloudstackTestCase): project_1 = Project.create( self.apiclient, self.services["project"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Cleanup created project at end of test self.cleanup.append(project_1) @@ -218,8 +218,8 @@ class TestMultipleProjectCreation(cloudstackTestCase): project_2 = Project.create( self.apiclient, self.services["project"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Cleanup created project at end of test self.cleanup.append(project_2) @@ -248,15 +248,15 @@ class TestMultipleProjectCreation(cloudstackTestCase): # Add user to the project project_1.addAccount( self.apiclient, - self.user.account.name, - self.user.account.email + self.user.name, + self.user.email ) # listProjectAccount to verify the user is added to project or not accounts_reponse = Project.listAccounts( self.apiclient, projectid=project_1.id, - account=self.user.account.name, + account=self.user.name, ) self.debug(accounts_reponse) self.assertEqual( @@ -280,15 +280,15 @@ class TestMultipleProjectCreation(cloudstackTestCase): # Add user to the project project_2.addAccount( self.apiclient, - self.user.account.name, - self.user.account.email + self.user.name, + self.user.email ) # listProjectAccount to verify the user is added to project or not accounts_reponse = Project.listAccounts( self.apiclient, projectid=project_2.id, - account=self.user.account.name, + account=self.user.name, ) self.debug(accounts_reponse) self.assertEqual( @@ -398,8 +398,8 @@ class TestCrossDomainAccountAdd(cloudstackTestCase): project = Project.create( self.apiclient, self.services["project"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Cleanup created project at end of test self.cleanup.append(project) @@ -432,15 +432,15 @@ class TestCrossDomainAccountAdd(cloudstackTestCase): ) self.debug("Adding user: %s from domain: %s to project: %s" % ( - self.user.account.name, - self.user.account.domainid, + self.user.name, + self.user.domainid, project.id )) with self.assertRaises(Exception): # Add user to the project from different domain project.addAccount( self.apiclient, - self.user.account.name + self.user.name ) self.debug("User add to project failed!") return @@ -519,8 +519,8 @@ class TestDeleteAccountWithProject(cloudstackTestCase): project = Project.create( self.apiclient, self.services["project"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Cleanup created project at end of test self.cleanup.append(project) @@ -555,7 +555,7 @@ class TestDeleteAccountWithProject(cloudstackTestCase): with self.assertRaises(Exception): self.account.delete(self.apiclient) self.debug("Deleting account %s failed!" % - self.account.account.name) + self.account.name) return @@ -635,8 +635,8 @@ class TestDeleteDomainWithProject(cloudstackTestCase): project = Project.create( self.apiclient, self.services["project"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Cleanup created project at end of test self.debug("Created project with domain admin with ID: %s" % @@ -938,7 +938,7 @@ class TestProjectOwners(cloudstackTestCase): ) self.cleanup.append(self.user) self.debug("Created account with ID: %s" % - self.user.account.name) + self.user.name) list_projects_reponse = Project.list( self.apiclient, @@ -1033,20 +1033,20 @@ class TestProjectOwners(cloudstackTestCase): ) self.debug("Adding %s user to project: %s" % ( - self.user.account.name, + self.user.name, project.name )) # Add user to the project project.addAccount( self.apiclient, - self.user.account.name, + self.user.name, ) # listProjectAccount to verify the user is added to project or not accounts_reponse = Project.listAccounts( self.apiclient, projectid=project.id, - account=self.user.account.name, + account=self.user.name, ) self.assertEqual( isinstance(accounts_reponse, list), @@ -1068,19 +1068,19 @@ class TestProjectOwners(cloudstackTestCase): ) self.debug("Updating project with new Admin: %s" % - self.user.account.name) + self.user.name) # Update the project with new admin project.update( self.apiclient, - account=self.user.account.name + account=self.user.name ) # listProjectAccount to verify the user is new admin of the project accounts_reponse = Project.listAccounts( self.apiclient, projectid=project.id, - account=self.user.account.name, + account=self.user.name, ) self.debug(accounts_reponse) self.assertEqual( @@ -1215,8 +1215,8 @@ class TestProjectResources(cloudstackTestCase): project = Project.create( self.apiclient, self.services["project"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Cleanup created project at end of test self.cleanup.append(project) @@ -1248,20 +1248,20 @@ class TestProjectResources(cloudstackTestCase): "Check project name from list response" ) self.debug("Adding %s user to project: %s" % ( - self.user.account.name, + self.user.name, project.name )) # Add user to the project project.addAccount( self.apiclient, - self.user.account.name, + self.user.name, ) # listProjectAccount to verify the user is added to project or not accounts_reponse = Project.listAccounts( self.apiclient, projectid=project.id, - account=self.user.account.name, + account=self.user.name, ) self.assertEqual( isinstance(accounts_reponse, list), @@ -1331,8 +1331,8 @@ class TestProjectResources(cloudstackTestCase): project = Project.create( self.apiclient, self.services["project"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Cleanup created project at end of test self.debug("Created project with domain admin with ID: %s" % @@ -1370,20 +1370,20 @@ class TestProjectResources(cloudstackTestCase): ) self.cleanup.append(self.user) self.debug("Adding %s user to project: %s" % ( - self.user.account.name, + self.user.name, project.name )) # Add user to the project project.addAccount( self.apiclient, - self.user.account.name + self.user.name ) # listProjectAccount to verify the user is added to project or not accounts_reponse = Project.listAccounts( self.apiclient, projectid=project.id, - account=self.user.account.name, + account=self.user.name, ) self.assertEqual( isinstance(accounts_reponse, list), @@ -1496,8 +1496,8 @@ class TestProjectSuspendActivate(cloudstackTestCase): cls.project = Project.create( cls.api_client, cls.services["project"], - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) cls.services["virtual_machine"]["zoneid"] = cls.zone.id cls._cleanup = [ @@ -1543,20 +1543,20 @@ class TestProjectSuspendActivate(cloudstackTestCase): # account deletion. self.debug("Adding %s user to project: %s" % ( - self.user.account.name, + self.user.name, self.project.name )) # Add user to the project self.project.addAccount( self.apiclient, - self.user.account.name, + self.user.name, ) # listProjectAccount to verify the user is added to project or not accounts_reponse = Project.listAccounts( self.apiclient, projectid=self.project.id, - account=self.user.account.name, + account=self.user.name, ) self.assertEqual( isinstance(accounts_reponse, list), diff --git a/test/integration/component/test_regions.py b/test/integration/component/test_regions.py new file mode 100644 index 00000000000..daf16cd1f44 --- /dev/null +++ b/test/integration/component/test_regions.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# 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. + +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.integration.lib.utils import * +from marvin.integration.lib.base import * +from marvin.integration.lib.common import * +from nose.plugins.attrib import attr +from random import choice + +class Services: + def __init__(self): + self.services = { + "region": { + "regionid": "2", + "regionname": "Region2", + "regionendpoint": "http://region2:8080/client" + } + } + +class TestRegions(cloudstackTestCase): + """Test Regions - CRUD tests for regions + """ + + @classmethod + def setUpClass(cls): + cls.api_client = super(TestRegions, cls).getClsTestClient().getApiClient() + cls.services = Services().services + cls.domain = get_domain(cls.api_client, cls.services) + cls.cleanup = [] + return + + def setUp(self): + pseudo_random_int = choice(xrange(1, 200)) + self.services["region"]["regionid"] = pseudo_random_int + self.services["region"]["regionname"] = "region" + str(pseudo_random_int) + self.services["region"]["regionendpoint"] = "http://region" + str(pseudo_random_int) + ":8080/client" + + self.region = Region.create(self.api_client, + self.services["region"] + ) + self.cleanup = [] + self.cleanup.append(self.region) + + list_region = Region.list(self.api_client, + id=self.services["region"]["regionid"] + ) + + self.assertEqual( + isinstance(list_region, list), + True, + msg="Region creation failed" + ) + + @attr(tags=["simulator", "basic", "advanced"]) + def test_createRegionWithExistingRegionId(self): + """Test for duplicate checks on region id + """ + self.services["region"]["regionname"] = random_gen() #alter region name but not id + self.assertRaises(Exception, Region.create, self.api_client, self.services["region"]) + + @attr(tags=["simulator", "basic", "advanced"]) + def test_createRegionWithExistingRegionName(self): + """Test for duplicate checks on region name + """ + random_int = choice(xrange(1, 200)) + self.services["region"]["regionid"] = random_int #alter id but not name + self.services["region"]["regionendpoint"] = "http://region" + str(random_int) + ":8080/client" + self.assertRaises(Exception, Region.create, self.api_client, self.services["region"]) + + @attr(tags=["simulator", "basic", "advanced"]) + def test_updateRegion(self): + """ Test for update Region + """ + self.services["region"]["regionname"] = "Region3" + random_gen() + self.services["region"]["regionendpoint"] = "http://region3updated:8080/client" + + updated_region = self.region.update(self.api_client, + self.services["region"] + ) + + list_region = Region.list(self.api_client, + id=self.services["region"]["regionid"] + ) + + self.assertEqual( + isinstance(list_region, list), + True, + "Check for list Region response" + ) + region_response = list_region[0] + + self.assertEqual( + region_response.id, + updated_region.id, + "listRegion response does not match with region Id created" + ) + + self.assertEqual( + region_response.name, + updated_region.name, + "listRegion response does not match with region name created" + ) + self.assertEqual( + region_response.endpoint, + updated_region.endpoint, + "listRegion response does not match with region endpoint created" + ) + + def tearDown(self): + """ Test for delete region as cleanup + """ + try: + #Clean up + cleanup_resources(self.api_client, self.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + + @classmethod + def tearDownClass(cls): + """ + Nothing to do + """ + pass diff --git a/test/integration/component/test_regions_accounts.py b/test/integration/component/test_regions_accounts.py new file mode 100644 index 00000000000..113f725f598 --- /dev/null +++ b/test/integration/component/test_regions_accounts.py @@ -0,0 +1,206 @@ +# 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. + +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.integration.lib.utils import * +from marvin.integration.lib.base import * +from marvin.integration.lib.common import * +from nose.plugins.attrib import attr + +class Services: + def __init__(self): + self.services = { + "domain": { + "name": "testuuid", + "domainUUID": "domain1" + }, + "account": { + "email": "test@test.com", + "firstname": "Testuuid", + "lastname": "Useruuid", + "username": "test", + "password": "password", + "accountUUID": "account1", + "userUUID": "user1" + }, + "user": { + "email": "test@test.com", + "firstname": "Testuuid", + "lastname": "Useruuid", + "username": "test", + "password": "password", + "userUUID": "user2" + }, + } + + +class TestRegionsAccounts(cloudstackTestCase): + """Test Accounts in Regions - CRUD tests for accounts in regions + """ + + @classmethod + def setUpClass(cls): + cls.api_client = super(TestRegionsAccounts, cls).getClsTestClient().getApiClient() + cls.services = Services().services + cls.domain = get_domain(cls.api_client, cls.services) + cls.cleanup = [] + return + + @attr(tags=["simulator", "basic", "advanced"]) + def test_createAccountWithUUID(self): + """Test for creating account by passing id parameter + + # Validate the following + # 1.Create an Account by passing id parameter.Verify the account is created. + # 2.List this account by passing id parameter.Verify that list account is able to lis this account. + # 3.Delete account should succeed. + """ + account = Account.create( + self.api_client, + self.services["account"], + domainid=self.domain.id + ) + self.assertIn(self.services["account"]["accountUUID"], account.id, + "Account is not created with the accountId passed") + + list_account = Account.list(self.api_client, + id=account.id) + + self.assertEqual( + isinstance(list_account, list), + True, + "Check for list account response by uuid failed" + ) + + account_response = list_account[0] + self.assertEqual(account_response.id, + account.id, + "listAccount response does not match with account Id " + ) + self.assertEqual( + account_response.user[0].firstname, + self.services["account"]["firstname"], + "listAccount response does not match with account firstname" + ) + + self.cleanup.append(account) + return + + @attr(tags=["simulator", "basic", "advanced"]) + def test_createUserWithUUID(self): + """Test for creating User by passing id parameter + + # Validate the following + # 1.Create a User by passing id parameter.Verify the user is created. + # 2.List this user by passing id parameter.Verify that list user is able to list this user. + # 3.Delete User should succeed. + """ + + user = User.create( + self.api_client, + self.services["user"], + account="admin", + domainid=self.domain.id + ) + self.assertIn(self.services["user"]["userUUID"], user.id, + "User is not created successfully with the userId passed") + + list_user = User.list(self.api_client, id=user.id) + + self.assertEqual( + isinstance(list_user, list), + True, + "Check for list user response by uuid failed" + ) + + user_response = list_user[0] + + self.assertEqual(user_response.id, + user.id, + "list User response does not match with user Id " + ) + self.assertEqual( + user_response.firstname, + self.services["user"]["firstname"], + "listUser response does not match with user firstname" + ) + + user.delete(self.api_client) + + list_user = User.list(self.api_client, + id=user.id + ) + + self.assertIsNone( + list_user, + "Deletion of user failed" + ) + return + + @attr(tags=["simulator", "basic", "advanced"]) + def test_createdomainWithUUID(self): + """Test for creating Domain by passing id parameter + + # Validate the following + # 1.Create a domain by passing id parameter.Verify the domain is created. + # 2.List this domain by passing id parameter.Verify that list domain is able to list this domain. + # 3.Delete domain should succeed. + """ + + domain = Domain.create( + self.api_client, + self.services["domain"] + ) + + self.assertIn(self.services["domain"]["domainUUID"], domain.id, + "Domain is not created with the doaminId passed") + + list_domain = Domain.list(self.api_client, + id=domain.id + ) + + self.assertEqual( + isinstance(list_domain, list), + True, + "Check for list domain response by uuid failed" + ) + + domain_response = list_domain[0] + + self.assertEqual(domain_response.id, + domain.id, + "list domain response does not match with domain Id " + ) + self.assertIn( + self.services["domain"]["name"], + domain_response.name, + "list domaiin response does not match with user firstname" + ) + try: + domain.delete(self.api_client) + except Exception as e: + self.fail("Failed to delete domain: %s" % e) + return + + @classmethod + def tearDownClass(cls): + try: + #Clean up + cleanup_resources(cls.api_client, cls.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) \ No newline at end of file diff --git a/test/integration/component/test_resource_limits.py b/test/integration/component/test_resource_limits.py index 641825b4a0c..1d876b6195f 100644 --- a/test/integration/component/test_resource_limits.py +++ b/test/integration/component/test_resource_limits.py @@ -51,7 +51,7 @@ class Services: "cpunumber": 1, "cpuspeed": 100, # in MHz - "memory": 64, + "memory": 128, # In MBs }, "disk_offering": { @@ -902,7 +902,7 @@ class TestResourceLimitsDomain(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name # Create Service offering and disk offerings etc cls.service_offering = ServiceOffering.create( @@ -957,22 +957,22 @@ class TestResourceLimitsDomain(cloudstackTestCase): self.debug( "Updating instance resource limits for domain: %s" % - self.account.account.domainid) + self.account.domainid) # Set usage_vm=1 for Account 1 update_resource_limit( self.apiclient, 0, # Instance - domainid=self.account.account.domainid, + domainid=self.account.domainid, max=2 ) - self.debug("Deploying VM for account: %s" % self.account.account.name) + self.debug("Deploying VM for account: %s" % self.account.name) virtual_machine_1 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) self.cleanup.append(virtual_machine_1) @@ -982,13 +982,13 @@ class TestResourceLimitsDomain(cloudstackTestCase): 'Running', "Check VM state is Running or not" ) - self.debug("Deploying VM for account: %s" % self.account.account.name) + self.debug("Deploying VM for account: %s" % self.account.name) virtual_machine_2 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) self.cleanup.append(virtual_machine_2) @@ -1005,7 +1005,7 @@ class TestResourceLimitsDomain(cloudstackTestCase): self.services["server"], templateid=self.template.id, accountid=self.account_1.account.name, - domainid=self.account.account.domainid, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) return @@ -1025,22 +1025,22 @@ class TestResourceLimitsDomain(cloudstackTestCase): self.debug( "Updating public IP resource limits for domain: %s" % - self.account.account.domainid) + self.account.domainid) # Set usage_vm=1 for Account 1 update_resource_limit( self.apiclient, 1, # Public Ip - domainid=self.account.account.domainid, + domainid=self.account.domainid, max=2 ) - self.debug("Deploying VM for account: %s" % self.account.account.name) + self.debug("Deploying VM for account: %s" % self.account.name) virtual_machine_1 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) self.cleanup.append(virtual_machine_1) @@ -1050,7 +1050,7 @@ class TestResourceLimitsDomain(cloudstackTestCase): 'Running', "Check VM state is Running or not" ) - self.debug("Associating public IP for account: %s" % self.account.account.name) + self.debug("Associating public IP for account: %s" % self.account.name) public_ip_1 = PublicIPAddress.create( self.apiclient, virtual_machine_1.account, @@ -1097,22 +1097,22 @@ class TestResourceLimitsDomain(cloudstackTestCase): self.debug( "Updating snapshot resource limits for domain: %s" % - self.account.account.domainid) + self.account.domainid) # Set usage_vm=1 for Account 1 update_resource_limit( self.apiclient, 3, # Snapshot - domainid=self.account.account.domainid, + domainid=self.account.domainid, max=1 ) - self.debug("Deploying VM for account: %s" % self.account.account.name) + self.debug("Deploying VM for account: %s" % self.account.name) virtual_machine_1 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) self.cleanup.append(virtual_machine_1) @@ -1141,8 +1141,8 @@ class TestResourceLimitsDomain(cloudstackTestCase): # Create a snapshot from the ROOTDISK snapshot_1 = Snapshot.create(self.apiclient, volumes[0].id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.cleanup.append(snapshot_1) # Verify Snapshot state @@ -1159,8 +1159,8 @@ class TestResourceLimitsDomain(cloudstackTestCase): with self.assertRaises(Exception): Snapshot.create(self.apiclient, volumes[0].id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) return @@ -1179,22 +1179,22 @@ class TestResourceLimitsDomain(cloudstackTestCase): self.debug( "Updating volume resource limits for domain: %s" % - self.account.account.domainid) + self.account.domainid) # Set usage_vm=1 for Account 1 update_resource_limit( self.apiclient, 2, # Volume - domainid=self.account.account.domainid, + domainid=self.account.domainid, max=2 ) - self.debug("Deploying VM for account: %s" % self.account.account.name) + self.debug("Deploying VM for account: %s" % self.account.name) virtual_machine_1 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) self.cleanup.append(virtual_machine_1) @@ -1211,8 +1211,8 @@ class TestResourceLimitsDomain(cloudstackTestCase): self.apiclient, self.services["volume"], zoneid=self.zone.id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, diskofferingid=self.disk_offering.id ) return @@ -1234,28 +1234,28 @@ class TestResourceLimitsDomain(cloudstackTestCase): update_resource_limit( self.apiclient, 2, # Volume - domainid=self.account.account.domainid, + domainid=self.account.domainid, max=5 ) self.debug( "Updating template resource limits for domain: %s" % - self.account.account.domainid) + self.account.domainid) # Set usage_vm=1 for Account 1 update_resource_limit( self.apiclient, 4, # Template - domainid=self.account.account.domainid, + domainid=self.account.domainid, max=2 ) - self.debug("Deploying VM for account: %s" % self.account.account.name) + self.debug("Deploying VM for account: %s" % self.account.name) virtual_machine_1 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) self.cleanup.append(virtual_machine_1) @@ -1286,8 +1286,8 @@ class TestResourceLimitsDomain(cloudstackTestCase): self.apiclient, self.services["template"], volumeid=volume.id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.cleanup.append(template_1) @@ -1303,8 +1303,8 @@ class TestResourceLimitsDomain(cloudstackTestCase): self.apiclient, self.services["template"], volumeid=volume.id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.cleanup.append(template_2) @@ -1321,8 +1321,8 @@ class TestResourceLimitsDomain(cloudstackTestCase): self.apiclient, self.services["template"], volumeid=volume.id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) return @@ -1432,8 +1432,8 @@ class TestMaxAccountNetworks(cloudstackTestCase): network = Network.create( self.apiclient, self.services["network"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, networkofferingid=self.network_offering.id, zoneid=self.zone.id ) @@ -1446,8 +1446,8 @@ class TestMaxAccountNetworks(cloudstackTestCase): Network.create( self.apiclient, self.services["network"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, networkofferingid=self.network_offering.id, zoneid=self.zone.id ) diff --git a/test/integration/component/test_routers.py b/test/integration/component/test_routers.py index 452c034d5eb..bc33d754260 100644 --- a/test/integration/component/test_routers.py +++ b/test/integration/component/test_routers.py @@ -41,7 +41,7 @@ class Services: "displaytext": "Tiny Instance", "cpunumber": 1, "cpuspeed": 100, # in MHz - "memory": 64, # In MBs + "memory": 128, # In MBs }, "virtual_machine": { @@ -127,16 +127,16 @@ class TestRouterServices(cloudstackTestCase): cls.api_client, cls.services["virtual_machine"], templateid=cls.template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) cls.vm_2 = VirtualMachine.create( cls.api_client, cls.services["virtual_machine"], templateid=cls.template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) cls.cleanup = [ @@ -189,8 +189,8 @@ class TestRouterServices(cloudstackTestCase): routers = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.assertEqual( @@ -216,8 +216,8 @@ class TestRouterServices(cloudstackTestCase): # Network state associated with account should be 'Implemented' networks = list_networks( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.assertEqual( isinstance(networks, list), @@ -243,8 +243,8 @@ class TestRouterServices(cloudstackTestCase): # VM state associated with account should be 'Running' virtual_machines = list_virtual_machines( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( @@ -271,8 +271,8 @@ class TestRouterServices(cloudstackTestCase): # Check status of DNS, DHCP, FIrewall, LB VPN processes networks = list_networks( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.assertEqual( isinstance(networks, list), @@ -332,8 +332,8 @@ class TestRouterServices(cloudstackTestCase): routers = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.assertEqual( @@ -360,8 +360,8 @@ class TestRouterServices(cloudstackTestCase): # Network state associated with account should be 'Implemented' networks = list_networks( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.assertEqual( isinstance(networks, list), @@ -387,8 +387,8 @@ class TestRouterServices(cloudstackTestCase): # VM state associated with account should be 'Running' virtual_machines = list_virtual_machines( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.assertEqual( @@ -445,8 +445,8 @@ class TestRouterServices(cloudstackTestCase): routers = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.assertEqual( @@ -488,8 +488,8 @@ class TestRouterServices(cloudstackTestCase): self.apiclient, self.services["virtual_machine"], templateid=self.template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) self.debug("Deployed a VM with ID: %s" % vm.id) @@ -497,8 +497,8 @@ class TestRouterServices(cloudstackTestCase): virtual_machines = list_virtual_machines( self.apiclient, id=vm.id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.assertEqual( @@ -522,8 +522,8 @@ class TestRouterServices(cloudstackTestCase): routers = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.assertEqual( @@ -554,8 +554,8 @@ class TestRouterServices(cloudstackTestCase): virtual_machines = list_virtual_machines( self.apiclient, id=self.vm_1.id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.assertEqual( @@ -615,8 +615,8 @@ class TestRouterStopCreatePF(cloudstackTestCase): cls.api_client, cls.services["virtual_machine"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) cls.cleanup = [ @@ -668,8 +668,8 @@ class TestRouterStopCreatePF(cloudstackTestCase): # Get router details associated for that account routers = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.assertEqual( @@ -693,8 +693,8 @@ class TestRouterStopCreatePF(cloudstackTestCase): routers = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.assertEqual( isinstance(routers, list), @@ -711,8 +711,8 @@ class TestRouterStopCreatePF(cloudstackTestCase): public_ips = list_publicIP( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, zoneid=self.zone.id ) self.assertEqual( @@ -749,8 +749,8 @@ class TestRouterStopCreatePF(cloudstackTestCase): routers = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, zoneid=self.zone.id ) self.assertEqual( @@ -827,8 +827,8 @@ class TestRouterStopCreateLB(cloudstackTestCase): cls.api_client, cls.services["virtual_machine"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) cls.cleanup = [ @@ -874,8 +874,8 @@ class TestRouterStopCreateLB(cloudstackTestCase): # Get router details associated for that account routers = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.assertEqual( @@ -900,8 +900,8 @@ class TestRouterStopCreateLB(cloudstackTestCase): routers = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.assertEqual( isinstance(routers, list), @@ -918,8 +918,8 @@ class TestRouterStopCreateLB(cloudstackTestCase): public_ips = list_publicIP( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(public_ips, list), @@ -943,7 +943,7 @@ class TestRouterStopCreateLB(cloudstackTestCase): self.apiclient, self.services["lbrule"], public_ip.id, - accountid=self.account.account.name + accountid=self.account.name ) self.debug("Assigning VM %s to LB rule: %s" % ( self.vm_1.id, @@ -958,8 +958,8 @@ class TestRouterStopCreateLB(cloudstackTestCase): routers = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.assertEqual( isinstance(routers, list), @@ -1038,8 +1038,8 @@ class TestRouterStopCreateFW(cloudstackTestCase): cls.api_client, cls.services["virtual_machine"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) cls.cleanup = [ @@ -1084,8 +1084,8 @@ class TestRouterStopCreateFW(cloudstackTestCase): # Get the router details associated with account routers = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.assertEqual( @@ -1110,8 +1110,8 @@ class TestRouterStopCreateFW(cloudstackTestCase): routers = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.assertEqual( isinstance(routers, list), @@ -1128,8 +1128,8 @@ class TestRouterStopCreateFW(cloudstackTestCase): public_ips = list_publicIP( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(public_ips, list), @@ -1157,8 +1157,8 @@ class TestRouterStopCreateFW(cloudstackTestCase): routers = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.assertEqual( isinstance(routers, list), diff --git a/test/integration/component/test_security_groups.py b/test/integration/component/test_security_groups.py index 7459d2a2913..54b5c67fa4d 100644 --- a/test/integration/component/test_security_groups.py +++ b/test/integration/component/test_security_groups.py @@ -74,7 +74,7 @@ class Services: "displaytext": "Tiny Instance", "cpunumber": 1, "cpuspeed": 100, # in MHz - "memory": 64, # In MBs + "memory": 128, # In MBs }, "security_group": { "name": 'SSH', @@ -144,7 +144,7 @@ class TestDefaultSecurityGroup(cloudstackTestCase): admin=True, domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls._cleanup = [ cls.account, @@ -178,8 +178,8 @@ class TestDefaultSecurityGroup(cloudstackTestCase): self.virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) self.debug("Deployed VM with ID: %s" % self.virtual_machine.id) @@ -222,7 +222,7 @@ class TestDefaultSecurityGroup(cloudstackTestCase): # Verify List Routers response for account self.debug( "Verify list routers response for account: %s" \ - % self.account.account.name + % self.account.name ) routers = list_routers( self.apiclient, @@ -256,8 +256,8 @@ class TestDefaultSecurityGroup(cloudstackTestCase): sercurity_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(sercurity_groups, list), @@ -292,8 +292,8 @@ class TestDefaultSecurityGroup(cloudstackTestCase): self.virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) self.debug("Deployed VM with ID: %s" % self.virtual_machine.id) @@ -336,8 +336,8 @@ class TestDefaultSecurityGroup(cloudstackTestCase): # Default Security group should not have any ingress rule sercurity_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(sercurity_groups, list), @@ -416,7 +416,7 @@ class TestAuthorizeIngressRule(cloudstackTestCase): cls.services["account"], domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls._cleanup = [ cls.account, cls.service_offering @@ -450,15 +450,15 @@ class TestAuthorizeIngressRule(cloudstackTestCase): security_group = SecurityGroup.create( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created security group with ID: %s" % security_group.id) # Default Security group should not have any ingress rule sercurity_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(sercurity_groups, list), @@ -475,8 +475,8 @@ class TestAuthorizeIngressRule(cloudstackTestCase): ingress_rule = security_group.authorize( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(ingress_rule, dict), @@ -489,12 +489,12 @@ class TestAuthorizeIngressRule(cloudstackTestCase): self.virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, securitygroupids=[security_group.id] ) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) # Should be able to SSH VM try: self.debug("SSH into VM: %s" % self.virtual_machine.id) @@ -552,7 +552,7 @@ class TestRevokeIngressRule(cloudstackTestCase): cls.services["account"], domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls._cleanup = [ cls.account, cls.service_offering @@ -587,16 +587,16 @@ class TestRevokeIngressRule(cloudstackTestCase): security_group = SecurityGroup.create( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created security group with ID: %s" % security_group.id) # Default Security group should not have any ingress rule sercurity_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(sercurity_groups, list), @@ -615,8 +615,8 @@ class TestRevokeIngressRule(cloudstackTestCase): ingress_rule = security_group.authorize( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( @@ -629,12 +629,12 @@ class TestRevokeIngressRule(cloudstackTestCase): self.virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, securitygroupids=[security_group.id] ) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) # Should be able to SSH VM try: @@ -712,12 +712,12 @@ class TestDhcpOnlyRouter(cloudstackTestCase): cls.services["account"], domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.virtual_machine = VirtualMachine.create( cls.api_client, cls.services["virtual_machine"], - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) cls._cleanup = [ @@ -849,7 +849,7 @@ class TestdeployVMWithUserData(cloudstackTestCase): cls.services["account"], domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls._cleanup = [ cls.account, cls.service_offering @@ -897,15 +897,15 @@ class TestdeployVMWithUserData(cloudstackTestCase): security_group = SecurityGroup.create( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created security group with ID: %s" % security_group.id) # Default Security group should not have any ingress rule sercurity_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(sercurity_groups, list), @@ -922,15 +922,15 @@ class TestdeployVMWithUserData(cloudstackTestCase): "Authorize Ingress Rule for Security Group %s for account: %s" \ % ( security_group.id, - self.account.account.name + self.account.name )) # Authorize Security group to SSH to VM ingress_rule = security_group.authorize( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(ingress_rule, dict), @@ -940,12 +940,12 @@ class TestdeployVMWithUserData(cloudstackTestCase): self.virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, securitygroupids=[security_group.id] ) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) # Should be able to SSH VM try: self.debug( @@ -1009,7 +1009,7 @@ class TestDeleteSecurityGroup(cloudstackTestCase): self.services["account"], domainid=self.domain.id ) - self.services["account"] = self.account.account.name + self.services["account"] = self.account.name self.cleanup = [ self.account, self.service_offering @@ -1059,15 +1059,15 @@ class TestDeleteSecurityGroup(cloudstackTestCase): security_group = SecurityGroup.create( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created security group with ID: %s" % security_group.id) # Default Security group should not have any ingress rule sercurity_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(sercurity_groups, list), @@ -1084,15 +1084,15 @@ class TestDeleteSecurityGroup(cloudstackTestCase): "Authorize Ingress Rule for Security Group %s for account: %s" \ % ( security_group.id, - self.account.account.name + self.account.name )) # Authorize Security group to SSH to VM ingress_rule = security_group.authorize( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(ingress_rule, dict), @@ -1103,12 +1103,12 @@ class TestDeleteSecurityGroup(cloudstackTestCase): self.virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, securitygroupids=[security_group.id] ) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) # Deleting Security group should raise exception security_group.delete(self.apiclient) @@ -1143,15 +1143,15 @@ class TestDeleteSecurityGroup(cloudstackTestCase): security_group = SecurityGroup.create( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created security group with ID: %s" % security_group.id) # Default Security group should not have any ingress rule sercurity_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(sercurity_groups, list), @@ -1168,14 +1168,14 @@ class TestDeleteSecurityGroup(cloudstackTestCase): "Authorize Ingress Rule for Security Group %s for account: %s" \ % ( security_group.id, - self.account.account.name + self.account.name )) # Authorize Security group to SSH to VM ingress_rule = security_group.authorize( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(ingress_rule, dict), @@ -1186,12 +1186,12 @@ class TestDeleteSecurityGroup(cloudstackTestCase): self.virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, securitygroupids=[security_group.id] ) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) # Destroy the VM self.virtual_machine.delete(self.apiclient) @@ -1255,7 +1255,7 @@ class TestIngressRule(cloudstackTestCase): self.services["account"], domainid=self.domain.id ) - self.services["account"] = self.account.account.name + self.services["account"] = self.account.name self.cleanup = [ self.account, self.service_offering @@ -1305,15 +1305,15 @@ class TestIngressRule(cloudstackTestCase): security_group = SecurityGroup.create( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created security group with ID: %s" % security_group.id) # Default Security group should not have any ingress rule sercurity_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(sercurity_groups, list), @@ -1329,15 +1329,15 @@ class TestIngressRule(cloudstackTestCase): "Authorize Ingress Rule for Security Group %s for account: %s" \ % ( security_group.id, - self.account.account.name + self.account.name )) # Authorize Security group to SSH to VM ingress_rule_1 = security_group.authorize( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(ingress_rule_1, dict), @@ -1347,25 +1347,25 @@ class TestIngressRule(cloudstackTestCase): self.virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, securitygroupids=[security_group.id] ) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) self.debug( "Authorize Ingress Rule for Security Group %s for account: %s" \ % ( security_group.id, - self.account.account.name + self.account.name )) # Authorize Security group to SSH to VM ingress_rule_2 = security_group.authorize( self.apiclient, self.services["security_group_2"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(ingress_rule_2, dict), @@ -1421,16 +1421,16 @@ class TestIngressRule(cloudstackTestCase): security_group = SecurityGroup.create( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created security group with ID: %s" % security_group.id) # Default Security group should not have any ingress rule sercurity_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(sercurity_groups, list), @@ -1447,15 +1447,15 @@ class TestIngressRule(cloudstackTestCase): "Authorize Ingress Rule for Security Group %s for account: %s" \ % ( security_group.id, - self.account.account.name + self.account.name )) # Authorize Security group to SSH to VM ingress_rule = security_group.authorize( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(ingress_rule, dict), @@ -1465,26 +1465,26 @@ class TestIngressRule(cloudstackTestCase): self.virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, securitygroupids=[security_group.id] ) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) self.debug( "Authorize Ingress Rule for Security Group %s for account: %s" \ % ( security_group.id, - self.account.account.name + self.account.name )) # Authorize Security group to SSH to VM ingress_rule_2 = security_group.authorize( self.apiclient, self.services["security_group_2"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(ingress_rule_2, dict), @@ -1528,7 +1528,7 @@ class TestIngressRule(cloudstackTestCase): "Revoke Ingress Rule for Security Group %s for account: %s" \ % ( security_group.id, - self.account.account.name + self.account.name )) result = security_group.revoke( @@ -1573,15 +1573,15 @@ class TestIngressRule(cloudstackTestCase): security_group = SecurityGroup.create( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created security group with ID: %s" % security_group.id) # Default Security group should not have any ingress rule sercurity_groups = SecurityGroup.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(sercurity_groups, list), @@ -1599,15 +1599,15 @@ class TestIngressRule(cloudstackTestCase): "Authorize Ingress Rule for Security Group %s for account: %s" \ % ( security_group.id, - self.account.account.name + self.account.name )) # Authorize Security group to SSH to VM ingress_rule = security_group.authorize( self.apiclient, self.services["security_group"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(ingress_rule, dict), @@ -1618,12 +1618,12 @@ class TestIngressRule(cloudstackTestCase): self.virtual_machine = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, securitygroupids=[security_group.id] ) - self.debug("Deploying VM in account: %s" % self.account.account.name) + self.debug("Deploying VM in account: %s" % self.account.name) # SSH should be allowed on 22 port try: diff --git a/test/integration/component/test_snapshots.py b/test/integration/component/test_snapshots.py index 5567917371e..014b55afcc1 100644 --- a/test/integration/component/test_snapshots.py +++ b/test/integration/component/test_snapshots.py @@ -152,7 +152,7 @@ class TestSnapshotRootDisk(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, @@ -163,8 +163,8 @@ class TestSnapshotRootDisk(cloudstackTestCase): cls.api_client, cls.services["server_without_disk"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, mode=cls.services["mode"] ) @@ -220,8 +220,8 @@ class TestSnapshotRootDisk(cloudstackTestCase): snapshot = Snapshot.create( self.apiclient, volumes[0].id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Snapshot created: ID - %s" % snapshot.id) @@ -384,7 +384,7 @@ class TestSnapshots(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, @@ -395,8 +395,8 @@ class TestSnapshots(cloudstackTestCase): cls.api_client, cls.services["server_with_disk"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, mode=cls.services["mode"] ) @@ -405,8 +405,8 @@ class TestSnapshots(cloudstackTestCase): cls.api_client, cls.services["server_without_disk"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, mode=cls.services["mode"] ) @@ -462,8 +462,8 @@ class TestSnapshots(cloudstackTestCase): snapshot = Snapshot.create( self.apiclient, volume[0].id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) snapshots = list_snapshots( self.apiclient, @@ -663,8 +663,8 @@ class TestSnapshots(cloudstackTestCase): snapshot = Snapshot.create( self.apiclient, volume_response.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created Snapshot from volume: %s" % volume_response.id) @@ -674,8 +674,8 @@ class TestSnapshots(cloudstackTestCase): self.apiclient, snapshot.id, self.services, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) volumes = list_volumes( @@ -789,8 +789,8 @@ class TestSnapshots(cloudstackTestCase): snapshot = Snapshot.create( self.apiclient, volumes[0].id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) snapshot.delete(self.apiclient) @@ -1079,8 +1079,8 @@ class TestSnapshots(cloudstackTestCase): snapshot = Snapshot.create( self.apiclient, volume.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Snapshot created from volume ID: %s" % volume.id) @@ -1118,8 +1118,8 @@ class TestSnapshots(cloudstackTestCase): self.apiclient, self.services["server_without_disk"], templateid=template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, mode=self.services["mode"] ) @@ -1209,7 +1209,7 @@ class TestCreateVMsnapshotTemplate(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, @@ -1269,8 +1269,8 @@ class TestCreateVMsnapshotTemplate(cloudstackTestCase): self.apiclient, self.services["server"], templateid=self.template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) self.debug("Created VM with ID: %s" % self.virtual_machine.id) @@ -1359,8 +1359,8 @@ class TestCreateVMsnapshotTemplate(cloudstackTestCase): self.apiclient, self.services["server"], templateid=template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) self.debug("Created VM with ID: %s from template: %s" % ( @@ -1373,8 +1373,8 @@ class TestCreateVMsnapshotTemplate(cloudstackTestCase): virtual_machines = list_virtual_machines( self.apiclient, id=new_virtual_machine.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(virtual_machines, list), @@ -1505,7 +1505,7 @@ class TestAccountSnapshotClean(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, @@ -1515,8 +1515,8 @@ class TestAccountSnapshotClean(cloudstackTestCase): cls.api_client, cls.services["server"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) # Get the Root disk of VM @@ -1577,7 +1577,7 @@ class TestAccountSnapshotClean(cloudstackTestCase): accounts = list_accounts( self.apiclient, - id=self.account.account.id + id=self.account.id ) self.assertEqual( isinstance(accounts, list), @@ -1737,7 +1737,7 @@ class TestAccountSnapshotClean(cloudstackTestCase): "Check snapshot UUID in secondary storage and database" ) - self.debug("Deleting account: %s" % self.account.account.name) + self.debug("Deleting account: %s" % self.account.name) # Delete account self.account.delete(self.apiclient) @@ -1757,7 +1757,7 @@ class TestAccountSnapshotClean(cloudstackTestCase): accounts = list_accounts( self.apiclient, - id=self.account.account.id + id=self.account.id ) self.assertEqual( @@ -1859,7 +1859,7 @@ class TestSnapshotDetachedDisk(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, @@ -1869,8 +1869,8 @@ class TestSnapshotDetachedDisk(cloudstackTestCase): cls.api_client, cls.services["server"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, mode=cls.services["mode"] ) @@ -2142,7 +2142,7 @@ class TestSnapshotLimit(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, @@ -2152,8 +2152,8 @@ class TestSnapshotLimit(cloudstackTestCase): cls.api_client, cls.services["server"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) cls._cleanup = [ @@ -2401,7 +2401,7 @@ class TestSnapshotEvents(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, @@ -2411,8 +2411,8 @@ class TestSnapshotEvents(cloudstackTestCase): cls.api_client, cls.services["server"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) @@ -2498,8 +2498,8 @@ class TestSnapshotEvents(cloudstackTestCase): time.sleep(self.services["sleep"]) events = list_events( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, type='SNAPSHOT.DELETE' ) self.assertEqual( diff --git a/test/integration/component/test_storage_motion.py b/test/integration/component/test_storage_motion.py index b893b8b7df4..c05d79e6861 100644 --- a/test/integration/component/test_storage_motion.py +++ b/test/integration/component/test_storage_motion.py @@ -98,16 +98,16 @@ class TestStorageMotion(cloudstackTestCase): # Get Zone, Domain and templates domain = get_domain(cls.api_client, cls.services) - zone = get_zone(cls.api_client, cls.services) + cls.zone = get_zone(cls.api_client, cls.services) cls.services['mode'] = cls.zone.networktype template = get_template( cls.api_client, - zone.id, + cls.zone.id, cls.services["ostype"] ) # Set Zones and disk offerings - cls.services["small"]["zoneid"] = zone.id + cls.services["small"]["zoneid"] = cls.zone.id cls.services["small"]["template"] = template.id # Create VMs, NAT Rules etc @@ -126,8 +126,8 @@ class TestStorageMotion(cloudstackTestCase): cls.virtual_machine = VirtualMachine.create( cls.api_client, cls.services["small"], - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.small_offering.id, mode=cls.services["mode"] ) @@ -258,6 +258,17 @@ class TestStorageMotion(cloudstackTestCase): self.apiclient, id=volume.id ) + self.assertEqual( + isinstance(pools, list), + True, + "Check list storage pools response for valid list" + ) + self.assertNotEqual( + pools, + None, + "Check if pools exists in ListStoragePools" + ) + pool = pools[0] self.debug("Migrating Volume-ID: %s to Pool: %s" % ( volume.id, diff --git a/test/integration/component/test_templates.py b/test/integration/component/test_templates.py index a743bf7e690..1a60123b820 100644 --- a/test/integration/component/test_templates.py +++ b/test/integration/component/test_templates.py @@ -51,7 +51,7 @@ class Services: "displaytext": "Tiny Instance", "cpunumber": 1, "cpuspeed": 100, # in MHz - "memory": 64, # In MBs + "memory": 128, # In MBs }, "disk_offering": { "displaytext": "Small", @@ -139,7 +139,7 @@ class TestCreateTemplate(cloudstackTestCase): cls.services["account"], domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls._cleanup = [ cls.account, @@ -183,8 +183,8 @@ class TestCreateTemplate(cloudstackTestCase): self.apiclient, v, zoneid=self.zone.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug( "Registered a template of format: %s with ID: %s" % ( @@ -205,8 +205,8 @@ class TestCreateTemplate(cloudstackTestCase): self.services["templatefilter"], id=template.id, zoneid=self.zone.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) if isinstance(list_template_response, list): break @@ -240,8 +240,8 @@ class TestCreateTemplate(cloudstackTestCase): self.apiclient, self.services["virtual_machine"], templateid=template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, mode=self.services["mode"] ) @@ -249,8 +249,8 @@ class TestCreateTemplate(cloudstackTestCase): vm_response = list_virtual_machines( self.apiclient, id=virtual_machine.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(vm_response, list), @@ -304,7 +304,7 @@ class TestTemplates(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, cls.services["service_offering"] @@ -315,8 +315,8 @@ class TestTemplates(cloudstackTestCase): cls.api_client, cls.services["virtual_machine"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, ) #Stop virtual machine @@ -396,8 +396,8 @@ class TestTemplates(cloudstackTestCase): self.apiclient, self.services["virtual_machine"], templateid=self.template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, ) @@ -406,8 +406,8 @@ class TestTemplates(cloudstackTestCase): vm_response = list_virtual_machines( self.apiclient, id=virtual_machine.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) #Verify VM response to check whether VM deployment was successful self.assertNotEqual( @@ -591,8 +591,8 @@ class TestTemplates(cloudstackTestCase): snapshot = Snapshot.create( self.apiclient, volume.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Creating a template from snapshot: %s" % snapshot.id) # Generate template from the snapshot @@ -626,8 +626,8 @@ class TestTemplates(cloudstackTestCase): self.apiclient, self.services["virtual_machine"], templateid=template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, ) self.cleanup.append(virtual_machine) @@ -635,8 +635,8 @@ class TestTemplates(cloudstackTestCase): vm_response = list_virtual_machines( self.apiclient, id=virtual_machine.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(vm_response, list), diff --git a/test/integration/component/test_usage.py b/test/integration/component/test_usage.py index 39228ba3b7a..a3779e4dc2f 100644 --- a/test/integration/component/test_usage.py +++ b/test/integration/component/test_usage.py @@ -48,7 +48,7 @@ class Services: "displaytext": "Tiny Instance", "cpunumber": 1, "cpuspeed": 100, # in MHz - "memory": 64, # In MBs + "memory": 128, # In MBs }, "disk_offering": { "displaytext": "Small", @@ -135,7 +135,7 @@ class TestVmUsage(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, @@ -145,8 +145,8 @@ class TestVmUsage(cloudstackTestCase): cls.api_client, cls.services["server"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) cls._cleanup = [ @@ -202,11 +202,11 @@ class TestVmUsage(cloudstackTestCase): # Fetch account ID from account_uuid self.debug("select id from account where uuid = '%s';" \ - % self.account.account.id) + % self.account.id) qresultset = self.dbclient.execute( "select id from account where uuid = '%s';" \ - % self.account.account.id + % self.account.id ) self.assertEqual( isinstance(qresultset, list), @@ -319,7 +319,7 @@ class TestPublicIPUsage(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, @@ -329,8 +329,8 @@ class TestPublicIPUsage(cloudstackTestCase): cls.api_client, cls.services["server"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) @@ -382,18 +382,18 @@ class TestPublicIPUsage(cloudstackTestCase): # 3. Delete the newly created account self.debug("Deleting public IP: %s" % - self.public_ip.ipaddress.ipaddress) + self.public_ip.ipaddress) # Release one of the IP self.public_ip.delete(self.apiclient) # Fetch account ID from account_uuid self.debug("select id from account where uuid = '%s';" \ - % self.account.account.id) + % self.account.id) qresultset = self.dbclient.execute( "select id from account where uuid = '%s';" \ - % self.account.account.id + % self.account.id ) self.assertEqual( isinstance(qresultset, list), @@ -474,7 +474,7 @@ class TestVolumeUsage(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, @@ -484,8 +484,8 @@ class TestVolumeUsage(cloudstackTestCase): cls.api_client, cls.services["server"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) cls._cleanup = [ @@ -562,11 +562,11 @@ class TestVolumeUsage(cloudstackTestCase): # Fetch account ID from account_uuid self.debug("select id from account where uuid = '%s';" \ - % self.account.account.id) + % self.account.id) qresultset = self.dbclient.execute( "select id from account where uuid = '%s';" \ - % self.account.account.id + % self.account.id ) self.assertEqual( isinstance(qresultset, list), @@ -640,7 +640,7 @@ class TestTemplateUsage(cloudstackTestCase): cls.services["account"], domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, @@ -651,8 +651,8 @@ class TestTemplateUsage(cloudstackTestCase): cls.api_client, cls.services["server"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, mode=cls.services["mode"] ) @@ -726,11 +726,11 @@ class TestTemplateUsage(cloudstackTestCase): # Fetch account ID from account_uuid self.debug("select id from account where uuid = '%s';" \ - % self.account.account.id) + % self.account.id) qresultset = self.dbclient.execute( "select id from account where uuid = '%s';" \ - % self.account.account.id + % self.account.id ) self.assertEqual( isinstance(qresultset, list), @@ -801,12 +801,12 @@ class TestISOUsage(cloudstackTestCase): cls.services["account"], domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.iso = Iso.create( cls.api_client, cls.services["iso"], - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) try: # Wait till ISO gets downloaded @@ -862,11 +862,11 @@ class TestISOUsage(cloudstackTestCase): # Fetch account ID from account_uuid self.debug("select id from account where uuid = '%s';" \ - % self.account.account.id) + % self.account.id) qresultset = self.dbclient.execute( "select id from account where uuid = '%s';" \ - % self.account.account.id + % self.account.id ) self.assertEqual( isinstance(qresultset, list), @@ -946,7 +946,7 @@ class TestLBRuleUsage(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, @@ -956,8 +956,8 @@ class TestLBRuleUsage(cloudstackTestCase): cls.api_client, cls.services["server"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) cls.public_ip_1 = PublicIPAddress.create( @@ -1016,7 +1016,7 @@ class TestLBRuleUsage(cloudstackTestCase): self.apiclient, self.services["lbrule"], self.public_ip_1.ipaddress.id, - accountid=self.account.account.name + accountid=self.account.name ) # Delete LB Rule self.debug("Deleting LB rule with ID: %s" % lb_rule.id) @@ -1024,11 +1024,11 @@ class TestLBRuleUsage(cloudstackTestCase): # Fetch account ID from account_uuid self.debug("select id from account where uuid = '%s';" \ - % self.account.account.id) + % self.account.id) qresultset = self.dbclient.execute( "select id from account where uuid = '%s';" \ - % self.account.account.id + % self.account.id ) self.assertEqual( isinstance(qresultset, list), @@ -1109,7 +1109,7 @@ class TestSnapshotUsage(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, @@ -1119,8 +1119,8 @@ class TestSnapshotUsage(cloudstackTestCase): cls.api_client, cls.services["server"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) cls._cleanup = [ @@ -1190,11 +1190,11 @@ class TestSnapshotUsage(cloudstackTestCase): # Fetch account ID from account_uuid self.debug("select id from account where uuid = '%s';" \ - % self.account.account.id) + % self.account.id) qresultset = self.dbclient.execute( "select id from account where uuid = '%s';" \ - % self.account.account.id + % self.account.id ) self.assertEqual( isinstance(qresultset, list), @@ -1275,7 +1275,7 @@ class TestNatRuleUsage(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, @@ -1285,8 +1285,8 @@ class TestNatRuleUsage(cloudstackTestCase): cls.api_client, cls.services["server"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) cls.public_ip_1 = PublicIPAddress.create( @@ -1354,11 +1354,11 @@ class TestNatRuleUsage(cloudstackTestCase): # Fetch account ID from account_uuid self.debug("select id from account where uuid = '%s';" \ - % self.account.account.id) + % self.account.id) qresultset = self.dbclient.execute( "select id from account where uuid = '%s';" \ - % self.account.account.id + % self.account.id ) self.assertEqual( isinstance(qresultset, list), @@ -1438,7 +1438,7 @@ class TestVpnUsage(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, @@ -1448,8 +1448,8 @@ class TestVpnUsage(cloudstackTestCase): cls.api_client, cls.services["server"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) cls.public_ip = PublicIPAddress.create( @@ -1506,19 +1506,19 @@ class TestVpnUsage(cloudstackTestCase): vpn = Vpn.create( self.apiclient, self.public_ip.ipaddress.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("Created VPN user for account: %s" % - self.account.account.name) + self.account.name) vpnuser = VpnUser.create( self.apiclient, self.services["vpn_user"]["username"], self.services["vpn_user"]["password"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Remove VPN user @@ -1531,11 +1531,11 @@ class TestVpnUsage(cloudstackTestCase): # Fetch account ID from account_uuid self.debug("select id from account where uuid = '%s';" \ - % self.account.account.id) + % self.account.id) qresultset = self.dbclient.execute( "select id from account where uuid = '%s';" \ - % self.account.account.id + % self.account.id ) self.assertEqual( isinstance(qresultset, list), diff --git a/test/integration/component/test_vm_passwdenabled.py b/test/integration/component/test_vm_passwdenabled.py index e3bcf678948..65b068dc2d2 100644 --- a/test/integration/component/test_vm_passwdenabled.py +++ b/test/integration/component/test_vm_passwdenabled.py @@ -108,8 +108,8 @@ class TestVMPasswordEnabled(cloudstackTestCase): cls.virtual_machine = VirtualMachine.create( cls.api_client, cls.services["small"], - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.small_offering.id, mode=cls.services["mode"] ) @@ -159,8 +159,8 @@ class TestVMPasswordEnabled(cloudstackTestCase): cls.api_client, cls.services["template"], cls.volume.id, - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) # Delete the VM - No longer needed cls.virtual_machine.delete(cls.api_client) @@ -169,8 +169,8 @@ class TestVMPasswordEnabled(cloudstackTestCase): cls.vm = VirtualMachine.create( cls.api_client, cls.services["small"], - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.small_offering.id, mode=cls.services["mode"] ) diff --git a/test/integration/component/test_volumes.py b/test/integration/component/test_volumes.py index f50113b1532..34a067930de 100644 --- a/test/integration/component/test_volumes.py +++ b/test/integration/component/test_volumes.py @@ -52,7 +52,7 @@ class Services: "displaytext": "Tiny Instance", "cpunumber": 1, "cpuspeed": 100, # in MHz - "memory": 64, # In MBs + "memory": 128, # In MBs }, "disk_offering": { "displaytext": "Small", @@ -121,7 +121,7 @@ class TestAttachVolume(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, cls.services["service_offering"] @@ -129,8 +129,8 @@ class TestAttachVolume(cloudstackTestCase): cls.virtual_machine = VirtualMachine.create( cls.api_client, cls.services["virtual_machine"], - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, ) cls._cleanup = [ @@ -162,13 +162,13 @@ class TestAttachVolume(cloudstackTestCase): self.apiclient, self.services["volume"], zoneid=self.zone.id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, diskofferingid=self.disk_offering.id ) self.debug("Created volume: %s for account: %s" % ( volume.id, - self.account.account.name + self.account.name )) # Check List Volume response for newly created volume list_volume_response = list_volumes( @@ -311,13 +311,13 @@ class TestAttachVolume(cloudstackTestCase): self.apiclient, self.services["volume"], zoneid=self.zone.id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, diskofferingid=self.disk_offering.id ) self.debug("Created volume: %s for account: %s" % ( volume.id, - self.account.account.name + self.account.name )) # Check List Volume response for newly created volume list_volume_response = list_volumes( @@ -392,7 +392,7 @@ class TestAttachDetachVolume(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, cls.services["service_offering"] @@ -400,8 +400,8 @@ class TestAttachDetachVolume(cloudstackTestCase): cls.virtual_machine = VirtualMachine.create( cls.api_client, cls.services["virtual_machine"], - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, ) cls._cleanup = [ @@ -449,13 +449,13 @@ class TestAttachDetachVolume(cloudstackTestCase): self.apiclient, self.services["volume"], zoneid=self.zone.id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, diskofferingid=self.disk_offering.id ) self.debug("Created volume: %s for account: %s" % ( volume.id, - self.account.account.name + self.account.name )) self.cleanup.append(volume) volumes.append(volume) @@ -639,7 +639,7 @@ class TestAttachVolumeISO(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, cls.services["service_offering"] @@ -647,8 +647,8 @@ class TestAttachVolumeISO(cloudstackTestCase): cls.virtual_machine = VirtualMachine.create( cls.api_client, cls.services["virtual_machine"], - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, ) cls._cleanup = [ @@ -694,13 +694,13 @@ class TestAttachVolumeISO(cloudstackTestCase): self.apiclient, self.services["volume"], zoneid=self.zone.id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, diskofferingid=self.disk_offering.id ) self.debug("Created volume: %s for account: %s" % ( volume.id, - self.account.account.name + self.account.name )) # Check List Volume response for newly created volume list_volume_response = list_volumes( @@ -749,12 +749,12 @@ class TestAttachVolumeISO(cloudstackTestCase): iso = Iso.create( self.apiclient, self.services["iso"], - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.debug("Created ISO with ID: %s for account: %s" % ( iso.id, - self.account.account.name + self.account.name )) try: @@ -831,7 +831,7 @@ class TestVolumes(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, cls.services["service_offering"] @@ -839,8 +839,8 @@ class TestVolumes(cloudstackTestCase): cls.virtual_machine = VirtualMachine.create( cls.api_client, cls.services["virtual_machine"], - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, ) @@ -848,8 +848,8 @@ class TestVolumes(cloudstackTestCase): cls.api_client, cls.services["volume"], zoneid=cls.zone.id, - account=cls.account.account.name, - domainid=cls.account.account.domainid, + account=cls.account.name, + domainid=cls.account.domainid, diskofferingid=cls.disk_offering.id ) cls._cleanup = [ @@ -1071,7 +1071,7 @@ class TestDeployVmWithCustomDisk(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, cls.services["service_offering"] @@ -1137,8 +1137,8 @@ class TestDeployVmWithCustomDisk(cloudstackTestCase): Volume.create_custom_disk( self.apiclient, self.services["custom_volume"], - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, diskofferingid=self.disk_offering.id ) self.debug("Create volume failed!") @@ -1149,8 +1149,8 @@ class TestDeployVmWithCustomDisk(cloudstackTestCase): Volume.create_custom_disk( self.apiclient, self.services["custom_volume"], - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, diskofferingid=self.disk_offering.id ) self.debug("Create volume failed!") @@ -1163,8 +1163,8 @@ class TestDeployVmWithCustomDisk(cloudstackTestCase): Volume.create_custom_disk( self.apiclient, self.services["custom_volume"], - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, diskofferingid=self.disk_offering.id ) self.debug("Create volume of cust disk size succeeded") diff --git a/test/integration/component/test_vpn_users.py b/test/integration/component/test_vpn_users.py new file mode 100644 index 00000000000..93186546d94 --- /dev/null +++ b/test/integration/component/test_vpn_users.py @@ -0,0 +1,447 @@ +# 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. + +""" P1 tests for VPN users +""" +# Import Local Modules +from nose.plugins.attrib import attr +from marvin.cloudstackTestCase import cloudstackTestCase +from marvin.integration.lib.base import ( + Account, + ServiceOffering, + VirtualMachine, + PublicIPAddress, + Vpn, + VpnUser, + Configurations, + NATRule + ) +from marvin.integration.lib.common import (get_domain, + get_zone, + get_template, + cleanup_resources, + ) + + +class Services: + """Test VPN users Services + """ + + def __init__(self): + self.services = { + "account": { + "email": "test@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + # Random characters are appended for unique + # username + "password": "password", + }, + "service_offering": { + "name": "Tiny Instance", + "displaytext": "Tiny Instance", + "cpunumber": 1, + "cpuspeed": 100, # in MHz + "memory": 128, # In MBs + }, + "disk_offering": { + "displaytext": "Small Disk Offering", + "name": "Small Disk Offering", + "disksize": 1 + }, + "virtual_machine": { + "displayname": "TestVM", + "username": "root", + "password": "password", + "ssh_port": 22, + "hypervisor": 'KVM', + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + }, + "vpn_user": { + "username": "test", + "password": "test", + }, + "natrule": { + "privateport": 1701, + "publicport": 1701, + "protocol": "UDP" + }, + "ostype": 'CentOS 5.5 (64-bit)', + "sleep": 60, + "timeout": 10, + # Networking mode: Advanced, Basic + } + + +class TestVPNUsers(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cls.api_client = super(TestVPNUsers, + cls).getClsTestClient().getApiClient() + cls.services = Services().services + # Get Zone, Domain and templates + cls.domain = get_domain(cls.api_client, cls.services) + cls.zone = get_zone(cls.api_client, cls.services) + cls.services["mode"] = cls.zone.networktype + + cls.template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostype"] + ) + + cls.services["virtual_machine"]["zoneid"] = cls.zone.id + cls.service_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offering"] + ) + + cls._cleanup = [cls.service_offering, ] + return + + @classmethod + def tearDownClass(cls): + try: + # Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.account = Account.create( + self.apiclient, + self.services["account"], + domainid=self.domain.id + ) + self.virtual_machine = VirtualMachine.create( + self.apiclient, + self.services["virtual_machine"], + templateid=self.template.id, + accountid=self.account.name, + domainid=self.account.domainid, + serviceofferingid=self.service_offering.id + ) + self.public_ip = PublicIPAddress.create( + self.apiclient, + self.virtual_machine.account, + self.virtual_machine.zoneid, + self.virtual_machine.domainid, + self.services["virtual_machine"] + ) + self.cleanup = [ + self.account, + ] + return + + def tearDown(self): + try: + # Clean up, terminate the created instance, volumes and snapshots + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def create_VPN(self, public_ip): + """Creates VPN for the network""" + + self.debug("Creating VPN with public IP: %s" % public_ip.ipaddress.id) + try: + # Assign VPN to Public IP + vpn = Vpn.create(self.apiclient, + self.public_ip.ipaddress.id, + account=self.account.name, + domainid=self.account.domainid) + + self.debug("Verifying the remote VPN access") + vpns = Vpn.list(self.apiclient, + publicipid=public_ip.ipaddress.id, + listall=True) + self.assertEqual( + isinstance(vpns, list), + True, + "List VPNs shall return a valid response" + ) + return vpn + except Exception as e: + self.fail("Failed to create remote VPN access: %s" % e) + + def create_VPN_Users(self, rand_name=True, api_client=None): + """Creates VPN users for the network""" + + self.debug("Creating VPN users for account: %s" % + self.account.name) + if api_client is None: + api_client = self.apiclient + try: + vpnuser = VpnUser.create( + api_client, + self.services["vpn_user"]["username"], + self.services["vpn_user"]["password"], + account=self.account.name, + domainid=self.account.domainid, + rand_name=rand_name + ) + + self.debug("Verifying the remote VPN access") + vpn_users = VpnUser.list(self.apiclient, + id=vpnuser.id, + listall=True) + self.assertEqual( + isinstance(vpn_users, list), + True, + "List VPNs shall return a valid response" + ) + return vpnuser + except Exception as e: + self.fail("Failed to create remote VPN users: %s" % e) + + @attr(tags=["advanced", "advancedns"]) + @attr(configuration='remote.access.vpn.user.limit') + def test_01_VPN_user_limit(self): + """VPN remote access user limit tests""" + + # Validate the following + # prerequisite: change management configuration setting of + # remote.access.vpn.user.limit + # 1. provision more users than is set in the limit + # Provisioning of users after the limit should failProvisioning of + # users after the limit should fail + + self.debug("Fetching the limit for remote access VPN users") + configs = Configurations.list( + self.apiclient, + name='remote.access.vpn.user.limit', + listall=True) + self.assertEqual(isinstance(configs, list), + True, + "List configs should return a valid response") + + limit = int(configs[0].value) + + self.debug("Enabling the VPN access for IP: %s" % + self.public_ip.ipaddress) + + self.create_VPN(self.public_ip) + self.debug("Creating %s VPN users" % limit) + for x in range(limit): + self.create_VPN_Users() + + self.debug("Adding another user exceeding limit for remote VPN users") + with self.assertRaises(Exception): + self.create_VPN_Users() + self.debug("Limit exceeded exception raised!") + return + + @attr(tags=["advanced", "advancedns"]) + def test_02_use_vpn_port(self): + """Test create VPN when L2TP port in use""" + + # Validate the following + # 1. set a port forward for UDP: 1701 and enable VPN + # 2. set port forward rule for the udp port 1701 over which L2TP works + # 3. port forward should prevent VPN from being enabled + + self.debug("Creating a port forwarding rule on port 1701") + # Create NAT rule + nat_rule = NATRule.create( + self.apiclient, + self.virtual_machine, + self.services["natrule"], + self.public_ip.ipaddress.id) + + self.debug("Verifying the NAT rule created") + nat_rules = NATRule.list(self.apiclient, id=nat_rule.id, listall=True) + + self.assertEqual(isinstance(nat_rules, list), + True, + "List NAT rules should return a valid response") + + self.debug("Enabling the VPN connection for IP: %s" % + self.public_ip.ipaddress) + with self.assertRaises(Exception): + self.create_VPN(self.public_ip) + self.debug("Create VPN connection failed! Test successful!") + return + + @attr(tags=["advanced", "advancedns"]) + def test_03_enable_vpn_use_port(self): + """Test create NAT rule when VPN when L2TP enabled""" + + # Validate the following + # 1. Enable a VPN connection on source NAT + # 2. Add a VPN user + # 3. add a port forward rule for UDP port 1701. Should result in error + # saying that VPN is enabled over port 1701 + + self.debug("Enabling the VPN connection for IP: %s" % + self.public_ip.ipaddress) + self.create_VPN(self.public_ip) + + self.debug("Creating a port forwarding rule on port 1701") + # Create NAT rule + with self.assertRaises(Exception): + NATRule.create( + self.apiclient, + self.virtual_machine, + self.services["natrule"], + self.public_ip.ipaddress.id) + + self.debug("Create NAT rule failed! Test successful!") + return + + @attr(tags=["advanced", "advancedns"]) + def test_04_add_new_users(self): + """Test add new users to existing VPN""" + + # Validate the following + # 1. Enable a VPN connection on source NAT + # 2. Add new user to VPN when there are already existing users. + # 3. We should be able to successfully establish a VPN connection using + # the newly added user credential. + + self.debug("Enabling the VPN connection for IP: %s" % + self.public_ip.ipaddress) + self.create_VPN(self.public_ip) + + try: + self.debug("Adding new VPN user to account: %s" % + self.account.name) + self.create_VPN_Users() + + # TODO: Verify the VPN connection + self.debug("Adding another user to account") + self.create_VPN_Users() + + # TODO: Verify the VPN connection with new user + except Exception as e: + self.fail("Failed to create new VPN user: %s" % e) + return + + @attr(tags=["advanced", "advancedns"]) + def test_05_add_duplicate_user(self): + """Test add duplicate user to existing VPN""" + + # Validate the following + # 1. Enable a VPN connection on source NAT + # 2. Add a VPN user say "abc" that already an added user to the VPN. + # 3. Adding this VPN user should fail. + + self.debug("Enabling the VPN connection for IP: %s" % + self.public_ip.ipaddress) + self.create_VPN(self.public_ip) + + self.debug("Adding new VPN user to account: %s" % + self.account.name) + self.create_VPN_Users(rand_name=False) + + # TODO: Verify the VPN connection + self.debug("Adding another user to account with same username") + with self.assertRaises(Exception): + self.create_VPN_Users(rand_name=False) + return + + @attr(tags=["advanced", "advancedns"]) + def test_06_add_VPN_user_global_admin(self): + """Test as global admin, add a new VPN user to an existing VPN entry + that was created by another account.""" + + # Steps for verification + # 1. Create a new user and deploy few Vms. + # 2. Enable VPN access. Add few VPN users. + # 3. Make sure that VPN access works as expected. + # 4. As global Admin , add VPN user to this user's existing VPN entry. + # Validate the following + # 1. The newly added VPN user should get configured to the router of + # user account. + # 2. We should be able to use this newly created user credential to + # establish VPN connection that will give access all VMs of this user + + self.debug("Enabling VPN connection to account: %s" % + self.account.name) + self.create_VPN(self.public_ip) + self.debug("Creating VPN user for the account: %s" % + self.account.name) + self.create_VPN_Users() + + self.debug("Creating a global admin account") + admin = Account.create(self.apiclient, + self.services["account"], + admin=True, + domainid=self.account.domainid) + self.cleanup.append(admin) + self.debug("Creating API client for newly created user") + api_client = self.testClient.createUserApiClient( + UserName=self.account.name, + DomainName=self.account.domain) + + self.debug("Adding new user to VPN as a global admin: %s" % + admin.account.name) + try: + self.create_VPN_Users(api_client=api_client) + except Exception as e: + self.fail("Global admin should be allowed to create VPN user: %s" % + e) + return + + @attr(tags=["advanced", "advancedns"]) + def test_07_add_VPN_user_domain_admin(self): + """Test as domain admin, add a new VPN user to an existing VPN entry + that was created by another account.""" + + # Steps for verification + # 1. Create a new user and deploy few Vms. + # 2. Enable VPN access. Add few VPN users. + # 3. Make sure that VPN access works as expected. + # 4. As domain Admin , add VPN user to this user's existing VPN entry. + # Validate the following + # 1. The newly added VPN user should get configured to the router of + # user account. + # 2. We should be able to use this newly created user credential to + # establish VPN connection that will give access all VMs of this user + + self.debug("Enabling VPN connection to account: %s" % + self.account.name) + self.create_VPN(self.public_ip) + self.debug("Creating VPN user for the account: %s" % + self.account.name) + self.create_VPN_Users() + + self.debug("Creating a domain admin account") + admin = Account.create(self.apiclient, + self.services["account"], + domainid=self.account.domainid) + self.cleanup.append(admin) + self.debug("Creating API client for newly created user") + api_client = self.testClient.createUserApiClient( + UserName=self.account.name, + DomainName=self.account.domain) + + self.debug("Adding new user to VPN as a domain admin: %s" % + admin.account.name) + try: + self.create_VPN_Users(api_client=api_client) + except Exception as e: + self.fail("Domain admin should be allowed to create VPN user: %s" % + e) + return diff --git a/test/integration/smoke/test_affinity_groups.py b/test/integration/smoke/test_affinity_groups.py index 3ed31152643..e0e1a17273b 100644 --- a/test/integration/smoke/test_affinity_groups.py +++ b/test/integration/smoke/test_affinity_groups.py @@ -48,7 +48,7 @@ class Services: "cpunumber": 1, "cpuspeed": 100, # in MHz - "memory": 64, + "memory": 128, # In MBs }, "ostype": 'CentOS 5.3 (64-bit)', @@ -187,7 +187,7 @@ class TestDeployVmWithAffinityGroup(cloudstackTestCase): @classmethod def tearDown(cls): try: - cls.api_client = super(TestDeployVmWithAffinityGroup, cls).getClsTestClient().getApiClient() + #cls.api_client = super(TestDeployVmWithAffinityGroup, cls).getClsTestClient().getApiClient() #Clean up, terminate the created templates cleanup_resources(cls.api_client, cls.cleanup) except Exception as e: diff --git a/test/integration/smoke/test_deploy_vm_with_userdata.py b/test/integration/smoke/test_deploy_vm_with_userdata.py index fd9e320addc..8ca9bd05a2d 100644 --- a/test/integration/smoke/test_deploy_vm_with_userdata.py +++ b/test/integration/smoke/test_deploy_vm_with_userdata.py @@ -111,6 +111,7 @@ class TestDeployVmWithUserData(cloudstackTestCase): vm = vms[0] self.assert_(vm.id == str(deployVmResponse.id), "Vm deployed is different from the test") self.assert_(vm.state == "Running", "VM is not in Running state") + self.cleanup.append(deployVmResponse) @attr(tags=["simulator", "devcloud", "basic", "advanced"]) def test_deployvm_userdata(self): @@ -134,6 +135,7 @@ class TestDeployVmWithUserData(cloudstackTestCase): vm = vms[0] self.assert_(vm.id == str(deployVmResponse.id), "Vm deployed is different from the test") self.assert_(vm.state == "Running", "VM is not in Running state") + self.cleanup.append(deployVmResponse) @classmethod def tearDownClass(cls): diff --git a/test/integration/smoke/test_global_settings.py b/test/integration/smoke/test_global_settings.py index 12b35d774b7..a7cdb3e1574 100644 --- a/test/integration/smoke/test_global_settings.py +++ b/test/integration/smoke/test_global_settings.py @@ -39,22 +39,22 @@ class TestUpdateConfigWithScope(cloudstackTestCase): updateConfigurationCmd = updateConfiguration.updateConfigurationCmd() updateConfigurationCmd.name = "use.external.dns" updateConfigurationCmd.value = "true" - updateConfigurationCmd.scope = "zone" - updateConfigurationCmd.id = 1 + updateConfigurationCmd.scopename = "zone" + updateConfigurationCmd.scopeid = 1 updateConfigurationResponse = self.apiClient.updateConfiguration(updateConfigurationCmd) self.debug("updated the parameter %s with value %s"%(updateConfigurationResponse.name, updateConfigurationResponse.value)) listConfigurationsCmd = listConfigurations.listConfigurationsCmd() listConfigurationsCmd.cfgName = updateConfigurationResponse.name - listConfigurationsCmd.scope = "zone" - listConfigurationsCmd.id = 1 + listConfigurationsCmd.scopename = "zone" + listConfigurationsCmd.scopeid = 1 listConfigurationsResponse = self.apiClient.listConfigurations(listConfigurationsCmd) self.assertNotEqual(len(listConfigurationsResponse), 0, "Check if the list API \ returns a non-empty response") - configParam = listConfigurationsResponse[0] + configParam = listConfigurationsResponse[7] self.assertEqual(configParam.value, updateConfigurationResponse.value, "Check if the update API returned \ is the same as the one we got in the list API") @@ -67,6 +67,6 @@ class TestUpdateConfigWithScope(cloudstackTestCase): updateConfigurationCmd = updateConfiguration.updateConfigurationCmd() updateConfigurationCmd.name = "use.external.dns" updateConfigurationCmd.value = "false" - updateConfigurationCmd.scope = "zone" - updateConfigurationCmd.id = 1 + updateConfigurationCmd.scopename = "zone" + updateConfigurationCmd.scopeid = 1 self.apiClient.updateConfiguration(updateConfigurationCmd) diff --git a/test/integration/smoke/test_guest_vlan_range.py b/test/integration/smoke/test_guest_vlan_range.py new file mode 100644 index 00000000000..704fe59bfff --- /dev/null +++ b/test/integration/smoke/test_guest_vlan_range.py @@ -0,0 +1,175 @@ +# 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. +""" P1 tests for Dedicating Guest Vlan Ranges +""" +#Import Local Modules +import marvin +from nose.plugins.attrib import attr +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.integration.lib.utils import * +from marvin.integration.lib.base import * +from marvin.integration.lib.common import * +import datetime + + +class Services: + """Test Dedicating Guest Vlan Ranges + """ + + def __init__(self): + self.services = { + "domain": { + "name": "Domain", + }, + "account": { + "email": "test@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + "password": "password", + }, + "name": "testphysicalnetwork", + + "vlan": "2118-2120", + } + + +class TestDedicateGuestVlanRange(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cls.api_client = super(TestDedicateGuestVlanRange, cls).getClsTestClient().getApiClient() + cls.services = Services().services + # Get Zone, Domain + cls.domain = get_domain(cls.api_client, cls.services) + cls.zone = get_zone(cls.api_client, cls.services) + + # Create Account + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=cls.domain.id + ) + cls._cleanup = [ + cls.account, + ] + return + + @classmethod + def tearDownClass(cls): + try: + # Cleanup resources used + list_physical_network_response = PhysicalNetwork.list(cls.api_client) + if list_physical_network_response is not None and len(list_physical_network_response) > 0: + physical_network = list_physical_network_response[0] + removeGuestVlanRangeResponse = \ + physical_network.update(cls.api_client, + id=physical_network.id, + removevlan=cls.services["vlan"]) + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + return + + def tearDown(self): + try: + # Clean up + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr(tags=["simulator", "advanced", "guestvlanrange", "dedicate", "release"]) + def test_dedicateGuestVlanRange(self): + """Test guest vlan range dedication + """ + + """Assume a physical network is available + """ + # Validate the following: + # 1. List the available physical network using ListPhysicalNetwork + # 2. Add a Guest Vlan range to the available physical network using UpdatePhysicalNetwork + # 3. Dedicate the created guest vlan range to user account using DedicateGuestVlanRange + # 4. Verify vlan range is dedicated with listDedicatedGuestVlanRanges + # 5. Release the dedicated guest vlan range back to the system + # 6. Verify guest vlan range has been released, verify with listDedicatedGuestVlanRanges + # 7. Remove the added guest vlan range using UpdatePhysicalNetwork + + self.debug("Listing available physical network") + list_physical_network_response = PhysicalNetwork.list( + self.apiclient + ) + self.assertEqual( + isinstance(list_physical_network_response, list), + True, + "Check for list guest vlan range response" + ) + physical_network_response = list_physical_network_response[0] + + self.debug("Adding guest vlan range") + addGuestVlanRangeResponse = physical_network_response.update(self.apiclient, id=physical_network_response.id, vlan=self.services["vlan"]) + + self.debug("Dedicating guest vlan range"); + dedicate_guest_vlan_range_response = PhysicalNetwork.dedicate( + self.apiclient, + self.services["vlan"], + physicalnetworkid=physical_network_response.id, + account=self.account.name, + domainid=self.account.domainid + ) + list_dedicated_guest_vlan_range_response = PhysicalNetwork.listDedicated( + self.apiclient, + id=dedicate_guest_vlan_range_response.id + ) + dedicated_guest_vlan_response = list_dedicated_guest_vlan_range_response[0] + self.assertEqual( + dedicated_guest_vlan_response.account, + self.account.name, + "Check account name is in listDedicatedGuestVlanRanges as the account the range is dedicated to" + ) + + self.debug("Releasing guest vlan range"); +<<<<<<< HEAD + dedicated_guest_vlan_response.release(self.apiclient) + list_dedicated_guest_vlan_range_response = PhysicalNetwork.listDedicated( + self.apiclient, + id=dedicate_guest_vlan_range_response.id + ) + dedicated_guest_vlan_response = list_dedicated_guest_vlan_range_response[0] + self.assertEqual( + dedicated_guest_vlan_response.account, + "system", + "Check account name is system account in listDedicatedGuestVlanRanges" + ) +======= + dedicate_guest_vlan_range_response.release(self.apiclient) + list_dedicated_guest_vlan_range_response = PhysicalNetwork.listDedicated(self.apiclient) + self.assertEqual( + list_dedicated_guest_vlan_range_response, + None, + "Check vlan range is not available in listDedicatedGuestVlanRanges" + + ) +>>>>>>> master + diff --git a/test/integration/smoke/test_internal_lb.py b/test/integration/smoke/test_internal_lb.py new file mode 100644 index 00000000000..ae64297bf1c --- /dev/null +++ b/test/integration/smoke/test_internal_lb.py @@ -0,0 +1,250 @@ +# 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. +""" Tests for configuring Internal Load Balancing Rules. +""" +#Import Local Modules +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.integration.lib.utils import * +from marvin.integration.lib.base import * +from marvin.integration.lib.common import * + + +class TestInternalLb(cloudstackTestCase): + networkOfferingId = None + networkId = None + vmId = None + lbId = None + + zoneId = 1 + serviceOfferingId = 1 + templateId = 5 + + + serviceProviderList = [ + { + "provider": "VpcVirtualRouter", + "service": "Vpn" + }, + { + "provider": "VpcVirtualRouter", + "service": "UserData" + }, + { + "provider": "VpcVirtualRouter", + "service": "Dhcp" + }, + { + "provider": "VpcVirtualRouter", + "service": "Dns" + }, + { + "provider": "InternalLbVM", + "service": "Lb" + }, + { + "provider": "VpcVirtualRouter", + "service": "SourceNat" + }, + { + "provider": "VpcVirtualRouter", + "service": "StaticNat" + }, + { + "provider": "VpcVirtualRouter", + "service": "PortForwarding" + }, + { + "provider": "VpcVirtualRouter", + "service": "NetworkACL" + } + ] + + serviceCapsList = [ + { + "service": "SourceNat", + "capabilitytype": "SupportedSourceNatTypes", + "capabilityvalue": "peraccount" + }, + { + "service": "Lb", + "capabilitytype": "SupportedLbIsolation", + "capabilityvalue": "dedicated" + }, + { + "service": "Lb", + "capabilitytype": "lbSchemes", + "capabilityvalue": "internal" + } + ] + + def setUp(self): + self.apiClient = self.testClient.getApiClient() + + + + def test_internallb(self): + + #1) Create and enable network offering with Internal Lb vm service + self.createNetworkOffering() + + #2) Create VPC and network in it + self.createNetwork() + + #3) Deploy a vm + self.deployVm() + + #4) Create an Internal Load Balancer + self.createInternalLoadBalancer() + + #5) Assign the VM to the Internal Load Balancer + self.assignToLoadBalancerRule() + + #6) Remove the vm from the Interanl Load Balancer + self.removeFromLoadBalancerRule() + + #7) Delete the Load Balancer + self.deleteLoadBalancer() + + + def deployVm(self): + deployVirtualMachineCmd = deployVirtualMachine.deployVirtualMachineCmd() + deployVirtualMachineCmd.networkids = TestInternalLb.networkId + deployVirtualMachineCmd.serviceofferingid = TestInternalLb.serviceOfferingId + deployVirtualMachineCmd.zoneid = TestInternalLb.zoneId + deployVirtualMachineCmd.templateid = TestInternalLb.templateId + deployVirtualMachineCmd.hypervisor = "XenServer" + deployVMResponse = self.apiClient.deployVirtualMachine(deployVirtualMachineCmd) + TestInternalLb.vmId = deployVMResponse.id + + + def createInternalLoadBalancer(self): + createLoadBalancerCmd = createLoadBalancer.createLoadBalancerCmd() + createLoadBalancerCmd.name = "lb rule" + createLoadBalancerCmd.sourceport = 22 + createLoadBalancerCmd.instanceport = 22 + createLoadBalancerCmd.algorithm = "roundrobin" + createLoadBalancerCmd.scheme = "internal" + createLoadBalancerCmd.sourceipaddressnetworkid = TestInternalLb.networkId + createLoadBalancerCmd.networkid = TestInternalLb.networkId + createLoadBalancerResponse = self.apiClient.createLoadBalancer(createLoadBalancerCmd) + TestInternalLb.lbId = createLoadBalancerResponse.id + self.assertIsNotNone(createLoadBalancerResponse.id, "Failed to create a load balancer") + + + def assignToLoadBalancerRule(self): + assignToLoadBalancerRuleCmd = assignToLoadBalancerRule.assignToLoadBalancerRuleCmd() + assignToLoadBalancerRuleCmd.id = TestInternalLb.lbId + assignToLoadBalancerRuleCmd.virtualMachineIds = TestInternalLb.vmId + assignToLoadBalancerRuleResponse = self.apiClient.assignToLoadBalancerRule(assignToLoadBalancerRuleCmd) + self.assertTrue(assignToLoadBalancerRuleResponse.success, "Failed to assign the vm to the load balancer") + + + + def removeFromLoadBalancerRule(self): + removeFromLoadBalancerRuleCmd = removeFromLoadBalancerRule.removeFromLoadBalancerRuleCmd() + removeFromLoadBalancerRuleCmd.id = TestInternalLb.lbId + removeFromLoadBalancerRuleCmd.virtualMachineIds = TestInternalLb.vmId + removeFromLoadBalancerRuleResponse = self.apiClient.removeFromLoadBalancerRule(removeFromLoadBalancerRuleCmd) + self.assertTrue(removeFromLoadBalancerRuleResponse.success, "Failed to remove the vm from the load balancer") + + + + #def removeInternalLoadBalancer(self): + def deleteLoadBalancer(self): + deleteLoadBalancerCmd = deleteLoadBalancer.deleteLoadBalancerCmd() + deleteLoadBalancerCmd.id = TestInternalLb.lbId + deleteLoadBalancerResponse = self.apiClient.deleteLoadBalancer(deleteLoadBalancerCmd) + self.assertTrue(deleteLoadBalancerResponse.success, "Failed to remove the load balancer") + + + + def createNetwork(self): + createVPCCmd = createVPC.createVPCCmd() + createVPCCmd.name = "new vpc" + createVPCCmd.cidr = "10.1.1.0/24" + createVPCCmd.displaytext = "new vpc" + createVPCCmd.vpcofferingid = 1 + createVPCCmd.zoneid = self.zoneId + createVPCResponse = self.apiClient.createVPC(createVPCCmd) + + + createNetworkCmd = createNetwork.createNetworkCmd() + createNetworkCmd.name = "vpc network" + createNetworkCmd.displaytext = "vpc network" + createNetworkCmd.netmask = "255.255.255.0" + createNetworkCmd.gateway = "10.1.1.1" + createNetworkCmd.zoneid = self.zoneId + createNetworkCmd.vpcid = createVPCResponse.id + createNetworkCmd.networkofferingid = TestInternalLb.networkOfferingId + createNetworkResponse = self.apiClient.createNetwork(createNetworkCmd) + TestInternalLb.networkId = createNetworkResponse.id + + self.assertIsNotNone(createNetworkResponse.id, "Network failed to create") + + + def createNetworkOffering(self): + createNetworkOfferingCmd = createNetworkOffering.createNetworkOfferingCmd() + createNetworkOfferingCmd.name = "Network offering for internal lb service - " + str(random.randrange(1,100+1)) + createNetworkOfferingCmd.displaytext = "Network offering for internal lb service" + createNetworkOfferingCmd.guestiptype = "isolated" + createNetworkOfferingCmd.traffictype = "Guest" + createNetworkOfferingCmd.conservemode = "false" + createNetworkOfferingCmd.supportedservices = "Vpn,Dhcp,Dns,Lb,UserData,SourceNat,StaticNat,PortForwarding,NetworkACL" + + + createNetworkOfferingCmd.serviceproviderlist = [] + for item in self.serviceProviderList: + createNetworkOfferingCmd.serviceproviderlist.append({ + 'service': item['service'], + 'provider': item['provider'] + }) + + createNetworkOfferingCmd.servicecapabilitylist = [] + for item in self.serviceCapsList: + createNetworkOfferingCmd.servicecapabilitylist.append({ + 'service': item['service'], + 'capabilitytype': item['capabilitytype'], + 'capabilityvalue': item['capabilityvalue'] + }) + + + createNetworkOfferingResponse = self.apiClient.createNetworkOffering(createNetworkOfferingCmd) + TestInternalLb.networkOfferingId = createNetworkOfferingResponse.id + + #enable network offering + updateNetworkOfferingCmd = updateNetworkOffering.updateNetworkOfferingCmd() + updateNetworkOfferingCmd.id = TestInternalLb.networkOfferingId + updateNetworkOfferingCmd.state = "Enabled" + updateNetworkOfferingResponse = self.apiClient.updateNetworkOffering(updateNetworkOfferingCmd) + + + #list network offering to see if its enabled + listNetworkOfferingsCmd = listNetworkOfferings.listNetworkOfferingsCmd() + listNetworkOfferingsCmd.id = TestInternalLb.networkOfferingId + listOffResponse = self.apiClient.listNetworkOfferings(listNetworkOfferingsCmd) + + self.assertNotEqual(len(listOffResponse), 0, "Check if the list network offerings API \ + returns a non-empty response") + + + def tearDown(self): + #destroy the vm + if TestInternalLb.vmId is not None: + destroyVirtualMachineCmd = destroyVirtualMachine.destroyVirtualMachineCmd() + destroyVirtualMachineCmd.id = TestInternalLb.vmId + destroyVirtualMachineResponse = self.apiClient.destroyVirtualMachine(destroyVirtualMachineCmd) diff --git a/test/integration/smoke/test_iso.py b/test/integration/smoke/test_iso.py index 0b7d2765775..ad4a8f280d1 100644 --- a/test/integration/smoke/test_iso.py +++ b/test/integration/smoke/test_iso.py @@ -139,8 +139,8 @@ class TestCreateIso(cloudstackTestCase): iso = Iso.create( self.apiclient, self.services["iso_2"], - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.debug("ISO created with ID: %s" % iso.id) @@ -214,7 +214,7 @@ class TestISO(cloudstackTestCase): cls.services["account"], domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name # Finding the OsTypeId from Ostype ostypes = list_os_types( cls.api_client, @@ -230,8 +230,8 @@ class TestISO(cloudstackTestCase): cls.iso_1 = Iso.create( cls.api_client, cls.services["iso_1"], - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) try: cls.iso_1.download(cls.api_client) @@ -242,8 +242,8 @@ class TestISO(cloudstackTestCase): cls.iso_2 = Iso.create( cls.api_client, cls.services["iso_2"], - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) try: cls.iso_2.download(cls.api_client) @@ -448,8 +448,8 @@ class TestISO(cloudstackTestCase): list_iso_response = list_isos( self.apiclient, id=self.iso_2.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(list_iso_response, list), diff --git a/test/integration/smoke/test_network.py b/test/integration/smoke/test_network.py index df89eaaa695..4a7bb44da2c 100644 --- a/test/integration/smoke/test_network.py +++ b/test/integration/smoke/test_network.py @@ -145,28 +145,28 @@ class TestPublicIP(cloudstackTestCase): cls.account_network = Network.create( cls.api_client, cls.services["network"], - cls.account.account.name, - cls.account.account.domainid + cls.account.name, + cls.account.domainid ) cls.user_network = Network.create( cls.api_client, cls.services["network"], - cls.user.account.name, - cls.user.account.domainid + cls.user.name, + cls.user.domainid ) # Create Source NAT IP addresses account_src_nat_ip = PublicIPAddress.create( cls.api_client, - cls.account.account.name, + cls.account.name, cls.zone.id, - cls.account.account.domainid + cls.account.domainid ) user_src_nat_ip = PublicIPAddress.create( cls.api_client, - cls.user.account.name, + cls.user.name, cls.zone.id, - cls.user.account.domainid + cls.user.domainid ) cls._cleanup = [ cls.account_network, @@ -197,9 +197,9 @@ class TestPublicIP(cloudstackTestCase): ip_address = PublicIPAddress.create( self.apiclient, - self.account.account.name, + self.account.name, self.zone.id, - self.account.account.domainid + self.account.domainid ) list_pub_ip_addr_resp = list_publicIP( self.apiclient, @@ -248,9 +248,9 @@ class TestPublicIP(cloudstackTestCase): ip_address = PublicIPAddress.create( self.apiclient, - self.user.account.name, + self.user.name, self.zone.id, - self.user.account.domainid + self.user.domainid ) #listPublicIpAddresses should return newly created public IP @@ -321,8 +321,8 @@ class TestPortForwarding(cloudstackTestCase): cls.api_client, cls.services["server"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) cls._cleanup = [ @@ -358,8 +358,8 @@ class TestPortForwarding(cloudstackTestCase): src_nat_ip_addrs = list_publicIP( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( @@ -481,9 +481,9 @@ class TestPortForwarding(cloudstackTestCase): ip_address = PublicIPAddress.create( self.apiclient, - self.account.account.name, + self.account.name, self.zone.id, - self.account.account.domainid, + self.account.domainid, self.services["server"] ) self.cleanup.append(ip_address) @@ -554,9 +554,9 @@ class TestPortForwarding(cloudstackTestCase): self.debug("SSHing into VM with IP address %s with NAT IP %s" % ( self.virtual_machine.ipaddress, - ip_address.ipaddress.ipaddress + ip_address.ipaddress )) - self.virtual_machine.get_ssh_client(ip_address.ipaddress.ipaddress) + self.virtual_machine.get_ssh_client(ip_address.ipaddress) except Exception as e: self.fail( "SSH Access failed for %s: %s" % \ @@ -581,7 +581,7 @@ class TestPortForwarding(cloudstackTestCase): self.virtual_machine.ipaddress) remoteSSHClient( - ip_address.ipaddress.ipaddress, + ip_address.ipaddress, self.virtual_machine.ssh_port, self.virtual_machine.username, self.virtual_machine.password @@ -621,23 +621,23 @@ class TestLoadBalancingRule(cloudstackTestCase): cls.api_client, cls.services["server"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) cls.vm_2 = VirtualMachine.create( cls.api_client, cls.services["server"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) cls.non_src_nat_ip = PublicIPAddress.create( cls.api_client, - cls.account.account.name, + cls.account.name, cls.zone.id, - cls.account.account.domainid, + cls.account.domainid, cls.services["server"] ) # Open up firewall port for SSH @@ -680,8 +680,8 @@ class TestLoadBalancingRule(cloudstackTestCase): src_nat_ip_addrs = list_publicIP( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(src_nat_ip_addrs, list), @@ -693,8 +693,8 @@ class TestLoadBalancingRule(cloudstackTestCase): # Check if VM is in Running state before creating LB rule vm_response = VirtualMachine.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( @@ -720,7 +720,7 @@ class TestLoadBalancingRule(cloudstackTestCase): self.apiclient, self.services["lbrule"], src_nat_ip_addr.id, - accountid=self.account.account.name + accountid=self.account.name ) self.cleanup.append(lb_rule) @@ -889,8 +889,8 @@ class TestLoadBalancingRule(cloudstackTestCase): # Check if VM is in Running state before creating LB rule vm_response = VirtualMachine.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( @@ -916,7 +916,7 @@ class TestLoadBalancingRule(cloudstackTestCase): self.apiclient, self.services["lbrule"], self.non_src_nat_ip.ipaddress.id, - accountid=self.account.account.name + accountid=self.account.name ) self.cleanup.append(lb_rule) @@ -974,12 +974,12 @@ class TestLoadBalancingRule(cloudstackTestCase): try: self.debug("SSHing into IP address: %s after adding VMs (ID: %s , %s)" % ( - self.non_src_nat_ip.ipaddress.ipaddress, + self.non_src_nat_ip.ipaddress, self.vm_1.id, self.vm_2.id )) ssh_1 = remoteSSHClient( - self.non_src_nat_ip.ipaddress.ipaddress, + self.non_src_nat_ip.ipaddress, self.services['lbrule']["publicport"], self.vm_1.username, self.vm_1.password @@ -993,12 +993,12 @@ class TestLoadBalancingRule(cloudstackTestCase): self.debug("SSHing again into IP address: %s with VMs (ID: %s , %s) added to LB rule" % ( - self.non_src_nat_ip.ipaddress.ipaddress, + self.non_src_nat_ip.ipaddress, self.vm_1.id, self.vm_2.id )) ssh_2 = remoteSSHClient( - self.non_src_nat_ip.ipaddress.ipaddress, + self.non_src_nat_ip.ipaddress, self.services['lbrule']["publicport"], self.vm_1.username, self.vm_1.password @@ -1022,11 +1022,11 @@ class TestLoadBalancingRule(cloudstackTestCase): self.debug("SSHing into IP address: %s after removing VM (ID: %s) from LB rule" % ( - self.non_src_nat_ip.ipaddress.ipaddress, + self.non_src_nat_ip.ipaddress, self.vm_2.id )) ssh_1 = remoteSSHClient( - self.non_src_nat_ip.ipaddress.ipaddress, + self.non_src_nat_ip.ipaddress, self.services['lbrule']["publicport"], self.vm_1.username, self.vm_1.password @@ -1036,7 +1036,7 @@ class TestLoadBalancingRule(cloudstackTestCase): self.debug("Hostnames after removing VM2: %s" % str(hostnames)) except Exception as e: self.fail("%s: SSH failed for VM with IP Address: %s" % - (e, self.non_src_nat_ip.ipaddress.ipaddress)) + (e, self.non_src_nat_ip.ipaddress)) self.assertIn( self.vm_1.name, @@ -1048,11 +1048,11 @@ class TestLoadBalancingRule(cloudstackTestCase): with self.assertRaises(Exception): self.fail("SSHing into IP address: %s after removing VM (ID: %s) from LB rule" % ( - self.non_src_nat_ip.ipaddress.ipaddress, + self.non_src_nat_ip.ipaddress, self.vm_1.id )) ssh_1 = remoteSSHClient( - self.non_src_nat_ip.ipaddress.ipaddress, + self.non_src_nat_ip.ipaddress, self.services['lbrule']["publicport"], self.vm_1.username, self.vm_1.password @@ -1093,15 +1093,15 @@ class TestRebootRouter(cloudstackTestCase): self.apiclient, self.services["server"], templateid=template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) src_nat_ip_addrs = list_publicIP( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) try: src_nat_ip_addr = src_nat_ip_addrs[0] @@ -1129,7 +1129,7 @@ class TestRebootRouter(cloudstackTestCase): self.apiclient, self.services["lbrule"], src_nat_ip_addr.id, - self.account.account.name + self.account.name ) lb_rule.assign(self.apiclient, [self.vm_1]) self.nat_rule = NATRule.create( @@ -1159,8 +1159,8 @@ class TestRebootRouter(cloudstackTestCase): #Retrieve router for the user account routers = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(routers, list), @@ -1254,8 +1254,8 @@ class TestAssignRemoveLB(cloudstackTestCase): self.apiclient, self.services["server"], templateid=template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) @@ -1263,8 +1263,8 @@ class TestAssignRemoveLB(cloudstackTestCase): self.apiclient, self.services["server"], templateid=template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) @@ -1272,8 +1272,8 @@ class TestAssignRemoveLB(cloudstackTestCase): self.apiclient, self.services["server"], templateid=template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) @@ -1297,8 +1297,8 @@ class TestAssignRemoveLB(cloudstackTestCase): src_nat_ip_addrs = list_publicIP( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(src_nat_ip_addrs, list), @@ -1320,8 +1320,8 @@ class TestAssignRemoveLB(cloudstackTestCase): # Check if VM is in Running state before creating LB rule vm_response = VirtualMachine.list( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( @@ -1346,7 +1346,7 @@ class TestAssignRemoveLB(cloudstackTestCase): self.apiclient, self.services["lbrule"], self.non_src_nat_ip.id, - self.account.account.name + self.account.name ) lb_rule.assign(self.apiclient, [self.vm_1, self.vm_2]) @@ -1514,28 +1514,28 @@ class TestReleaseIP(cloudstackTestCase): self.apiclient, self.services["server"], templateid=template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) self.ip_address = PublicIPAddress.create( self.apiclient, - self.account.account.name, + self.account.name, self.zone.id, - self.account.account.domainid + self.account.domainid ) ip_addrs = list_publicIP( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) try: self.ip_addr = ip_addrs[0] except Exception as e: raise Exception("Failed: During acquiring source NAT for account: %s" % - self.account.account.name) + self.account.name) self.nat_rule = NATRule.create( self.apiclient, @@ -1547,7 +1547,7 @@ class TestReleaseIP(cloudstackTestCase): self.apiclient, self.services["lbrule"], self.ip_addr.id, - accountid=self.account.account.name + accountid=self.account.name ) self.cleanup = [ self.virtual_machine, @@ -1652,15 +1652,15 @@ class TestDeleteAccount(cloudstackTestCase): self.apiclient, self.services["server"], templateid=template.id, - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id ) src_nat_ip_addrs = list_publicIP( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) try: @@ -1674,7 +1674,7 @@ class TestDeleteAccount(cloudstackTestCase): self.apiclient, self.services["lbrule"], src_nat_ip_addr.id, - self.account.account.name + self.account.name ) self.lb_rule.assign(self.apiclient, [self.vm_1]) @@ -1717,8 +1717,8 @@ class TestDeleteAccount(cloudstackTestCase): try: list_lb_reponse = list_lb_rules( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( list_lb_reponse, @@ -1729,14 +1729,14 @@ class TestDeleteAccount(cloudstackTestCase): raise Exception( "Exception raised while fetching LB rules for account: %s" % - self.account.account.name) + self.account.name) # ListPortForwardingRules should not # list associated rules with deleted account try: list_nat_reponse = list_nat_rules( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( list_nat_reponse, @@ -1747,13 +1747,13 @@ class TestDeleteAccount(cloudstackTestCase): raise Exception( "Exception raised while fetching NAT rules for account: %s" % - self.account.account.name) + self.account.name) #Retrieve router for the user account try: routers = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( routers, @@ -1764,7 +1764,7 @@ class TestDeleteAccount(cloudstackTestCase): raise Exception( "Exception raised while fetching routers for account: %s" % - self.account.account.name) + self.account.name) return def tearDown(self): diff --git a/test/integration/smoke/test_nic.py b/test/integration/smoke/test_nic.py index ad30122cd47..bae6dfda15d 100644 --- a/test/integration/smoke/test_nic.py +++ b/test/integration/smoke/test_nic.py @@ -181,8 +181,8 @@ class TestDeployVM(cloudstackTestCase): self.test_network = Network.create( self.apiclient, self.services["network"], - self.account.account.name, - self.account.account.domainid, + self.account.name, + self.account.domainid, ) self.cleanup.insert(0, self.test_network) except Exception as ex: @@ -198,8 +198,8 @@ class TestDeployVM(cloudstackTestCase): self.virtual_machine = VirtualMachine.create( self.apiclient, self.services["small"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, + accountid=self.account.name, + domainid=self.account.domainid, serviceofferingid=self.service_offering.id, mode=self.services['mode'] ) diff --git a/test/integration/smoke/test_non_contigiousvlan.py b/test/integration/smoke/test_non_contigiousvlan.py index 91b6325782c..4e130d97aa0 100644 --- a/test/integration/smoke/test_non_contigiousvlan.py +++ b/test/integration/smoke/test_non_contigiousvlan.py @@ -81,6 +81,6 @@ class TestUpdatePhysicalNetwork(cloudstackTestCase): self.network = phy_networks[0] self.networkid = phy_networks[0].id updateResponse = self.network.update(self.apiClient, id = self.networkid, removevlan = self.vlan["full"]) - self.assert_(updateResponse.vlan.find(self.vlan["full"]) > 0, + self.assert_(updateResponse.vlan.find(self.vlan["full"]) < 0, "VLAN was not removed successfully") diff --git a/test/integration/smoke/test_regions.py b/test/integration/smoke/test_regions.py new file mode 100644 index 00000000000..5d12e74e8dd --- /dev/null +++ b/test/integration/smoke/test_regions.py @@ -0,0 +1,93 @@ +# 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. + +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.integration.lib.utils import * +from marvin.integration.lib.base import * +from marvin.integration.lib.common import * +from nose.plugins.attrib import attr + +class Services: + def __init__(self): + self.services = { + "region": { + "regionid": "2", + "regionname": "Region2", + "regionendpoint": "http://region2:8080/client" + } + } + + +class TestRegions(cloudstackTestCase): + """Test Regions - basic region creation + """ + + @classmethod + def setUpClass(cls): + cls.api_client = super(TestRegions, cls).getClsTestClient().getApiClient() + cls.services = Services().services + cls.domain = get_domain(cls.api_client, cls.services) + cls.cleanup = [] + + @attr(tags=["simulator", "basic", "advanced"]) + def test_createRegion(self): + """ Test for create region + """ + region = Region.create(self.api_client, + self.services["region"] + ) + + list_region = Region.list(self.api_client, + id=self.services["region"]["regionid"] + ) + + self.assertEqual( + isinstance(list_region, list), + True, + "Check for list Region response" + ) + region_response = list_region[0] + + self.assertEqual( + str(region_response.id), + self.services["region"]["regionid"], + "listRegion response does not match with region Id created" + ) + + self.assertEqual( + region_response.name, + self.services["region"]["regionname"], + "listRegion response does not match with region name created" + ) + self.assertEqual( + region_response.endpoint, + self.services["region"]["regionendpoint"], + "listRegion response does not match with region endpoint created" + ) + self.cleanup.append(region) + return + + @classmethod + def tearDownClass(cls): + try: + #Clean up + cleanup_resources(cls.api_client, cls.cleanup) + list_region = Region.list(cls.api_client, id=cls.services["region"]["regionid"]) + assert list_region is None, "Region deletion fails" + except Exception as e: + raise Exception("Warning: Region cleanup/delete fails with : %s" % e) \ No newline at end of file diff --git a/test/integration/smoke/test_routers.py b/test/integration/smoke/test_routers.py index 7785576423a..9ec2e918c42 100644 --- a/test/integration/smoke/test_routers.py +++ b/test/integration/smoke/test_routers.py @@ -102,8 +102,8 @@ class TestRouterServices(cloudstackTestCase): cls.api_client, cls.services["virtual_machine"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id ) cls.cleanup = [ @@ -143,8 +143,8 @@ class TestRouterServices(cloudstackTestCase): # Find router associated with user account list_router_response = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(list_router_response, list), @@ -205,8 +205,8 @@ class TestRouterServices(cloudstackTestCase): # Find router associated with user account list_router_response = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(list_router_response, list), @@ -284,8 +284,8 @@ class TestRouterServices(cloudstackTestCase): # Find router associated with user account list_router_response = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(list_router_response, list), @@ -302,8 +302,8 @@ class TestRouterServices(cloudstackTestCase): while True: networks = list_networks( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(networks, list), @@ -332,8 +332,8 @@ class TestRouterServices(cloudstackTestCase): # Get router details after restart list_router_response = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(list_router_response, list), @@ -364,8 +364,8 @@ class TestRouterServices(cloudstackTestCase): while True: networks = list_networks( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(networks, list), @@ -394,8 +394,8 @@ class TestRouterServices(cloudstackTestCase): # Get router details after restart list_router_response = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(list_router_response, list), @@ -462,8 +462,8 @@ class TestRouterServices(cloudstackTestCase): list_router_response = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(list_router_response, list), @@ -528,8 +528,8 @@ class TestRouterServices(cloudstackTestCase): list_router_response = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(list_router_response, list), @@ -609,8 +609,8 @@ class TestRouterServices(cloudstackTestCase): list_router_response = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(list_router_response, list), @@ -653,8 +653,8 @@ class TestRouterServices(cloudstackTestCase): list_router_response = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(list_router_response, list), @@ -698,8 +698,8 @@ class TestRouterServices(cloudstackTestCase): list_router_response = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(list_router_response, list), @@ -755,8 +755,8 @@ class TestRouterServices(cloudstackTestCase): list_vms = list_virtual_machines( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(list_vms, list), @@ -809,8 +809,8 @@ class TestRouterServices(cloudstackTestCase): #Check status of network router list_router_response = list_routers( self.apiclient, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) if isinstance(list_router_response, list): break diff --git a/test/integration/smoke/test_scale_vm.py b/test/integration/smoke/test_scale_vm.py index 64fe4dc9aa4..fa2418b7cd8 100644 --- a/test/integration/smoke/test_scale_vm.py +++ b/test/integration/smoke/test_scale_vm.py @@ -137,8 +137,8 @@ class TestScaleVm(cloudstackTestCase): cls.virtual_machine = VirtualMachine.create( cls.api_client, cls.services["small"], - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.small_offering.id, mode=cls.services["mode"] ) diff --git a/test/integration/smoke/test_templates.py b/test/integration/smoke/test_templates.py index a648098079f..382f56f8980 100644 --- a/test/integration/smoke/test_templates.py +++ b/test/integration/smoke/test_templates.py @@ -148,7 +148,7 @@ class TestCreateTemplate(cloudstackTestCase): cls.services["account"], domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, @@ -159,8 +159,8 @@ class TestCreateTemplate(cloudstackTestCase): cls.api_client, cls.services["virtual_machine"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, mode=cls.services["mode"] ) @@ -235,8 +235,8 @@ class TestCreateTemplate(cloudstackTestCase): self.apiclient, self.services["template_1"], self.volume.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.cleanup.append(template) @@ -292,6 +292,7 @@ class TestTemplates(cloudstackTestCase): # Get Zone, Domain and templates cls.domain = get_domain(cls.api_client, cls.services) cls.zone = get_zone(cls.api_client, cls.services) + cls.services['mode'] = cls.zone.networktype #populate second zone id for iso copy cmd = listZones.listZonesCmd() zones = cls.api_client.listZones(cmd) @@ -332,7 +333,7 @@ class TestTemplates(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, @@ -343,8 +344,8 @@ class TestTemplates(cloudstackTestCase): cls.api_client, cls.services["virtual_machine"], templateid=template.id, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, mode=cls.services["mode"] ) @@ -393,15 +394,15 @@ class TestTemplates(cloudstackTestCase): cls.api_client, cls.services["template_1"], cls.volume.id, - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) cls.template_2 = Template.create( cls.api_client, cls.services["template_2"], cls.volume.id, - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) cls._cleanup = [ cls.service_offering, @@ -474,8 +475,8 @@ class TestTemplates(cloudstackTestCase): templatefilter=\ self.services["templatefilter"], id=self.template_1.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) if isinstance(list_template_response, list): break @@ -540,8 +541,8 @@ class TestTemplates(cloudstackTestCase): templatefilter=\ self.services["templatefilter"], id=self.template_1.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) # Verify template is deleted properly using ListTemplates self.assertEqual( @@ -626,8 +627,8 @@ class TestTemplates(cloudstackTestCase): self.apiclient, templatefilter='featured', id=self.template_2.id, - account=self.account.account.name, - domainid=self.account.account.domainid + account=self.account.name, + domainid=self.account.domainid ) self.assertEqual( isinstance(list_template_response, list), @@ -751,8 +752,8 @@ class TestTemplates(cloudstackTestCase): list_template_response = list_templates( self.apiclient, templatefilter='featured', - account=self.user.account.name, - domainid=self.user.account.domainid + account=self.user.name, + domainid=self.user.domainid ) self.assertEqual( isinstance(list_template_response, list), @@ -783,8 +784,8 @@ class TestTemplates(cloudstackTestCase): list_template_response = list_templates( self.apiclient, templatefilter='featured', - account=self.user.account.name, - domainid=self.user.account.domainid + account=self.user.name, + domainid=self.user.domainid ) self.assertEqual( isinstance(list_template_response, list), diff --git a/test/integration/smoke/test_vm_life_cycle.py b/test/integration/smoke/test_vm_life_cycle.py index ae36c648e0a..21c26357ab2 100644 --- a/test/integration/smoke/test_vm_life_cycle.py +++ b/test/integration/smoke/test_vm_life_cycle.py @@ -163,6 +163,8 @@ class TestDeployVM(cloudstackTestCase): cls.services["account"], domainid=domain.id ) + cls.debug(str("============" )) + cls.debug(cls.account.id) cls.service_offering = ServiceOffering.create( cls.apiclient, diff --git a/test/integration/smoke/test_vm_snapshots.py b/test/integration/smoke/test_vm_snapshots.py new file mode 100644 index 00000000000..353d499f7a1 --- /dev/null +++ b/test/integration/smoke/test_vm_snapshots.py @@ -0,0 +1,308 @@ +# 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. + +# Import Local Modules +import marvin +from nose.plugins.attrib import attr +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.integration.lib.utils import * +from marvin.integration.lib.base import * +from marvin.integration.lib.common import * +from marvin.remoteSSHClient import remoteSSHClient + +class Services: + """Test Snapshots Services + """ + + def __init__(self): + self.services = { + "account": { + "email": "test@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + # Random characters are appended for unique + # username + "password": "password", + }, + "service_offering": { + "name": "Tiny Instance", + "displaytext": "Tiny Instance", + "cpunumber": 1, + "cpuspeed": 200, # in MHz + "memory": 256, # In MBs + }, + "server": { + "displayname": "TestVM", + "username": "root", + "password": "password", + "ssh_port": 22, + "hypervisor": 'XenServer', + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + }, + "mgmt_server": { + "ipaddress": '1.2.2.152', + "username": "root", + "password": "password", + "port": 22, + }, + "templates": { + "displaytext": 'Template', + "name": 'Template', + "ostype": "CentOS 5.3 (64-bit)", + "templatefilter": 'self', + }, + "test_dir": "/tmp", + "random_data": "random.data", + "snapshot_name":"TestSnapshot", + "snapshot_displaytext":"Test", + "ostype": "CentOS 5.3 (64-bit)", + "sleep": 60, + "timeout": 10, + "mode": 'advanced', # Networking mode: Advanced, Basic + } + +class TestVmSnapshot(cloudstackTestCase): + @classmethod + def setUpClass(cls): + cls.api_client = super(TestVmSnapshot, cls).getClsTestClient().getApiClient() + cls.services = Services().services + # Get Zone, Domain and templates + cls.domain = get_domain(cls.api_client, cls.services) + cls.zone = get_zone(cls.api_client, cls.services) + + template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostype"] + ) + cls.services["domainid"] = cls.domain.id + cls.services["server"]["zoneid"] = cls.zone.id + cls.services["templates"]["ostypeid"] = template.ostypeid + cls.services["zoneid"] = cls.zone.id + + # Create VMs, NAT Rules etc + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=cls.domain.id + ) + + cls.services["account"] = cls.account.name + + cls.service_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offering"] + ) + cls.virtual_machine = VirtualMachine.create( + cls.api_client, + cls.services["server"], + templateid=template.id, + accountid=cls.account.name, + domainid=cls.account.domainid, + serviceofferingid=cls.service_offering.id, + mode=cls.services["mode"] + ) + cls.random_data_0 = random_gen(100) + cls._cleanup = [ + cls.service_offering, + cls.account, + ] + return + + @classmethod + def tearDownClass(cls): + try: + # Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + return + + def tearDown(self): + try: + # Clean up, terminate the created instance, volumes and snapshots + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr(tags=["advanced", "advancedns", "smoke"]) + def test_01_create_vm_snapshots(self): + + try: + # Login to VM and write data to file system + ssh_client = self.virtual_machine.get_ssh_client() + + cmds = [ + "echo %s > %s/%s" % (self.random_data_0, self.services["test_dir"], self.services["random_data"]), + "cat %s/%s" % (self.services["test_dir"], self.services["random_data"]) + ] + + for c in cmds: + self.debug(c) + result = ssh_client.execute(c) + self.debug(result) + + except Exception: + self.fail("SSH failed for Virtual machine: %s" % + self.virtual_machine.ipaddress) + self.assertEqual( + self.random_data_0, + result[0], + "Check the random data has be write into temp file!" + ) + + time.sleep(self.services["sleep"]) + + vm_snapshot = VmSnapshot.create( + self.apiclient, + self.virtual_machine.id, + "false", + self.services["snapshot_name"], + self.services["snapshot_displaytext"] + ) + self.assertEqual( + vm_snapshot.state, + "Ready", + "Check the snapshot of vm is ready!" + ) + return + + @attr(tags=["advanced", "advancedns", "smoke"]) + def test_02_revert_vm_snapshots(self): + try: + ssh_client = self.virtual_machine.get_ssh_client() + + cmds = [ + "rm -rf %s/%s" % (self.services["test_dir"], self.services["random_data"]), + "ls %s/%s" % (self.services["test_dir"], self.services["random_data"]) + ] + + for c in cmds: + self.debug(c) + result = ssh_client.execute(c) + self.debug(result) + + except Exception: + self.fail("SSH failed for Virtual machine: %s" % + self.virtual_machine.ipaddress) + + if str(result[0]).index("No such file or directory") == -1: + self.fail("Check the random data has be delete from temp file!") + + time.sleep(self.services["sleep"]) + + list_snapshot_response = VmSnapshot.list(self.apiclient,vmid=self.virtual_machine.id,listall=True) + + self.assertEqual( + isinstance(list_snapshot_response, list), + True, + "Check list response returns a valid list" + ) + self.assertNotEqual( + list_snapshot_response, + None, + "Check if snapshot exists in ListSnapshot" + ) + + self.assertEqual( + list_snapshot_response[0].state, + "Ready", + "Check the snapshot of vm is ready!" + ) + + VmSnapshot.revertToSnapshot(self.apiclient,list_snapshot_response[0].id) + + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.virtual_machine.id + ) + + self.assertEqual( + list_vm_response[0].state, + "Stopped", + "Check the state of vm is Stopped!" + ) + + cmd = startVirtualMachine.startVirtualMachineCmd() + cmd.id = list_vm_response[0].id + self.apiclient.startVirtualMachine(cmd) + + time.sleep(self.services["sleep"]) + + try: + ssh_client = self.virtual_machine.get_ssh_client(reconnect=True) + + cmds = [ + "cat %s/%s" % (self.services["test_dir"], self.services["random_data"]) + ] + + for c in cmds: + self.debug(c) + result = ssh_client.execute(c) + self.debug(result) + + except Exception: + self.fail("SSH failed for Virtual machine: %s" % + self.virtual_machine.ipaddress) + + self.assertEqual( + self.random_data_0, + result[0], + "Check the random data is equal with the ramdom file!" + ) + @attr(tags=["advanced", "advancedns", "smoke"]) + def test_03_delete_vm_snapshots(self): + + list_snapshot_response = VmSnapshot.list(self.apiclient,vmid=self.virtual_machine.id,listall=True) + + self.assertEqual( + isinstance(list_snapshot_response, list), + True, + "Check list response returns a valid list" + ) + self.assertNotEqual( + list_snapshot_response, + None, + "Check if snapshot exists in ListSnapshot" + ) + """ + cmd = deleteVMSnapshot.deleteVMSnapshotCmd() + cmd.vmsnapshotid = list_snapshot_response[0].id + self.apiclient.deleteVMSnapshot(cmd) + """ + VmSnapshot.deleteVMSnapshot(self.apiclient,list_snapshot_response[0].id) + + time.sleep(self.services["sleep"]*3) + + list_snapshot_response = VmSnapshot.list(self.apiclient,vmid=self.virtual_machine.id,listall=True) + + self.assertEqual( + list_snapshot_response, + None, + "Check list vm snapshot has be deleted" + ) diff --git a/test/integration/smoke/test_volumes.py b/test/integration/smoke/test_volumes.py index 750f9856b22..4bf8203e74c 100644 --- a/test/integration/smoke/test_volumes.py +++ b/test/integration/smoke/test_volumes.py @@ -126,7 +126,7 @@ class TestCreateVolume(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, cls.services["service_offering"] @@ -134,8 +134,8 @@ class TestCreateVolume(cloudstackTestCase): cls.virtual_machine = VirtualMachine.create( cls.api_client, cls.services, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, mode=cls.services["mode"] ) @@ -167,8 +167,8 @@ class TestCreateVolume(cloudstackTestCase): self.apiClient, v, zoneid=self.zone.id, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, diskofferingid=self.disk_offering.id ) self.debug("Created a volume with ID: %s" % volume.id) @@ -177,8 +177,8 @@ class TestCreateVolume(cloudstackTestCase): volume = Volume.create_custom_disk( self.apiClient, self.services, - account=self.account.account.name, - domainid=self.account.account.domainid, + account=self.account.name, + domainid=self.account.domainid, ) self.debug("Created a volume with custom offering: %s" % volume.id) self.volumes.append(volume) @@ -287,6 +287,7 @@ class TestVolumes(cloudstackTestCase): # Get Zone, Domain and templates cls.domain = get_domain(cls.api_client, cls.services) cls.zone = get_zone(cls.api_client, cls.services) + cls.services['mode'] = cls.zone.networktype cls.disk_offering = DiskOffering.create( cls.api_client, cls.services["disk_offering"] @@ -320,7 +321,7 @@ class TestVolumes(cloudstackTestCase): domainid=cls.domain.id ) - cls.services["account"] = cls.account.account.name + cls.services["account"] = cls.account.name cls.service_offering = ServiceOffering.create( cls.api_client, cls.services["service_offering"] @@ -328,8 +329,8 @@ class TestVolumes(cloudstackTestCase): cls.virtual_machine = VirtualMachine.create( cls.api_client, cls.services, - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, + accountid=cls.account.name, + domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, mode=cls.services["mode"] ) @@ -337,8 +338,8 @@ class TestVolumes(cloudstackTestCase): cls.volume = Volume.create( cls.api_client, cls.services, - account=cls.account.account.name, - domainid=cls.account.account.domainid + account=cls.account.name, + domainid=cls.account.domainid ) cls._cleanup = [ cls.resized_disk_offering, diff --git a/test/selenium/ReadMe.txt b/test/selenium/ReadMe.txt index 30b0e0df7a0..bc968f1dc93 100644 --- a/test/selenium/ReadMe.txt +++ b/test/selenium/ReadMe.txt @@ -1,31 +1,41 @@ ############################################## + +Questions? Post'em @ dev@cloudstack.apache.org + +############################################## + This files contains following: 1) Installation requirements -2) Test Pre requisites -3) Running the Test and Generating the report +2) Testing pre-requisites +3) Running the Tests and Generating the report ############################################## ########################################################################################################################################## -1) Installtion Requirements +1) Installation Requirements +--------------------------- -1)Firefox depending on your OS (Good to have Firebug and Selenium IDE for troubleshooting and dev work) +1) Firefox depending on your OS (Good to have Firebug and Selenium IDE for troubleshooting and dev work) -2)Install Python 2.7. Recommend to use Active State Python +2) Install Python 2.7. 3) Now Open CMD/Terminal and type all of following -- pypm install pycrypto (Installs Pycrypto) -- pypm install paramiko (Install paramiko) +- pip install pycrypto (Installs Pycrypto) +- pip install paramiko (Install paramiko) - pip install unittest-xml-reporting (Install XML Test Runner) - pip install -U selenium (Installs Selenium) +4) Get PhoantomJS for your OS from http://phantomjs.org/ + +- PhantomJS will run selenium test in headless mode. Follow the instruction on PhantomJS.org. +- Make sure the executable is in PATH. (TIP: Drop it in Python27 folder :-)) 5) Now get the HTMLTestRunner for nice looking report generation. - http://tungwaiyip.info/software/HTMLTestRunner.html @@ -35,18 +45,22 @@ This files contains following: ########################################################################################################################################## 2) Test Prerequisites +--------------------- + +- Download and install CS. /cwiki.apache.org has links to Installation Guide and API reference. +- Log into the management server and Add a Zone. (Must be Advance Zone and Hypervisor type must be Xen) -- Download and install CS -- Log into the management server nad Add a Zone. (Must be Advance Zone and Hypervisor type must be Xen) ########################################################################################################################################## 3) Running the Test and Generating the report +--------------------------------------------- - Folder smoke contains main.py - main.py is the file where all the tests are serialized. - main.py supports HTML and XML reporting. Please refer to end of file to choose either. -- Typical usage is: python main.py for XML Reporting -- And python main.py >> results.html for HTML Reporting. +- Typical usage is: python main.py 10.1.1.10 >> result.xml for XML Reporting +- And python main.py 10.1.1.10 >> result.html for HTML Reporting. +- 10.1.1.10 (your management server IP) is an argument required for main. ########################################################################################################################################## diff --git a/test/selenium/lib/initialize.py b/test/selenium/lib/initialize.py index e8cc49adff4..55e5d9aa3b1 100644 --- a/test/selenium/lib/initialize.py +++ b/test/selenium/lib/initialize.py @@ -21,11 +21,26 @@ This will help pass webdriver (Browser instance) across our test cases. from selenium import webdriver +import sys DRIVER = None +MS_ip = None + def getOrCreateWebdriver(): global DRIVER - DRIVER = DRIVER or webdriver.Firefox() + DRIVER = DRIVER or webdriver.PhantomJS('phantomjs') # phantomjs executable must be in PATH. return DRIVER + +def getMSip(): + global MS_ip + if len(sys.argv) >= 3: + sys.exit("Only One argument is required .. Enter your Management Server IP") + + if len(sys.argv) == 1: + sys.exit("Atleast One argument is required .. Enter your Management Server IP") + + for arg in sys.argv[1:]: + MS_ip = arg + return MS_ip \ No newline at end of file diff --git a/test/selenium/smoke/Login_and_Accounts.py b/test/selenium/smoke/Login_and_Accounts.py index c5132d9754c..44b1e836b4c 100644 --- a/test/selenium/smoke/Login_and_Accounts.py +++ b/test/selenium/smoke/Login_and_Accounts.py @@ -34,11 +34,12 @@ class login(unittest.TestCase): def setUp(self): + MS_URL = initialize.getMSip() self.driver = initialize.getOrCreateWebdriver() - self.base_url = "http://10.223.49.206:8080/" # Your management Server IP goes here + self.base_url = "http://"+ MS_URL +":8080/" # Your management Server IP goes here self.verificationErrors = [] - + def test_login(self): # Here we will clear the test box for Username and Password and fill them with actual login data. diff --git a/test/selenium/smoke/main.py b/test/selenium/smoke/main.py index 86bb9308c2f..921192dc847 100644 --- a/test/selenium/smoke/main.py +++ b/test/selenium/smoke/main.py @@ -21,7 +21,7 @@ import xmlrunner global DRIVER - +global MS_ip # Import test cases diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index f8bdae281b2..bd8c0f1668f 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -140,6 +140,7 @@ known_categories = { 'removeIpFromNic': 'Nic', 'listNics':'Nic', 'AffinityGroup': 'Affinity Group', + 'InternalLoadBalancer': 'Internal LB', } diff --git a/tools/appliance/definitions/systemvmtemplate/definition.rb b/tools/appliance/definitions/systemvmtemplate/definition.rb index 27336f17f8b..87dbfad09ad 100644 --- a/tools/appliance/definitions/systemvmtemplate/definition.rb +++ b/tools/appliance/definitions/systemvmtemplate/definition.rb @@ -3,9 +3,9 @@ Veewee::Definition.declare({ :memory_size=> '256', :disk_size => '2000', :disk_format => 'VDI', :hostiocache => 'off', :os_type_id => 'Debian', - :iso_file => "debian-wheezy-DI-rc1-i386-netinst.iso", - :iso_src => "http://cdimage.debian.org/cdimage/wheezy_di_rc1/i386/iso-cd/debian-wheezy-DI-rc1-i386-netinst.iso", - :iso_md5 => "db12ca9554bb8f121c98e268682a55d0", + :iso_file => "debian-7.0.0-i386-netinst.iso", + :iso_src => "http://cdimage.debian.org/debian-cd/7.0.0/i386/iso-cd/debian-7.0.0-i386-netinst.iso", + :iso_md5 => "a6b93666a5393334accb7ac4ee28d949", :iso_download_timeout => "1000", :boot_wait => "10", :boot_cmd_sequence => [ '', diff --git a/tools/appliance/definitions/systemvmtemplate/postinstall.sh b/tools/appliance/definitions/systemvmtemplate/postinstall.sh index ae8f1adfb9c..f532f88537c 100644 --- a/tools/appliance/definitions/systemvmtemplate/postinstall.sh +++ b/tools/appliance/definitions/systemvmtemplate/postinstall.sh @@ -37,10 +37,9 @@ install_packages() { apt-get --no-install-recommends -q -y --force-yes install sysstat # apache apt-get --no-install-recommends -q -y --force-yes install apache2 ssl-cert - # haproxy - apt-get --no-install-recommends -q -y --force-yes install haproxy + # dnsmasq - apt-get --no-install-recommends -q -y --force-yes install dnsmasq + apt-get --no-install-recommends -q -y --force-yes install dnsmasq dnsmasq-utils # nfs client apt-get --no-install-recommends -q -y --force-yes install nfs-common @@ -78,6 +77,11 @@ install_packages() { # cd $PREV # rm -fr /opt/vmware-tools-distrib # apt-get -q -y --force-yes purge build-essential + + # haproxy. Wheezy doesn't have haproxy, install from backports + #apt-get --no-install-recommends -q -y --force-yes install haproxy + wget http://ftp.us.debian.org/debian/pool/main/h/haproxy/haproxy_1.4.8-1_i386.deb + dpkg -i haproxy_1.4.8-1_i386.deb } setup_accounts() { diff --git a/tools/appliance/definitions/systemvmtemplate64/definition.rb b/tools/appliance/definitions/systemvmtemplate64/definition.rb index 35ef878d35a..38828da70de 100644 --- a/tools/appliance/definitions/systemvmtemplate64/definition.rb +++ b/tools/appliance/definitions/systemvmtemplate64/definition.rb @@ -3,9 +3,9 @@ Veewee::Definition.declare({ :memory_size=> '256', :disk_size => '2000', :disk_format => 'VDI', :hostiocache => 'off', :os_type_id => 'Debian_64', - :iso_file => "debian-wheezy-DI-rc1-amd64-netinst.iso", - :iso_src => "http://cdimage.debian.org/cdimage/wheezy_di_rc1/amd64/iso-cd/debian-wheezy-DI-rc1-amd64-netinst.iso", - :iso_md5 => "412f77d4b98adf2a7d575745fd282d78", + :iso_file => "debian-7.0.0-amd64-netinst.iso", + :iso_src => "http://cdimage.debian.org/debian-cd/7.0.0/amd64/iso-cd/debian-7.0.0-amd64-netinst.iso", + :iso_md5 => "6a55096340b5b1b7d335d5b559e13ea0", :iso_download_timeout => "1000", :boot_wait => "10", :boot_cmd_sequence => [ '', diff --git a/tools/appliance/definitions/systemvmtemplate64/postinstall.sh b/tools/appliance/definitions/systemvmtemplate64/postinstall.sh index ae8f1adfb9c..3ccf3cefdef 100644 --- a/tools/appliance/definitions/systemvmtemplate64/postinstall.sh +++ b/tools/appliance/definitions/systemvmtemplate64/postinstall.sh @@ -37,10 +37,9 @@ install_packages() { apt-get --no-install-recommends -q -y --force-yes install sysstat # apache apt-get --no-install-recommends -q -y --force-yes install apache2 ssl-cert - # haproxy - apt-get --no-install-recommends -q -y --force-yes install haproxy + # dnsmasq - apt-get --no-install-recommends -q -y --force-yes install dnsmasq + apt-get --no-install-recommends -q -y --force-yes install dnsmasq dnsmasq-utils # nfs client apt-get --no-install-recommends -q -y --force-yes install nfs-common @@ -78,6 +77,11 @@ install_packages() { # cd $PREV # rm -fr /opt/vmware-tools-distrib # apt-get -q -y --force-yes purge build-essential + + # haproxy. Wheezy doesn't have haproxy temporarily, install from backports + #apt-get --no-install-recommends -q -y --force-yes install haproxy + wget http://ftp.us.debian.org/debian/pool/main/h/haproxy/haproxy_1.4.8-1_amd64.deb + dpkg -i haproxy_1.4.8-1_amd64.deb } setup_accounts() { diff --git a/tools/marvin/marvin/asyncJobMgr.py b/tools/marvin/marvin/asyncJobMgr.py index 40304fa4141..698462783bd 100644 --- a/tools/marvin/marvin/asyncJobMgr.py +++ b/tools/marvin/marvin/asyncJobMgr.py @@ -28,6 +28,8 @@ class job(object): def __init__(self): self.id = None self.cmd = None + + class jobStatus(object): def __init__(self): self.result = None @@ -37,8 +39,11 @@ class jobStatus(object): self.duration = None self.jobId = None self.responsecls = None + def __str__(self): return '{%s}' % str(', '.join('%s : %s' % (k, repr(v)) for (k, v) in self.__dict__.iteritems())) + + class workThread(threading.Thread): def __init__(self, in_queue, outqueue, apiClient, db=None, lock=None): threading.Thread.__init__(self) @@ -47,11 +52,11 @@ class workThread(threading.Thread): self.connection = apiClient.connection.__copy__() self.db = None self.lock = lock - + def queryAsynJob(self, job): if job.jobId is None: return job - + try: self.lock.acquire() result = self.connection.poll(job.jobId, job.responsecls).jobresult @@ -59,10 +64,10 @@ class workThread(threading.Thread): result = str(e) finally: self.lock.release() - + job.result = result return job - + def executeCmd(self, job): cmd = job.cmd @@ -70,14 +75,15 @@ class workThread(threading.Thread): jobId = None try: self.lock.acquire() - + if cmd.isAsync == "false": jobstatus.startTime = datetime.datetime.now() - + result = self.connection.make_request(cmd) jobstatus.result = result jobstatus.endTime = datetime.datetime.now() - jobstatus.duration = time.mktime(jobstatus.endTime.timetuple()) - time.mktime(jobstatus.startTime.timetuple()) + jobstatus.duration = time.mktime(jobstatus.endTime.timetuple()) - time.mktime( + jobstatus.startTime.timetuple()) else: result = self.connection.make_request(cmd, None, True) if result is None: @@ -99,9 +105,9 @@ class workThread(threading.Thread): jobstatus.result = sys.exc_info() finally: self.lock.release() - + return jobstatus - + def run(self): while self.inqueue.qsize() > 0: job = self.inqueue.get() @@ -109,18 +115,20 @@ class workThread(threading.Thread): jobstatus = self.queryAsynJob(job) else: jobstatus = self.executeCmd(job) - + self.output.put(jobstatus) self.inqueue.task_done() - + '''release the resource''' self.connection.close() + class jobThread(threading.Thread): def __init__(self, inqueue, interval): threading.Thread.__init__(self) self.inqueue = inqueue self.interval = interval + def run(self): while self.inqueue.qsize() > 0: job = self.inqueue.get() @@ -130,23 +138,25 @@ class jobThread(threading.Thread): job.apiClient.connection.close() except: pass - + self.inqueue.task_done() time.sleep(self.interval) - + + class outputDict(object): def __init__(self): self.lock = threading.Condition() - self.dict = {} + self.dict = {} + class asyncJobMgr(object): def __init__(self, apiClient, db): self.inqueue = Queue.Queue() - self.output = outputDict() + self.output = outputDict() self.outqueue = Queue.Queue() self.apiClient = apiClient self.db = db - + def submitCmds(self, cmds): if not self.inqueue.empty(): return False @@ -160,11 +170,12 @@ class asyncJobMgr(object): id += 1 ids.append(id) return ids - + def updateTimeStamp(self, jobstatus): jobId = jobstatus.jobId if jobId is not None and self.db is not None: - result = self.db.execute("select job_status, created, last_updated from async_job where id=%s"%jobId) + result = self.db.execute( + "select job_status, created, last_updated from async_job where id='%s'" % str(jobId)) if result is not None and len(result) > 0: if result[0][0] == 1: jobstatus.status = True @@ -174,7 +185,7 @@ class asyncJobMgr(object): jobstatus.endTime = result[0][2] delta = jobstatus.endTime - jobstatus.startTime jobstatus.duration = delta.total_seconds() - + def waitForComplete(self, workers=10): self.inqueue.join() lock = threading.Lock() @@ -183,28 +194,30 @@ class asyncJobMgr(object): for i in range(workers): worker = workThread(self.outqueue, resultQueue, self.apiClient, self.db, lock) worker.start() - + self.outqueue.join() - + asyncJobResult = [] while resultQueue.qsize() > 0: jobstatus = resultQueue.get() self.updateTimeStamp(jobstatus) asyncJobResult.append(jobstatus) - + return asyncJobResult - + '''put commands into a queue at first, then start workers numbers threads to execute this commands''' + def submitCmdsAndWait(self, cmds, workers=10): self.submitCmds(cmds) lock = threading.Lock() for i in range(workers): worker = workThread(self.inqueue, self.outqueue, self.apiClient, self.db, lock) worker.start() - + return self.waitForComplete(workers) '''submit one job and execute the same job ntimes, with nums_threads of threads''' + def submitJobExecuteNtimes(self, job, ntimes=1, nums_threads=1, interval=1): inqueue1 = Queue.Queue() lock = threading.Condition() @@ -213,22 +226,23 @@ class asyncJobMgr(object): setattr(newjob, "apiClient", copy.copy(self.apiClient)) setattr(newjob, "lock", lock) inqueue1.put(newjob) - + for i in range(nums_threads): work = jobThread(inqueue1, interval) work.start() inqueue1.join() - + '''submit n jobs, execute them with nums_threads of threads''' + def submitJobs(self, jobs, nums_threads=1, interval=1): inqueue1 = Queue.Queue() lock = threading.Condition() - + for job in jobs: setattr(job, "apiClient", copy.copy(self.apiClient)) setattr(job, "lock", lock) inqueue1.put(job) - + for i in range(nums_threads): work = jobThread(inqueue1, interval) work.start() diff --git a/tools/marvin/marvin/cloudstackConnection.py b/tools/marvin/marvin/cloudstackConnection.py index 5d30803d930..803911721e9 100644 --- a/tools/marvin/marvin/cloudstackConnection.py +++ b/tools/marvin/marvin/cloudstackConnection.py @@ -33,13 +33,18 @@ from requests import RequestException class cloudConnection(object): """ Connections to make API calls to the cloudstack management server """ - def __init__(self, mgtSvr, port=8096, apiKey=None, securityKey=None, + def __init__(self, mgtSvr, port=8096, user=None, passwd=None, + apiKey=None, securityKey=None, asyncTimeout=3600, logging=None, scheme='http', path='client/api'): self.apiKey = apiKey self.securityKey = securityKey self.mgtSvr = mgtSvr self.port = port + if user: + self.user = user + if passwd: + self.passwd = passwd self.logging = logging self.path = path self.retries = 5 @@ -55,9 +60,10 @@ class cloudConnection(object): % (self.protocol, self.mgtSvr, self.port, self.path) def __copy__(self): - return cloudConnection(self.mgtSvr, self.port, self.apiKey, - self.securityKey, self.asyncTimeout, - self.logging, self.protocol, self.path) + return cloudConnection(self.mgtSvr, self.port, self.user, self.passwd, + self.apiKey, self.securityKey, + self.asyncTimeout, self.logging, self.protocol, + self.path) def poll(self, jobid, response): """ @@ -107,7 +113,7 @@ class cloudConnection(object): ) signature = base64.encodestring(hmac.new( self.securityKey, hashStr, hashlib.sha1).digest()).strip() - self.logging.info("Computed Signature by Marvin: %s" % signature) + self.logging.debug("Computed Signature by Marvin: %s" % signature) return signature def request(self, command, auth=True, payload={}, method='GET'): @@ -200,7 +206,8 @@ class cloudConnection(object): @return: """ cmdname, isAsync, payload = self.sanitize_command(cmd) - self.logging.debug("sending %s request: %s %s" % (method, cmdname, str(payload))) + self.logging.debug("sending %s request: %s %s" % (method, cmdname, + str(payload))) response = self.request( cmdname, self.auth, payload=payload, method=method) self.logging.debug("Request: %s Response: %s" % diff --git a/tools/marvin/marvin/cloudstackTestClient.py b/tools/marvin/marvin/cloudstackTestClient.py index 85552ed5523..d85a61c4872 100644 --- a/tools/marvin/marvin/cloudstackTestClient.py +++ b/tools/marvin/marvin/cloudstackTestClient.py @@ -18,24 +18,29 @@ import cloudstackConnection import asyncJobMgr import dbConnection -from cloudstackAPI import * +from cloudstackAPI import * import random import string import hashlib class cloudstackTestClient(object): - def __init__(self, mgtSvr=None, port=8096, apiKey = None, securityKey = None, asyncTimeout=3600, + def __init__(self, mgtSvr=None, port=8096, user=None, passwd=None, + apiKey=None, securityKey=None, asyncTimeout=3600, defaultWorkerThreads=10, logging=None): - self.connection = cloudstackConnection.cloudConnection(mgtSvr, port, apiKey, securityKey, asyncTimeout, logging) + self.connection = \ + cloudstackConnection.cloudConnection( + mgtSvr, port, user, + passwd, apiKey, securityKey, + asyncTimeout, logging) self.apiClient = cloudstackAPIClient.CloudStackAPIClient(self.connection) self.dbConnection = None self.asyncJobMgr = None self.ssh = None self.defaultWorkerThreads = defaultWorkerThreads - + def dbConfigure(self, host="localhost", port=3306, user='cloud', passwd='cloud', db='cloud'): self.dbConnection = dbConnection.dbConnection(host, port, user, passwd, db) - + def isAdminContext(self): """ A user is a regular user if he fails to listDomains; @@ -53,7 +58,7 @@ class cloudstackTestClient(object): return 2 #domain-admin except: return 0 #user - + def random_gen(self, size=6, chars=string.ascii_uppercase + string.digits): """Generate Random Strings of variable length""" return ''.join(random.choice(chars) for x in range(size)) @@ -61,7 +66,7 @@ class cloudstackTestClient(object): def createUserApiClient(self, UserName, DomainName, acctType=0): if not self.isAdminContext(): return self.apiClient - + listDomain = listDomains.listDomainsCmd() listDomain.listall = True listDomain.name = DomainName @@ -73,11 +78,11 @@ class cloudstackTestClient(object): cdomain.name = DomainName domain = self.apiClient.createDomain(cdomain) domId = domain.id - + mdf = hashlib.md5() mdf.update("password") mdf_pass = mdf.hexdigest() - + cmd = listAccounts.listAccountsCmd() cmd.name = UserName cmd.domainid = domId @@ -95,46 +100,47 @@ class cloudstackTestClient(object): createAcctCmd.username = UserName acct = self.apiClient.createAccount(createAcctCmd) acctId = acct.id - - listuser = listUsers.listUsersCmd() + + listuser = listUsers.listUsersCmd() listuser.username = UserName - + listuserRes = self.apiClient.listUsers(listuser) userId = listuserRes[0].id apiKey = listuserRes[0].apikey securityKey = listuserRes[0].secretkey - + if apiKey is None: registerUser = registerUserKeys.registerUserKeysCmd() registerUser.id = userId registerUserRes = self.apiClient.registerUserKeys(registerUser) apiKey = registerUserRes.apikey securityKey = registerUserRes.secretkey - + newUserConnection = cloudstackConnection.cloudConnection(self.connection.mgtSvr, self.connection.port, + self.connection.user, self.connection.passwd, apiKey, securityKey, self.connection.asyncTimeout, self.connection.logging) self.userApiClient = cloudstackAPIClient.CloudStackAPIClient(newUserConnection) self.userApiClient.connection = newUserConnection return self.userApiClient - + def close(self): if self.connection is not None: self.connection.close() - + def getDbConnection(self): return self.dbConnection def executeSql(self, sql=None): if sql is None or self.dbConnection is None: return None - + return self.dbConnection.execute() - + def executeSqlFromFile(self, sqlFile=None): if sqlFile is None or self.dbConnection is None: return None return self.dbConnection.executeSqlFromFile(sqlFile) - + def getApiClient(self): return self.apiClient @@ -151,18 +157,21 @@ class cloudstackTestClient(object): '''FixME, httplib has issue if more than one thread submitted''' + def submitCmdsAndWait(self, cmds, workers=1): if self.asyncJobMgr is None: self.asyncJobMgr = asyncJobMgr.asyncJobMgr(self.apiClient, self.dbConnection) return self.asyncJobMgr.submitCmdsAndWait(cmds, workers) - + '''submit one job and execute the same job ntimes, with nums_threads of threads''' + def submitJob(self, job, ntimes=1, nums_threads=10, interval=1): if self.asyncJobMgr is None: self.asyncJobMgr = asyncJobMgr.asyncJobMgr(self.apiClient, self.dbConnection) self.asyncJobMgr.submitJobExecuteNtimes(job, ntimes, nums_threads, interval) - - '''submit n jobs, execute them with nums_threads of threads''' + + '''submit n jobs, execute them with nums_threads of threads''' + def submitJobs(self, jobs, nums_threads=10, interval=1): if self.asyncJobMgr is None: self.asyncJobMgr = asyncJobMgr.asyncJobMgr(self.apiClient, self.dbConnection) diff --git a/tools/marvin/marvin/configGenerator.py b/tools/marvin/marvin/configGenerator.py index e2a6a24d69f..4e82bbe387d 100644 --- a/tools/marvin/marvin/configGenerator.py +++ b/tools/marvin/marvin/configGenerator.py @@ -133,6 +133,7 @@ class physical_network(): self.traffictypes = [] self.broadcastdomainrange = 'Zone' self.vlan = None + self.isolationmethods = [] '''enable default virtual router provider''' vrouter = provider() vrouter.name = 'VirtualRouter' diff --git a/tools/marvin/marvin/dbConnection.py b/tools/marvin/marvin/dbConnection.py index 8fa86438ab0..958299aff2a 100644 --- a/tools/marvin/marvin/dbConnection.py +++ b/tools/marvin/marvin/dbConnection.py @@ -37,7 +37,11 @@ class dbConnection(object): return None resultRow = [] - with contextlib.closing(mysql.connector.connect(host=self.host, port=self.port, user=self.user, password=self.passwd, db=self.database)) as conn: + with contextlib.closing(mysql.connector.connect(host=str(self.host), + port=int(self.port), + user=str(self.user), + password=str(self.passwd), + db=str(self.database))) as conn: conn.autocommit = True with contextlib.closing(conn.cursor(buffered=True)) as cursor: cursor.execute(sql, params) diff --git a/tools/marvin/marvin/deployDataCenter.py b/tools/marvin/marvin/deployDataCenter.py index d358789d8da..7059059beb1 100644 --- a/tools/marvin/marvin/deployDataCenter.py +++ b/tools/marvin/marvin/deployDataCenter.py @@ -169,6 +169,7 @@ class deployDataCenters(): phynet = createPhysicalNetwork.createPhysicalNetworkCmd() phynet.zoneid = zoneid phynet.name = net.name + phynet.isolationmethods = net.isolationmethods phynetwrk = self.apiClient.createPhysicalNetwork(phynet) self.addTrafficTypes(phynetwrk.id, net.traffictypes) return phynetwrk @@ -215,6 +216,18 @@ class deployDataCenters(): vrconfig.id = vrprovid self.apiClient.configureVirtualRouterElement(vrconfig) self.enableProvider(pnetprovres[0].id) + elif provider.name == 'InternalLbVm': + internallbprov = listInternalLoadBalancerElements.listInternalLoadBalancerElementsCmd() + internallbprov.nspid = pnetprovres[0].id + internallbresponse = self.apiClient.listInternalLoadBalancerElements(internallbprov) + internallbid = internallbresponse[0].id + + internallbconfig = \ + configureInternalLoadBalancerElement.configureInternalLoadBalancerElementCmd() + internallbconfig.enabled = "true" + internallbconfig.id = internallbid + self.apiClient.configureInternalLoadBalancerElement(internallbconfig) + self.enableProvider(pnetprovres[0].id) elif provider.name == 'SecurityGroupProvider': self.enableProvider(pnetprovres[0].id) elif provider.name in ['Netscaler', 'JuniperSRX', 'F5BigIp']: @@ -402,6 +415,7 @@ class deployDataCenters(): self.testClient = \ cloudstackTestClient.cloudstackTestClient(mgt.mgtSvrIp, mgt.port, \ + mgt.user, mgt.passwd, \ mgt.apiKey, \ mgt.securityKey, \ logging=self.testClientLogger) @@ -409,6 +423,7 @@ class deployDataCenters(): apiKey, securityKey = self.registerApiKey() self.testClient = \ cloudstackTestClient.cloudstackTestClient(mgt.mgtSvrIp, 8080, \ + mgt.user, mgt.passwd, \ apiKey, securityKey, \ logging=self.testClientLogger) @@ -419,6 +434,11 @@ class deployDataCenters(): dbSvr.passwd, dbSvr.db) self.apiClient = self.testClient.getApiClient() + """set hypervisor""" + if mgt.hypervisor: + self.apiClient.hypervisor = mgt.hypervisor + else: + self.apiClient.hypervisor = "XenServer" #Defaults to Xenserver def updateConfiguration(self, globalCfg): if globalCfg is None: diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py index 6c285233a82..ecdc8412fdb 100755 --- a/tools/marvin/marvin/integration/lib/base.py +++ b/tools/marvin/marvin/integration/lib/base.py @@ -5,9 +5,9 @@ # 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 @@ -22,7 +22,7 @@ import marvin from utils import is_server_ssh_ready, random_gen from marvin.cloudstackAPI import * -#Import System modules +# Import System modules import time import hashlib import base64 @@ -40,6 +40,9 @@ class Domain: cmd = createDomain.createDomainCmd() + if "domainUUID" in services: + cmd.domainid = "-".join([services["domainUUID"], random_gen()]) + if name: cmd.name = "-".join([name, random_gen()]) elif "name" in services: @@ -54,8 +57,12 @@ class Domain: cmd.parentdomainid = parentdomainid elif "parentdomainid" in services: cmd.parentdomainid = services["parentdomainid"] - - return Domain(apiclient.createDomain(cmd).__dict__) + try: + domain = apiclient.createDomain(cmd) + if domain is not None: + return Domain(domain.__dict__) + except Exception as e: + raise e def delete(self, apiclient, cleanup=None): """Delete an domain""" @@ -83,7 +90,7 @@ class Account: """Creates an account""" cmd = createAccount.createAccountCmd() - #0 - User, 1 - Root Admin, 2 - Domain Admin + # 0 - User, 1 - Root Admin, 2 - Domain Admin cmd.accounttype = 2 if (admin and domainid) else int(admin) cmd.email = services["email"] @@ -93,6 +100,13 @@ class Account: cmd.password = services["password"] cmd.username = "-".join([services["username"], random_gen()]) + if "accountUUID" in services: + cmd.accountid = "-".join([services["accountUUID"],random_gen()]) + + if "userUUID" in services: + cmd.userid = "-".join([services["userUUID"],random_gen()]) + + if domainid: cmd.domainid = domainid account = apiclient.createAccount(cmd) @@ -131,6 +145,9 @@ class User: cmd.firstname = services["firstname"] cmd.lastname = services["lastname"] + if "userUUID" in services: + cmd.userid = "-".join([services["userUUID"],random_gen()]) + # Password Encoding mdf = hashlib.md5() mdf.update(services["password"]) @@ -213,14 +230,15 @@ class VirtualMachine: else: self.ssh_port = 22 self.ssh_client = None - #extract out the ipaddress + # extract out the ipaddress self.ipaddress = self.nic[0].ipaddress @classmethod def create(cls, apiclient, services, templateid=None, accountid=None, domainid=None, zoneid=None, networkids=None, serviceofferingid=None, securitygroupids=None, projectid=None, startvm=None, - diskofferingid=None, affinitygroupnames=None, hostid=None, mode='basic', method='GET'): + diskofferingid=None, affinitygroupnames=None, group=None, + hostid=None, keypair=None, mode='basic', method='GET'): """Create the instance""" cmd = deployVirtualMachine.deployVirtualMachineCmd() @@ -234,7 +252,13 @@ class VirtualMachine: cmd.zoneid = zoneid elif "zoneid" in services: cmd.zoneid = services["zoneid"] - cmd.hypervisor = services["hypervisor"] + cmd.hypervisor = apiclient.hypervisor + + if "displayname" in services: + cmd.displayname = services["displayname"] + + if "name" in services: + cmd.name = services["name"] if accountid: cmd.account = accountid @@ -256,9 +280,16 @@ class VirtualMachine: elif "template" in services: cmd.templateid = services["template"] - if "diskoffering" in services: + if diskofferingid: + cmd.diskofferingid = diskofferingid + elif "diskoffering" in services: cmd.diskofferingid = services["diskoffering"] + if keypair: + cmd.keypair = keypair + elif "keypair" in services: + cmd.keypair = services["keypair"] + if securitygroupids: cmd.securitygroupids = [str(sg_id) for sg_id in securitygroupids] @@ -280,8 +311,16 @@ class VirtualMachine: if "userdata" in services: cmd.userdata = base64.b64encode(services["userdata"]) + if group: + cmd.group = group + virtual_machine = apiclient.deployVirtualMachine(cmd, method=method) + if startvm == False: + virtual_machine.ssh_ip = virtual_machine.nic[0].ipaddress + virtual_machine.public_ip = virtual_machine.nic[0].ipaddress + return VirtualMachine(virtual_machine.__dict__, services) + # VM should be in Running state after deploy timeout = 10 while True: @@ -308,14 +347,14 @@ class VirtualMachine: virtual_machine.domainid, services ) - fw_rule = FireWallRule.create( + FireWallRule.create( apiclient, ipaddressid=public_ip.ipaddress.id, protocol='TCP', cidrlist=['0.0.0.0/0'], startport=22, endport=22 - ) + ) nat_rule = NATRule.create( apiclient, virtual_machine, @@ -348,7 +387,13 @@ class VirtualMachine: cmd.id = self.id apiclient.rebootVirtualMachine(cmd) - def get_ssh_client(self, ipaddress=None, reconnect=False, port=None): + def recover(self, apiclient): + """Recover the instance""" + cmd = recoverVirtualMachine.recoverVirtualMachineCmd() + cmd.id = self.id + apiclient.recoverVirtualMachine(cmd) + + def get_ssh_client(self, ipaddress=None, reconnect=False, port=None, keyPairFileLocation=None): """Get SSH object of VM""" # If NAT Rules are not created while VM deployment in Advanced mode @@ -358,27 +403,56 @@ class VirtualMachine: if port: self.ssh_port = port + if keyPairFileLocation is not None: + self.password = None + if reconnect: self.ssh_client = is_server_ssh_ready( self.ssh_ip, self.ssh_port, self.username, - self.password + self.password, + keyPairFileLocation=keyPairFileLocation ) self.ssh_client = self.ssh_client or is_server_ssh_ready( self.ssh_ip, self.ssh_port, self.username, - self.password + self.password, + keyPairFileLocation=keyPairFileLocation ) return self.ssh_client + def resetSshKey(self, apiclient, **kwargs): + """Resets SSH key""" + + cmd = resetSSHKeyForVirtualMachine.resetSSHKeyForVirtualMachineCmd() + cmd.id = self.id + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.resetSSHKeyForVirtualMachine(cmd)) + + def update(self, apiclient, **kwargs): + """Updates the VM data""" + + cmd = updateVirtualMachine.updateVirtualMachineCmd() + cmd.id = self.id + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.updateVirtualMachine(cmd)) + def delete(self, apiclient): """Destroy an Instance""" cmd = destroyVirtualMachine.destroyVirtualMachineCmd() cmd.id = self.id apiclient.destroyVirtualMachine(cmd) + def migrate(self, apiclient, hostid=None): + """migrate an Instance""" + cmd = migrateVirtualMachine.migrateVirtualMachineCmd() + cmd.virtualmachineid = self.id + if hostid: + cmd.hostid = hostid + apiclient.migrateVirtualMachine(cmd) + def attach_volume(self, apiclient, volume): """Attach volume to instance""" cmd = attachVolume.attachVolumeCmd() @@ -394,7 +468,7 @@ class VirtualMachine: def add_nic(self, apiclient, networkId): """Add a NIC to a VM""" - cmd = addNicToVirtualMachine.addNicToVirtualMachineCmd(); + cmd = addNicToVirtualMachine.addNicToVirtualMachineCmd() cmd.virtualmachineid = self.id cmd.networkid = networkId return apiclient.addNicToVirtualMachine(cmd) @@ -413,6 +487,26 @@ class VirtualMachine: cmd.virtualmachineid = self.id return apiclient.updateDefaultNicForVirtualMachine(cmd) + def attach_iso(self, apiclient, iso): + """Attach ISO to instance""" + cmd = attachIso.attachIsoCmd() + cmd.id = iso.id + cmd.virtualmachineid = self.id + return apiclient.attachIso(cmd) + + def detach_iso(self, apiclient): + """Detach ISO to instance""" + cmd = detachIso.detachIsoCmd() + cmd.id = self.id + return apiclient.detachIso(cmd) + + def change_service_offering(self, apiclient, serviceOfferingId): + """Change service offering of the instance""" + cmd = changeServiceForVirtualMachine.changeServiceForVirtualMachineCmd() + cmd.id = self.id + cmd.serviceofferingid = serviceOfferingId + return apiclient.changeServiceForVirtualMachine(cmd) + @classmethod def list(cls, apiclient, **kwargs): """List all VMs matching criteria""" @@ -428,16 +522,14 @@ class VirtualMachine: cmd.id = self.id try: response = apiclient.resetPasswordForVirtualMachine(cmd) - print response except Exception as e: raise Exception("Reset Password failed! - %s" % e) - print type(response) if isinstance(response, list): return response[0].password class Volume: - """Manage Volume Lifecycle + """Manage Volume Life cycle """ def __init__(self, items): self.__dict__.update(items) @@ -533,7 +625,7 @@ class Volume: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listVolumes(cmd)) - def resize(cls, apiclient, **kwargs): + def resize(self, apiclient, **kwargs): """Resize a volume""" cmd = resizeVolume.resizeVolumeCmd() cmd.id = self.id @@ -541,6 +633,58 @@ class Volume: return(apiclient.resizeVolume(cmd)) @classmethod + def upload(cls, apiclient, services, zoneid=None, account=None, domainid=None, url=None): + """Uploads the volume to specified account""" + + cmd = uploadVolume.uploadVolumeCmd() + if zoneid: + cmd.zoneid = zoneid + if account: + cmd.account = account + if domainid: + cmd.domainid = domainid + cmd.format = services["format"] + cmd.name = services["diskname"] + if url: + cmd.url = url + else: + cmd.url = services["url"] + return Volume(apiclient.uploadVolume(cmd).__dict__) + + def wait_for_upload(self, apiclient, timeout=5, interval=60): + """Wait for upload""" + # Sleep to ensure template is in proper state before download + time.sleep(interval) + + while True: + volume_response = Volume.list( + apiclient, + id=self.id, + zoneid=self.zoneid, + ) + if isinstance(volume_response, list): + + volume = volume_response[0] + # If volume is ready, + # volume.state = Allocated + if volume.state == 'Uploaded': + break + + elif 'Uploading' in volume.state: + time.sleep(interval) + + elif 'Installing' not in volume.state: + raise Exception( + "Error in uploading volume: status - %s" % + volume.state) + elif timeout == 0: + break + + else: + time.sleep(interval) + timeout = timeout - 1 + return + def migrate(cls, apiclient, **kwargs): """Migrate a volume""" cmd = migrateVolume.migrateVolumeCmd() @@ -592,7 +736,7 @@ class Template: def create(cls, apiclient, services, volumeid=None, account=None, domainid=None, projectid=None): """Create template from Volume""" - #Create template from Virtual machine and Volume ID + # Create template from Virtual machine and Volume ID cmd = createTemplate.createTemplateCmd() cmd.displaytext = services["displaytext"] cmd.name = "-".join([services["name"], random_gen()]) @@ -617,7 +761,6 @@ class Template: cmd.ispublic = services["ispublic"] if "ispublic" in services else False cmd.isextractable = services["isextractable"] if "isextractable" in services else False cmd.passwordenabled = services["passwordenabled"] if "passwordenabled" in services else False - cmd.passwordenabled = services["passwordenabled"] if "passwordenabled" in services else False if volumeid: cmd.volumeid = volumeid @@ -637,12 +780,12 @@ class Template: account=None, domainid=None): """Create template from URL""" - #Create template from Virtual machine and Volume ID + # Create template from Virtual machine and Volume ID cmd = registerTemplate.registerTemplateCmd() cmd.displaytext = services["displaytext"] cmd.name = "-".join([services["name"], random_gen()]) cmd.format = services["format"] - cmd.hypervisor = services["hypervisor"] + cmd.hypervisor = apiclient.hypervisor if "ostypeid" in services: cmd.ostypeid = services["ostypeid"] @@ -689,7 +832,7 @@ class Template: def create_from_snapshot(cls, apiclient, snapshot, services, random_name=True): """Create Template from snapshot""" - #Create template from Virtual machine and Snapshot ID + # Create template from Virtual machine and Snapshot ID cmd = createTemplate.createTemplateCmd() cmd.displaytext = services["displaytext"] cmd.name = "-".join([ @@ -726,7 +869,7 @@ class Template: def download(self, apiclient, timeout=5, interval=60): """Download Template""" - #Sleep to ensure template is in proper state before download + # Sleep to ensure template is in proper state before download time.sleep(interval) while True: @@ -789,7 +932,7 @@ class Iso: def create(cls, apiclient, services, account=None, domainid=None, projectid=None): """Create an ISO""" - #Create ISO from URL + # Create ISO from URL cmd = registerIso.registerIsoCmd() cmd.displaytext = services["displaytext"] cmd.name = services["name"] @@ -841,7 +984,7 @@ class Iso: def download(self, apiclient, timeout=5, interval=60): """Download an ISO""" - #Ensuring ISO is successfully downloaded + # Ensuring ISO is successfully downloaded while True: time.sleep(interval) @@ -853,7 +996,6 @@ class Iso: response = iso_response[0] # Again initialize timeout to avoid listISO failure timeout = 5 - print response.status # Check whether download is in progress(for Ex:10% Downloaded) # or ISO is 'Successfully Installed' if response.status == 'Successfully Installed': @@ -940,7 +1082,7 @@ class NATRule: @classmethod def create(cls, apiclient, virtual_machine, services, ipaddressid=None, - projectid=None, networkid=None): + projectid=None, openfirewall=False, networkid=None, vpcid=None): """Create Port forwarding rule""" cmd = createPortForwardingRule.createPortForwardingRuleCmd() @@ -951,15 +1093,24 @@ class NATRule: cmd.privateport = services["privateport"] cmd.publicport = services["publicport"] + if "privateendport" in services: + cmd.privateendport = services["privateendport"] + if "publicendport" in services: + cmd.publicendport = services["publicendport"] cmd.protocol = services["protocol"] cmd.virtualmachineid = virtual_machine.id if projectid: cmd.projectid = projectid + if openfirewall: + cmd.openfirewall = True + if networkid: cmd.networkid = networkid + if vpcid: + cmd.vpcid = vpcid return NATRule(apiclient.createPortForwardingRule(cmd).__dict__) def delete(self, apiclient): @@ -985,10 +1136,10 @@ class StaticNATRule: self.__dict__.update(items) @classmethod - def create(cls, apiclient, services, ipaddressid=None, vpcid=None): + def create(cls, apiclient, services, ipaddressid=None, networkid=None, vpcid=None): """Creates static ip forwarding rule""" - cmd = createIpForwardingRule.createIpForwardingRuleCmd() + cmd = createFirewallRule.createFirewallRuleCmd() cmd.protocol = services["protocol"] cmd.startport = services["startport"] @@ -1003,10 +1154,12 @@ class StaticNATRule: elif "ipaddressid" in services: cmd.ipaddressid = services["ipaddressid"] + if networkid: + cmd.networkid = networkid + if vpcid: cmd.vpcid = vpcid - - return StaticNATRule(apiclient.createIpForwardingRule(cmd).__dict__) + return StaticNATRule(apiclient.createFirewallRule(cmd).__dict__) def delete(self, apiclient): """Delete IP forwarding rule""" @@ -1024,12 +1177,14 @@ class StaticNATRule: return(apiclient.listIpForwardingRules(cmd)) @classmethod - def enable(cls, apiclient, ipaddressid, virtualmachineid): + def enable(cls, apiclient, ipaddressid, virtualmachineid, networkid=None): """Enables Static NAT rule""" cmd = enableStaticNat.enableStaticNatCmd() cmd.ipaddressid = ipaddressid cmd.virtualmachineid = virtualmachineid + if networkid: + cmd.networkid = networkid apiclient.enableStaticNat(cmd) return @@ -1105,6 +1260,14 @@ class ServiceOffering: if "storagetype" in services: cmd.storagetype = services["storagetype"] + if "systemvmtype" in services: + cmd.systemvmtype = services['systemvmtype'] + + if "issystem" in services: + cmd.issystem = services['issystem'] + + if "tags" in services: + cmd.tags = services["tags"] # Service Offering private to that domain if domainid: cmd.domainid = domainid @@ -1183,20 +1346,25 @@ class NetworkOffering: cmd.displaytext = "-".join([services["displaytext"], random_gen()]) cmd.name = "-".join([services["name"], random_gen()]) cmd.guestiptype = services["guestiptype"] - cmd.supportedservices = services["supportedservices"] + cmd.supportedservices = '' + if "supportedservices" in services: + cmd.supportedservices = services["supportedservices"] cmd.traffictype = services["traffictype"] + if "useVpc" in services: + cmd.useVpc = services["useVpc"] cmd.serviceProviderList = [] - for service, provider in services["serviceProviderList"].items(): - cmd.serviceProviderList.append({ + if "serviceProviderList" in services: + for service, provider in services["serviceProviderList"].items(): + cmd.serviceProviderList.append({ 'service': service, 'provider': provider }) if "servicecapabilitylist" in services: - cmd.servicecapabilitylist = [] + cmd.serviceCapabilityList = [] for service, capability in services["servicecapabilitylist"].items(): for ctype, value in capability.items(): - cmd.servicecapabilitylist.append({ + cmd.serviceCapabilityList.append({ 'service': service, 'capabilitytype': ctype, 'capabilityvalue': value @@ -1205,6 +1373,7 @@ class NetworkOffering: cmd.specifyVlan = services["specifyVlan"] if "specifyIpRanges" in services: cmd.specifyIpRanges = services["specifyIpRanges"] + cmd.availability = 'Optional' [setattr(cmd, k, v) for k, v in kwargs.items()] @@ -1275,7 +1444,7 @@ class LoadBalancerRule: @classmethod def create(cls, apiclient, services, ipaddressid=None, accountid=None, - networkid=None, projectid=None, domainid=None): + networkid=None, vpcid=None, projectid=None, domainid=None): """Create Load balancing Rule""" cmd = createLoadBalancerRule.createLoadBalancerRuleCmd() @@ -1293,6 +1462,8 @@ class LoadBalancerRule: if domainid: cmd.domainid = domainid + if vpcid: + cmd.vpcid = vpcid cmd.name = services["name"] cmd.algorithm = services["alg"] cmd.privateport = services["privateport"] @@ -1359,19 +1530,19 @@ class LoadBalancerRule: for name, value in param.items(): cmd.param.append({'name': name, 'value': value}) return apiclient.createLBStickinessPolicy(cmd) - + def deleteSticky(self, apiclient, id): """Deletes stickyness policy""" - + cmd = deleteLBStickinessPolicy.deleteLBStickinessPolicyCmd() cmd.id = id return apiclient.deleteLBStickinessPolicy(cmd) - + @classmethod def listStickyPolicies(cls, apiclient, lbruleid, **kwargs): """Lists stickiness policies for load balancing rule""" - - cmd= listLBStickinessPolicies.listLBStickinessPoliciesCmd() + + cmd = listLBStickinessPolicies.listLBStickinessPoliciesCmd() cmd.lbruleid = lbruleid [setattr(cmd, k, v) for k, v in kwargs.items()] return apiclient.listLBStickinessPolicies(cmd) @@ -1396,7 +1567,7 @@ class Cluster: """Create Cluster""" cmd = addCluster.addClusterCmd() cmd.clustertype = services["clustertype"] - cmd.hypervisor = services["hypervisor"] + cmd.hypervisor = apiclient.hypervisor if zoneid: cmd.zoneid = zoneid @@ -1446,7 +1617,7 @@ class Host: """Create Host in cluster""" cmd = addHost.addHostCmd() - cmd.hypervisor = services["hypervisor"] + cmd.hypervisor = apiclient.hypervisor cmd.url = services["url"] cmd.clusterid = cluster.id @@ -1493,6 +1664,29 @@ class Host: cmd.id = self.id return apiclient.prepareHostForMaintenance(cmd) + @classmethod + def enableMaintenance(cls, apiclient, id): + """enables maintainance mode Host""" + + cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd() + cmd.id = id + return apiclient.prepareHostForMaintenance(cmd) + + def cancelMaintenance(self, apiclient): + """Cancels maintainance mode Host""" + + cmd = cancelHostMaintenance.cancelHostMaintenanceCmd() + cmd.id = self.id + return apiclient.cancelHostMaintenance(cmd) + + @classmethod + def cancelMaintenance(cls, apiclient, id): + """Cancels maintainance mode Host""" + + cmd = cancelHostMaintenance.cancelHostMaintenanceCmd() + cmd.id = id + return apiclient.cancelHostMaintenance(cmd) + @classmethod def list(cls, apiclient, **kwargs): """List all Hosts matching criteria""" @@ -1586,7 +1780,8 @@ class Network: @classmethod def create(cls, apiclient, services, accountid=None, domainid=None, - networkofferingid=None, projectid=None, zoneid=None, + networkofferingid=None, projectid=None, + subdomainaccess=None, zoneid=None, gateway=None, netmask=None, vpcid=None, guestcidr=None): """Create Network for account""" cmd = createNetwork.createNetworkCmd() @@ -1603,6 +1798,9 @@ class Network: elif "zoneid" in services: cmd.zoneid = services["zoneid"] + if subdomainaccess is not None: + cmd.subdomainaccess = subdomainaccess + if gateway: cmd.gateway = gateway elif "gateway" in services: @@ -1717,7 +1915,7 @@ class Vpn: @classmethod def create(cls, apiclient, publicipid, account=None, domainid=None, - projectid=None, vpcid=None): + projectid=None, networkid=None, vpcid=None): """Create VPN for Public IP address""" cmd = createRemoteAccessVpn.createRemoteAccessVpnCmd() cmd.publicipid = publicipid @@ -1727,6 +1925,8 @@ class Vpn: cmd.domainid = domainid if projectid: cmd.projectid = projectid + if networkid: + cmd.networkid = networkid if vpcid: cmd.vpcid = vpcid return Vpn(apiclient.createRemoteAccessVpn(cmd).__dict__) @@ -1755,10 +1955,11 @@ class VpnUser: @classmethod def create(cls, apiclient, username, password, account=None, domainid=None, - projectid=None): + projectid=None, rand_name=True): """Create VPN user""" cmd = addVpnUser.addVpnUserCmd() - cmd.username = username + cmd.username = "-".join([username, + random_gen()]) if rand_name else username cmd.password = password if account: @@ -1989,6 +2190,33 @@ class PhysicalNetwork: cmd.traffictype = type return apiclient.addTrafficType(cmd) + @classmethod + def dedicate(cls, apiclient, vlanrange, physicalnetworkid, account=None, domainid=None, projectid=None): + """Dedicate guest vlan range""" + + cmd = dedicateGuestVlanRange.dedicateGuestVlanRangeCmd() + cmd.vlanrange = vlanrange + cmd.physicalnetworkid = physicalnetworkid + cmd.account = account + cmd.domainid = domainid + cmd.projectid = projectid + return PhysicalNetwork(apiclient.dedicateGuestVlanRange(cmd).__dict__) + + def release(self, apiclient): + """Release guest vlan range""" + + cmd = releaseDedicatedGuestVlanRange.releaseDedicatedGuestVlanRangeCmd() + cmd.id = self.id + return apiclient.releaseDedicatedGuestVlanRange(cmd) + + @classmethod + def listDedicated(cls, apiclient, **kwargs): + """Lists all dedicated guest vlan ranges""" + + cmd = listDedicatedGuestVlanRanges.listDedicatedGuestVlanRangesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return apiclient.listDedicatedGuestVlanRanges(cmd) + @classmethod def list(cls, apiclient, **kwargs): """Lists all physical networks""" @@ -1997,6 +2225,7 @@ class PhysicalNetwork: [setattr(cmd, k, v) for k, v in kwargs.items()] return map(lambda pn : PhysicalNetwork(pn.__dict__), apiclient.listPhysicalNetworks(cmd)) + class SecurityGroup: """Manage Security Groups""" @@ -2364,6 +2593,104 @@ class NetworkServiceProvider: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listNetworkServiceProviders(cmd)) + +class Router: + """Manage router life cycle""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def start(cls, apiclient, id): + """Starts the router""" + cmd = startRouter.startRouterCmd() + cmd.id = id + return apiclient.startRouter(cmd) + + @classmethod + def stop(cls, apiclient, id, forced=None): + """Stops the router""" + cmd = stopRouter.stopRouterCmd() + cmd.id = id + if forced: + cmd.forced = forced + return apiclient.stopRouter(cmd) + + @classmethod + def reboot(cls, apiclient, id): + """Reboots the router""" + cmd = rebootRouter.rebootRouterCmd() + cmd.id = id + return apiclient.rebootRouter(cmd) + + @classmethod + def destroy(cls, apiclient, id): + """Destroy the router""" + cmd = destroyRouter.destroyRouterCmd() + cmd.id = id + return apiclient.destroyRouter(cmd) + + @classmethod + def change_service_offering(cls, apiclient, id, serviceofferingid): + """Change service offering of the router""" + cmd = changeServiceForRouter.changeServiceForRouterCmd() + cmd.id = id + cmd.serviceofferingid = serviceofferingid + return apiclient.changeServiceForRouter(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List routers""" + + cmd = listRouters.listRoutersCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listRouters(cmd)) + + +class Tag: + """Manage tags""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, resourceIds, resourceType, tags): + """Create tags""" + + cmd = createTags.createTagsCmd() + cmd.resourceIds = resourceIds + cmd.resourcetype = resourceType + cmd.tags = [] + for key, value in tags.items(): + cmd.tags.append({ + 'key': key, + 'value': value + }) + return Tag(apiclient.createTags(cmd).__dict__) + + def delete(self, apiclient, resourceIds, resourceType, tags): + """Delete tags""" + + cmd = deleteTags.deleteTagsCmd() + cmd.resourceIds = resourceIds + cmd.resourcetype = resourceType + cmd.tags = [] + for key, value in tags.items(): + cmd.tags.append({ + 'key': key, + 'value': value + }) + apiclient.deleteTags(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all tags matching the criteria""" + + cmd = listTags.listTagsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listTags(cmd)) + + class VpcOffering: """Manage VPC offerings""" @@ -2417,7 +2744,7 @@ class VPC: @classmethod def create(cls, apiclient, services, vpcofferingid, - zoneid, networkDomain=None, account=None, domainid=None): + zoneid, networkDomain=None, account=None, domainid=None): """Creates the virtual private connection (VPC)""" cmd = createVPC.createVPCCmd() @@ -2467,6 +2794,40 @@ class VPC: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listVPCs(cmd)) + +class PrivateGateway: + """Manage private gateway lifecycle""" + def create(cls, apiclient, gateway, ipaddress, netmask, vlan, vpcid, + physicalnetworkid=None): + """Create private gateway""" + + cmd = createPrivateGateway.createPrivateGatewayCmd() + cmd.gateway = gateway + cmd.ipaddress = ipaddress + cmd.netmask = netmask + cmd.vlan = vlan + cmd.vpcid = vpcid + if physicalnetworkid: + cmd.physicalnetworkid = physicalnetworkid + + return PrivateGateway(apiclient.createPrivateGateway(cmd).__dict__) + + def delete(self, apiclient): + """Delete private gateway""" + + cmd = deletePrivateGateway.deletePrivateGatewayCmd() + cmd.id = self.id + return apiclient.deletePrivateGateway(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List private gateways""" + + cmd = listPrivateGateways.listPrivateGatewaysCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listPrivateGateways(cmd)) + + class AffinityGroup: def __init__(self, items): self.__dict__.update(items) @@ -2495,9 +2856,35 @@ class AffinityGroup: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listVPCs(cmd)) +class StaticRoute: + """Manage static route lifecycle""" + @classmethod + def create(cls, apiclient, cidr, gatewayid): + """Create static route""" + + cmd = createStaticRoute.createStaticRouteCmd() + cmd.cidr = cidr + cmd.gatewayid = gatewayid + return StaticRoute(apiclient.createStaticRoute(cmd).__dict__) + + def delete(self, apiclient): + """Delete static route""" + + cmd = deleteStaticRoute.deleteStaticRouteCmd() + cmd.id = self.id + return apiclient.deleteStaticRoute(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List static route""" + + cmd = listStaticRoutes.listStaticRoutesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listStaticRoutes(cmd)) + + class VNMC: """Manage VNMC lifecycle""" - def __init__(self, items): self.__dict__.update(items) @@ -2526,13 +2913,153 @@ class VNMC: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listCiscoVnmcResources(cmd)) -class ASA1000V: - """Manage ASA 1000v lifecycle""" + +class SSHKeyPair: + """Manage SSH Key pairs""" + + def __init__(self, items, services): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, name=None, account=None, + domainid=None, projectid=None): + """Creates SSH keypair""" + cmd = createSSHKeyPair.createSSHKeyPairCmd() + cmd.name = name + if account is not None: + cmd.account = account + if domainid is not None: + cmd.domainid = domainid + if projectid is not None: + cmd.projectid = projectid + return (apiclient.createSSHKeyPair(cmd)) + + def delete(self, apiclient): + """Delete SSH key pair""" + cmd = deleteSSHKeyPair.deleteSSHKeyPairCmd() + cmd.name = self.name + apiclient.deleteSSHKeyPair(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all SSH key pairs""" + cmd = listSSHKeyPairs.listSSHKeyPairsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listSSHKeyPairs(cmd)) + + +class Capacities: + """Manage Capacities""" + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists capacities""" + + cmd = listCapacity.listCapacityCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listCapacity(cmd)) + + +class Alert: + """Manage alerts""" + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists alerts""" + + cmd = listAlerts.listAlertsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listAlerts(cmd)) + + +class InstanceGroup: + """Manage VM instance groups""" def __init__(self, items): self.__dict__.update(items) @classmethod + def create(cls, apiclient, name=None, account=None, domainid=None, + projectid=None, networkid=None, rand_name=True): + """Creates instance groups""" + + cmd = createInstanceGroup.createInstanceGroupCmd() + cmd.name = "-".join([name, random_gen()]) if rand_name else name + if account is not None: + cmd.account = account + if domainid is not None: + cmd.domainid = domainid + if projectid is not None: + cmd.projectid = projectid + if networkid is not None: + cmd.networkid = networkid + return InstanceGroup(apiclient.createInstanceGroup(cmd).__dict__) + + def delete(self, apiclient): + """Delete instance group""" + cmd = deleteInstanceGroup.deleteInstanceGroupCmd() + cmd.id = self.id + apiclient.deleteInstanceGroup(cmd) + + def update(self, apiclient, **kwargs): + """Updates the instance groups""" + cmd = updateInstanceGroup.updateInstanceGroupCmd() + cmd.id = self.id + [setattr(cmd, k, v) for k, v in kwargs.items()] + return (apiclient.updateInstanceGroup(cmd)) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all instance groups""" + cmd = listInstanceGroups.listInstanceGroupsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return (apiclient.listInstanceGroups(cmd)) + + def startInstances(self, apiclient): + """Starts all instances in a VM tier""" + + cmd = startVirtualMachine.startVirtualMachineCmd() + cmd.group = self.id + return apiclient.startVirtualMachine(cmd) + + def stopInstances(self, apiclient): + """Stops all instances in a VM tier""" + + cmd = stopVirtualMachine.stopVirtualMachineCmd() + cmd.group = self.id + return apiclient.stopVirtualMachine(cmd) + + def rebootInstances(self, apiclient): + """Reboot all instances in a VM tier""" + + cmd = rebootVirtualMachine.rebootVirtualMachineCmd() + cmd.group = self.id + return apiclient.rebootVirtualMachine(cmd) + + def deleteInstances(self, apiclient): + """Stops all instances in a VM tier""" + + cmd = destroyVirtualMachine.destroyVirtualMachineCmd() + cmd.group = self.id + return apiclient.destroyVirtualMachine(cmd) + + def changeServiceOffering(self, apiclient, serviceOfferingId): + """Change service offering of the vm tier""" + + cmd = changeServiceForVirtualMachine.changeServiceForVirtualMachineCmd() + cmd.group = self.id + cmd.serviceofferingid = serviceOfferingId + return apiclient.changeServiceForVirtualMachine(cmd) + + def recoverInstances(self, apiclient): + """Recover the instances from vm tier""" + cmd = recoverVirtualMachine.recoverVirtualMachineCmd() + cmd.group = self.id + apiclient.recoverVirtualMachine(cmd) + + +class ASA1000V: + """Manage ASA 1000v lifecycle""" def create(cls, apiclient, hostname, insideportprofile, clusterid, physicalnetworkid): """Registers ASA 1000v appliance""" @@ -2557,3 +3084,81 @@ class ASA1000V: cmd = listCiscoAsa1000vResources.listCiscoAsa1000vResourcesCmd() [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listCiscoAsa1000vResources(cmd)) + +class VmSnapshot: + """Manage VM Snapshot life cycle""" + def __init__(self, items): + self.__dict__.update(items) + @classmethod + def create(cls,apiclient,vmid,snapshotmemory="false",name=None,description=None): + cmd = createVMSnapshot.createVMSnapshotCmd() + cmd.virtualmachineid = vmid + + if snapshotmemory: + cmd.snapshotmemory = snapshotmemory + if name: + cmd.name = name + if description: + cmd.description = description + return VmSnapshot(apiclient.createVMSnapshot(cmd).__dict__) + + @classmethod + def list(cls, apiclient, **kwargs): + cmd = listVMSnapshot.listVMSnapshotCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listVMSnapshot(cmd)) + + @classmethod + def revertToSnapshot(cls, apiclient,vmsnapshotid): + cmd = revertToVMSnapshot.revertToVMSnapshotCmd() + cmd.vmsnapshotid = vmsnapshotid + + return apiclient.revertToVMSnapshot(cmd) + + @classmethod + def deleteVMSnapshot(cls,apiclient,vmsnapshotid): + cmd = deleteVMSnapshot.deleteVMSnapshotCmd() + cmd.vmsnapshotid = vmsnapshotid + + return apiclient.deleteVMSnapshot(cmd) + +class Region: + """ Regions related Api """ + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services): + cmd = addRegion.addRegionCmd() + cmd.id = services["regionid"] + cmd.endpoint = services["regionendpoint"] + cmd.name = services["regionname"] + try: + region = apiclient.addRegion(cmd) + if region is not None: + return Region(region.__dict__) + except Exception as e: + raise e + + @classmethod + def list(cls, apiclient, **kwargs): + cmd = listRegions.listRegionsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + region = apiclient.listRegions(cmd) + return region + + def update(self, apiclient, services): + cmd = updateRegion.updateRegionCmd() + cmd.id = self.id + if services["regionendpoint"]: + cmd.endpoint = services["regionendpoint"] + if services["regionname"]: + cmd.name = services["regionname"] + region = apiclient.updateRegion(cmd) + return region + + def delete(self, apiclient): + cmd = removeRegion.removeRegionCmd() + cmd.id = self.id + region = apiclient.removeRegion(cmd) + return region diff --git a/tools/marvin/marvin/integration/lib/utils.py b/tools/marvin/marvin/integration/lib/utils.py index cff24a1b2d5..6892c41d1ec 100644 --- a/tools/marvin/marvin/integration/lib/utils.py +++ b/tools/marvin/marvin/integration/lib/utils.py @@ -106,12 +106,17 @@ def cleanup_resources(api_client, resources): obj.delete(api_client) -def is_server_ssh_ready(ipaddress, port, username, password, retries=50): +def is_server_ssh_ready(ipaddress, port, username, password, retries=50, keyPairFileLocation=None): """Return ssh handle else wait till sshd is running""" loop_cnt = retries while True: try: - ssh = remoteSSHClient(ipaddress, port, username, password) + ssh = remoteSSHClient( + host=ipaddress, + port=port, + user=username, + passwd=password, + keyPairFileLocation=keyPairFileLocation) except Exception as e: if loop_cnt == 0: raise e @@ -149,12 +154,16 @@ def fetch_api_client(config_file='datacenterCfg'): ) -def get_process_status(hostip, port, username, password, linklocalip, process): +def get_process_status(hostip, port, username, password, linklocalip, process, hypervisor=None): """Double hop and returns a process status""" #SSH to the machine ssh = remoteSSHClient(hostip, port, username, password) - ssh_command = "ssh -i ~/.ssh/id_rsa.cloud -ostricthostkeychecking=no " + if str(hypervisor).lower() == 'vmware': + ssh_command = "ssh -i /var/lib/cloud/management/.ssh/id_rsa -ostricthostkeychecking=no " + else: + ssh_command = "ssh -i ~/.ssh/id_rsa.cloud -ostricthostkeychecking=no " + ssh_command = ssh_command + \ "-oUserKnownHostsFile=/dev/null -p 3922 %s %s" % ( linklocalip, diff --git a/tools/marvin/marvin/remoteSSHClient.py b/tools/marvin/marvin/remoteSSHClient.py index 4fb2f0de8f0..04450fdf0e2 100644 --- a/tools/marvin/marvin/remoteSSHClient.py +++ b/tools/marvin/marvin/remoteSSHClient.py @@ -23,11 +23,12 @@ import logging from contextlib import closing class remoteSSHClient(object): - def __init__(self, host, port, user, passwd, retries = 10, log_lvl=logging.INFO): + def __init__(self, host, port, user, passwd, retries = 10, log_lvl=logging.INFO, keyPairFileLocation=None): self.host = host self.port = port self.user = user self.passwd = passwd + self.keyPairFile = keyPairFileLocation self.ssh = paramiko.SSHClient() self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) self.logger = logging.getLogger('sshClient') @@ -38,8 +39,19 @@ class remoteSSHClient(object): retry_count = retries while True: try: - self.ssh.connect(str(host),int(port), user, passwd) - self.logger.debug("SSH connect: %s@%s with passwd %s"%(user, str(host), passwd)) + if keyPairFileLocation == None: + self.ssh.connect(str(host),int(port), user, passwd) + self.logger.debug("SSH connect: %s@%s with passwd %s"%(user, str(host), passwd)) + else: + self.ssh.connect( + hostname=str(host), + port=int(port), + username=str(user), + key_filename=str(keyPairFileLocation), + look_for_keys=False + ) + self.logger.debug("connecting to server %s with user %s key %s"%(str(host), user, keyPairFileLocation)) + self.logger.debug("SSH connect: %s@%s with passwd %s"%(user, str(host), passwd)) except paramiko.SSHException, sshex: if retry_count == 0: raise cloudstackException.InvalidParameterException(repr(sshex)) diff --git a/tools/marvin/marvin/sandbox/advanced/advanced_env.py b/tools/marvin/marvin/sandbox/advanced/advanced_env.py index db78a84b33b..6343293aa62 100644 --- a/tools/marvin/marvin/sandbox/advanced/advanced_env.py +++ b/tools/marvin/marvin/sandbox/advanced/advanced_env.py @@ -46,9 +46,13 @@ def describeResources(config): z.name = 'Sandbox-%s'%(config.get('cloudstack', 'hypervisor')) z.networktype = 'Advanced' z.guestcidraddress = '10.1.1.0/24' + z.securitygroupenabled = 'false' vpcprovider = provider() vpcprovider.name = 'VpcVirtualRouter' + + lbprovider = provider() + lbprovider.name = 'InternalLbVm' pn = physical_network() pn.name = "Sandbox-pnet" @@ -57,14 +61,18 @@ def describeResources(config): pn.traffictypes = [traffictype("Guest"), traffictype("Management", {"simulator" : "cloud-simulator-mgmt"}), traffictype("Public", {"simulator":"cloud-simulator-public"})] + pn.isolationmethods = ["VLAN"] pn.providers.append(vpcprovider) + pn.providers.append(lbprovider) pn2 = physical_network() pn2.name = "Sandbox-pnet2" pn2.vlan = config.get('cloudstack', 'pnet2.vlan') pn2.tags = ["cloud-simulator-guest"] pn2.traffictypes = [traffictype('Guest', {'simulator': 'cloud-simulator-guest'})] + pn2.isolationmethods = ["VLAN"] pn2.providers.append(vpcprovider) + pn2.providers.append(lbprovider) z.physical_networks.append(pn) z.physical_networks.append(pn2) diff --git a/tools/marvin/marvin/sandbox/advanced/sandbox.cfg b/tools/marvin/marvin/sandbox/advanced/sandbox.cfg new file mode 100644 index 00000000000..01a84730dad --- /dev/null +++ b/tools/marvin/marvin/sandbox/advanced/sandbox.cfg @@ -0,0 +1,209 @@ +{ + "zones": [ + { + "name": "Sandbox-Simulator", + "guestcidraddress": "10.1.1.0/24", + "dns1": "10.147.28.6", + "physical_networks": [ + { + "providers": [ + { + "broadcastdomainrange": "ZONE", + "name": "VirtualRouter" + }, + { + "broadcastdomainrange": "ZONE", + "name": "VpcVirtualRouter" + }, + { + "broadcastdomainrange": "ZONE", + "name": "InternalLb" + } + ], + "name": "Sandbox-pnet", + "tags": [ + "cloud-simulator-public" + ], + "broadcastdomainrange": "Zone", + "vlan": "675-679", + "traffictypes": [ + { + "typ": "Guest" + }, + { + "typ": "Management", + "simulator": "cloud-simulator-mgmt" + }, + { + "typ": "Public", + "simulator": "cloud-simulator-public" + } + ], + "isolationmethods": [ + "VLAN" + ] + }, + { + "providers": [ + { + "broadcastdomainrange": "ZONE", + "name": "VirtualRouter" + }, + { + "broadcastdomainrange": "ZONE", + "name": "VpcVirtualRouter" + }, + { + "broadcastdomainrange": "ZONE", + "name": "InternalLb" + } + ], + "name": "Sandbox-pnet2", + "tags": [ + "cloud-simulator-guest" + ], + "broadcastdomainrange": "Zone", + "vlan": "800-1000", + "traffictypes": [ + { + "typ": "Guest", + "simulator": "cloud-simulator-guest" + } + ], + "isolationmethods": [ + "VLAN" + ] + } + ], + "securitygroupenabled": "false", + "ipranges": [ + { + "startip": "10.147.31.150", + "endip": "10.147.31.159", + "netmask": "255.255.255.0", + "vlan": "31", + "gateway": "10.147.31.1" + } + ], + "networktype": "Advanced", + "pods": [ + { + "endip": "10.147.29.159", + "name": "POD0", + "startip": "10.147.29.150", + "netmask": "255.255.255.0", + "clusters": [ + { + "clustername": "C0", + "hypervisor": "Simulator", + "hosts": [ + { + "username": "root", + "url": "http://simulator0", + "password": "password" + } + ], + "clustertype": "CloudManaged", + "primaryStorages": [ + { + "url": "nfs://10.147.28.6:/export/home/sandbox/primary", + "name": "PS0" + } + ] + } + ], + "gateway": "10.147.29.1" + } + ], + "internaldns1": "10.147.28.6", + "secondaryStorages": [ + { + "url": "nfs://10.147.28.6:/export/home/sandbox/sstor" + } + ] + } + ], + "dbSvr": { + "dbSvr": "localhost", + "passwd": "cloud", + "db": "cloud", + "port": 3306, + "user": "cloud" + }, + "logger": [ + { + "name": "TestClient", + "file": "testclient.log" + }, + { + "name": "TestCase", + "file": "testcase.log" + } + ], + "globalConfig": [ + { + "name": "storage.cleanup.interval", + "value": "300" + }, + { + "name": "direct.agent.load.size", + "value": "1000" + }, + { + "name": "default.page.size", + "value": "10000" + }, + { + "name": "instance.name", + "value": "QA" + }, + { + "name": "workers", + "value": "10" + }, + { + "name": "vm.op.wait.interval", + "value": "5" + }, + { + "name": "account.cleanup.interval", + "value": "600" + }, + { + "name": "guest.domain.suffix", + "value": "sandbox.simulator" + }, + { + "name": "expunge.delay", + "value": "60" + }, + { + "name": "vm.allocation.algorithm", + "value": "random" + }, + { + "name": "expunge.interval", + "value": "60" + }, + { + "name": "expunge.workers", + "value": "3" + }, + { + "name": "secstorage.allowed.internal.sites", + "value": "10.147.28.0/24" + }, + { + "name": "check.pod.cidrs", + "value": "true" + } + ], + "mgtSvr": [ + { + "mgtSvrIp": "localhost", + "passwd": "password", + "user": "root", + "port": 8096 + } + ] +} \ No newline at end of file diff --git a/tools/marvin/marvin/sandbox/basic/basic_env.py b/tools/marvin/marvin/sandbox/basic/basic_env.py index e588fdcc882..cf1869fa499 100644 --- a/tools/marvin/marvin/sandbox/basic/basic_env.py +++ b/tools/marvin/marvin/sandbox/basic/basic_env.py @@ -55,6 +55,7 @@ def describeResources(config): pn = physical_network() pn.name = "Sandbox-pnet" pn.traffictypes = [traffictype("Guest"), traffictype("Management")] + pn.isolationmethods = ["L3"] pn.providers.append(sgprovider) z.physical_networks.append(pn) diff --git a/tools/marvin/marvin/sandbox/demo/simulator/simulator_setup.py b/tools/marvin/marvin/sandbox/demo/simulator/simulator_setup.py index e4ec9b7b1b1..d45d48243bd 100644 --- a/tools/marvin/marvin/sandbox/demo/simulator/simulator_setup.py +++ b/tools/marvin/marvin/sandbox/demo/simulator/simulator_setup.py @@ -41,6 +41,7 @@ def describeResources(config): z.name = 'Sandbox-%s'%(config.get('environment', 'hypervisor')) z.networktype = 'Advanced' z.guestcidraddress = '10.1.1.0/24' + z.securitygroupenabled = 'false' vpcprovider = provider() vpcprovider.name = 'VpcVirtualRouter' @@ -48,6 +49,7 @@ def describeResources(config): pn = physical_network() pn.name = "Sandbox-pnet" pn.traffictypes = [traffictype("Guest"), traffictype("Management"), traffictype("Public")] + pn.isolationmethods = ["VLAN"] pn.providers.append(vpcprovider) pn.vlan = config.get('cloudstack', 'zone.vlan') diff --git a/tools/marvin/pom.xml b/tools/marvin/pom.xml index c0505664486..b8f7d7430a5 100644 --- a/tools/marvin/pom.xml +++ b/tools/marvin/pom.xml @@ -1,15 +1,14 @@ + 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. --> + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 cloud-marvin Apache CloudStack marvin @@ -35,7 +34,7 @@ - + Deleting ${project.artifactId} API sources @@ -83,7 +82,7 @@ - + marvin.sync @@ -160,6 +159,26 @@ + + org.codehaus.gmaven + gmaven-plugin + 1.5 + + + setproperty + validate + + execute + + + + pom.properties['resolved.basedir']=project.basedir.absolutePath.replace('\','/').replace('D:','/cyg/d'); + pom.properties['resolved.userdir']='${user.dir}'.replace('\','/').replace('D:','/cyg/d'); + + + + + org.codehaus.mojo exec-maven-plugin @@ -177,18 +196,18 @@ deployAndRun.py -c - ${user.dir}/${marvin.config} + ${resolved.userdir}/${marvin.config} -t /tmp/t.log -r /tmp/r.log -f - ${basedir}/marvin/testSetupSuccess.py + ${resolved.basedir}/marvin/testSetupSuccess.py - - + + @@ -201,6 +220,30 @@ + + org.codehaus.gmaven + gmaven-plugin + 1.5 + + + setproperty + validate + + execute + + + + ${user.dir} + ${marvin.config} + + + project.properties['resolved.user.dir']='${user.dir}'.replace('\','/').replace('D:','/cyg/d'); + project.properties['resolved.marvin.config']='${marvin.config}'.replace('\','/').replace('D:','/cyg/d'); + + + + + org.codehaus.mojo exec-maven-plugin @@ -218,11 +261,11 @@ --with-marvin --marvin-config - ${user.dir}/${marvin.config} + ${resolved.user.dir}/${resolved.marvin.config} --load -a tags=${tag} - ${user.dir}/${test} + ${resolved.user.dir}/${test} -v diff --git a/tools/transifex/.tx/config b/tools/transifex/.tx/config new file mode 100644 index 00000000000..9c495cce520 --- /dev/null +++ b/tools/transifex/.tx/config @@ -0,0 +1,32 @@ +[main] +host = https://www.transifex.com + +[CloudStack_UI.2-2messagesproperties] +file_filter = translations/CloudStack_UI.2-2messagesproperties/.properties +source_lang = en + +[CloudStack_UI.30xmessagesproperties] +file_filter = translations/CloudStack_UI.30xmessagesproperties/.properties +source_lang = en + +[CloudStack_UI.41xmessageproperties] +file_filter = translations/CloudStack_UI.41xmessageproperties/.properties +source_lang = en + +[CloudStack_UI.42xmessagesproperties] +file_filter = translations/CloudStack_UI.42xmessagesproperties/.properties +source_file = work-dir/messages.properties +source_lang = en +trans.ar = work-dir/messages_ar.properties +trans.ca = work-dir/messages_ca.properties +trans.de_DE = work-dir/messages_de_DE.properties +trans.es = work-dir/messages_es.properties +trans.fr_FR = work-dir/messages_fr_FR.properties +trans.it_IT = work-dir/messages_it_IT.properties +trans.ja = work-dir/messages_ja.properties +trans.ko_KR = work-dir/messages_ko_KR.properties +trans.nb_NO = work-dir/messages_nb_NO.properties +trans.pt_BR = work-dir/messages_pt_BR.properties +trans.ru_RU = work-dir/messages_ru_RU.properties +trans.zh_CN = work-dir/messages_zh_CN.properties + diff --git a/tools/transifex/README-transifex.txt b/tools/transifex/README-transifex.txt new file mode 100644 index 00000000000..4b1cd8d00de --- /dev/null +++ b/tools/transifex/README-transifex.txt @@ -0,0 +1,71 @@ +# 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. + +sync-transifex-ui is a script to automate the synchronisation between +Apache CloudStack L10N resource files and Transifex CloudStack project. + +Requirements to use this script: +* A GNU/Linux or Unix machine +* Transifex client installed +http://support.transifex.com/customer/portal/topics/440187-transifex-client/articles +On Debian/Ubuntu: apt-get install transifex-client + +Commun usage is: + +1/ Init and configure the transifex client CLI +(Already made on git CloudStack repo) + + ./sync-transifex-ui.sh init-transifex https://www.transifex.com/projects/p/CloudStack_UI/ + +2/ Upload to Transifex the last version of the source language (en) +which generally have the new keys/values to translate. + + ./sync-transifex-ui.sh upload-source-language CloudStack_UI.42xmessagesproperties + +3/ Download the last L10N resource files from Transifex to resources +files directory in CloudStack tree to upade the L10N resource files +with the translatons from traductors. + + ./sync-transifex-ui.sh download-l10n-languages CloudStack_UI.42xmessagesproperties + +===== +The sync-transifex-ui provide too the ability to : + +* Download from Transifex the source language resource files. Be carrefully, +with this,you can remove some transation on Transifex if some keys has +been removed inside the source language resource files. + + ./sync-transifex-ui.sh download-source-language CloudStack_UI.42xmessagesproperties + +* Upload the L10N resource files on Transifex. + + ./sync-transifex-ui.sh upload-l10n-languages CloudStack_UI.42xmessagesproperties + +===== +Note 1: +Choose the good branch on git matching with the good resource on Transifex: +(no branch) <--> CloudStack_UI.2-2messagesproperties +(no branch) <--> CloudStack_UI.30xmessagesproperties +(4.1) <--> CloudStack_UI.41xmessageproperties +(master) <--> CloudStack_UI.42xmessagesproperties + +Note 2: +If you want add a new L10N language, we need edit the sync-transifex-ui.sh script +to add his language code in LIST_LANG variable, before run the download-l10n-languages +command. + + diff --git a/tools/transifex/sync-transifex-ui.sh b/tools/transifex/sync-transifex-ui.sh new file mode 100755 index 00000000000..9124ed6a633 --- /dev/null +++ b/tools/transifex/sync-transifex-ui.sh @@ -0,0 +1,160 @@ +#!/bin/sh +# 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. + +SRCLANG=en +LIST_LANG="ar ca de_DE es fr_FR it_IT ja ko_KR nb_NO pt_BR ru_RU zh_CN" + +DIRECTORY_RESOURCES="../../client/WEB-INF/classes/resources" +WORKDIR="./work-dir" + +AL2_STRING="# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements. See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership. The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License. You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied. See the License for the\n# specific language governing permissions and limitations\n# under the License.\n" + +doInit() +{ + tx init + tx set --auto-remote ${ARGUMENTS} +} + +doMakeWdir() +{ + mkdir -p ${WORKDIR} +} + +doCheckInit() +{ + if [ ! -f ./.tx/config ]; then + echo "Error: Transifex project isn't init. Please run $0 init-transifex URL-transifex-project" >&2 + exit 2 + fi +} + +doUploadL10NLangs() +{ + # l10n languages + for CODELANG in ${LIST_LANG} ; do + if [ -f "${DIRECTORY_RESOURCES}/messages_${CODELANG}.properties" ]; then + native2ascii -reverse -encoding UTF-8 ${DIRECTORY_RESOURCES}/messages_${CODELANG}.properties ${WORKDIR}/messages_${CODELANG}.properties + sed -i"" "s/\\\\\\\'/'/g" ${WORKDIR}/messages_${CODELANG}.properties + tx set -r ${ARGUMENTS} -l ${CODELANG} ${WORKDIR}/messages_${CODELANG}.properties + tx push -t -r ${ARGUMENTS} -l ${CODELANG} + else + echo "Warning: the resource file for language ${CODELANG} doesn't exist." + fi + done +} + +doDownloadL10NLangs() +{ + # prepare l10n languages + for CODELANG in ${LIST_LANG} ; do + if [ -f "${DIRECTORY_RESOURCES}/messages_${CODELANG}.properties" ]; then + native2ascii -reverse -encoding UTF-8 ${DIRECTORY_RESOURCES}/messages_${CODELANG}.properties ${WORKDIR}/messages_${CODELANG}.properties + sed -i"" "s/\\\\\\\'/'/g" ${WORKDIR}/messages_${CODELANG}.properties + tx set -r ${ARGUMENTS} -l ${CODELANG} ${WORKDIR}/messages_${CODELANG}.properties + else + echo "\nWarning: the resource file for language ${CODELANG} doesn't exist." + echo "Run this command to force get this language from transifex:" + echo "\ntx set -r ${ARGUMENTS} -l ${CODELANG} ${WORKDIR}/messages_${CODELANG}.properties\n" + fi + done + + # get all resource files from transifex + tx pull -f -r ${ARGUMENTS} + + # l10n languages + for CODELANG in ${LIST_LANG} ; do + #tx pull -r ${ARGUMENTS} -l ${CODELANG} + if [ -f "${WORKDIR}/messages_${CODELANG}.properties" ]; then + native2ascii -encoding UTF-8 ${WORKDIR}/messages_${CODELANG}.properties ${WORKDIR}/messages_${CODELANG}.properties.tmp1 + grep -v "^#" ${WORKDIR}/messages_${CODELANG}.properties.tmp1 | sort -f | uniq | sed "s/'/\\\\\\\\\'/g" > ${WORKDIR}/messages_${CODELANG}.properties.tmp2 + echo "$AL2_STRING" | cat - ${WORKDIR}/messages_${CODELANG}.properties.tmp2 > ${DIRECTORY_RESOURCES}/messages_${CODELANG}.properties + else + echo "Warning: the resource file for language ${CODELANG} doesn't exist on transifex" + fi + done +} + +doUploadSourceLang() +{ + # Source language + if [ -f ${DIRECTORY_RESOURCES}/messages.properties ]; then + native2ascii -reverse -encoding UTF-8 ${DIRECTORY_RESOURCES}/messages.properties ${WORKDIR}/messages.properties + sed -i"" "s/\\\\\\\'/'/g" ${WORKDIR}/messages.properties + tx set --source -r ${ARGUMENTS} -l ${SRCLANG} ${WORKDIR}/messages.properties + tx push -s -r ${ARGUMENTS} + else + echo "Warning: the source language doesn't exist!" + fi +} + +doDownloadSourceLang() +{ + # get all resource files from transifex + tx pull -s -r ${ARGUMENTS} + # Source language + if [ -f "${WORKDIR}/messages.properties" ]; then + native2ascii -encoding UTF-8 ${WORKDIR}/messages.properties ${WORKDIR}/messages.properties.tmp1 + grep -v "^#" ${WORKDIR}/messages.properties.tmp1 | sort -f | uniq | sed "s/'/\\\\\\\\\'/g" > ${WORKDIR}/messages.properties.tmp2 + echo "$AL2_STRING" | cat - ${WORKDIR}/messages.properties.tmp2 > ${DIRECTORY_RESOURCES}/messages.properties + else + echo "Warning: the source language hasn't been retrieve!" + fi +} + +if [ $# -ne 2 ]; then + COMMAND="error" +else + COMMAND="$1" + ARGUMENTS="$2" + doMakeWdir +fi + +case "$COMMAND" in + upload-source-language) + doCheckInit + doUploadSourceLang + ;; + + download-source-language) + doCheckInit + doDownloadSourceLang + ;; + + upload-l10n-languages) + doCheckInit + doUploadL10NLangs + ;; + + download-l10n-languages) + doCheckInit + doDownloadL10NLangs + ;; + + init-transifex) + doInit + ;; + + *|error) + echo "Usage: $0 [upload-source-language|download-source-language] [upload-l10n-languages|download-l10n-languages] transifex-resource" >&2 + echo "\n\tExemple: $0 download-l10n-languages CloudStack_UI-42xmessagesproperties\n" >&2 + echo "Usage: $0 init-transifex URL-transifex-project" >&2 + echo "\n\tExemple: $0 init-transifex https://www.transifex.com/projects/p/CloudStack_UI/\n" >&2 + exit 1 + ;; +esac + diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 85f7dff433d..7f6df22797e 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -1502,7 +1502,6 @@ div.list-view td.state.off span { position: relative; left: 0px; float: left; - width: 460px; height: 22px; border-top: 1px solid #808080; /*+box-shadow:inset 0px 1px #FFFFFF;*/ @@ -1700,6 +1699,8 @@ div.list-view td.state.off span { max-height: 407px; overflow: auto; overflow-x: hidden; + width: 100%; + /*[empty]padding:;*/ margin-right: 12px; } @@ -1777,6 +1778,23 @@ div.list-view td.state.off span { background-position: 100% -431px; } +.detail-view .detail-group .button.add { + clear: both; + margin: 0px 21px 13px 0 !important; +} + +.detail-view .details.group-multiple { + float: left; + width: 100%; + margin-bottom: 30px; +} + +.detail-view .details.group-multiple .main-groups { + overflow: visible; + width: 98%; + margin-bottom: 35px; +} + /*List-view: subselect dropdown*/ .list-view .subselect { width: 116px; @@ -1907,7 +1925,7 @@ div.detail-group td.view-all a { background: url(../images/gradients.png) repeat-x 0px -529px; font-size: 11px; display: block; - height: 25px; + height: 27px; text-decoration: none; color: #4C5D6C; /*+text-shadow:0px 1px 2px #FFFFFF;*/ @@ -1916,7 +1934,7 @@ div.detail-group td.view-all a { -o-text-shadow: 0px 1px 2px #FFFFFF; text-shadow: 0px 1px 2px #FFFFFF; float: left; - padding: 0 8px 0 5px; + padding: 0 1px; border-left: 1px solid #9B9EA2; /*+border-radius:5px 0 0 5px;*/ -moz-border-radius: 5px 0 0 5px; @@ -1971,10 +1989,10 @@ div.details .main-groups label.error { } .detail-view td.view-all.multiple { - width: 123px !important; - height: 22px; - float: left; + max-width: 145px; + height: 17px; display: block; + float: left; margin: 8px 2px 8px 8px; border: none !important; /*+box-shadow:none;*/ @@ -2003,6 +2021,40 @@ div.detail-group.actions td { vertical-align: middle; } +.details.group-multiple div.detail-group.actions { + float: right; + max-width: 75%; + height: 23px; + position: relative; + margin: -15px 0 -5px; +} + +.details.group-multiple div.detail-group.actions table { + background: none; +} + +.details.group-multiple div.detail-group.actions td.detail-actions { + background: none; + display: block; + height: 35px; + float: right; + padding: 0; +} + +.details.group-multiple div.detail-group.actions .detail-actions .action { + float: left; + width: 32px; + /*+placement:shift 11px 7px;*/ + position: relative; + left: 11px; + top: 7px; +} + +.details.group-multiple div.detail-group.actions .detail-actions .action a { + background: none; + width: 31px; +} + .detail-group table td.detail-actions { width: 59%; height: 26px; @@ -2480,6 +2532,10 @@ div.detail-group.actions td { background-position: -73px -23px; } +#navigation ul li.affinityGroups span.icon { + background-position: -73px -87px; +} + #navigation ul li.storage span.icon { background-position: -127px -23px; } @@ -2765,7 +2821,8 @@ div.toolbar div.button.add, div.toolbar div.button.refresh, div.toolbar div.button.add, div.toolbar div.button.main-action, -.toolbar div.button.header-action { +.toolbar div.button.header-action, +.detail-group .button.add { /*+placement:shift 0px 5px;*/ position: relative; left: 0px; @@ -2797,7 +2854,8 @@ div.toolbar div.button.main-action, div.toolbar div.button.add:hover, div.toolbar div.button.refresh:hover, div.toolbar div.button.main-action:hover, -.toolbar div.button.header-action:hover { +.toolbar div.button.header-action:hover, +.detail-group .button.add:hover { background-position: 0 -132px; border-left: 1px solid #585D60; } @@ -2827,7 +2885,8 @@ div.toolbar div.button.refresh span { background-repeat: no-repeat; } -div.toolbar div.button.add span { +div.toolbar div.button.add span, +.detail-group .button.add span.icon { padding: 0px 0 0px 18px; background: url(../images/icons.png) no-repeat -626px -209px; /*+placement:shift 0px 0px;*/ @@ -5265,6 +5324,10 @@ label.error { position: relative; } +.multi-wizard.instance-wizard .progress ul li { + width: 109px; +} + .multi-wizard .progress ul li.first { /*+border-radius:5px 0 0 5px;*/ -moz-border-radius: 5px 0 0 5px; @@ -5306,6 +5369,10 @@ label.error { text-align: center; } +.multi-wizard.instance-wizard .progress ul li span { + left: 36px; +} + .multi-wizard .progress ul li span.multiline { width: 71px; top: 12px; @@ -5322,6 +5389,10 @@ label.error { z-index: 1000; } +.multi-wizard.instance-wizard .progress ul li span.arrow { + left: 27px; +} + .multi-wizard .progress ul li.active span.arrow { background-position: -1px -396px; } @@ -5342,6 +5413,15 @@ label.error { background: transparent; } +.multi-wizard.instance-wizard .progress ul li span.number { + left: 16px; +} + +.multi-wizard.instance-wizard .progress ul li span.multiline { + width: 79px; + left: 23px; +} + .multi-wizard .progress ul li.active span { /*+text-shadow:0px -1px 1px #004AFF;*/ -moz-text-shadow: 0px -1px 1px #004AFF; @@ -5623,7 +5703,7 @@ label.error { /*** Select container*/ .multi-wizard .select-container { - height: 94%; + height: 352px; overflow: auto; overflow-x: hidden; border: 1px solid #D9DFE1; @@ -5636,6 +5716,12 @@ label.error { margin: 10px 10px 0px; } +.multi-wizard .select-container p { + padding: 11px; + color: #424242; + background: #DFDFDF; +} + .multi-wizard .select-container .select { font-size: 13px; margin: -1px 0 0; @@ -11670,7 +11756,6 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it background-position: 0px -707px; } - .attach .icon, .attachISO .icon, .attachDisk .icon { @@ -11854,16 +11939,13 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it } .removeVlanRange .icon { - background-position: 1px -92px; } -.removeVlanRange:hover .icon{ - +.removeVlanRange:hover .icon { background-position: 1px -92px; } - .resize .icon, .updateResourceCount .icon { background-position: -167px -66px; @@ -11893,9 +11975,8 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it background-position: -168px -31px; } -.scaleUp .icon{ - background-position: -167px -66px; - +.scaleUp .icon { + background-position: -167px -66px; } .restoreVM:hover .icon, @@ -12027,6 +12108,30 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it background-position: -228px -646px; } +.changeAffinity .icon { + background-position: -264px -2px; +} + +.changeAffinity:hover .icon { + background-position: -263px -583px; +} + +.releaseFromAccount .icon { + background-position: -230px -123px; +} + +.releaseFromAccount:hover .icon { + background-position: -229px -704px; +} + +.addAccount .icon { + background-position: -231px -96px; +} + +.addAccount:hover .icon { + background-position: -230px -677px; +} + .label-hovered { cursor: pointer; color: #0000FF !important; diff --git a/ui/dictionary.jsp b/ui/dictionary.jsp index 11e98cf5024..ded9ea063d4 100644 --- a/ui/dictionary.jsp +++ b/ui/dictionary.jsp @@ -25,564 +25,145 @@ under the License. <% long now = System.currentTimeMillis(); %> diff --git a/ui/images/icons.png b/ui/images/icons.png index ea1a39cdf7f0a934d4041265470b4b0ade4a2b41..e2083da1969a1143fe90b21404e6689719c5faab 100644 GIT binary patch literal 50052 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,d70FLrU= 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 diff --git a/ui/index.jsp b/ui/index.jsp index 12cb9557912..8f31740a039 100644 --- a/ui/index.jsp +++ b/ui/index.jsp @@ -81,6 +81,7 @@ under the License. + @@ -94,8 +95,9 @@ under the License.

  • 2
  • 3
  • 4
  • -
  • 5
  • -
  • 6
  • +
  • 5
  • +
  • 6
  • +
  • 7
  • @@ -225,7 +227,15 @@ under the License. - + +
    +
    + +
    +
    +
    + +
    @@ -325,7 +335,7 @@ under the License.
    - +
    @@ -1652,6 +1662,7 @@ under the License. + @@ -1660,6 +1671,8 @@ under the License. + + diff --git a/ui/scripts/accounts.js b/ui/scripts/accounts.js index 7e82c0fc163..bad8435e27e 100644 --- a/ui/scripts/accounts.js +++ b/ui/scripts/accounts.js @@ -277,6 +277,7 @@ detailView: { name: 'Account details', + isMaximized: true, viewAll: { path: 'accounts.users', label: 'label.users' }, actions: { @@ -895,6 +896,56 @@ } }); } + }, + + // Granular settings for account + settings: { + title: 'Settings', + custom: cloudStack.uiCustom.granularSettings({ + dataProvider: function(args) { + $.ajax({ + url:createURL('listConfigurations&accountid=' + args.context.accounts[0].id), + data: { page: args.page, pageSize: pageSize, listAll: true }, + success:function(json){ + args.response.success({ + data:json.listconfigurationsresponse.configuration + + }); + + }, + + error:function(json){ + args.response.error(parseXMLHttpResponse(json)); + + } + }); + + }, + actions: { + edit: function(args) { + // call updateAccountLevelParameters + var data = { + name: args.data.jsonObj.name, + value: args.data.value + }; + + $.ajax({ + url:createURL('updateConfiguration&accountid=' + args.context.accounts[0].id), + data:data, + success:function(json){ + var item = json.updateconfigurationresponse.configuration; + args.response.success({data:item}); + }, + + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + + } + } + }) } } } diff --git a/ui/scripts/affinity.js b/ui/scripts/affinity.js new file mode 100644 index 00000000000..a9c66957ad5 --- /dev/null +++ b/ui/scripts/affinity.js @@ -0,0 +1,183 @@ +// 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) { + cloudStack.sections.affinityGroups = { + title: 'label.affinity.groups', + listView: { + id: 'affinityGroups', + fields: { + name: { label: 'label.name' }, + type: { label: 'label.type' } + }, + dataProvider: function(args) { + var data = {}; + if (args.context != null) { + if ("instances" in args.context) { + $.extend(data, { + virtualmachineid: args.context.instances[0].id + }); + } + } + $.ajax({ + url: createURL('listAffinityGroups'), + data: data, + success: function(json) { + var items = json.listaffinitygroupsresponse.affinitygroup; + args.response.success({data: items}); + } + }); + }, + actions: { + add: { + label: 'label.add.affinity.group', + + messages: { + notification: function(args) { + return 'label.add.affinity.group'; + } + }, + + createForm: { + title: 'label.add.affinity.group', + fields: { + name: { + label: 'label.name', + validation: { required: true } + }, + description: { + label: 'label.description' + }, + type: { + label: 'label.type', + select: function(args) { + $.ajax({ + url: createURL('listAffinityGroupTypes'), + success: function(json) { + var types = []; + var items = json.listaffinitygrouptypesresponse.affinityGroupType; + if(items != null) { + for(var i = 0; i < items.length; i++) { + types.push({id: items[i].type, description: items[i].type}); + } + } + args.response.success({data: types}) + } + }); + } + } + } + }, + + action: function(args) { + var data = { + name: args.data.name, + type: args.data.type + }; + if(args.data.description != null && args.data.description.length > 0) + $.extend(data, {description: args.data.description}); + + $.ajax({ + url: createURL('createAffinityGroup'), + data: data, + success: function(json) { + var jid = json.createaffinitygroupresponse.jobid; + args.response.success( + {_custom: + {jobId: jid, + getUpdatedItem: function(json) { + return json.queryasyncjobresultresponse.jobresult.affinitygroup; + } + } + } + ); + } + }); + }, + + notification: { + poll: pollAsyncJobResult + } + } + }, + detailView: { + actions: { + remove: { + label: 'label.delete.affinity.group', + messages: { + confirm: function(args) { + return 'message.delete.affinity.group'; + }, + notification: function(args) { + return 'label.delete.affinity.group'; + } + }, + action: function(args) { + $.ajax({ + url: createURL('deleteAffinityGroup'), + data: { + id: args.context.affinityGroups[0].id + }, + success: function(json) { + var jid = json.deleteaffinitygroupresponse.jobid; + args.response.success({ + _custom:{ + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + + viewAll: { path: 'instances', label: 'label.instances' }, + + tabs: { + details: { + title: 'label.details', + fields: [ + { + name: { label: 'label.name' } + }, + { + description: { label: 'label.description' }, + type: { label: 'label.type' }, + id: { label: 'label.id' } + } + ], + + dataProvider: function(args) { + $.ajax({ + url: createURL('listAffinityGroups'), + data: { + id: args.context.affinityGroups[0].id + }, + success: function(json) { + var item = json.listaffinitygroupsresponse.affinitygroup[0]; + args.response.success({data: item}); + } + }); + } + } + } + } + } + }; +})(cloudStack); diff --git a/ui/scripts/cloudStack.js b/ui/scripts/cloudStack.js index 35969a27251..b943a946c8f 100644 --- a/ui/scripts/cloudStack.js +++ b/ui/scripts/cloudStack.js @@ -22,16 +22,16 @@ var sections = []; if(isAdmin()) { - sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "system", "global-settings", "configuration", "projects", "regions"]; + sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "system", "global-settings", "configuration", "projects", "regions", "affinityGroups"]; } else if(isDomainAdmin()) { - sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "projects", "regions"]; + sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "projects", "regions", "affinityGroups"]; } else if (g_userProjectsEnabled) { - sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "events", "projects", "regions"]; + sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "events", "projects", "regions", "affinityGroups"]; } else { //normal user - sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "events", "regions"]; + sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "events", "regions", "affinityGroups"]; } if (cloudStack.plugins.length) { @@ -46,6 +46,7 @@ */ dashboard: {}, instances: {}, + affinityGroups: {}, storage: {}, network: {}, templates: {}, diff --git a/ui/scripts/configuration.js b/ui/scripts/configuration.js index 4a64eeac1a5..9a08c4c56b1 100644 --- a/ui/scripts/configuration.js +++ b/ui/scripts/configuration.js @@ -1210,7 +1210,7 @@ } } }); - if(havingVpcVirtualRouterForAtLeastOneService == true || $guestTypeField.val() == 'Shared') { + if(havingVpcVirtualRouterForAtLeastOneService == true ) { $conservemode.find("input[type=checkbox]").attr("disabled", "disabled"); $conservemode.find("input[type=checkbox]").attr('checked', false); diff --git a/ui/scripts/domains.js b/ui/scripts/domains.js index 8ee0ee6816a..e82f8ff44e8 100644 --- a/ui/scripts/domains.js +++ b/ui/scripts/domains.js @@ -530,7 +530,7 @@ case "10": domainObj["primaryStorageLimit"] = limit.max; break; - case "7": + case "11": domainObj["secondaryStorageLimit"] = limit.max; break; } diff --git a/ui/scripts/instanceWizard.js b/ui/scripts/instanceWizard.js index 13828c848b6..ff130d3e301 100644 --- a/ui/scripts/instanceWizard.js +++ b/ui/scripts/instanceWizard.js @@ -18,7 +18,7 @@ (function($, cloudStack) { var zoneObjs, hypervisorObjs, featuredTemplateObjs, communityTemplateObjs, myTemplateObjs, featuredIsoObjs, community, networkObjs; var selectedZoneObj, selectedTemplateObj, selectedHypervisor, selectedDiskOfferingObj; - var step5ContainerType = 'nothing-to-select'; //'nothing-to-select', 'select-network', 'select-security-group', 'select-advanced-sg'(advanced sg-enabled zone) + var step6ContainerType = 'nothing-to-select'; //'nothing-to-select', 'select-network', 'select-security-group', 'select-advanced-sg'(advanced sg-enabled zone) cloudStack.instanceWizard = { maxDiskOfferingSize: function() { @@ -68,492 +68,493 @@ // Data providers for each wizard step steps: [ - - // Step 1: Setup - function(args) { - if(args.initArgs.pluginForm != null && args.initArgs.pluginForm.name == "vpcTierInstanceWizard") { //from VPC Tier chart (VPC is only available in Advanced zone) - if(args.context.zoneType == 'Basic'){ //Basic type - zoneObjs = []; + // Step 1: Setup + function(args) { + if(args.initArgs.pluginForm != null && args.initArgs.pluginForm.name == "vpcTierInstanceWizard") { //from VPC Tier chart + //populate only one zone to the dropdown, the zone which the VPC is under. + zoneObjs = [{ + id: args.context.vpc[0].zoneid, + name: args.context.vpc[0].zonename, + networktype: 'Advanced' + }]; + args.response.success({ data: {zones: zoneObjs}}); + } + else { //from Instance page + $.ajax({ + url: createURL("listZones&available=true"), + dataType: "json", + async: false, + success: function(json) { + zoneObjs = json.listzonesresponse.zone; + args.response.success({ data: {zones: zoneObjs}}); + } + }); + } + }, + + // Step 2: Select template + function(args) { + $(zoneObjs).each(function(){ + if(this.id == args.currentData.zoneid) { + selectedZoneObj = this; + return false; //break the $.each() loop + } + }); + if(selectedZoneObj == null) { + alert("error: can't find matched zone object"); + return; } - else { //Advanced type or all types - //populate only one zone to the dropdown, the zone which the VPC is under. (networktype should be 'Advanced' since VPC is only available in Advanced zone) - zoneObjs = [{ - id: args.context.vpc[0].zoneid, - name: args.context.vpc[0].zonename, - networktype: 'Advanced' - }]; - } - args.response.success({ data: {zones: zoneObjs}}); - } - else { //from Instance page - $.ajax({ - url: createURL("listZones&available=true"), - dataType: "json", - async: false, - success: function(json) { - if(args.context.zoneType == null || args.context.zoneType == '') { //all types - zoneObjs = json.listzonesresponse.zone; + + $.ajax({ + url: createURL("listHypervisors&zoneid="+args.currentData.zoneid), + dataType: "json", + async: false, + success: function(json) { + hypervisorObjs = json.listhypervisorsresponse.hypervisor; + } + }); + + //***** get templates/ISOs (begin) ***** + var selectedTemplate = args.currentData['select-template']; + if (selectedTemplate == 'select-template') { + var hypervisorArray = []; + $(hypervisorObjs).each(function(index, item) { + hypervisorArray.push(item.name); + }); + + $.ajax({ + url: createURL("listTemplates&templatefilter=featured&zoneid="+args.currentData.zoneid), + dataType: "json", + async: false, + success: function(json) { + if(json.listtemplatesresponse.template == null) { + featuredTemplateObjs = null; + } + else { + featuredTemplateObjs = $.grep(json.listtemplatesresponse.template, function(item, index) { + if($.inArray(item.hypervisor, hypervisorArray) > -1) + return true; + }); + } } - else { //Basic type or Advanced type - zoneObjs = []; - var items = json.listzonesresponse.zone; - if(items != null) { - for(var i = 0; i < items.length; i++) { - if(items[i].networktype == args.context.zoneType) - zoneObjs.push(items[i]); - } - } - } - args.response.success({ data: {zones: zoneObjs}}); - } - }); - } - }, - - // Step 2: Select template - function(args) { - $(zoneObjs).each(function(){ - if(this.id == args.currentData.zoneid) { - selectedZoneObj = this; - return false; //break the $.each() loop - } - }); - if(selectedZoneObj == null) { - alert("error: can't find matched zone object"); - return; - } - - $.ajax({ - url: createURL("listHypervisors&zoneid="+args.currentData.zoneid), - dataType: "json", - async: false, - success: function(json) { - hypervisorObjs = json.listhypervisorsresponse.hypervisor; - } - }); - - //***** get templates/ISOs (begin) ***** - var selectedTemplate = args.currentData['select-template']; - if (selectedTemplate == 'select-template') { - var hypervisorArray = []; - $(hypervisorObjs).each(function(index, item) { - hypervisorArray.push(item.name); - }); - - $.ajax({ - url: createURL("listTemplates&templatefilter=featured&zoneid="+args.currentData.zoneid), - dataType: "json", - async: false, - success: function(json) { - if(json.listtemplatesresponse.template == null) { - featuredTemplateObjs = null; - } - else { - featuredTemplateObjs = $.grep(json.listtemplatesresponse.template, function(item, index) { - if($.inArray(item.hypervisor, hypervisorArray) > -1) - return true; - }); - } - } - }); - $.ajax({ - url: createURL("listTemplates&templatefilter=community&zoneid="+args.currentData.zoneid), - dataType: "json", - async: false, - success: function(json) { - if(json.listtemplatesresponse.template == null) { - communityTemplateObjs = null; - } - else { - communityTemplateObjs = $.grep(json.listtemplatesresponse.template, function(item, index) { - if($.inArray(item.hypervisor, hypervisorArray) > -1) - return true; - }); - } - } - }); - $.ajax({ - url: createURL("listTemplates&templatefilter=selfexecutable&zoneid="+args.currentData.zoneid), - dataType: "json", - async: false, - success: function(json) { - if(json.listtemplatesresponse.template == null) { - myTemplateObjs = null; - } - else { - myTemplateObjs = $.grep(json.listtemplatesresponse.template, function(item, index) { - if($.inArray(item.hypervisor, hypervisorArray) > -1) - return true; - }); - } - } - }); - } else if (selectedTemplate == 'select-iso') { - $.ajax({ - url: createURL("listIsos&isofilter=featured&zoneid=" + args.currentData.zoneid + "&bootable=true"), - dataType: "json", - async: false, - success: function(json) { - if(json.listisosresponse.iso == null) { - featuredIsoObjs = null; - } - else { - featuredIsoObjs = json.listisosresponse.iso; - } - } - }); - $.ajax({ - url: createURL("listIsos&isofilter=community&zoneid=" + args.currentData.zoneid + "&bootable=true"), - dataType: "json", - async: false, - success: function(json) { - if(json.listisosresponse.iso == null) { - communityIsoObjs = null; - } - else { - communityIsoObjs = json.listisosresponse.iso; - } - } - }); - $.ajax({ - url: createURL("listIsos&isofilter=selfexecutable&zoneid=" + args.currentData.zoneid + "&bootable=true"), - dataType: "json", - async: false, - success: function(json) { - if(json.listisosresponse.iso == null) { - myIsoObjs = null; - } - else { - myIsoObjs = json.listisosresponse.iso; - } - } - }); - } - //***** get templates/ISOs (end) ***** - - - var templatesObj = {}; - if (selectedTemplate == 'select-template') { - templatesObj = { - featuredtemplates: featuredTemplateObjs, - communitytemplates: communityTemplateObjs, - mytemplates: myTemplateObjs - } - } else if (selectedTemplate == 'select-iso') { - templatesObj = { - featuredisos: featuredIsoObjs, - communityisos: communityIsoObjs, - myisos: myIsoObjs - } - } - args.response.success({ - hypervisor: { - idField: 'name', - nameField: 'name' - }, - data: { - templates: templatesObj, - hypervisors: hypervisorObjs - } - }); - }, - - // Step 3: Service offering - function(args) { - if(args.currentData["select-template"] == "select-template") { - if(featuredTemplateObjs != null && featuredTemplateObjs.length > 0) { - for(var i=0; i < featuredTemplateObjs.length; i++) { - if(featuredTemplateObjs[i].id == args.currentData.templateid) { - selectedTemplateObj = featuredTemplateObjs[i]; - break; + }); + $.ajax({ + url: createURL("listTemplates&templatefilter=community&zoneid="+args.currentData.zoneid), + dataType: "json", + async: false, + success: function(json) { + if(json.listtemplatesresponse.template == null) { + communityTemplateObjs = null; + } + else { + communityTemplateObjs = $.grep(json.listtemplatesresponse.template, function(item, index) { + if($.inArray(item.hypervisor, hypervisorArray) > -1) + return true; + }); + } } + }); + $.ajax({ + url: createURL("listTemplates&templatefilter=selfexecutable&zoneid="+args.currentData.zoneid), + dataType: "json", + async: false, + success: function(json) { + if(json.listtemplatesresponse.template == null) { + myTemplateObjs = null; + } + else { + myTemplateObjs = $.grep(json.listtemplatesresponse.template, function(item, index) { + if($.inArray(item.hypervisor, hypervisorArray) > -1) + return true; + }); + } + } + }); + } else if (selectedTemplate == 'select-iso') { + $.ajax({ + url: createURL("listIsos&isofilter=featured&zoneid=" + args.currentData.zoneid + "&bootable=true"), + dataType: "json", + async: false, + success: function(json) { + if(json.listisosresponse.iso == null) { + featuredIsoObjs = null; + } + else { + featuredIsoObjs = json.listisosresponse.iso; + } + } + }); + $.ajax({ + url: createURL("listIsos&isofilter=community&zoneid=" + args.currentData.zoneid + "&bootable=true"), + dataType: "json", + async: false, + success: function(json) { + if(json.listisosresponse.iso == null) { + communityIsoObjs = null; + } + else { + communityIsoObjs = json.listisosresponse.iso; + } + } + }); + $.ajax({ + url: createURL("listIsos&isofilter=selfexecutable&zoneid=" + args.currentData.zoneid + "&bootable=true"), + dataType: "json", + async: false, + success: function(json) { + if(json.listisosresponse.iso == null) { + myIsoObjs = null; + } + else { + myIsoObjs = json.listisosresponse.iso; + } + } + }); + } + //***** get templates/ISOs (end) ***** + + + var templatesObj = {}; + if (selectedTemplate == 'select-template') { + templatesObj = { + featuredtemplates: featuredTemplateObjs, + communitytemplates: communityTemplateObjs, + mytemplates: myTemplateObjs + } + } else if (selectedTemplate == 'select-iso') { + templatesObj = { + featuredisos: featuredIsoObjs, + communityisos: communityIsoObjs, + myisos: myIsoObjs } } - if(selectedTemplateObj == null) { - if(communityTemplateObjs != null && communityTemplateObjs.length > 0) { - for(var i=0; i < communityTemplateObjs.length; i++) { - if(communityTemplateObjs[i].id == args.currentData.templateid) { - selectedTemplateObj = communityTemplateObjs[i]; + args.response.success({ + hypervisor: { + idField: 'name', + nameField: 'name' + }, + data: { + templates: templatesObj, + hypervisors: hypervisorObjs + } + }); + }, + + // Step 3: Service offering + function(args) { + if(args.currentData["select-template"] == "select-template") { + if(featuredTemplateObjs != null && featuredTemplateObjs.length > 0) { + for(var i=0; i < featuredTemplateObjs.length; i++) { + if(featuredTemplateObjs[i].id == args.currentData.templateid) { + selectedTemplateObj = featuredTemplateObjs[i]; break; } } } - } - if(selectedTemplateObj == null) { - if(myTemplateObjs != null && myTemplateObjs.length > 0) { - for(var i=0; i < myTemplateObjs.length; i++) { - if(myTemplateObjs[i].id == args.currentData.templateid) { - selectedTemplateObj = myTemplateObjs[i]; - break; - } - } - } - } - if(selectedTemplateObj == null) - alert("unable to find matched template object"); - else - selectedHypervisor = selectedTemplateObj.hypervisor; - } - else { //(args.currentData["select-template"] == "select-iso" - selectedHypervisor = args.currentData.hypervisorid; - } - - $.ajax({ - url: createURL("listServiceOfferings&issystem=false"), - dataType: "json", - async: true, - success: function(json) { - serviceOfferingObjs = json.listserviceofferingsresponse.serviceoffering; - args.response.success({ - data: {serviceOfferings: serviceOfferingObjs} - }); - } - }); - }, - - // Step 4: Data disk offering - function(args) { - var isRequred = (args.currentData["select-template"] == "select-iso"? true: false); - $.ajax({ - url: createURL("listDiskOfferings"), - dataType: "json", - async: true, - success: function(json) { - diskOfferingObjs = json.listdiskofferingsresponse.diskoffering; - args.response.success({ - required: isRequred, - customFlag: 'iscustomized', // Field determines if custom slider is shown - data: {diskOfferings: diskOfferingObjs} - }); - } - }); - }, - - // Step 5: Network - function(args) { - if(diskOfferingObjs != null && diskOfferingObjs.length > 0) { - for(var i=0; i < diskOfferingObjs.length; i++) { - if(diskOfferingObjs[i].id == args.currentData.diskofferingid) { - selectedDiskOfferingObj = diskOfferingObjs[i]; - break; - } - } - } - - if (selectedZoneObj.networktype == "Advanced") { //Advanced zone. Show network list. - var $networkStep = $(".step.network:visible .nothing-to-select"); - var $networkStepContainer = $('.step.network:visible'); - - if(args.initArgs.pluginForm != null && args.initArgs.pluginForm.name == "vpcTierInstanceWizard") { //from VPC Tier chart - step5ContainerType = 'nothing-to-select'; - $networkStep.find("#from_instance_page_1").hide(); - $networkStep.find("#from_instance_page_2").hide(); - $networkStep.find("#from_vpc_tier").text("tier " + args.context.networks[0].name); - $networkStep.find("#from_vpc_tier").show(); - } else { //from Instance page - if(selectedZoneObj.securitygroupsenabled != true) { // Advanced SG-disabled zone - step5ContainerType = 'select-network'; - $networkStep.find("#from_instance_page_1").show(); - $networkStep.find("#from_instance_page_2").show(); - $networkStep.find("#from_vpc_tier").text(""); - $networkStep.find("#from_vpc_tier").hide(); - $networkStepContainer.removeClass('next-use-security-groups'); - } else { // Advanced SG-enabled zone - step5ContainerType = 'select-advanced-sg'; - } - - if ($networkStepContainer.hasClass('next-use-security-groups')) { - $networkStepContainer.removeClass('repeat next-use-security-groups loaded'); - step5ContainerType = 'select-security-group'; - } - } - } - else { //Basic zone. Show securigy group list or nothing(when no SecurityGroup service in guest network) - var includingSecurityGroupService = false; - $.ajax({ - url: createURL("listNetworks&trafficType=Guest&zoneId=" + selectedZoneObj.id), - dataType: "json", - async: false, - success: function(json) { - //basic zone should have only one guest network returned in this API call - var items = json.listnetworksresponse.network; - if(items != null && items.length > 0) { - var networkObj = items[0]; //basic zone has only one guest network - var serviceObjArray = networkObj.service; - for(var k = 0; k < serviceObjArray.length; k++) { - if(serviceObjArray[k].name == "SecurityGroup") { - includingSecurityGroupService = true; + if(selectedTemplateObj == null) { + if(communityTemplateObjs != null && communityTemplateObjs.length > 0) { + for(var i=0; i < communityTemplateObjs.length; i++) { + if(communityTemplateObjs[i].id == args.currentData.templateid) { + selectedTemplateObj = communityTemplateObjs[i]; break; } } } } - }); - - if(includingSecurityGroupService == false || selectedHypervisor == "VMware") { - step5ContainerType = 'nothing-to-select'; - } - else { - step5ContainerType = 'select-security-group'; - } - } - - //step5ContainerType = 'nothing-to-select'; //for testing only, comment it out before checking in - if(step5ContainerType == 'select-network' || step5ContainerType == 'select-advanced-sg') { - var defaultNetworkArray = [], optionalNetworkArray = []; - var networkData = { - zoneId: args.currentData.zoneid, - canusefordeploy: true - }; - - if(selectedZoneObj.networktype == 'Advanced' && selectedZoneObj.securitygroupsenabled == true) { - $.extend(networkData, { - type: 'Shared' - }); - } - - if (!(cloudStack.context.projects && cloudStack.context.projects[0])) { - networkData.domainid = g_domainid; - networkData.account = g_account; - } - - var vpcObjs; - - //listVPCs without account/domainid/listAll parameter will return only VPCs belonging to the current login. That's what should happen in Instances page's VM Wizard. - //i.e. If the current login is root-admin, do not show VPCs belonging to regular-user/domain-admin in Instances page's VM Wizard. - $.ajax({ - url: createURL('listVPCs'), - async: false, - success: function(json) { - vpcObjs = json.listvpcsresponse.vpc ? json.listvpcsresponse.vpc : []; - } - }); - - var networkObjsToPopulate = []; - $.ajax({ - url: createURL('listNetworks'), - data: networkData, - async: false, - success: function(json) { - networkObjs = json.listnetworksresponse.network ? json.listnetworksresponse.network : []; - if(networkObjs.length > 0) { - for(var i = 0; i < networkObjs.length; i++) { - var networkObj = networkObjs[i]; - var includingSecurityGroup = false; - var serviceObjArray = networkObj.service; - for(var k = 0; k < serviceObjArray.length; k++) { - if(serviceObjArray[k].name == "SecurityGroup") { - networkObjs[i].type = networkObjs[i].type + ' (sg)'; - includingSecurityGroup = true; - break; - } - } - - if (networkObj.vpcid) { - networkObj._singleSelect = true; + if(selectedTemplateObj == null) { + if(myTemplateObjs != null && myTemplateObjs.length > 0) { + for(var i=0; i < myTemplateObjs.length; i++) { + if(myTemplateObjs[i].id == args.currentData.templateid) { + selectedTemplateObj = myTemplateObjs[i]; + break; } - - //for Advanced SG-enabled zone, list only SG network offerings - if(selectedZoneObj.networktype == 'Advanced' && selectedZoneObj.securitygroupsenabled == true) { - if(includingSecurityGroup == false) - continue; //skip to next network offering - } - networkObjsToPopulate.push(networkObj); - } - } - } - }); - - $.ajax({ - url: createURL("listNetworkOfferings"), - dataType: "json", - data: { - forvpc: false, - zoneid: args.currentData.zoneid, - guestiptype: 'Isolated', - supportedServices: 'SourceNat', - specifyvlan: false, - state: 'Enabled' - }, - async: false, - success: function(json) { - networkOfferingObjs = json.listnetworkofferingsresponse.networkoffering; - } - }); - //get network offerings (end) *** - - $networkStepContainer.removeClass('repeat next-use-security-groups'); - - if (step5ContainerType == 'select-advanced-sg') { - $networkStepContainer.addClass('repeat next-use-security-groups'); - - // Add guest network is disabled - $networkStepContainer.find('.select-network').addClass('no-add-network'); - } else { - $networkStepContainer.find('.select-network').removeClass('no-add-network'); - } - - args.response.success({ - type: 'select-network', - data: { - networkObjs: networkObjsToPopulate, - securityGroups: [], - networkOfferings: networkOfferingObjs, - vpcs: vpcObjs - } - }); - } - - else if(step5ContainerType == 'select-security-group') { - var securityGroupArray = []; - var data = { - domainid: g_domainid, - account: g_account - }; - - $.ajax({ - url: createURL("listSecurityGroups"), - dataType: "json", - async: false, - data: cloudStack.context.projects ? {} : data, - success: function(json) { - var items = json.listsecuritygroupsresponse.securitygroup; - if (items != null && items.length > 0) { - for (var i = 0; i < items.length; i++) { - securityGroupArray.push(items[i]); } } } - }); - args.response.success({ - type: 'select-security-group', - data: { - networkObjs: [], - securityGroups: securityGroupArray, - networkOfferings: [], - vpcs: [] + if(selectedTemplateObj == null) + alert("unable to find matched template object"); + else + selectedHypervisor = selectedTemplateObj.hypervisor; + } + else { //(args.currentData["select-template"] == "select-iso" + selectedHypervisor = args.currentData.hypervisorid; + } + + $.ajax({ + url: createURL("listServiceOfferings&issystem=false"), + dataType: "json", + async: true, + success: function(json) { + serviceOfferingObjs = json.listserviceofferingsresponse.serviceoffering; + args.response.success({ + data: {serviceOfferings: serviceOfferingObjs} + }); } }); - } + }, - else if(step5ContainerType == 'nothing-to-select') { - args.response.success({ - type: 'nothing-to-select', - data: { - networkObjs: [], - securityGroups: [], - networkOfferings: [], - vpcs: [] + // Step 4: Data disk offering + function(args) { + var isRequred = (args.currentData["select-template"] == "select-iso"? true: false); + $.ajax({ + url: createURL("listDiskOfferings"), + dataType: "json", + async: true, + success: function(json) { + diskOfferingObjs = json.listdiskofferingsresponse.diskoffering; + args.response.success({ + required: isRequred, + customFlag: 'iscustomized', // Field determines if custom slider is shown + data: {diskOfferings: diskOfferingObjs} + }); } }); + }, + + // Step 5: Affinity + function(args) { + $.ajax({ + url: createURL('listAffinityGroups'), + success: function(json) { + var items = json.listaffinitygroupsresponse.affinitygroup; + var data = { + affinityGroups: items + }; + if('affinityGroups' in args.context) { + $.extend(data, { + selectedObj: args.context.affinityGroups[0] + }); + } + args.response.success({data: data}); + } + }); + }, + + // Step 6: Network + function(args) { + if(diskOfferingObjs != null && diskOfferingObjs.length > 0) { + for(var i=0; i < diskOfferingObjs.length; i++) { + if(diskOfferingObjs[i].id == args.currentData.diskofferingid) { + selectedDiskOfferingObj = diskOfferingObjs[i]; + break; + } + } + } + + if (selectedZoneObj.networktype == "Advanced") { //Advanced zone. Show network list. + var $networkStep = $(".step.network:visible .nothing-to-select"); + var $networkStepContainer = $('.step.network:visible'); + + if(args.initArgs.pluginForm != null && args.initArgs.pluginForm.name == "vpcTierInstanceWizard") { //from VPC Tier chart + step6ContainerType = 'nothing-to-select'; + $networkStep.find("#from_instance_page_1").hide(); + $networkStep.find("#from_instance_page_2").hide(); + $networkStep.find("#from_vpc_tier").text("tier " + args.context.networks[0].name); + $networkStep.find("#from_vpc_tier").show(); + } else { //from Instance page + if(selectedZoneObj.securitygroupsenabled != true) { // Advanced SG-disabled zone + step6ContainerType = 'select-network'; + $networkStep.find("#from_instance_page_1").show(); + $networkStep.find("#from_instance_page_2").show(); + $networkStep.find("#from_vpc_tier").text(""); + $networkStep.find("#from_vpc_tier").hide(); + $networkStepContainer.removeClass('next-use-security-groups'); + } else { // Advanced SG-enabled zone + step6ContainerType = 'select-advanced-sg'; + } + + if ($networkStepContainer.hasClass('next-use-security-groups')) { + $networkStepContainer.removeClass('repeat next-use-security-groups loaded'); + step6ContainerType = 'select-security-group'; + } + } + } + else { //Basic zone. Show securigy group list or nothing(when no SecurityGroup service in guest network) + var includingSecurityGroupService = false; + $.ajax({ + url: createURL("listNetworks&trafficType=Guest&zoneId=" + selectedZoneObj.id), + dataType: "json", + async: false, + success: function(json) { + //basic zone should have only one guest network returned in this API call + var items = json.listnetworksresponse.network; + if(items != null && items.length > 0) { + var networkObj = items[0]; //basic zone has only one guest network + var serviceObjArray = networkObj.service; + for(var k = 0; k < serviceObjArray.length; k++) { + if(serviceObjArray[k].name == "SecurityGroup") { + includingSecurityGroupService = true; + break; + } + } + } + } + }); + + if(includingSecurityGroupService == false || selectedHypervisor == "VMware") { + step6ContainerType = 'nothing-to-select'; + } + else { + step6ContainerType = 'select-security-group'; + } + } + + //step6ContainerType = 'nothing-to-select'; //for testing only, comment it out before checking in + if(step6ContainerType == 'select-network' || step6ContainerType == 'select-advanced-sg') { + var defaultNetworkArray = [], optionalNetworkArray = []; + var networkData = { + zoneId: args.currentData.zoneid, + canusefordeploy: true + }; + + if(selectedZoneObj.networktype == 'Advanced' && selectedZoneObj.securitygroupsenabled == true) { + $.extend(networkData, { + type: 'Shared' + }); + } + + if (!(cloudStack.context.projects && cloudStack.context.projects[0])) { + networkData.domainid = g_domainid; + networkData.account = g_account; + } + + var vpcObjs; + + //listVPCs without account/domainid/listAll parameter will return only VPCs belonging to the current login. That's what should happen in Instances page's VM Wizard. + //i.e. If the current login is root-admin, do not show VPCs belonging to regular-user/domain-admin in Instances page's VM Wizard. + $.ajax({ + url: createURL('listVPCs'), + async: false, + success: function(json) { + vpcObjs = json.listvpcsresponse.vpc ? json.listvpcsresponse.vpc : []; + } + }); + + var networkObjsToPopulate = []; + $.ajax({ + url: createURL('listNetworks'), + data: networkData, + async: false, + success: function(json) { + networkObjs = json.listnetworksresponse.network ? json.listnetworksresponse.network : []; + if(networkObjs.length > 0) { + for(var i = 0; i < networkObjs.length; i++) { + var networkObj = networkObjs[i]; + var includingSecurityGroup = false; + var serviceObjArray = networkObj.service; + for(var k = 0; k < serviceObjArray.length; k++) { + if(serviceObjArray[k].name == "SecurityGroup") { + networkObjs[i].type = networkObjs[i].type + ' (sg)'; + includingSecurityGroup = true; + break; + } + } + + if (networkObj.vpcid) { + networkObj._singleSelect = true; + } + + //for Advanced SG-enabled zone, list only SG network offerings + if(selectedZoneObj.networktype == 'Advanced' && selectedZoneObj.securitygroupsenabled == true) { + if(includingSecurityGroup == false) + continue; //skip to next network offering + } + networkObjsToPopulate.push(networkObj); + } + } + } + }); + + $.ajax({ + url: createURL("listNetworkOfferings"), + dataType: "json", + data: { + forvpc: false, + zoneid: args.currentData.zoneid, + guestiptype: 'Isolated', + supportedServices: 'SourceNat', + specifyvlan: false, + state: 'Enabled' + }, + async: false, + success: function(json) { + networkOfferingObjs = json.listnetworkofferingsresponse.networkoffering; + } + }); + //get network offerings (end) *** + + $networkStepContainer.removeClass('repeat next-use-security-groups'); + + if (step6ContainerType == 'select-advanced-sg') { + $networkStepContainer.addClass('repeat next-use-security-groups'); + + // Add guest network is disabled + $networkStepContainer.find('.select-network').addClass('no-add-network'); + } else { + $networkStepContainer.find('.select-network').removeClass('no-add-network'); + } + + args.response.success({ + type: 'select-network', + data: { + networkObjs: networkObjsToPopulate, + securityGroups: [], + networkOfferings: networkOfferingObjs, + vpcs: vpcObjs + } + }); + } + + else if(step6ContainerType == 'select-security-group') { + var securityGroupArray = []; + var data = { + domainid: g_domainid, + account: g_account + }; + + $.ajax({ + url: createURL("listSecurityGroups"), + dataType: "json", + async: false, + data: cloudStack.context.projects ? {} : data, + success: function(json) { + var items = json.listsecuritygroupsresponse.securitygroup; + if (items != null && items.length > 0) { + for (var i = 0; i < items.length; i++) { + securityGroupArray.push(items[i]); + } + } + } + }); + args.response.success({ + type: 'select-security-group', + data: { + networkObjs: [], + securityGroups: securityGroupArray, + networkOfferings: [], + vpcs: [] + } + }); + } + + else if(step6ContainerType == 'nothing-to-select') { + args.response.success({ + type: 'nothing-to-select', + data: { + networkObjs: [], + securityGroups: [], + networkOfferings: [], + vpcs: [] + } + }); + } + + }, + + // Step 7: Review + function(args) { + return false; } - - }, - - // Step 6: Review - function(args) { - return false; - } ], action: function(args) { // Create a new VM!!!! @@ -575,9 +576,25 @@ if(selectedDiskOfferingObj.iscustomized == true) array1.push("&size=" + args.data.size); } + + //step 5: select an affinity group + var checkedAffinityGroupIdArray; + if(typeof(args.data["affinity-groups"]) == "object" && args.data["affinity-groups"].length != null) { //args.data["affinity-groups"] is an array of string, e.g. ["2375f8cc-8a73-4b8d-9b26-50885a25ffe0", "27c60d2a-de7f-4bb7-96e5-a602cec681df","c6301d77-99b5-4e8a-85e2-3ea2ab31c342"], + checkedAffinityGroupIdArray = args.data["affinity-groups"]; + } + else if(typeof(args.data["affinity-groups"]) == "string" && args.data["affinity-groups"].length > 0) { //args.data["affinity-groups"] is a string, e.g. "2375f8cc-8a73-4b8d-9b26-50885a25ffe0" + checkedAffinityGroupIdArray = []; + checkedAffinityGroupIdArray.push(args.data["affinity-groups"]); + } + else { // typeof(args.data["affinity-groups"]) == null + checkedAffinityGroupIdArray = []; + } - //step 5: select network - if (step5ContainerType == 'select-network' || step5ContainerType == 'select-advanced-sg') { + if(checkedAffinityGroupIdArray.length > 0) + array1.push("&affinitygroupids=" + checkedAffinityGroupIdArray.join(",")); + + //step 6: select network + if (step6ContainerType == 'select-network' || step6ContainerType == 'select-advanced-sg') { var array2 = []; var defaultNetworkId = args.data.defaultNetwork; //args.data.defaultNetwork might be equal to string "new-network" or a network ID @@ -640,7 +657,7 @@ array1.push("&networkIds=" + array2.join(",")); } - else if (step5ContainerType == 'select-security-group') { + else if (step6ContainerType == 'select-security-group') { var checkedSecurityGroupIdArray; if(typeof(args.data["security-groups"]) == "object" && args.data["security-groups"].length != null) { //args.data["security-groups"] is an array of string, e.g. ["2375f8cc-8a73-4b8d-9b26-50885a25ffe0", "27c60d2a-de7f-4bb7-96e5-a602cec681df","c6301d77-99b5-4e8a-85e2-3ea2ab31c342"], checkedSecurityGroupIdArray = args.data["security-groups"]; @@ -655,12 +672,12 @@ if(checkedSecurityGroupIdArray.length > 0) array1.push("&securitygroupids=" + checkedSecurityGroupIdArray.join(",")); - + if(selectedZoneObj.networktype == "Advanced" && selectedZoneObj.securitygroupsenabled == true) { // Advanced SG-enabled zone var array2 = []; var myNetworks = $('.multi-wizard:visible form').data('my-networks'); //widget limitation: If using an advanced security group zone, get the guest networks like this var defaultNetworkId = $('.multi-wizard:visible form').find('input[name=defaultNetwork]:checked').val(); - + var checkedNetworkIdArray; if(typeof(myNetworks) == "object" && myNetworks.length != null) { //myNetworks is an array of string, e.g. ["203", "202"], checkedNetworkIdArray = myNetworks; @@ -688,7 +705,7 @@ array1.push("&networkIds=" + array2.join(",")); } } - else if (step5ContainerType == 'nothing-to-select') { + else if (step6ContainerType == 'nothing-to-select') { if(args.context.networks != null) { //from VPC tier array1.push("&networkIds=" + args.context.networks[0].id); array1.push("&domainid=" + args.context.vpc[0].domainid); @@ -720,30 +737,30 @@ var vmid = json.deployvirtualmachineresponse.id; args.response.success( {_custom: - {jobId: jid, - getUpdatedItem: function(json) { - var item = json.queryasyncjobresultresponse.jobresult.virtualmachine; - if (item.password != null) - alert("Password of new VM " + item.displayname + " is " + item.password); - return item; - }, - getActionFilter: function() { - return cloudStack.actionFilter.vmActionFilter; - }, - getUpdatedItemWhenAsyncJobFails: function() { - var item; - $.ajax({ - url: createURL("listVirtualMachines&id="+vmid), - dataType: "json", - async: false, - success: function(json) { - item = json.listvirtualmachinesresponse.virtualmachine[0]; - } - }); - return item; - } - } - } + {jobId: jid, + getUpdatedItem: function(json) { + var item = json.queryasyncjobresultresponse.jobresult.virtualmachine; + if (item.password != null) + alert("Password of new VM " + item.displayname + " is " + item.password); + return item; + }, + getActionFilter: function() { + return cloudStack.actionFilter.vmActionFilter; + }, + getUpdatedItemWhenAsyncJobFails: function() { + var item; + $.ajax({ + url: createURL("listVirtualMachines&id="+vmid), + dataType: "json", + async: false, + success: function(json) { + item = json.listvirtualmachinesresponse.virtualmachine[0]; + } + }); + return item; + } + } + } ); }, error: function(XMLHttpResponse) { diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js index 0c4c7d2172a..c76d843ed6e 100644 --- a/ui/scripts/instances.js +++ b/ui/scripts/instances.js @@ -194,17 +194,17 @@ } if("hosts" in args.context) { - $.extend(data, { - hostid: args.context.hosts[0].id - }); - } - - if(args.context.zoneType != null && args.context.zoneType.length > 0) { //Basic type or Advanced type - $.extend(data, { - zonetype: args.context.zoneType - }); - } - + $.extend(data, { + hostid: args.context.hosts[0].id + }); + } + + if("affinityGroups" in args.context) { + $.extend(data, { + affinitygroupid: args.context.affinityGroups[0].id + }); + } + $.ajax({ url: createURL('listVirtualMachines'), data: data, @@ -223,6 +223,7 @@ viewAll: [ { path: 'storage.volumes', label: 'label.volumes' }, { path: 'vmsnapshots', label: 'label.snapshots' }, + { path: 'affinityGroups', label: 'label.affinity.groups' }, { path: '_zone.hosts', label: 'label.hosts', @@ -426,7 +427,6 @@ poll: pollAsyncJobResult } }, - snapshot: { messages: { notification: function(args) { @@ -489,7 +489,6 @@ pool: pollAsyncJobResult } }, - destroy: { label: 'label.action.destroy.instance', compactLabel: 'label.destroy', @@ -555,7 +554,6 @@ } } }, - reset: { label: 'Reset VM', messages:{ @@ -586,8 +584,128 @@ } } - }, + }, + changeAffinity: { + label: 'Change affinity', + + action: { + custom: cloudStack.uiCustom.affinity({ + tierSelect: function(args) { + if ('vpc' in args.context) { //from VPC section + args.$tierSelect.show(); //show tier dropdown + + $.ajax({ //populate tier dropdown + url: createURL("listNetworks"), + async: false, + data: { + vpcid: args.context.vpc[0].id, + //listAll: true, //do not pass listAll to listNetworks under VPC + domainid: args.context.vpc[0].domainid, + account: args.context.vpc[0].account, + supportedservices: 'StaticNat' + }, + success: function(json) { + var networks = json.listnetworksresponse.network; + var items = [{ id: -1, description: 'Please select a tier' }]; + $(networks).each(function(){ + items.push({id: this.id, description: this.displaytext}); + }); + args.response.success({ data: items }); + } + }); + } + else { //from Guest Network section + args.$tierSelect.hide(); + } + + args.$tierSelect.change(function() { + args.$tierSelect.closest('.list-view').listView('refresh'); + }); + args.$tierSelect.closest('.list-view').listView('refresh'); + }, + + listView: { + listView: { + id: 'affinityGroups', + fields: { + name: { label: 'label.name' }, + type: { label: 'label.type' } + }, + dataProvider: function(args) { + $.ajax({ + url: createURL('listAffinityGroups'), + async: false, //make it sync to avoid dataProvider() being called twice which produces duplicate data + success: function(json) { + var items = []; + var allAffinityGroups = json.listaffinitygroupsresponse.affinitygroup; + var previouslySelectedAffinityGroups = args.context.instances[0].affinitygroup; + if(allAffinityGroups != null) { + for(var i = 0; i < allAffinityGroups.length; i++) { + var isPreviouslySelected = false; + if(previouslySelectedAffinityGroups != null) { + for(var k = 0; k < previouslySelectedAffinityGroups.length; k++) { + if(previouslySelectedAffinityGroups[k].id == allAffinityGroups[i].id) { + isPreviouslySelected = true; + break; //break for loop + } + } + } + items.push($.extend(allAffinityGroups[i], { + _isSelected: isPreviouslySelected + })); + } + } + args.response.success({data: items}); + } + }); + } + } + }, + action: function(args) { + var affinityGroupIdArray = []; + if(args.context.affinityGroups != null) { + for(var i = 0; i < args.context.affinityGroups.length; i++) { + if(args.context.affinityGroups[i]._isSelected == true) { + affinityGroupIdArray.push(args.context.affinityGroups[i].id); + } + } + } + var data = { + id: args.context.instances[0].id, + affinitygroupids: affinityGroupIdArray.join(",") + }; + $.ajax({ + url: createURL('updateVMAffinityGroup'), + data: data, + success: function(json) { + var jid = json.updatevirtualmachineresponse.jobid; + args.response.success( + {_custom: + {jobId: jid, + getUpdatedItem: function(json) { + return json.queryasyncjobresultresponse.jobresult.virtualmachine; + }, + getActionFilter: function() { + return vmActionfilter; + } + } + } + ); + } + }); + } + }) + }, + messages: { + notification: function(args) { + return 'Change affinity'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, edit: { label: 'label.edit', @@ -597,7 +715,7 @@ group: args.data.group, ostypeid: args.data.guestosid }; - + if(args.data.displayname != args.context.instances[0].displayname) { $.extend(data, { displayName: args.data.displayname @@ -816,7 +934,7 @@ var serviceofferings = json.listserviceofferingsresponse.serviceoffering; var items = []; $(serviceofferings).each(function() { - items.push({id: this.id, description: this.displaytext}); + items.push({id: this.id, description: this.name}); }); args.response.success({data: items}); } @@ -1129,9 +1247,9 @@ dataType: "json", async: true, success: function(json) { - var jid = json.scalevirtualmachineresponse.jobid; - args.response.success( - {_custom: + // var jid = json.scalevirtualmachineresponse.jobid; + args.response.success(); + /* {_custom: {jobId: jid, getUpdatedItem: function(json) { return json.queryasyncjobresultresponse.jobresult.virtualmachine; @@ -1140,8 +1258,8 @@ return vmActionfilter; } } - } - ); + } */ + }, error:function(json){ args.response.error(parseXMLHttpResponse(json)); @@ -1310,8 +1428,124 @@ nics: { title: 'label.nics', multiple: true, + actions: { + add: { + label: 'Add network to VM', + messages: { + confirm: function(args) { + return 'Please confirm that you would like to add a new VM NIC for this network.'; + }, + notification: function(args) { + return 'Add network to VM'; + } + }, + createForm: { + title: 'Add network to VM', + desc: 'Please specify the network that you would like to add this VM to. A new NIC will be added for this network.', + fields: { + networkid: { + label: 'label.network', + select: function(args) { + $.ajax({ + url: createURL('listNetworks'), + data: { + listAll: true, + zoneid: args.context.instances[0].zoneid + }, + success: function(json) { + args.response.success({ + data: $.map(json.listnetworksresponse.network, function(network) { + return { + id: network.id, + description: network.name + }; + }) + }); + } + }); + } + } + } + }, + action: function(args) { + $.ajax({ + url: createURL('addNicToVirtualMachine'), + data: { + virtualmachineid: args.context.instances[0].id, + networkid: args.data.networkid + }, + success: function(json) { + args.response.success({ + _custom: { jobId: json.addnictovirtualmachineresponse.jobid } + }); + } + }); + }, + notification: { poll: pollAsyncJobResult } + }, + + makeDefault: { + label: 'Set default NIC', + messages: { + confirm: function() { + return 'Please confirm that you would like to make this NIC the default for this VM.'; + }, + notification: function(args) { + return 'Set default NIC' + } + }, + action: function (args) { + $.ajax({ + url: createURL('updateDefaultNicForVirtualMachine'), + data: { + virtualmachineid: args.context.instances[0].id, + nicid: args.context.nics[0].id + }, + success: function(json) { + args.response.success({ + _custom: { jobId: json.updatedefaultnicforvirtualmachineresponse.jobid } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + // Remove NIC/Network from VM + remove: { + label: 'label.action.delete.nic', + messages: { + confirm: function(args) { + return 'message.action.delete.nic'; + }, + notification: function(args) { + return 'label.action.delete.nic'; + } + }, + action: function(args) { + $.ajax({ + url: createURL('removeNicFromVirtualMachine'), + data: { + virtualmachineid: args.context.instances[0].id, + nicid: args.context.nics[0].id + }, + success: function(json) { + args.response.success({ + _custom: { jobId: json.removenicfromvirtualmachineresponse.jobid } + }) + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, fields: [ { + id: { label: 'ID' }, name: { label: 'label.name', header: true }, networkname: {label: 'Network Name' }, type: { label: 'label.type' }, @@ -1341,26 +1575,33 @@ } }, dataProvider: function(args) { - $.ajax({ - url:createURL("listVirtualMachines&details=nics&id=" + args.context.instances[0].id), - dataType: "json", - async:true, - success:function(json) { - // Handling the display of network name for a VM under the NICS tabs - args.response.success({ - data: $.map(json.listvirtualmachinesresponse.virtualmachine[0].nic, function(nic, index) { - var name = 'NIC ' + (index + 1); - if (nic.isdefault) { - name += ' (' + _l('label.default') + ')'; - } - return $.extend(nic, { + $.ajax({ + url:createURL("listVirtualMachines&details=nics&id=" + args.context.instances[0].id), + dataType: "json", + async:true, + success:function(json) { + // Handling the display of network name for a VM under the NICS tabs + args.response.success({ + actionFilter: function(args) { + if (args.context.item.isdefault) { + return []; + } else { + return ['remove', 'makeDefault']; + } + }, + data: $.map(json.listvirtualmachinesresponse.virtualmachine[0].nic, function(nic, index) { + var name = 'NIC ' + (index + 1); + if (nic.isdefault) { + name += ' (' + _l('label.default') + ')'; + } + return $.extend(nic, { name: name - }); - }) - }); - } - }); - } + }); + }) + }); + } + }); + } }, /** @@ -1377,10 +1618,19 @@ } ], dataProvider: function(args) { - args.response.success({data: args.context.instances[0].securitygroup}); + // args.response.success({data: args.context.instances[0].securitygroup}); + $.ajax({ + url:createURL("listVirtualMachines&details=secgrp&id=" + args.context.instances[0].id), + dataType: "json", + async:true, + success:function(json) { + args.response.success({data: json.listvirtualmachinesresponse.virtualmachine[0].securitygroup}); + } + + }); } }, - + /** * Statistics tab */ @@ -1393,15 +1643,22 @@ networkkbswrite: { label: 'label.network.write' } }, dataProvider: function(args) { - var jsonObj = args.context.instances[0]; - args.response.success({ + $.ajax({ + url:createURL("listVirtualMachines&details=stats&id=" + args.context.instances[0].id), + dataType: "json", + async:true, + success:function(json) { + var jsonObj = json.listvirtualmachinesresponse.virtualmachine[0]; + args.response.success({ data: { totalCPU: jsonObj.cpunumber + " x " + cloudStack.converters.convertHz(jsonObj.cpuspeed), cpuused: jsonObj.cpuused, networkkbsread: (jsonObj.networkkbsread == null)? "N/A": cloudStack.converters.convertBytes(jsonObj.networkkbsread * 1024), networkkbswrite: (jsonObj.networkkbswrite == null)? "N/A": cloudStack.converters.convertBytes(jsonObj.networkkbswrite * 1024) - } - }); + } + }); + } + }); } } } @@ -1450,6 +1707,7 @@ allowedActions.push("reset"); allowedActions.push("snapshot"); allowedActions.push("scaleUp"); + allowedActions.push("changeAffinity"); if(isAdmin()) allowedActions.push("migrateToAnotherStorage"); diff --git a/ui/scripts/network.js b/ui/scripts/network.js index 9ba725a8574..6b310ce0e83 100755 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -3981,13 +3981,12 @@ account: args.context.securityGroups[0].account }; - // TCP / ICMP if (args.data.icmptype && args.data.icmpcode) { // ICMP $.extend(data, { icmptype: args.data.icmptype, icmpcode: args.data.icmpcode }); - } else { // TCP + } else { // TCP/UDP $.extend(data, { startport: args.data.startport, endport: args.data.endport @@ -4081,121 +4080,142 @@ egressRules: { title: 'label.egress.rule', - custom: function(args) { - var context = args.context; + custom: cloudStack.uiCustom.securityRules({ + noSelect: true, + noHeaderActionsColumn: true, + fields: { + 'protocol': { + label: 'label.protocol', + select: function(args) { + args.$select.change(function() { + var $inputs = args.$form.find('th, td'); + var $icmpFields = $inputs.filter(function() { + var name = $(this).attr('rel'); - return $('
    ').multiEdit({ - context: context, - noSelect: true, - noHeaderActionsColumn: true, - fields: { - 'cidrlist': { edit: true, label: 'label.cidr' }, - 'protocol': { - label: 'label.protocol', - select: function(args) { - args.$select.change(function() { - var $inputs = args.$form.find('th, td'); - var $icmpFields = $inputs.filter(function() { - var name = $(this).attr('rel'); + return $.inArray(name, [ + 'icmptype', + 'icmpcode' + ]) > -1; + }); + var $otherFields = $inputs.filter(function() { + var name = $(this).attr('rel'); - return $.inArray(name, [ - 'icmptype', - 'icmpcode' - ]) > -1; - }); - var $otherFields = $inputs.filter(function() { - var name = $(this).attr('rel'); - - return name != 'cidrlist' && - name != 'icmptype' && - name != 'icmpcode' && - name != 'protocol' && - name != 'add-rule'; - }); - - if ($(this).val() == 'icmp') { - $icmpFields.show(); - $otherFields.hide(); - } else { - $icmpFields.hide(); - $otherFields.show(); - } + return name != 'icmptype' && + name != 'icmpcode' && + name != 'protocol' && + name != 'add-rule' && + name != 'cidr' && + name != 'accountname' && + name != 'securitygroup'; }); - args.response.success({ - data: [ - { name: 'tcp', description: 'TCP' }, - { name: 'udp', description: 'UDP' }, - { name: 'icmp', description: 'ICMP' } - ] - }); - } - }, - 'startport': { edit: true, label: 'label.start.port' }, - 'endport': { edit: true, label: 'label.end.port' }, - 'icmptype': { edit: true, label: 'ICMP.type', isHidden: true }, - 'icmpcode': { edit: true, label: 'ICMP.code', isHidden: true }, - 'add-rule': { - label: 'label.add', - addButton: true - } - }, - add: { - label: 'label.add', - action: function(args) { - var data = { - protocol: args.data.protocol, - cidrlist: args.data.cidrlist, - trafficType: 'Egress' - }; - - if (args.data.icmptype && args.data.icmpcode) { // ICMP - $.extend(data, { - icmptype: args.data.icmptype, - icmpcode: args.data.icmpcode - }); - } else { // TCP/UDP - $.extend(data, { - startport: args.data.startport, - endport: args.data.endport - }); - } - - // Get Source NAT IP - var sourceNATIP; - - $.ajax({ - url: createURL('listPublicIpAddresses'), - data: { - listAll: true, - associatednetworkid: args.context.networks[0].id - }, - async: false, - success: function(json) { - var ipAddresses = json.listpublicipaddressesresponse.publicipaddress; - - sourceNATIP = $.grep(ipAddresses, function(ipAddress) { - return ipAddress.issourcenat; - })[0]; + if ($(this).val() == 'icmp') { + $icmpFields.show(); + $otherFields.hide(); + } else { + $icmpFields.hide(); + $otherFields.show(); } }); - data.ipaddressid = sourceNATIP.id; + args.response.success({ + data: [ + { name: 'tcp', description: 'TCP' }, + { name: 'udp', description: 'UDP' }, + { name: 'icmp', description: 'ICMP' } + ] + }); + } + }, + 'startport': { edit: true, label: 'label.start.port' }, + 'endport': { edit: true, label: 'label.end.port' }, + 'icmptype': { edit: true, label: 'ICMP.type', isHidden: true }, + 'icmpcode': { edit: true, label: 'ICMP.code', isHidden: true }, + 'cidr': { edit: true, label: 'label.cidr', isHidden: true }, + 'accountname': { + edit: true, + label: 'label.account.and.security.group', + isHidden: true, + range: ['accountname', 'securitygroup'] + }, + 'add-rule': { + label: 'label.add', + addButton: true + } + }, + add: { + label: 'label.add', + action: function(args) { + var data = { + securitygroupid: args.context.securityGroups[0].id, + protocol: args.data.protocol, + domainid: args.context.securityGroups[0].domainid, + account: args.context.securityGroups[0].account + }; + if (args.data.icmptype && args.data.icmpcode) { // ICMP + $.extend(data, { + icmptype: args.data.icmptype, + icmpcode: args.data.icmpcode + }); + } else { // TCP/UDP + $.extend(data, { + startport: args.data.startport, + endport: args.data.endport + }); + } + + // CIDR / account + if (args.data.cidr) { + data.cidrlist = args.data.cidr; + } else { + data['usersecuritygrouplist[0].account'] = args.data.accountname; + data['usersecuritygrouplist[0].group'] = args.data.securitygroup; + } + + $.ajax({ + url: createURL('authorizeSecurityGroupEgress'), + data: data, + dataType: 'json', + async: true, + success: function(data) { + var jobId = data.authorizesecuritygroupegressresponse.jobid; + + args.response.success({ + _custom: { + jobId: jobId + }, + notification: { + label: 'label.add.egress.rule', + poll: pollAsyncJobResult + } + }); + } + }); + } + }, + actions: { + destroy: { + label: 'label.remove.rule', + action: function(args) { $.ajax({ - url: createURL('createFirewallRule'), - data: data, + url: createURL('revokeSecurityGroupEgress'), + data: { + domainid: args.context.securityGroups[0].domainid, + account: args.context.securityGroups[0].account, + id: args.context.multiRule[0].id + }, dataType: 'json', async: true, - success: function(json) { - var jobId = json.createfirewallruleresponse.jobid; + success: function(data) { + var jobID = data.revokesecuritygroupegress.jobid; args.response.success({ _custom: { - jobId: jobId + jobId: jobID }, notification: { - label: 'label.add.egress.rule', + label: 'label.remove.egress.rule', poll: pollAsyncJobResult } }); @@ -4205,60 +4225,29 @@ } }); } - }, - actions: { - destroy: { - label: 'label.remove.rule', - action: function(args) { - $.ajax({ - url: createURL('deleteFirewallRule'), - data: { - id: args.context.multiRule[0].id - }, - dataType: 'json', - async: true, - success: function(data) { - var jobID = data.deletefirewallruleresponse.jobid; - - args.response.success({ - _custom: { - jobId: jobID - }, - notification: { - label: 'label.remove.egress.rule', - poll: pollAsyncJobResult - } - }); - }, - error: function(json) { - args.response.error(parseXMLHttpResponse(json)); - } - }); - } - } - }, - ignoreEmptyFields: true, - dataProvider: function(args) { - $.ajax({ - url: createURL('listFirewallRules'), - data: { - listAll: true, - networkid: args.context.networks[0].id, - trafficType: 'Egress' - }, - dataType: 'json', - async: true, - success: function(json) { - var response = json.listfirewallrulesresponse.firewallrule; - - args.response.success({ - data: response - }); - } - }); } - }); - } + }, + ignoreEmptyFields: true, + dataProvider: function(args) { + $.ajax({ + url: createURL('listSecurityGroups'), + data: { + id: args.context.securityGroups[0].id + }, + dataType: 'json', + async: true, + success: function(data) { + args.response.success({ + data: $.map( + data.listsecuritygroupsresponse.securitygroup[0].egressrule ? + data.listsecuritygroupsresponse.securitygroup[0].egressrule : [], + ingressEgressDataMap + ) + }); + } + }); + } + }) } }, diff --git a/ui/scripts/plugins.js b/ui/scripts/plugins.js index 122f4a03491..6a886ba0ae6 100644 --- a/ui/scripts/plugins.js +++ b/ui/scripts/plugins.js @@ -20,15 +20,20 @@ } var loadCSS = function(path) { - var $link = $(''); + if (document.createStyleSheet) { + // IE-compatible CSS loading + document.createStyleSheet(path); + } else { + var $link = $(''); - $link.attr({ - rel: 'stylesheet', - type: 'text/css', - href: path - }); + $link.attr({ + rel: 'stylesheet', + type: 'text/css', + href: path + }); - $('head').append($link); + $('html head').append($link); + } }; $.extend(cloudStack.pluginAPI, { diff --git a/ui/scripts/regions.js b/ui/scripts/regions.js index 334eb267bd8..2bbbbeea672 100644 --- a/ui/scripts/regions.js +++ b/ui/scripts/regions.js @@ -461,18 +461,27 @@ id: 'lbUnderGSLB', label: 'assigned load balancing', fields: { - 'name': { label: 'label.name' }, + name: { label: 'label.name' }, publicport: { label: 'label.public.port' }, - privateport: { label: 'label.private.port' }, - algorithm: { label: 'label.algorithm' } + privateport: { label: 'label.private.port' }, + algorithm: { label: 'label.algorithm' } }, - dataProvider: function(args) { - var items = args.context.GSLB[0].loadbalancerrule; - args.response.success({ - data: items - }); + dataProvider: function(args) { + var data = { + id: args.context.GSLB[0].id + }; + $.ajax({ + url: createURL('listGlobalLoadBalancerRules'), + data: data, + success: function(json) { + var items = json.listgloballoadbalancerrulesresponse.globalloadbalancerrule[0].loadbalancerrule; + args.response.success({ + data: items + }); + } + }); }, - actions: { + actions: { add: { label: 'assign more load balancing', messages: { diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js index 74675314040..a01840637e3 100644 --- a/ui/scripts/sharedFunctions.js +++ b/ui/scripts/sharedFunctions.js @@ -114,6 +114,10 @@ function createURL(apiName, options) { if (cloudStack.context && cloudStack.context.projects && !options.ignoreProject) { urlString = urlString + '&projectid=' + cloudStack.context.projects[0].id; } + + if(cloudStack.context != null && cloudStack.context.zoneType != null && cloudStack.context.zoneType.length > 0) { //Basic type or Advanced type + urlString = urlString + '&zonetype=' + cloudStack.context.zoneType; + } return urlString; } diff --git a/ui/scripts/storage.js b/ui/scripts/storage.js index cf4076945ac..e81633466bc 100644 --- a/ui/scripts/storage.js +++ b/ui/scripts/storage.js @@ -89,20 +89,7 @@ dataType: "json", async: true, success: function(json) { - var zoneObjs; - if(args.context.zoneType == null || args.context.zoneType == '') { //all types - zoneObjs = json.listzonesresponse.zone; - } - else { //Basic type or Advanced type - zoneObjs = []; - var items = json.listzonesresponse.zone; - if(items != null) { - for(var i = 0; i < items.length; i++) { - if(items[i].networktype == args.context.zoneType) - zoneObjs.push(items[i]); - } - } - } + var zoneObjs = json.listzonesresponse.zone; args.response.success({descriptionField: 'name', data: zoneObjs}); } }); @@ -227,20 +214,7 @@ dataType: "json", async: true, success: function(json) { - var zoneObjs; - if(args.context.zoneType == null || args.context.zoneType == '') { //all types - zoneObjs = json.listzonesresponse.zone; - } - else { //Basic type or Advanced type - zoneObjs = []; - var items = json.listzonesresponse.zone; - if(items != null) { - for(var i = 0; i < items.length; i++) { - if(items[i].networktype == args.context.zoneType) - zoneObjs.push(items[i]); - } - } - } + var zoneObjs = json.listzonesresponse.zone; args.response.success({descriptionField: 'name', data: zoneObjs}); } }); @@ -398,18 +372,12 @@ if(args.context != null) { if("instances" in args.context) { - $.extend(data, { - virtualMachineId: args.context.instances[0].id - }); + $.extend(data, { + virtualMachineId: args.context.instances[0].id + }); } } - - if(args.context.zoneType != null && args.context.zoneType.length > 0) { //Basic type or Advanced type - $.extend(data, { - zonetype: args.context.zoneType - }); - } - + $.ajax({ url: createURL('listVolumes'), data: data, @@ -1056,7 +1024,7 @@ }, action: function(args) { $.ajax({ - url: createURL("migrateVolume&storageid=" + args.data.storagePool + "&volumeid=" + args.context.volumes[0].id), + url: createURL("migrateVolume&storageid=" + args.data.storageId + "&volumeid=" + args.context.volumes[0].id), dataType: "json", async: true, success: function(json) { @@ -1644,7 +1612,7 @@ if(jsonObj.hypervisor != "Ovm" && jsonObj.state == "Ready") { allowedActions.push("takeSnapshot"); allowedActions.push("recurringSnapshot"); - if((jsonObj.hypervisor == "XenServer" || jsonObj.hypervisor == "KVM" || jsonObj.hypervisor == "VMware") && jsonObj.type == "DATADISK") { + if(jsonObj.type == "DATADISK") { allowedActions.push("resize"); } } diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 8f07ee46251..34ba64c917d 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -184,9 +184,9 @@ dashboard: { dataProvider: function(args) { var dataFns = { - zoneCount: function(data) { + zoneCount: function(data) { $.ajax({ - url: createURL('listZones'), + url: createURL('listZones'), success: function(json) { dataFns.podCount($.extend(data, { zoneCount: json.listzonesresponse.count ? @@ -239,13 +239,14 @@ }, hostCount: function(data) { + var data2= { + type: 'routing', + page: 1, + pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. + }; $.ajax({ url: createURL('listHosts'), - data: { - type: 'routing', - page: 1, - pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. - }, + data: data2, success: function(json) { dataFns.primaryStorageCount($.extend(data, { hostCount: json.listhostsresponse.count ? @@ -256,29 +257,30 @@ }, primaryStorageCount: function(data) { + var data2 = { + page: 1, + pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. + }; $.ajax({ url: createURL('listStoragePools'), - data: { - page: 1, - pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. - }, + data: data2, success: function(json) { - dataFns.secondaryStorageCount($.extend(data, { - primaryStorageCount: json.liststoragepoolsresponse.count ? - json.liststoragepoolsresponse.count : 0 + dataFns.secondaryStorageCount($.extend(data, { + primaryStorageCount: json.liststoragepoolsresponse.count ? json.liststoragepoolsresponse.count : 0 })); } }); }, secondaryStorageCount: function(data) { + var data2 = { + type: 'SecondaryStorage', + page: 1, + pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. + }; $.ajax({ url: createURL('listHosts'), - data: { - type: 'SecondaryStorage', - page: 1, - pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. - }, + data: data2, success: function(json) { dataFns.systemVmCount($.extend(data, { secondaryStorageCount: json.listhostsresponse.count ? @@ -305,22 +307,25 @@ }, virtualRouterCount: function(data) { + var data2 = { + projectid: -1, + page: 1, + pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. + }; $.ajax({ url: createURL('listRouters'), - data: { - projectid: -1, - page: 1, - pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. - }, + data: data2, success: function(json) { - var total1 = json.listroutersresponse.count ? json.listroutersresponse.count : 0; + var total1 = json.listroutersresponse.count ? json.listroutersresponse.count : 0; + + var data3 = { + listAll: true, + page: 1, + pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. + }; $.ajax({ url: createURL('listRouters'), - data: { - listAll: true, - page: 1, - pagesize: 1 //specifying pagesize as 1 because we don't need any embedded objects to be returned here. The only thing we need from API response is "count" property. - }, + data: data3, success: function(json) { var total2 = json.listroutersresponse.count ? json.listroutersresponse.count : 0; dataFns.capacity($.extend(data, { @@ -1013,12 +1018,7 @@ dataType: "json", success: function(json) { var jobId = json.updatephysicalnetworkresponse.jobid; - - var trafficType = getTrafficType(selectedPhysicalNetworkObj, 'Guest'); - - updateTrafficLabels(trafficType, args.data, function() { args.response.success({ _custom: { jobId: jobId }}); - }); }, error:function(json){ @@ -1066,10 +1066,7 @@ dataType: "json", success: function(json) { var jobId = json.updatephysicalnetworkresponse.jobid; - var trafficType = getTrafficType(selectedPhysicalNetworkObj, 'Guest'); - updateTrafficLabels(trafficType, args.data, function() { args.response.success({ _custom: { jobId: jobId }}); - }); }, error:function(json){ @@ -2293,12 +2290,13 @@ } } + var data2 = { + forvpc: false + }; var routers = []; $.ajax({ url: createURL("listRouters&zoneid=" + selectedZoneObj.id + "&listAll=true&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), - data: { - forvpc: false - }, + data: data2, success: function(json) { var items = json.listroutersresponse.router ? json.listroutersresponse.router : []; @@ -2310,9 +2308,7 @@ // Get project routers $.ajax({ url: createURL("listRouters&zoneid=" + selectedZoneObj.id + "&listAll=true&page=" + args.page + "&pagesize=" + pageSize + array1.join("") + "&projectid=-1"), - data: { - forvpc: false - }, + data: data2, success: function(json) { var items = json.listroutersresponse.router ? json.listroutersresponse.router : []; @@ -2774,13 +2770,14 @@ } } + var data2 = { + forvpc: true + }; var routers = []; $.ajax({ url: createURL("listRouters&zoneid=" + selectedZoneObj.id + "&listAll=true&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), dataType: 'json', - data: { - forvpc: true - }, + data: data2, async: true, success: function(json) { var items = json.listroutersresponse.router; @@ -2792,9 +2789,7 @@ $.ajax({ url: createURL("listRouters&zoneid=" + selectedZoneObj.id + "&listAll=true&page=" + args.page + "&pagesize=" + pageSize + array1.join("") + "&projectid=-1"), dataType: 'json', - data: { - forvpc: true - }, + data: data2, async: true, success: function(json) { var items = json.listroutersresponse.router; @@ -4663,8 +4658,7 @@ break; } } - } - + } $.ajax({ url: createURL("listZones&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), dataType: "json", @@ -4926,8 +4920,11 @@ async: true, success: function(json) { args.response.success({data:{}}); - } - }); + }, + error:function(json){ + args.response.error(parseXMLHttpResponse(json)); + } + }); }, notification: { poll: function(args) { args.complete(); } @@ -5000,8 +4997,8 @@ localstorageenabled: { label: 'label.local.storage.enabled', isBoolean: true, - isEditable: true, - converter:cloudStack.converters.toBooleanText + isEditable: true, + converter:cloudStack.converters.toBooleanText } } ], @@ -5375,6 +5372,83 @@ poll: pollAsyncJobResult } }, + + scaleUp:{ + label:'scaleUp System VM', + createForm: { + title: 'label.change.service.offering', + desc: '', + fields: { + serviceOfferingId: { + label: 'label.compute.offering', + select: function(args) { + var apiCmd = "listServiceOfferings&issystem=true"; + if(args.context.systemVMs[0].systemvmtype == "secondarystoragevm") + apiCmd += "&systemvmtype=secondarystoragevm"; + else if(args.context.systemVMs[0].systemvmtype == "consoleproxy") + apiCmd += "&systemvmtype=consoleproxy"; + $.ajax({ + url: createURL(apiCmd), + dataType: "json", + async: true, + success: function(json) { + var serviceofferings = json.listserviceofferingsresponse.serviceoffering; + var items = []; + $(serviceofferings).each(function() { + if(this.id != args.context.systemVMs[0].serviceofferingid) { + items.push({id: this.id, description: this.name}); + } + }); + args.response.success({data: items}); + } + }); + } + } + } + }, + + action: function(args) { + $.ajax({ + url: createURL("scaleVirtualMachine&id=" + args.context.systemVMs[0].id + "&serviceofferingid=" + args.data.serviceOfferingId), + dataType: "json", + async: true, + success: function(json) { + // var jid = json.scalevirtualmachineresponse.jobid; + args.response.success(); + /* {_custom: + {jobId: jid, + getUpdatedItem: function(json) { + return json.queryasyncjobresultresponse.jobresult.virtualmachine; + }, + getActionFilter: function() { + return vmActionfilter; + } + + } + } */ + + }, + error:function(json){ + args.response.error(parseXMLHttpResponse(json)); + } + + }); + }, + messages: { + confirm: function(args) { + return 'Do you really want to scale up the system VM ?'; + }, + notification: function(args) { + + return 'System VM Scaled Up'; + } + }, + notification: { + poll: pollAsyncJobResult + } + + }, + viewConsole: { label: 'label.view.console', @@ -5440,6 +5514,55 @@ } } } + }, + + // Granular settings for zone + settings: { + title: 'Settings', + custom: cloudStack.uiCustom.granularSettings({ + dataProvider: function(args) { + $.ajax({ + url:createURL('listConfigurations&zoneid=' + args.context.physicalResources[0].id), + data: { page: args.page, pageSize: pageSize, listAll: true }, + success:function(json){ + args.response.success({ + data:json.listconfigurationsresponse.configuration + + }); + + }, + + error:function(json){ + args.response.error(parseXMLHttpResponse(json)); + + } + }); + + }, + actions: { + edit: function(args) { + // call updateZoneLevelParamter + var data = { + name: args.data.jsonObj.name, + value: args.data.value + }; + + $.ajax({ + url:createURL('updateConfiguration&zoneid=' + args.context.physicalResources[0].id), + data:data, + success:function(json){ + var item = json.updateconfigurationresponse.configuration; + args.response.success({data:item}); + }, + + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + } + } + }) } } } @@ -5534,9 +5657,16 @@ var searchByArgs = args.filterBy.search.value.length ? '&name=' + args.filterBy.search.value : ''; + var data = { + page: args.page, + pageSize: pageSize, + type: 'routing', + listAll: true + }; + $.ajax({ url: createURL('listHosts' + searchByArgs), - data: { page: args.page, pageSize: pageSize, type: 'routing', listAll: true }, + data: data, success: function (json) { args.response.success({ data: json.listhostsresponse.host }); }, @@ -5581,11 +5711,7 @@ pageSize: pageSize, listAll: true }; - if(args.context.zoneType != null && args.context.zoneType.length > 0) { //Basic type or Advanced type - $.extend(data, { - zonetype: args.context.zoneType - }); - } + $.ajax({ url: createURL('listStoragePools' + searchByArgs), data: data, @@ -5628,9 +5754,16 @@ var searchByArgs = args.filterBy.search.value.length ? '&name=' + args.filterBy.search.value : ''; + var data = { + type: 'SecondaryStorage', + page: args.page, + pageSize: pageSize, + listAll: true + }; + $.ajax({ url: createURL('listHosts' + searchByArgs), - data: { type: 'SecondaryStorage', page: args.page, pageSize: pageSize, listAll: true }, + data: data, success: function (json) { args.response.success({ data: json.listhostsresponse.host }); }, @@ -5710,12 +5843,11 @@ var listView = $.extend(true, {}, cloudStack.sections.system.subsections.virtualRouters.listView, { dataProvider: function (args) { var searchByArgs = args.filterBy.search.value.length ? - '&name=' + args.filterBy.search.value : ''; - + '&name=' + args.filterBy.search.value : ''; + var routers = []; $.ajax({ - url: createURL("listRouters&listAll=true&page=" + args.page + "&pagesize=" + pageSize + searchByArgs), - dataType: 'json', + url: createURL("listRouters&listAll=true&page=" + args.page + "&pagesize=" + pageSize + searchByArgs), async: true, success: function(json) { var items = json.listroutersresponse.router ? @@ -5727,8 +5859,7 @@ // Get project routers $.ajax({ - url: createURL("listRouters&listAll=true&page=" + args.page + "&pagesize=" + pageSize + "&projectid=-1"), - dataType: 'json', + url: createURL("listRouters&listAll=true&page=" + args.page + "&pagesize=" + pageSize + "&projectid=-1"), async: true, success: function(json) { var items = json.listroutersresponse.router ? @@ -5812,12 +5943,14 @@ } } + var data2 = { + forvpc: false + }; + var routers = []; $.ajax({ url: createURL("listRouters&zoneid=" + selectedZoneObj.id + "&listAll=true&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), - data: { - forvpc: false - }, + data: data2, success: function(json) { var items = json.listroutersresponse.router ? json.listroutersresponse.router : []; @@ -5828,9 +5961,7 @@ // Get project routers $.ajax({ url: createURL("listRouters&zoneid=" + selectedZoneObj.id + "&listAll=true&page=" + args.page + "&pagesize=" + pageSize + array1.join("") + "&projectid=-1"), - data: { - forvpc: false - }, + data: data2, success: function(json) { var items = json.listroutersresponse.router ? json.listroutersresponse.router : []; @@ -6128,6 +6259,80 @@ } }, + scaleUp:{ + label:'scaleUp Router VM', + createForm: { + title: 'label.change.service.offering', + desc: '', + fields: { + + serviceOfferingId: { + label: 'label.compute.offering', + select: function(args) { + $.ajax({ + url: createURL('listServiceOfferings'), + data: { + issystem: true, + systemvmtype: 'domainrouter' + }, + success: function(json) { + var serviceofferings = json.listserviceofferingsresponse.serviceoffering; + var items = []; + $(serviceofferings).each(function() { + // if(this.id != args.context.routers[0].serviceofferingid) { + items.push({id: this.id, description: this.name}); //default one (i.e. "System Offering For Software Router") doesn't have displaytext property. So, got to use name property instead. + + }); + args.response.success({data: items}); + } + }); + } + } + } + }, + + action: function(args) { + $.ajax({ + url: createURL("scaleVirtualMachine&id=" + args.context.routers[0].id + "&serviceofferingid=" + args.data.serviceOfferingId), + dataType: "json", + async: true, + success: function(json) { + // var jid = json.scalevirtualmachineresponse.jobid; + args.response.success(); + /* {_custom: + {jobId: jid, + getUpdatedItem: function(json) { + return json.queryasyncjobresultresponse.jobresult.virtualmachine; + }, + getActionFilter: function() { + return vmActionfilter; + } + } + }*/ + + }, + error:function(json){ + args.response.error(parseXMLHttpResponse(json)); + } + + }); + }, + messages: { + confirm: function(args) { + return 'Do you really want to scale up the Router VM ?'; + }, + notification: function(args) { + + return 'Router VM Scaled Up'; + } + }, + notification: { + poll: pollAsyncJobResult + } + + }, + + viewConsole: { label: 'label.view.console', action: { @@ -6585,6 +6790,83 @@ } }, + scaleUp:{ + label:'scaleUp System VM', + createForm: { + title: 'label.change.service.offering', + desc: '', + fields: { + serviceOfferingId: { + label: 'label.compute.offering', + select: function(args) { + var apiCmd = "listServiceOfferings&issystem=true"; + if(args.context.systemVMs[0].systemvmtype == "secondarystoragevm") + apiCmd += "&systemvmtype=secondarystoragevm"; + else if(args.context.systemVMs[0].systemvmtype == "consoleproxy") + apiCmd += "&systemvmtype=consoleproxy"; + $.ajax({ + url: createURL(apiCmd), + dataType: "json", + async: true, + success: function(json) { + var serviceofferings = json.listserviceofferingsresponse.serviceoffering; + var items = []; + $(serviceofferings).each(function() { + if(this.id != args.context.systemVMs[0].serviceofferingid) { + items.push({id: this.id, description: this.name}); + } + }); + args.response.success({data: items}); + } + }); + } + } + } + }, + + action: function(args) { + $.ajax({ + url: createURL("scaleVirtualMachine&id=" + args.context.systemVMs[0].id + "&serviceofferingid=" + args.data.serviceOfferingId), + dataType: "json", + async: true, + success: function(json) { + var jid = json.scalevirtualmachineresponse.jobid; + args.response.success( + {_custom: + {jobId: jid, + getUpdatedItem: function(json) { + return json.queryasyncjobresultresponse.jobresult.virtualmachine; + }, + getActionFilter: function() { + return vmActionfilter; + } + } + } + ); + }, + error:function(json){ + args.response.error(parseXMLHttpResponse(json)); + } + + }); + }, + messages: { + confirm: function(args) { + return 'Do you really want to scale up the system VM ?'; + }, + notification: function(args) { + + return 'System VM Scaled Up'; + } + }, + notification: { + poll: pollAsyncJobResult + } + + }, + + + viewConsole: { label: 'label.view.console', action: { @@ -8858,6 +9140,57 @@ }); } } + }, + + // Granular settings for cluster + settings: { + title: 'Settings', + custom: cloudStack.uiCustom.granularSettings({ + dataProvider: function(args) { + $.ajax({ + url:createURL('listConfigurations&clusterid=' + args.context.clusters[0].id), + data: { page: args.page, pageSize: pageSize, listAll: true }, + success:function(json){ + args.response.success({ + data:json.listconfigurationsresponse.configuration + + }); + + }, + + error:function(json){ + args.response.error(parseXMLHttpResponse(json)); + + } + }); + + }, + actions: { + edit: function(args) { + // call updateClusterLevelParameters + + var data = { + name: args.data.jsonObj.name, + value: args.data.value + }; + + $.ajax({ + url:createURL('updateConfiguration&clusterid=' + args.context.clusters[0].id), + data:data, + success:function(json){ + var item = json.updateconfigurationresponse.configuration; + args.response.success({data:item}); + }, + + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + + } + } + }) } } } @@ -8908,7 +9241,7 @@ } else { array1.push("&hostid=" + args.context.instances[0].hostid); } - + $.ajax({ url: createURL("listHosts&type=Routing" + array1.join("") + "&page=" + args.page + "&pagesize=" + pageSize), dataType: "json", @@ -10293,6 +10626,7 @@ detailView: { name: "Primary storage details", + isMaximized: true, actions: { edit: { label: 'label.edit', @@ -10477,6 +10811,57 @@ } }); } + }, + + // Granular settings for storage pool + settings: { + title: 'Settings', + custom: cloudStack.uiCustom.granularSettings({ + dataProvider: function(args) { + + $.ajax({ + url:createURL('listConfigurations&storageid=' + args.context.primarystorages[0].id), + data: { page: args.page, pageSize: pageSize, listAll: true }, + success:function(json){ + args.response.success({ + data:json.listconfigurationsresponse.configuration + + }); + + }, + + error:function(json){ + args.response.error(parseXMLHttpResponse(json)); + + } + }); + + }, + actions: { + edit: function(args) { + // call updateStorageLevelParameters + var data = { + name: args.data.jsonObj.name, + value: args.data.value + }; + + $.ajax({ + url:createURL('updateConfiguration&storageid=' + args.context.primarystorages[0].id), + data:data, + success:function(json){ + var item = json.updateconfigurationresponse.configuration; + args.response.success({data:item}); + }, + + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + + } + } + }) } } } @@ -10515,6 +10900,7 @@ } } array1.push("&zoneid=" + args.context.zones[0].id); + $.ajax({ url: createURL("listHosts&type=SecondaryStorage&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), dataType: "json", @@ -10615,6 +11001,7 @@ detailView: { name: 'Secondary storage details', + isMaximized: true, actions: { remove: { label: 'label.action.delete.secondary.storage' , @@ -10671,6 +11058,27 @@ }); } } + + // Granular settings for storage pool for secondary storage is not required + /* settings: { + title: 'label.menu.global.settings', + custom: cloudStack.uiCustom.granularSettings({ + dataProvider: function(args) { + args.response.success({ + data: [ + { name: 'config.param.1', value: 1 }, + { name: 'config.param.2', value: 2 } + ] + }); + }, + actions: { + edit: function(args) { + // call updateStorageLevelParameters + args.response.success(); + } + } + }) + } */ } } } @@ -11580,9 +11988,9 @@ if (jsonObj.state == 'Running') { allowedActions.push("stop"); - + allowedActions.push("scaleUp"); // if(jsonObj.vpcid != null) - allowedActions.push("restart"); + allowedActions.push("restart"); allowedActions.push("viewConsole"); if (isAdmin()) @@ -11590,7 +11998,8 @@ } else if (jsonObj.state == 'Stopped') { allowedActions.push("start"); - allowedActions.push("remove"); + allowedActions.push("scaleUp"); + allowedActions.push("remove"); if(jsonObj.vpcid != null) allowedActions.push("changeService"); @@ -11605,14 +12014,16 @@ if (jsonObj.state == 'Running') { allowedActions.push("stop"); allowedActions.push("restart"); - allowedActions.push("remove"); + allowedActions.push("remove"); + allowedActions.push("scaleUp"); allowedActions.push("viewConsole"); if (isAdmin()) allowedActions.push("migrate"); } else if (jsonObj.state == 'Stopped') { allowedActions.push("start"); - allowedActions.push("changeService"); + allowedActions.push("scaleUp"); + allowedActions.push("changeService"); allowedActions.push("remove"); } else if (jsonObj.state == 'Error') { diff --git a/ui/scripts/templates.js b/ui/scripts/templates.js index 52e1135c681..91038b904fa 100644 --- a/ui/scripts/templates.js +++ b/ui/scripts/templates.js @@ -116,27 +116,13 @@ dataType: "json", async: true, success: function(json) { - var zoneObjs; - if(args.context.zoneType == null || args.context.zoneType == '') { //all types - zoneObjs = []; - var items = json.listzonesresponse.zone; - if(items != null) { - for(var i = 0; i < items.length; i++) { - zoneObjs.push({id: items[i].id, description: items[i].name}); - } + var zoneObjs= []; + var items = json.listzonesresponse.zone; + if(items != null) { + for(var i = 0; i < items.length; i++) { + zoneObjs.push({id: items[i].id, description: items[i].name}); } - } - else { //Basic type or Advanced type - zoneObjs = []; - var items = json.listzonesresponse.zone; - if(items != null) { - for(var i = 0; i < items.length; i++) { - if(items[i].networktype == args.context.zoneType) { - zoneObjs.push({id: items[i].id, description: items[i].name}); - } - } - } - } + } if (isAdmin() && !(cloudStack.context.projects && cloudStack.context.projects[0])){ zoneObjs.unshift({id: -1, description: "All Zones"}); } @@ -548,27 +534,14 @@ async: true, success: function(json) { var zoneObjs = []; - var items = json.listzonesresponse.zone; - if(args.context.zoneType == null || args.context.zoneType == '') { //all types - if(items != null) { - for(var i = 0; i < items.length; i++) { - if(items[i].id != args.context.templates[0].zoneid) { //destination zone must be different from source zone - zoneObjs.push({id: items[i].id, description: items[i].name}); - } - } + var items = json.listzonesresponse.zone; + if(items != null) { + for(var i = 0; i < items.length; i++) { + if(items[i].id != args.context.templates[0].zoneid) { //destination zone must be different from source zone + zoneObjs.push({id: items[i].id, description: items[i].name}); + } } - } - else { //Basic type or Advanced type - if(items != null) { - for(var i = 0; i < items.length; i++) { - if(items[i].networktype == args.context.zoneType) { //type must be matched - if(items[i].id != args.context.templates[0].zoneid) { //destination zone must be different from source zone - zoneObjs.push({id: items[i].id, description: items[i].name}); - } - } - } - } - } + } args.response.success({data: zoneObjs}); } }); @@ -894,27 +867,13 @@ dataType: "json", async: true, success: function(json) { - var zoneObjs; - if(args.context.zoneType == null || args.context.zoneType == '') { //all types - zoneObjs = []; - var items = json.listzonesresponse.zone; - if(items != null) { - for(var i = 0; i < items.length; i++) { - zoneObjs.push({id: items[i].id, description: items[i].name}); - } + var zoneObjs = []; + var items = json.listzonesresponse.zone; + if(items != null) { + for(var i = 0; i < items.length; i++) { + zoneObjs.push({id: items[i].id, description: items[i].name}); } - } - else { //Basic type or Advanced type - zoneObjs = []; - var items = json.listzonesresponse.zone; - if(items != null) { - for(var i = 0; i < items.length; i++) { - if(items[i].networktype == args.context.zoneType) { - zoneObjs.push({id: items[i].id, description: items[i].name}); - } - } - } - } + } if (isAdmin() && !(cloudStack.context.projects && cloudStack.context.projects[0])){ zoneObjs.unshift({id: -1, description: "All Zones"}); } @@ -1224,27 +1183,14 @@ async: true, success: function(json) { var zoneObjs = []; - var items = json.listzonesresponse.zone; - if(args.context.zoneType == null || args.context.zoneType == '') { //all types - if(items != null) { - for(var i = 0; i < items.length; i++) { - if(items[i].id != args.context.isos[0].zoneid) { //destination zone must be different from source zone - zoneObjs.push({id: items[i].id, description: items[i].name}); - } - } + var items = json.listzonesresponse.zone; + if(items != null) { + for(var i = 0; i < items.length; i++) { + if(items[i].id != args.context.isos[0].zoneid) { //destination zone must be different from source zone + zoneObjs.push({id: items[i].id, description: items[i].name}); + } } - } - else { //Basic type or Advanced type - if(items != null) { - for(var i = 0; i < items.length; i++) { - if(items[i].networktype == args.context.zoneType) { //type must be matched - if(items[i].id != args.context.isos[0].zoneid) { //destination zone must be different from source zone - zoneObjs.push({id: items[i].id, description: items[i].name}); - } - } - } - } - } + } args.response.success({data: zoneObjs}); } }); diff --git a/ui/scripts/ui-custom/affinity.js b/ui/scripts/ui-custom/affinity.js new file mode 100644 index 00000000000..1a23ff763ee --- /dev/null +++ b/ui/scripts/ui-custom/affinity.js @@ -0,0 +1,173 @@ +// 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, $) { + cloudStack.uiCustom.affinity = function(args) { + var listView = args.listView; + var action = args.action; + var tierSelect = args.tierSelect; + + return function(args) { + var context = args.context; + var $instanceRow = args.$instanceRow; + + var vmList = function(args) { + // Create a listing of instances, based on limited information + // from main instances list view + var $listView; + var instances = $.extend(true, {}, args.listView, { + context: context, + uiCustom: true + }); + + instances.listView.actions = { + select: { + label: _l('label.select.instance'), + type: 'checkbox', + action: { + uiCustom: function(args) { + var $item = args.$item; + var $input = $item.find('td.actions input:visible'); + + if ($input.attr('type') == 'checkbox') { + if ($input.is(':checked')) + $item.addClass('multi-edit-selected'); + else + $item.removeClass('multi-edit-selected'); + } else { + $item.siblings().removeClass('multi-edit-selected'); + $item.addClass('multi-edit-selected'); + } + } + } + } + }; + + $listView = $('
    ').listView(instances); + + // Change action label + $listView.find('th.actions').html(_l('label.select')); + + return $listView; + }; + + var $dataList = vmList({ + listView: listView + }).dialog({ + dialogClass: 'multi-edit-add-list panel', + width: 825, + title: _l('label.affinity.groups'), + buttons: [ + { + text: _l('label.apply'), + 'class': 'ok', + click: function() { + if ($dataList.find('.tier-select select').val() == -1) { + cloudStack.dialog.notice({ message: ('Please select a tier')}); + return false; + } + + var complete = args.complete; + var start = args.start; + + start(); + $dataList.fadeOut(function() { + action({ + tierID: $dataList.find('.tier-select select').val(), + _subselect: $dataList.find('tr.multi-edit-selected .subselect select').val(), + context: $.extend(true, {}, context, { + affinityGroups: $dataList.find('tbody tr').map(function(index, elem) { + var itemData = $(elem).data('json-obj'); + itemData._isSelected = false; + + if ($(elem).hasClass('multi-edit-selected')) { + itemData._isSelected = true; + } + + return itemData; + }) + }), + response: { + success: function(args) { + complete({ + _custom: args._custom, + $item: $instanceRow + }); + }, + error: function(args) { + cloudStack.dialog.notice({ message: args }); + } + } + }); + $dataList.remove(); + }); + + $('div.overlay').fadeOut(function() { + $('div.overlay').remove(); + $(':ui-dialog').dialog('destroy'); + }); + } + }, + { + text: _l('label.cancel'), + 'class': 'cancel', + click: function() { + $dataList.fadeOut(function() { + $dataList.remove(); + }); + $('div.overlay').fadeOut(function() { + $('div.overlay').remove(); + $(':ui-dialog').dialog('destroy'); + }); + } + } + ] + }).parent('.ui-dialog').overlay(); + + // Add tier select dialog + if (tierSelect) { + var $toolbar = $dataList.find('.toolbar'); + var $tierSelect = $('
    ').addClass('filters tier-select').prependTo($toolbar); + var $tierSelectLabel = $('

    VAYfk?^x~`13$Lr9a(1gx@ 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 literal 50745 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 a5MZ*=4=<_q#ybG~d7$=4wOZNY)&BtW=dJJn diff --git a/ui/images/sprites.png b/ui/images/sprites.png index 03b01b32fa118795756d73db565d603096e3c7c3..132588d10049a3d4058d35ba137015ac988fa27d 100644 GIT binary patch literal 192407 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 z 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�p8PyK1SrAsU9Zb+&BQd6Ky#R2kz91uPadNZ@nSTd_q_DaK3 zahV4Py>yDL!H|5YctPWxOG^qS0~xuQxxwb} zrH%#Hma}QIDMK@Duf4J59yhi$C1GJf!JtkEWZiGT-PE3kJ%^ckL8czCW)ZJZhg2B( zHU>b6BhQpH>$X{?98KH>wP`?dQYe1Nn~ruCYO}sh>)-1uk@}~=C}Bfe*pI&N(a@~k zzts1ZIvNbiTqJ!D5jP_vBar}FNWAgi&Xo6lWe3P6LVSGG6cmBTXFq(uF-mf4S-ENp zU*G=bwiC(`{lZa@w&Dr=?gkF)xL8sKq<5o>)bW>u!=nT+HSC0}(A_|>WB$Sfe)DJX zEv9N;+Y5Kh5&fcxz-YJ(|^~FFN$uv8qI(OQsy{D_W5IZTBy7*Sm(Q zpg3UbPdNetrY_TE2SXGvCO}3_&dayRgCgCs-}Cd))0vtjA2UvR1z zQYwj_zOKDqe`>|U!LjV_KbNqhJbooSkKLgO(pKWc>}27S`N(T-km=LDy4QZQ=e8O~ zi=w+bce`s`ff7Ij4^Z59;aT2$E3-9L+H5J|CAI}Dh7@l!E3{MF2@UY{?|o{c=wEp^ zl6h^2j&R{86jf%AWByeWlcjaQq7< zCZ@#SV{9ekQ#1PwE-`^p_k~Zc)bFmOt&GkS*H^lE7?MU-Lr<=anH`o<0aVH~5rLY}E;eBEx6vmJ%64@L zd~9fJ^7so4wN|yR&@klY`a6AC(?0AV0 z6=$Fs0|K|z5KyjWrnlezam>);FLotjNgB3R~b|I!0DKtd^;7amk(aHl=&;VD5E`UqW5BY$$K?`&Hc*>Qa$ z5?^OcN$G%oFSaY|K+UdaGJ%1Y!=^UF6*ER!xx5jx=^Z<|MD|duQtn8=j_QmB;#jb} z_ZJnxU}>C=H`g%_ljC5&o6!Jtmhs8SdTY>6Sqd}b6d>RiunXRUFexbi(n$IF zI}`NRQ#Egtg`6=dS`AN*$sFK(4ruu(4M{e9HjEpNZq(>ZAN?F~nxrW98E7ZJiWf9p7BVCkEcsLLoU`2RY=@Hl<5`JC zH&5?H5DGY$8^pM}?&A%5m3Odo%ycg7w762tHB2pQyUDD!|&;vq1hwgwu5n8zIrTXWW-zo5$_3QdTGHRY7}6K|w)P^FRSu zj5586sksc50dzYoN%Q>ergn7wI|Hj~S7&tBYnd`Y(g9_zo??R9dj2F*>%^M z06tDicpo;}c2BLvYBXZ=uSFj4!@nP~@r|8=&?dIwZ@}uC^oh5@zlZ*w2!>pZ-Q9Gl z(~A0^3WJXoz^BYg6BE?pzMp}6cw$U#C&6Fqd{d53q;YUQgz(@${ARD1ZZw-l@Upsd zDy+c9pxL1h=0z<51MD%r%9x$jH4jlkBg4PWF6&)4!!XoQlDgzs;I-fX?a0^bTKgw~ zYi!^mhk^~!jyVZew+b=!8fql_m6mUN@4cQY-fjNcOpZMVpYQu|^e}(zW9j`Hi;wrM zohvJQcUx}y-kfWd->vWOJj>4n?8!PFP8DEj$*kXdZ0T(&^}==GoVlkDmC4B5K2{nl zb6j!uN#G5g+j2i2|Ns5}yOmQ;H_EddJo4npmE!8}a$jrfXQT-9oquFv1D?U^nBK7K z%D(FAZ}K+p&%3*+Z(DSwZM7`OWoI7ldw1@zN^oz?H=%ss5a^zNb`eWu7BFmK{(C?w zLEr^zl&70xbX4}-vne{~KflQ_%T6_x)Si4YqVI9W@j{*3+omqvdg-NA!Plua42v|3 z3T0+1@H|%Fc%;CwC~K`4u=l$ISS?J=GUaJf=zDD8)x3gVq|x&MPl3^0x5mf?Nj;oT z!OICN3U7x0V*Fig^}V;p?~KHbNX^vvUh~u*PEni7*Y8@gMPz=c*cm#V$1`;;+muTU zQ?qZ#TOR0q95G#6G<01^iPV(W(|d2X&SMu_emOJeT(9)DU)eL+mo*e7sMY3v6}$<$ zEdW>&9B1GVkS>loJf{&jNc?WP#h>29GsU&GbGLr^dw0X@-*GMm-BM21U8J793bp7@ z`6Z{#TYGvtutuG${%2;JZc^sw&rZfBo|E$pdFzB#rXEPDs{LW~cMhn$l2&0jW|$Fs z=|e{&-_k2(3!b{x>2E$Z!&buh=Kaf=nf_dA1C%}P21_JVuLxcoG~juU6){5 zEUG8%oS=Gl)ywZj9N_3i^Sx0%GtpCZMOs+W@~E{TN6$Lf2R(+* zcnrKZ?bC1G8!PlLX#W2v>SzD*+XSrNr_0~`jq9PmE_WU944cQQ&p8@T1B<=@anqcy z3NQ3`$AL@7Vg{Z=4L6S5n8rJ;wXMojfOWH)%N0qcg|p_Sm$tpD}M8#>p;U> zDmr66Rx+%gR27`IcUOsPZ2xD5x`)B@cfGiM52#VxI&<-^BOl66GQN+B3kIHF-BNLr z4LsWhoI=06i5r+6;HwTepex~_tNwvg&!7^EO46h*V1T$0=lTY`($G~DL%=`bcmCTm YtQCG_bZUnHKLZeWy85}Sb4q9e0ENfp+5i9m literal 188552 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�+J@JVoTuOO?!NCj>ypGDLu_O?XEow(d)_d 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 z z(DAGy+@LI$pB3&)Zu*;adGS{#;Vp$5vJ2O$y{%K;1`-L&?3nqQ5dWlX@wktwK9msb z700?i1!RjANviB-D|Z;Ryl9^YxcU0sTv@2ehABaK^+m~(9Rc4K$f(nLN9oJ%=W1D` z$(pHcc=bU-Jz>-fzk*O7pedg>z^H8xFv7yBAq`{>?Mq?R?p3UG;(~33$jQhrPH`H0 zK(4EE0{fmUC`EZ8HS*wh@_%YGfM+V0wheu06X6IgzBuiHRFq^zWG;Qdbz0i2EV{Sb zo8Hq^CqweMYno@3Mil{{dkmC-IEuJCRkz&D4@5|aTwg}!gT78X^Ne1a zdaLLV52Y7D*|QkcLTa3xo)*POoG@SOw6O3}lDL?qO)@GD>}?2grRTR&xiju!9*O@! z3c7mP<0P{wzOm||7w}%Hdz1BmC8S6+(WE2B5h@*@#onKcK3))Ib?F?;Of$?`Hm!Pp zz2R0=*YV!rQK>#}xNL02Tx9JoDSctFSy)(cx*Xo}P`VS9tx4KW=?S04|!;%B_xIC|``OM1N=2stA<#U!Se66la(<=1lIG0SD zyqrJi+3{E`W?pRZTPrja$}HBWL|EKP&TGJ4K%^>xui90=`OF$pd%R%jLM4V0EO#HO z*pE~r{xqA zhvGzPKP^kIP4YE#V3-5@DH*ngN@Xg<6zO{;t2txZb5lPy=lz*t3lzz%nKSS$mJE(n zFA&5AG2M}`#QG9Md|-u%^C8rXV;+o@RysEJWv46KMxH#+{;=@`n2|=veGj|!0`&^0 zk}O69>8{o8&5?7ghzNbkaAH=b1SUgH`_N@~x8f)i_BnPYnb2jVEG2y?;56dS08x?! zS5ulKfBZ_iRZEU<0{|MxG%G_~$`&)@Avj#f2zJPvkU$f0Jm@r8Bg@e5W>k4+FZ~yQ zyJkEfiQ&^O2?rlTX$2o3_rh7p!4%2tKUEn>u-FM>iWmmXrm-Grocll?N=&O$-#2C! zDG*aLxH z1Iqy64|H1-+?10W;t5wyK5uNwX0w>4C}l_~s;!OZ+T!)HIp?5v-3KqitWPdQwSJdI z6{kfXp{+`3Y2IdUbFI~%BLs&wv=?cx2@gJ_H9t;ziIW)ZuzQ;Br$dr=s&3=vP%^t$ zY*E61&BFG2fcKBoh#JqfH#4lx2eBIj__+oeTwqC8>n)Jerxo-D=azK&g@$WByjc{2 zb$iBc&*{taKVe(DUoNy1!-nNf+OFrRRs~fGSbtGrmmfzSRF#`!!)Nvk!bo~Rs<)b`=4ZfOT`cK68FlHvk5-Cz8=>HS3RkPNx`|xA}aMn0n*rVWropwM$hvK;x&Kd$xYd3tnU8;V1M0Nv@z8lxF^Z#Jp`!}GEzWyS97sULVV zE@R($qESQ*vTjpgOkd94n|kueiJ405v?nznC|LSa-+|%scPZZGF4zHVcQSfr_BWB) z6N3X)6d7o}TDvYndsLl+L$iZa*FiMrjJYvlo2JQ$*q(_G!0iB2b^tU1>db92S`fX; z4?b}#^n|UP9jP=#>h^&Ns9yWhjk7r>9Zrd*Bm52o-Wz4P?>BP(L-0%GnOx?cz*ky6 zxK2;gb3*>bFRbNmj%luG=ilx*#WqZLfBr=0=n75yn8a~Mc*z~*z6X!{4|v3UlE6f9 zH3A!QO_tJMin0A176iAsZxnTUqHBX7#fvGUr?mfkXurZkz}~w@UP{q$Hv%A_Y?X`@ zH2K0#)B(!6Ra=(f0SjZk3k|qT=~hsJHozgTxME8O{7?DB>SD@NSps1oI*L50a#KIO zylhjG=DT!Dh1zkc%SN+=NQ81!qGWJCo5hQe`^E7nu@~gbow5^x4(T8O_xoFdQHHQZ zH7`;@rCS47nS7kOB}g`p2nOP?s7`V#k2SWiz|8%%=DNeXSpHu*a%mhl?$*+qNc2=5Ovrj2jWhuT`j4&7Dh&apb#pA!QGbNH@NS2CaKbA*5_}$)*SV6zRx(2 zP8}4v^NQ8YvCEXO2Y5(^Sdh`tyT2$)i{>ids0x|cwJLP&9%9==&BELTL`#vgY|iBK zdBYNt#Gbkn)s%cQeocwmh!D_C69`RAweCRbxSXazJm&)dR9C52XU{29c?U29Jdg}31Ty1gUtJFo|Rz`*9ffh|69&%P5D9Fmxd z5ki4ZEXd^ohln+kk5+}2a*FsAX;hDnu8|LnV&TG6n~u@gTj-gTo@*Yviu_whTBePn z3H7+K4G{yvWv&mK9MH_ZmcP%_sHidcgi&x18%r=)z;Yix{^{ZsH4b4j@4oSznQBGJ zanV0fr)&Eq+k8V&G9*AtyzLblQw2*+hl0QLNGwVJi zyt|5Ud{@o>ligRyt6r5a#&wHZ4AvA*%kG(NVKf#Nfjvw*4_)Qo`LIgId$#l!w&qY3 zNes0G+i525<{D2|rgmO!%8idurXc|xiS%YKw=5~Uw#bllvZSd_$Pb%X8gbPQDKVT7 zZ`%o7E$hWZSlVGSL>kh#PA1+K^Sr13Yyuwce-ZTEbFD_Dx|5Z{8b_2yqM&dj_j5Z} zO$QPd7qc?JlZNbq+zsi&*M@x2(RQM*@zcZ22X&GB{bFYk(bDaKVM3ijvi^;|CwmZ^ z%@zqaIm4DC#$*=t-AtpamO>6a-pD(@b}on3PMzO3E4_?2+Bc!@A>JP->&-y-qe5|f zXebnjcg~CuHC)u@_B6|h38nf1rcxEjj7Vm*8wIZEbS+-6`1CVgkr-igUOvvHVZ#Ab*P(f=GNjA2!?a` z-Ln=(XBs-XpkY~YVHViOObNk-4DEmAp-U+_{cB!WjZ0m0l*5#uOpojCtNCd!0o%X% zqV_yRL-|BdxO8jTQlne00xQC3;W6!I#!&Wy{hB|x`N17~0Bp|PMBf1x2bE^h9QMHM zUX{?={uSmImvEV7{k+adtPlUuLWGTOMII^L?WWLcnWE(~yujy)O>bH0y@r1^XjN@@ud*%i^xBNq zpLz9M_1o1+jk2b(;Du3IZs{~>E*A$o@O{7Fe=~vvmNtGK*unbRpf?mIRB-egjT zjcU&9zaA8fGGi@#*4~!}7Cm}d0i;E+V#8z9l9DR>fDx6Xas1I-AYuq@R5I{RE9R^{ z20OYUR6@LJm@e$_DbFV;h8;vFQ^ipUL6sV#9*HnUz@$<%C2%0ne1%x#(FddEfStYe z9pElwN+0B!KP*0MD0&MjPKTWTU$OBL^dVxSAe1)a(%B8eftSvOMJ`8CLj{l7aCf%E zrz4t>L%7=8$NhFd3q_rGR&J*J^T2EK2EJ>WP$|7uZ8 z`tKLAx{WAjyw1)!_@5^*U!hPu5V^QRMbK<0~YavJ_VCW7TL3%vN5D;HJ-hEyA{irCEIsIq}>xxEb&(_G-DFgwd&diRr3`mEDXt&@NDT9dF{YyahV5XqFUOHw{p#;+O*YRdf%A)~op0Zx!9uAKka#Z(QP8 zN~cY5vADFQJY6?Bd1pdZ`f3GV=yGfcsfr2h|MqfZc49M?8bFSR9&7s@!GDE;{DsQv zrVbCf9d1PgS-va?9J+#P;PbfeytaL=RRArT?y9rCIc^5zCZ-kK!Ou?7-1tpk%-TfE zF=E|6q+-%ox^c9hR3yqbc$#Yta_ld>DFdh=S2b5~fiNi+x^N9X-C$;F%X=o6! zm6)v1jfncHq(5S!Kva+9B<{cE)S)CXCOSR&DKm*^K#az!DxbSTu_0{GvL5ePGv6;N zF;HY5gQ7VqQI_gD9o&fTuNd7D*xyI~CV1mIY?W3%P^0bt z+nASwyiRi|0%3t}e7s`S?1|u+EJ=`&Bw)yx9m~(B%4K)0I*m6Ej~Y*`=3mKy zkuV~_`RbYlEra3dW9G>O4RZ0yDI2JhJ8hkx8^{S^fnBl@Yi`{W0Olx)Xl#8G*DvyF zrs;Zqm&ken7@Ul@=-1l=O$Rqb=zA$<1K_YU&8*J6rT+3t4OhI~8LK0BU&R}aXpmh2 z_SxU)C2nEH^kTef)YAa&xbcne^b@rRJG(iM__xqAN?7cjUTK%I8jKZ0YQ-%M1kNKumRf~(p@jF3{e#z(wMY4p&nh@aH z=0|Dcv19Wj1ONvsvm*~J$n;a1`)%n8RyYt-K;8(?-c%`W?sISk>UQ&9P_m_dM+mz`;f#HX~vjnl@k z46~?}-%O2KKMgCmW0tcBQ@anT(Xtqga0&x|&Gyv+Ti{ob<^MKg4al>enE9&VtgeHz ztvH_XU1S3Uz&Dst1M>ZtLYCvsf3XD*9m#zvn@}e%Uda#El*wa_*jOA`1Cu%Y7OuRS z*A5+ayos*}@IvYGv|F0v9dA$~h3@Ds0>Cj0l_3rapPe?0f-*9ncE2X_dxu8zc{=}Ea&=2t zV_R-?`SgkwAi^_1YH)_D!Y#0~AV6%e%M*s92}_V#h9;2Fs3qI$kT)-jmIp_dKk3ay zs?dT7k0w5UN_u}AGq8I=oPVfD>?gCPkWx_h4>iZ=;W)sz&T zd0;7Vf-;;$`K4ZBwA-5WlKbNPZ3ek^Ma3DQl2QF;z0qJJ=vQ8==OCa)SJL?1bzcqE(-%?8riIJp3X;bqe>6WOZeN`X3Df}XOXYLsO7hFAS}aMG(_1Bw zKmUiU_E5mo*)5g|m5i%H{rzOo&!xO2G^$EQ zr)`N_aVe`eFZ_5?^Rn>qSF`*XIFr9Wy6tr~A|e~9eW}yC%$|q|19D5f#r_w}iS-HAD2w7U zxbfyMRf5%N)5@6@>Qp(?hE#=GrWE*?7$nrNY*L2ose}nLocuPQPgBn9LSrWDdEcy1%ed53%Bu)jk?QT=s5Un6XjW0bX=uFXFdMDwT)ynyDPIv8=4K63bI8 zQ-J)2W0XDq;_i#jp8NX8fOWR1amox^!9GZs6m3_wF^H=@MAk?)P?l5wsGq74F+mQUwf)-rf0Se_z;?p&@(LzN;~KpR#+)r@q;(Prmb6u&C~}8b zsw!D%C|s7Zjh$0-i~{Ly8u6`*|1I2=|EQ6U-_XqG(~QeijZx2&0t~0$Me2ZFl^wKz zT@l{dZ1Xg8ODG1VbtyD$(VD?%Lp6ok;vERIa_YD}O9xUPmCSxTeF98sU;Yk88A8ch@=qn3n~bK?^r*vF@*T{Y?f-WSJ=J z;_UjV^qL|j)=~RJ?apVJ0w5}Uz2MwFb(L-%atz`aA(B3lf}p=C16XSenU;b{=l!)4 zKV-t^k$ z8QY|9xSxOdciy!5AeAQUejhu7nfHjQjkJhus?f&FW{FaFO$9Bo*(|>A6NVwHtLuS~ zhHgWu5Xk^7uG%J>2H{Qj+mY;8!R9&Ygkcz4mUVd;)-Vjv5g>4K$zmc=5FibU<>e+} zP`&K+)0bv13j-GldF0M*TsU{>vVD}wMf&?ITsXgZ<&Z+rA=lqW6onY=g5Em9Fs>Vt zkCJ|nxJ_}ak(&`$eT4^Om9%SwPQ5YRHR30%7;pNp>Z*n%9D>O2z^w-IGS3^zZ${U+ z=Gw;qR_NeGA&%u>8FuIOt)NLQs3mIwn${*~YFmDi3$=5&ag(f-L1|5_uR_SN0^@bJ zg}xF1+FIj>AzDKwJtiqcv)f|r)B|Lr-jht-Koc+p8LiaPM8 zG8z8$+A1%`5qaPr6ieKbLY)AjlP7ufzI*xN=`-Zg3y*g3Y2D@g=?#~!Gv`mG0f+Vp zN<!|D^(J}s8=za9NEm} z%&s*!j&ntj6jz~%jN^3Xg>8B~YhjofqQJ+>Bo0~}wa7Tu^*V|VV42AULJ(+d>oQ=w zkpWp>_8KV?FiNbf_M<`Ku*PX(lHN!jP|5weSMR*VNPdJkig4p57poULk5_ViOgE?b z)TNJea``ytmd{-Ez)mb2r|wo6F^B212k6iBcb>acyVTkDaDJroc++oke(h{hOxlpd zB*zxUQTt@Qjzuie^W5y@>g%-G)_xbYAG6WuARtnTQa01JmRB~-0fbF8_BQ`pZ_LF@ z9kv7jJr4Hu6V1$Y>hzgfadc#u&xHY&X|fLd4>U5D?YMk|AvKE5^P4 z{@ZWnPyhM1b8vhA6%V)jJ*+|&sq|(0G#m@5lGpZSVQ6Rw&+|Ilg_(t_H0=ZcEh}*| zqc{aXfe=DTK`br@nzjoQw;izr0yVy`aBP8Xcg||P(Y$hIZ8n?1Z?uy?lJl%BFOn+_ zlgVEGkp+H)lgV851H6)KCqr;nQL?r(C9iqJ}1!{Tu+hR zTsAP?0)f|avO1%=Hf55kZOAl*VFLhTr8_` zFVf&!_kBBc>Kt`nM>r*QP|0S5{ucv}_Dv zv%mjP=keL<3;`k1OlIDNDo&0yZa0BQY+KVv=9zk7a=u;dwxyrxYqVROf=>XD*C2c! zFNzq*7t*#gS33@17f@X`?@w$bh_sVIWO}s`#xW(sKzbggR+u^gyjsS=1{}+xXge%6 z8rYQzCK^L0$sJCzY-A_oZ6G>;+1}r#+wRBd%C3@f86a=l*rrL<^RU|hC^iA$CRenl zo_gx3ryBr3k%l>i5K2m7nPwH55>yz2kQnJA5Yozq$Io0?ZM9l>zK`p=3=a=ewmb~e zNG5yda~Rod^6&QMrOy|(Jf68~js&B9`Kumr=kIL`qgX~Xo15R)G_VR83>{;b21B`s z$;nAttrni=(QsY;+WCcf!_J2QW-bQ^q>8W%fguHk6rm6z9bAOw@(^5<4nT>kmeEw} zG5MS%n*yAI^|kdYudY!n=4q}bq1jUZAeNJ%xxPxKv<)Fzbg#7x&}y~F<#Jba2CoKy z*=&~Pmauy+pCby_X{;yNzx|`z5*KUb62)TvnwDJ*%K-g-CQ+o3BBqev^pda(0=Wjr zD6s{gRmOydmjGZ|I!7ax0d%O64B+lfYqZq7ws^Gj#(M_#u`|0HBs{zR3^Uc~&U4>& z==&ISh7lFP7sDrb_iw#}KY#g8iByErif7J!k-z_kKTO?RWADIT?kU~Rd-lDr^Y?Sr zS>{{w+)})i?;Za^_73dpJa>HIC|D2?6QhzVDl{ro?GsKaTj%WLUv7ZPZL&@yHit8> zB((+pJV?^A4d18cc?{(9$vi+I0wKl1mWw$>HxOiUu;Q8*;rynZUMhec9mgFB@S*DAqC5g z2D!}>PyHZzxmUWWsyL1+Q76e2RD2n`9g6o@!N2#J}l4q;{r{tL&?PdA%Q z>YhiV)nasXltH74X-JGPL}qM^taG^|=X;ptN|!^I!5klZ{bwUK96+m5L6R;hwPk;@ zTt;{ShG8(62^bz8rqO8NM-eZ)b|P%X*1F*&0BGd0$pm#3V{ZVUFQtftXb&!83kwm^ zwI)Hiq*+~yu`NL%XS7G`x#i{h6;GqDQe=HO;R4fk=pWmbB&f6$fnQ^2WN6dt8}$Z` zlSK$Yu~=k$d>aQ29%9eleN-y_9KQJ$cJJQ9;Ls3u8Y(tT2Y1WzZewF3*u^21XA(FX zoY;|Am8)y?Rj#~joz|LW!`CrXlVdkZzw22SAh%#6l1nQuwBn*ajFXLTfP7(2|)g`-=^|Ff~0BHC&fwt3?=wjE|2~v0Mz( z#0UbcLOHqLwTV^>)6QZJ4`O68SmWC;e4niK`ewst94m1di#e=;VPv&-*}jZ&2~%4b zT2pXf$ACj$Umx{)9WM-d{<)WGR<6>NrmduHVdnDaD8|$=SxaCU0#gcK3IYLfT6%12 z=rT+lh!p5xWi>lKycZPwZ~HckZ4#Z){QMpNoSQ~(?mRcWHqGbHJ;qXN znNOeoG~;ie(xM6_W3&GR?E?x-wgxHQ5beTim(!WsW5T7pm)=8X4I%M^7y+ z(f`yJdGFFP_ntgO{K_jBQPgn}_3$vicl{`86qZLI|>veYR+Qpz)#X9o^T~F4ftN0=^1|7rjmOgM#WM?h^y%~1JGPVAy%Skm!xUV$ zpUmh8vQfpfOeXV94jec@tyaSg0-CPN=f3#T1v6i1A%r$E8O&Us*bi}tu?>l3N=zwy zLx_MR3>;s@z4Fuh3=M)~$Fy9<_KC#ZiC|`Zy%nvlU3mqMzM{eU@&D0r;>v>~c+CcZ zpQl!xV*kNI2q7qyE9^gb3qcUkY&1A~<|Om;v(#!;JkKMJ6s=~H)zxLDE?wZ{iKA#G za58yz?cR@+64SKUf9NK>IA-QdQdoQUkvkDWuzvi1&|kVbh*xVa7pGP)0948b<&wed zd`P9diSgX7_K2_JWNii+AnwZ%ITETaqyVT9RbVxFwdgL;4M>#Gtm{?&{MG;6dGqb% zN&eoB9|tL@=BoVIpZz_&aAO|kgQIWaX6H7v0gp^<0N`YP2Zx3Zb94Sy-ni}I&f|XM z^M8HxgM4)EPx!a5{xUZW-OPA-Tj%*def57cAI{<`k01^^It88KcWs+x&%+e5^InqfxrgGiuU2PWusz-l4_0&^On{~Z1FbUKM5gI}Swjo{1kl2RAA)?`j zn7KSgCW8t>Z50RWUwrxHvu}NPc_=?NhG;Yx9v)`05K#51G>rjdvxz-8fLdDGf}#>L zYanwD(Tat#On&8$pWplv%cMA3##?vs>#ZwTfEhCTC%}*dGYV;KK0R410tzz@acs^0 zVuStr_fxG_iEW#gUwJj0S&c6C4-dEicDaI)$>1+n$r&2QO3vLhglk9<2nfYyXQu67 z1)x0;P0;0menGJqF~1NpF>aB~N?cck^`?LN%-O|5_uRGXvQrrw9pcQ{bt-WSVdU6< z&l`C5Fa8%(Cy%lF$Q{(HXSws9H_~c0ICJ_KVc>K4@Ld?jCE_&0RESMW!vZ9sVrlTo zOV2PoGR~pHcaq6uSy_3NdNV`ldkjtNWO&DJh+Sq@a_rqRbkz>BwA|p-#pP!JMu#md zQ!q0Za>uRuN&pyg^-SO^IjAiluT4oBMy(F`*N_>LLtsb^gV_vi3(BT{7Ffy z6-p?uHNWxff8;yv`W|dEfvSIaPsQ-P)S#Guhuq zC6{Hr<*LXqUd%+%gWXljFLMD?AlrD2?(EGm4Awl4pAQ25k(BIAvw@T6^`-;!h2T#n zxAQ+vouWURO_GMvB#^fI*IvS{UF_K)$$k-A)>{-1`i^}JVCTR98qLh|GCSI3oN$W{8(0J#2hcYS;X0 zMif!2)wucQn<@KKSeA*=Y~WO~IOQUiWhPtJCcA4KW3`4peFeP4Z5x{(cWj)I0kXTs5Yx+ub8}>OjAG?;n_n~5k5Q{*StgVAD!1Hn3$E+ZNE25+ z{;^NbI+f97BU1HGNdb|2sY*bUgiJ>>EPY5_XYl7x(1NA5&x&7~7(Ayc7IyGWtXM>d;B zYt7QqJUe$D?0Oe*8369wb&$E)q-04H#q|Y z4g<@V0gOOw#Fd3asbsxs9KmVt1i$t8Z){v6m|1@P-rr^{GlA@fk5&JScl_4d_{Sgq zNq*)}KfsVR%%ekZCu3|5d4Kchw=mb7<=cMeZ}EYTyq~xI`dj&n>Yow}2HY}oJOBBi z-zH;j{LODY^&6ZDjzdOlstcqwn27_ZV&p3TVtYR*jasM@4Q)!cX^EsAUQfGi0AOmf z^?5!g7Us!XHk18HR(T_nc~U~W3Gl?`Wo)*tZMeaA$!b6)+vdf^1%A|R@jv2-g%kqY zu3t-QJ|D;Yco6XKPMxA+r$xs};7=*NX+KGrS#*Asx|f4#za})z=VB?{yyI|SbcDHD z9b;{c(GBQyfd(7x7WLq-r=EK1=}Q1Wk~x5(lp?SU>Ds3B98*%T1cvVdlFZN$LJEvb zF~|%|tbFnd&z|>ISBV^l^;(T$vBExn z46VrS9Va_EiqluZD&}zV8LX_0m2;ARmkT)KLuB_&;FNNRxuqnlI1Dk?YGii|ClKh^ zWOt2WxE_{P3|K98Wb5qSy_>bQHAFVc^z=;p)T zY}|KBVg4o78ZiqOliGNw>vk+_nuE6JT#CPpE;SWf7Sszo8UA6i58MDC7fC#7{&aeM>6FLhkE>k{;Qyb!`womG zz3cq{ex3^5)!oX{D32zOCT>n%huzzCV!=O*eZZMyj4>=fA0}fk2gYZPAHfD}gO6-5 zwt+ivxN}&Xz4op*&ZY@FIcjD!%IaL<`TbGVQmaQ3cXnnp`+eE9EwwsUm!>}YKFOB~ zpb$b_L;y?{`iK-N)QXCwRWW7j*|cNP;#qi6m8eoB)!Bue%b~P3skVXXBU9%2=bnDH zTrC! zgI#$2?PR-~$@I134R(?m>?Gy6sFM?@(McS`++$dNfHhsjTe*zvx;`8YR=$Mi7&^j} z+W*-Q)T*WJY6z&g@i4of>^GtI1CwS|={ zH`ChI%^i2#M^mne-Fv>ysi}a`Bk`!;O?Tc+Xa8~tW*K?vQ!F1`K6lb?l+Rb#d*D?0 z)NJVyfHf;qxUS~;y=8_57gRK7>nea}>jT(0hhnXgH3JZ~cvM>7E#OMReaw%_%_zH%`Zn-tQNTc-+!8!%nYO;QpqIM z$rLqqr8W(aj)y4sw8Zb_`IA&SGxc)-Htx4`g&5ONea-_@5HFhCk}vSg$Ov6cIaYVY zP5KjF`fEl}Y7BvDkxHBbmRG7|EQ^X?U2u##TGOO8Wu@7H;z8hX6r)O!(F(6N>3ec4 zDWDXFyn59tOrbD$onEB+SpT|;j{Q*8vZgbx%MF8rjOO#?Pn@KGelU|+BmheI6GDiK zsQ{|D0vITzDvqU!uB~T1N0V_anyrZHbRIjK#p~_?z{#{!yzbS#;>J2=W68+ys*aukb2Qq9fm*s(Ks?{d!0k$+DV0$ zmnJhXh>5^07idfCBmi0^*HW{VRz)3GsltYN0P8#Bm%$X06A}PJgAvc}ERoAvtglr8 zqv-L&M<)uqojCHoctA&OvU!?LJnl*n;b3ab3m!1K(!X{%ssPIvF?nraf-B_dW*J zZ-&Tc;)xHC>UApg4OpZVut0jRA5@#x=)S*n9A^-njW7B-!q z&wi^l1J4J*Bt0z;0;WffGn&tH%ZeeIy)=Q=rCG=QDrX2>G*soB1N-^o*MASCAYiIg zVzyjnwo)Nqtx^aAs$qbMLR1t&6cU6Xg&-jB`^;7<%$Cbcmr6{OO5D4CJ@*D7s-a4~ z=pUg#sMN%m=Y11keRnsVO*x(!8KGr%mbw`*C+d#3x!^46PY5AScOHX4RHQJ0hN^Ap zQp(n|Y1b-dTr1P=X~y#fOwdB6zn|jB2tlC`d7Ue!rY4TA27YQ)kVC>Bs6?^xWIdZJZjn`**es6`zsi5k^SHJV! zeQ#LS)kJ^)>EWZLIm?*;G73-qF4?WWj_owD^{&^_(KpEcrypl_a)Q}On9k;yC~U`4 z+eka!+{z8wvZ)4DDq%>a95FLKKKIzYtJbmhraSPOnjx5_@XQ}j&AyV(<}*+HeB$IZ z+josjpPDT_2(W%ln)X(k|NF=^t5*d$^V8r>g2^`oz;m6C=PG~-iYDHFWguN$-9dT( zB$mOy&o4;p5N!1BXr>;kV!TUYSR=7M0o8%1ju3w;Ydn3-9w-@l*F{m>8boykdN z%9Yx@eDkkh(G)jd9@k2Mvw6yoJr)PfWPdJJiA)|g980G^9V%5_*3`r;D~32a zHO=&~V_dgz@W*6b<+O@S0xg6P7aag=|856LDPJp7ax9(q9BV4;TAAjwO-r%Lsp(nV z_BJwoea!6HgYC6cvi%!I9@_q`Cx_QQ{i-c@zARPk?PKQ9L6)yrfhibHKJze6>k!J# zqJeZ@8&SJYaD4jAFV@y%T!%0f68UFdn^w1Fu-kJ)GbMuY0z?tbQ_nECJjZqYYnh&& zrm3TYj%G5!YSOf9Z(X)}Tsx`I&SuFC4PlJJ&d<=1hOBFoO<6(Ov8G*17nD+E zrKlwdXQ^NwpPVjT_vjOc zhVIIwXlpxtRgcb&HfE;prn>C|v~Bze$gZS+-A1}suHpE;=Q+B22Qy=%lneQDf9P(C z?x9sI->{YD&ZLiD;Q*66{sGf;H=QlbXS{E*ROMR_?%~jh>HlLO?Ch|)?dB{;j#aVk zGMhFm2qe>WLFQZ|S*fd{1`U<0NuU>?JlKNw&w#DtMR$<#Vj~qNe_slHm`OkT*Zof4SoRI)1gb){A0i-q;U{xzsb}W@oJ9^4< zt&UvUN_Bdg>B20gIY(}2i1MjXs#DV@-PS*w8`yl{6QB8N+b{R_+}N{zy*25sqg<)7 zqN$9%V+Y3$9>W{lik%*SQ+ZNt8LW+cgtO(j;MN!bbFM|`+C=Gw^P$%0oQvI&13x4f z%M+D-Qo4dYv741m0bBZSfNYk|Y?kh>F8=l(KUsMA*~5>wt-JH6ooOqhAU8CG+ulKS ze40+Gv}YZ1X`75=jk~s$=T~Lx;=k-B;nJ z>oe@xU*YJnDizFUckCSb*_Ia1z4P|fq*AAUG|er|RMM~J$e3tFRm3mK(F=vYH3JHp6vWf@JwOlbn#vG>bQ5nsfZYF}ME| z%$oSb-T}Ck;Vw!?XUOb2j@s0Z*>?(#Ob}vy+9vqfbj39FVh)7nz;r%c>saKRJR|8--+5dY*!qR~;b z)^l_7)%V?NO!M_?Bu2)>>o=bz{ntO=tYtrX)bqX#aKqprtGhaR_|PHJ$4{_w{@;gy zcuBn(8v0Ed34cNeu_)`k?|turD~^pXtRN|cN*Zaj0ZS?D$lw@*8-}JSj11+9&r}&w z9c?IEQyCuzqar(%t5&O(>f;Z6BX!HhwH-t2)~af?!qmQfG&eWX;==Lm50TDf$+Y!i zRReUXir1PUv#gm^E{*M4xVD9xa`4hF?M-Qn0xS#Hb8s^$((O62z0J6p6l$u7nl51j zZhi!Ie}zpeds($=6+yL1Z)Ybf1_$}f7r#{fxPY( z5S+pcY=sN=7Fm%*emv`Ug=>!=N2f znJlf#dg)%VhJke(S-xQ_%QtRiaCi%StJl-nznolaJC@@>Si&6nIJ5gc$E3f8j{ciZ zTVuFhr4q31=_7pSk^Lv8{os>;*|09nt6tv3)7wi}R)M=;Id}RFfDzyn^PTeRn=uZW5hvMPpa~#yH14w}(1Y!${#MMvaZEKV0h1cDDdk&KoQOc1q&YZwRSJxi zJdzD2=|Nx&SlT8c!l?K@VHiQA2%?aDkS8!9rKogz%F$}>6GqiVuq6C>MVscl0}usR zpET$(I&h2NpH}+z@xr+7)U{uASw>FsJw5H6T`qKj}vg1_4@mGHgW&x)O zD3r_WjzTu~_R*fnaBOOdSrZkiS|4l=f-P3O>hgkl0Bb9UEEpkNTOKaiYIFP5HnYeU zC3F7O?WWVV+VwM*_1x}k_OpOl*S(BatzE}~$w~I?+Qr&@p}zWe0ys(B+&!~Ma6V1% zZ~d11>o0_m0C=_lICnx(D2&o3Su7wj#t99%FfxuJB44Obu~MYk+lZ#5DF2HRH-4Jo&!h0@FnuH!H`ILOqIUHG$Oc)2Fh*=BUbN0lnLwnaMY zl4{M6YEF}FO3~4p!FVnzn(^*nhA> z2%{FtK5=|%NNdgDK>MN}no^2vt^=K2%f$FN=EUc5CcXqjD4hn&1rvfw0$o%A6F~VS zX7amm@UJNxdxYt78`1y{46!*@*2s zXSnU=fY$j2#FJoZC*)bqGMC*V0r0f_r{+UU4sfEDG-|qpyLUVuM3J)L;5Y^~8vnIo zR%9wRRXYxWG?cWASy{bW-qMy95iftkEz?Pv>vwGMa-0w4?L2~?*)XMLYN z8v8_?RtY@I76N0o{ou}Q_WuB8sH2_NZrI3FrOYEccQ80ULD&3~PbGhBj3<9=oLB!p z34lTf34rGj0OM?+l&Td26qYf{GRD}Ep*0K*Q4lblucER!+?E!CLY|;dKs)Ks@mflS zLb3SZS01o7uN-XOylIo}9vDC=g$V+dFJDfRV;JANjq1cvQaU7^YsS_#+7HncA6@aW zB15ySsTO^LVi{fb(S8t5D-%^=@-XE?PZ1n?lGVNKY~H+?TrNj%Z!arWtUzhaul?@t z&wT3NA9$>3#f`gieH%utRL-|E9<3WTlIiKAGCobGKg(c?Lr2b~HRDV-r|siu*BZAi zJ*|~0)m8t(GgSZ16asCa1r*D=VDG+wa@peg%^t;4#PO3p0qj?y$(}qh(_bq4tQ_h% zV>r`V;pLWLH?53EzK4We07?Q!rS!DpEwzeDiPnM5O&djG%RY|XzC0EG||0MD-iI9CN!NprAL zXbe_lj2jt~QGj2mGF=RCT3c~jn((Km2+I|;n+cq3TcPR)#RtChg+Nyet#`frPN%=W zpZ&M9;;TZVp&@gR%w!n=O3psdH}1M#|lbV)jTN+nruy2DNq?Z2Bj&g$M;Y? z^elxvkJ9Oetn6FHrcImZ>gt*ce(mk;OwP`lx4z?DCm(t4;A1T-Z+$-7yMD|{=X@)b zqGkPhvdf3?XNzQKCm3qhbmd&yvQE(A*~c=jb;^yae+6r90Eh|!vq%73ECeR!QB`Zw z%($*1oiaTAY)Dg+%jOMf#>PX&Cj)%gZNeyhYIJ7sYbM_C?PLs;^l4@Fk z-LxJ%w;q$(gvo5e&aKC8T2HEJ1*vQ=mYqJYgJXO=&sV;-ljnAh%+C73#{xK+%UQhc zo@Q1oclp|bdAgSsdF7pR;V%g>W|X+^S)OyOWO0rPU}N!VzB$v@gjolB`w8r{i`qPZ znJvLso(R21L7*@z-B2q#(iENWv`S!Y2IaZSsG&lrNGg5{D}S}ZUz`Y&%3l;G87ok9 zj-|<#Yydw*e=fv&6hPfHgt~PlY#*UCI!WP{K1_N+)9*>Ouo-jF>fhM{APcK=i;c~2 zQFsoJt@<3y&ob*cZ0+l#Et6q1KTAFcf)Uq!x+x6ZY-9!(tj3|vI8ygC<^n5!6{RM3 zdg)J$xb8lH;hr8|vta|JAmppNcG5mF!rI!ZIq}DF6d2_U)4w1APzWJjZ~#=bDq!7t zK%>wKrBUP}gJUT}rBr36Vn}zi<1{zn&(08*D_CwOaB}Sh<)mgGf9%oXx4!n3^qRG+ zGn?11*Zuwd3=R&G%jL*qGIVx!vTofv`j&O#QN=1w;#Q_99@~Rko@DmuZc^15bbgGU zmJEYEU0iqFb@cW1(bLnz(9jTleSLIvbYNK)AN%*u`2Y34{@R|=inpz0)vbFo%T`TV zt`}J86wT|_(X?_ELCMFR9AnUn=x%oD$how5&aq6&KACo`xan7`l8RRV301tp*O>xf z)bYg6r| z^wiTw_{O((bLiOAiCI7RSP0{}oW(t_Y+`t=$HR{mK;^mnm4><{myg#q{nq!zI^zlX z3;}S_Fj&_OEd#hwE=8old1eINo{a~Ewa@8t_W@i}Jn$5kv47Rm1Q7kZ1E}N5% zvv%$Pk1Z|&5I5G2+uY6Ljs@>;-yYCEsveN0G?| zk!daaQD>nN^i3B1732A;K9#Sqe=1_iYbD*)Ms<3UsU15goroVdtQPI^*rC?K$gck4 zsr@VNy7ju1zy05Sy>-jRjoPxTxqwqHmzkWLq);eOsZP zWrn!*Xyp3rqU66OH|ep{=}y>~USc2$~3o+ywn%<{@R7cBWU1{_HO z;Cau-*4*@;&bI$_-Tuo0ttK7~T-$#RKzheXnxCJPUd~uLd=ZZJ}-+Lfx_w z4vkZN>L9b5x~Q)1sJ+i3a0ob|7WQL1>)OfR8T#6}0^nlDUklIbR8X^PB%RrlbH)4(hi1{(ult?Ac?>IvI^ zczZhiow8PCfbQmIUbbo#D>^&aGd9N4&+n#de2mrel|P8P7#vTke^bnln63~v{YIQ) z+MF9oCHdE12q6LRJOiMLZ;x$^aU+8l8Iubl(^jg6o%wRmH&yZn$MaRj@>LE@M@*(# zNH1$6EESpAw}--!BSe)dCJMA)m`at$4z?Fg?CC3yA71{Z?|b#oo8S0`+`V_-WoI&( zxgfY;1Yt7mLl6W+QA8MqaX&(1=9ZcoA0IdW@`W!3|N6;)o!GVi#D1@9<>5^Cnv?1F zff*~6^HIt;EzPtJ599Ur6BMi1P{P8 z*4CDB`uo~gIn=?*6`eFSrC;ztFg;V^(4lb-92)2NiD|~h^G7R~|M1};K!2~xy>~Uy z+wJh3M+#K^Ja^t6vaD+^{7nHz8>)Ye)4wcwLOx3XJmdZ|ahR*^KUE8XO}i(tZ(a$5 z?U<*JU>-XNr7D1B6W*$c?joN2g@PMUa05zCNTkgf7olA=3|evdJ6o{HPFrMV=SrZ{ zA^Phf)|2s@^H8_1LJjxAuH#gnA7OT5XMOmq0*8qQe$>KWt?%Dir++y|0IUyzc0-76 zPD0=^pdV-=sl@Ga9A>+har2rrtY~ZF*yI$C96Z3G@rk(y?el}a{=gsZ3d0Q8wUOaW6r#gM2TboMPtM9$55zy&-~lxW}kg#$0DPUmr_C+JIs^tZUQXC2zI?sSW1AI-SdsB7y9OQ{*HRZ%I*Dh_`O zPReHqfVERrt>0R0=DEfYI8eLkwx{9Q?Jk>!n_0Ie#m?PjzWv=iqo@2@Hp!(?_gZj$ zQ!cH$yPN3hYNorZiT3s^&CMR!jC;-xy;Q0)HC{hwaApMxoTgc9HGAvU_F++XBccpzj7V4W#Gxflut}h*w{sN#oS6S zL0mDN3x87$;qR>d*v=yW!u;$ljUliJXp4_QdV#juvmDWik>+MPmoMkWfkCp4!@g6e zc>35;My93->*nTc3&WOGzQ3s{iaK*q)MG?RT7g zLEL{f$;fF|cXn~z-~g>&hC@@6JidQF-smW+%N26-M?!6o%t_|=*MiDl68_F>9Cur~r`@KmS*NM9XnRdnrR@m7ZEYbpw1UjQAli1R zj8D;2nx@Y)^fbG)W#>lx9?Q7aXv(Pze^60MRe`y_f3=-)jsOS?=VEh-o8ofB&2e3z zdg?>qo_+AdHk;O#EVtg6rC5r1=+Qjeca^DBk`*bS%SFB1R%$~on@achwbI|$N>^7C zZEYDc85h^F7mV=D3yGsr%RkXIm6+j6O0_6Vm4nH@!|0*W?NDWqI;Rcowwx} zUYq8`sLz8B&9Y*s%q#CS$x?5Iq|#R#^if~=tFK_4^@Mzm00;}4g6l(cOI-*YsMUv@ zBU5B|jN!Q{c-d;OH0G(pnCC_yU#hVa+eXY!2AnCBS)=SJ?=9e=6h z7;Iv$O9I`%vf8Iq1P(Y3vmNcM92{h0cMmDc;`sD5+m9b-WO|CpLh+*i(MdTr9oZaf zmvymr*)npeG$-=2Y&&w4%JC6;@_7cM1y#Q?^G&|B<1D{O(9 zg+M0>f$1a!wv?)2N3jxi&y<7ysiLo^iaw)xpA%)ptlLDYqXlJas*@8Gjvb|R;simy zFdtNcsudKcQ+{E>3(NUbYtuQ*|~l#2YaYfPk-We1kyRkiC?we9-a^{TelTy}FE zB`cltYoQMXPIEKa{sA)m{W!U1f?}CyVv-J1VxZZgE#uIZacIsslg(*+#B;1uDMwFg zrDn8JMXji<`y19b{a!!-RCSdsXOT)^2dM5O#Ar~Ao`T1>X^x*r^NKri^maQOK3e6W zNAnyyQY8q?+}m?e>nvEUVU>!T_RfbN!NCX)`lKu6C=rX5SGor-=LfEf)U5bDfaSBLJRl|FtB20=tQuGi?A}tdiMwob1UG z`iAAOstaaHm?sZo4vftO!CF;N6Rp;95bOdRh3TrV5CUZrFXvY_aLSbgP5xUl;q!H#1T`g4?S=)>4^L9)#JbT74vX=C_1=gJ@F82}dxfwf9tZ67wr z#~__R58&3G^^}5Ht=$^GKWRznEP`H^X^_)&YQ8g|WAg5K$(@6D6~rb<31@*xwULp9rk)6$Hx zAjr>BI(d@P=t+XvS%Tu}|1g`-*O6bbqM&LS6De)kk+R)T+v!kgecC_zcE-bLZo%v6 zA-${{Cz~a#1XL$y$W`-nx*q)KDY!dz|N>Qb5)NkWS z<~#!6TxhPV1g4np)0TA1S6#$|8`8Bi-{ae0&t98sCc{nFXK2b<9646y@ofc;9ru}; z4I7`tv7pO}1ErN*=bHFLiNQ>UFd4=t)%p8rMb9#uO~W1=*Qd#5GzShL;YJn1)Km=-w&(4*|)y=@`VP##r9t<1ZII|69?Z~b7pp~(zIs`Z{H+oW1((b z4!x}~Tf*!<880C>mWLob%afWmgPJ^ZDa(e=Ce+$xs5Q&LbK%GY=7~d;GMdubj`}9w zTE+A@Fs9JvmEei+3|23hecKA!F1+BQll%0a+bp}?WZ2~LcSVNXrbRw~gS zMx+-8ze;kPjWNHkYE{4bX7URTe-Z$N5aQwkAW0Rl76NO{!Ko-B8yeGG@uQZqA9my` z!LmXn?3gM0%#;Eqivg#K5i`c2;^lCfb66>dDDVjic`6eVRHvr!XQl}&RU*GiM z^RBc)**4m7u~IHha|@~VcHFi$>}(Eg*@WdP)u~xB)dFo+KzGifIc?Jt2R}cTvQK1E z)~U2@jXSoQv6Pyv4fr@$_`84rc(xE&>zLmPs@5FWTD!~m1U$1{apZ_YN4v+?O&+Z+ z7Sl5!`wmvvy|>K7WXRM^7|%s_o;**}-fA=0@33}tn!cX6;C1Lol_#Dq(%MpCcwLxG z@H`j(Lgt#{%)}xm8?~tq2HN7@ zag#;NkqOMvNth`?p$cWcZX&??qg}^=FPDPW4645sHP{ZV8Suk6_&sx!a!OGiXrjES zyEcP*&1kKXrA`mcjm^I2+;0~c02@PKt(w|c4XiZ_wu zgUoCtAYTrdDg{iIBc?-(l9hr?20NQUyLMcw@~ecE3Sp%}R4Ehr0VWJF$%+live2%J zc3rHrhm~?swgW~HRegeD2~{kT3CpzD5uF)}rj$jKXVa9j$)@eeoNJ#-yL!U4^`xWK ztX3+owJOJb{_xKg{w^>8o-M?9$;r1FRIQqoRPo}I>G2b=YmegCF&nK@Y+N6QHqX