From 9c9e2ec9ccd2609246610c798d4a8d8f3bc5aee7 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Wed, 1 May 2013 13:23:08 -0700 Subject: [PATCH 01/59] PVLAN: Add pvlan in createNetworkCommand --- api/src/com/cloud/network/Networks.java | 1 + .../apache/cloudstack/api/ApiConstants.java | 1 + .../user/network/CreateNetworkCmd.java | 7 ++++ .../xen/resource/CitrixResourceBase.java | 5 +++ .../ConfigurationManagerImpl.java | 2 ++ .../src/com/cloud/network/NetworkManager.java | 3 +- .../com/cloud/network/NetworkManagerImpl.java | 35 +++++++++++++------ .../com/cloud/network/NetworkServiceImpl.java | 13 +++++-- .../com/cloud/network/vpc/VpcManagerImpl.java | 2 +- .../src/com/cloud/vm/UserVmManagerImpl.java | 4 +-- .../cloud/network/MockNetworkManagerImpl.java | 2 +- .../com/cloud/vpc/MockNetworkManagerImpl.java | 3 +- utils/src/com/cloud/utils/net/NetUtils.java | 26 ++++++++++++++ .../com/cloud/utils/net/NetUtilsTest.java | 8 +++++ 14 files changed, 93 insertions(+), 19 deletions(-) diff --git a/api/src/com/cloud/network/Networks.java b/api/src/com/cloud/network/Networks.java index f085e9f3029..5aede053d50 100755 --- a/api/src/com/cloud/network/Networks.java +++ b/api/src/com/cloud/network/Networks.java @@ -63,6 +63,7 @@ public class Networks { Storage("storage", Integer.class), Lswitch("lswitch", String.class), Mido("mido", String.class), + Pvlan("pvlan", String.class), UnDecided(null, null); private String scheme; diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 1165c7b34f6..9581f54ca61 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -223,6 +223,7 @@ public class ApiConstants { public static final String VLAN = "vlan"; public static final String REMOVE_VLAN="removevlan"; public static final String VLAN_ID = "vlanid"; + public static final String ISOLATED_PVLAN = "isolatedpvlan"; public static final String VM_AVAILABLE = "vmavailable"; public static final String VM_LIMIT = "vmlimit"; public static final String VM_TOTAL = "vmtotal"; 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..7f699fe0cc9 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 @@ -86,6 +86,9 @@ public class CreateNetworkCmd extends BaseCmd { @Parameter(name=ApiConstants.VLAN, type=CommandType.STRING, description="the ID or VID of the network") private String vlan; + @Parameter(name=ApiConstants.ISOLATED_PVLAN, type=CommandType.STRING, description="the isolated private vlan for this network") + private String isolatedPvlan; + @Parameter(name=ApiConstants.NETWORK_DOMAIN, type=CommandType.STRING, description="network domain") private String networkDomain; @@ -141,6 +144,10 @@ public class CreateNetworkCmd extends BaseCmd { return vlan; } + public String getIsolatedPvlan() { + return isolatedPvlan; + } + public String getAccountName() { return accountName; } 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..176dc00ec0e 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 @@ -1014,6 +1014,11 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } else if (nic.getBroadcastType() == BroadcastDomainType.Lswitch) { // Nicira Logical Switch return network.getNetwork(); + } else if (nic.getBroadcastType() == BroadcastDomainType.Pvlan) { + URI broadcastUri = nic.getBroadcastUri(); + assert broadcastUri.getScheme().equals(BroadcastDomainType.Pvlan.scheme()); + long vlan = Long.parseLong(NetUtils.getPrimaryPvlanFromUri(broadcastUri)); + return enableVlanNetwork(conn, vlan, network); } throw new CloudRuntimeException("Unable to support this type of network broadcast domain: " + nic.getBroadcastUri()); diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 37ca793c556..a47f3b3c80f 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -2505,6 +2505,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if (uri != null) { String[] vlan = uri.toString().split("vlan:\\/\\/"); networkVlanId = vlan[1]; + //For pvlan + networkVlanId = networkVlanId.split("-")[0]; } if (vlanId != null) { diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index 4af716ca12a..e11135161db 100755 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -128,7 +128,8 @@ public interface NetworkManager { 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) + long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr, + String isolatedPvlan) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException; /** diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 5179e872686..7a09eb553f8 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -1874,7 +1874,8 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L @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) + PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, + String ip6Gateway, String ip6Cidr, String isolatedPvlan) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId); @@ -1964,6 +1965,9 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L if (ipv6) { throw new InvalidParameterValueException("IPv6 is not supported with security group!"); } + if (isolatedPvlan != null) { + throw new InvalidParameterValueException("Isolated Private VLAN is not supported with security group!"); + } // Only Account specific Isolated network with sourceNat service disabled are allowed in security group // enabled zone if ( ntwkOff.getGuestType() != GuestType.Shared ){ @@ -2094,13 +2098,20 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L } if (vlanId != null) { - userNetwork.setBroadcastUri(URI.create("vlan://" + vlanId)); - userNetwork.setBroadcastDomainType(BroadcastDomainType.Vlan); - if (!vlanId.equalsIgnoreCase(Vlan.UNTAGGED)) { - userNetwork.setBroadcastDomainType(BroadcastDomainType.Vlan); - } else { - userNetwork.setBroadcastDomainType(BroadcastDomainType.Native); - } + if (isolatedPvlan == null) { + userNetwork.setBroadcastUri(URI.create("vlan://" + vlanId)); + if (!vlanId.equalsIgnoreCase(Vlan.UNTAGGED)) { + userNetwork.setBroadcastDomainType(BroadcastDomainType.Vlan); + } else { + userNetwork.setBroadcastDomainType(BroadcastDomainType.Native); + } + } else { + if (vlanId.equalsIgnoreCase(Vlan.UNTAGGED)) { + throw new InvalidParameterValueException("Cannot support pvlan with untagged primary vlan!"); + } + userNetwork.setBroadcastUri(NetUtils.generateUriForPvlan(vlanId, isolatedPvlan)); + userNetwork.setBroadcastDomainType(BroadcastDomainType.Pvlan); + } } List networks = setupNetwork(owner, ntwkOff, userNetwork, plan, name, displayText, true, domainId, @@ -2697,7 +2708,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, null); 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 " + @@ -3551,8 +3562,10 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L nic.setGateway(ip.getGateway()); nic.setNetmask(ip.getNetmask()); nic.setIsolationUri(IsolationType.Vlan.toUri(ip.getVlanTag())); - nic.setBroadcastType(BroadcastDomainType.Vlan); - nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(ip.getVlanTag())); + //nic.setBroadcastType(BroadcastDomainType.Vlan); + //nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(ip.getVlanTag())); + nic.setBroadcastType(network.getBroadcastDomainType()); + nic.setBroadcastUri(network.getBroadcastUri()); nic.setFormat(AddressFormat.Ip4); nic.setReservationId(String.valueOf(ip.getVlanTag())); nic.setMacAddress(ip.getMacAddress()); diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 2dcb47d0cd8..7c4d7027c6b 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -828,6 +828,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { String endIPv6 = cmd.getEndIpv6(); String ip6Gateway = cmd.getIp6Gateway(); String ip6Cidr = cmd.getIp6Cidr(); + String isolatedPvlan = cmd.getIsolatedPvlan(); // Validate network offering NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId); @@ -1014,6 +1015,10 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } } + if (isolatedPvlan != null && (zone.getNetworkType() != NetworkType.Advanced || ntwkOff.getGuestType() != Network.GuestType.Shared)) { + throw new InvalidParameterValueException("Can only support create Private VLAN network with advance shared network!"); + } + // Regular user can create Guest Isolated Source Nat enabled network only if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL && (ntwkOff.getTrafficType() != TrafficType.Guest || ntwkOff.getGuestType() != Network.GuestType.Isolated @@ -1045,6 +1050,9 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { if (ipv6 && providersConfiguredForExternalNetworking(ntwkProviders)) { throw new InvalidParameterValueException("Cannot support IPv6 on network offering with external devices!"); } + if (isolatedPvlan != null && providersConfiguredForExternalNetworking(ntwkProviders)) { + throw new InvalidParameterValueException("Cannot support private vlan on network offering with external devices!"); + } if (cidr != null && providersConfiguredForExternalNetworking(ntwkProviders)) { if (ntwkOff.getGuestType() == GuestType.Shared && (zone.getNetworkType() == NetworkType.Advanced) && @@ -1115,7 +1123,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { 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, isolatedPvlan); } if (caller.getType() == Account.ACCOUNT_TYPE_ADMIN && createVlan) { @@ -3363,7 +3372,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, null); s_logger.debug("Created private network " + privateNetwork); } else { s_logger.debug("Private network already exists: " + privateNetwork); diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index bc7bb0c75f2..18690d72ed5 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -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, null); return guestNetwork; } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 617994888bd..8f2d103d343 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2164,7 +2164,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, null); defaultNetwork = _networkDao.findById(newNetwork.getId()); } else if (virtualNetworks.size() > 1) { throw new InvalidParameterValueException( @@ -4005,7 +4005,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, null); // 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/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index e9987bd1b66..3381d60c564 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -249,7 +249,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, String isolatedPvlan) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { // 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 9b18358e258..7dcc970405b 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -831,7 +831,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) + PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, + String gatewayv6, String cidrv6, String isolatedPvlan) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { // TODO Auto-generated method stub return null; diff --git a/utils/src/com/cloud/utils/net/NetUtils.java b/utils/src/com/cloud/utils/net/NetUtils.java index 5988dd5f337..4dd404d4cc3 100755 --- a/utils/src/com/cloud/utils/net/NetUtils.java +++ b/utils/src/com/cloud/utils/net/NetUtils.java @@ -24,6 +24,7 @@ import java.net.InetAddress; import java.net.InterfaceAddress; import java.net.NetworkInterface; import java.net.SocketException; +import java.net.URI; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Formatter; @@ -1290,4 +1291,29 @@ public class NetUtils { } return resultIp; } + + public static URI generateUriForPvlan(String primaryVlan, String isolatedPvlan) { + return URI.create("pvlan://" + primaryVlan + "-i" + isolatedPvlan); + } + + public static String getPrimaryPvlanFromUri(URI uri) { + String[] vlans = uri.getHost().split("-"); + if (vlans.length < 1) { + return null; + } + return vlans[0]; + } + + public static String getIsolatedPvlanFromUri(URI uri) { + String[] vlans = uri.getHost().split("-"); + if (vlans.length < 2) { + return null; + } + for (String vlan : vlans) { + if (vlan.startsWith("i")) { + return vlan.replace("i", " ").trim(); + } + } + return null; + } } diff --git a/utils/test/com/cloud/utils/net/NetUtilsTest.java b/utils/test/com/cloud/utils/net/NetUtilsTest.java index 28bd71f18d7..16d3402f0e6 100644 --- a/utils/test/com/cloud/utils/net/NetUtilsTest.java +++ b/utils/test/com/cloud/utils/net/NetUtilsTest.java @@ -17,6 +17,7 @@ package com.cloud.utils.net; import java.math.BigInteger; +import java.net.URI; import java.util.SortedSet; import java.util.TreeSet; @@ -128,4 +129,11 @@ public class NetUtilsTest extends TestCase { assertFalse(NetUtils.isIp6InRange("1234:5678:abcd::1", null)); assertTrue(NetUtils.isIp6InRange("1234:5678:abcd::1", "1234:5678::1-1234:5679::1")); } + + public void testPvlan() { + URI uri = NetUtils.generateUriForPvlan("123", "456"); + assertTrue(uri.toString().equals("pvlan://123-i456")); + assertTrue(NetUtils.getPrimaryPvlanFromUri(uri).equals("123")); + assertTrue(NetUtils.getIsolatedPvlanFromUri(uri).equals("456")); + } } From b64039bafd194be78f0a873d4b2431d01931febf Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Wed, 1 May 2013 13:23:08 -0700 Subject: [PATCH 02/59] Implement PVLAN on Xen Start/stop vm/dhcp server are done. Not done with VM migration. A new command(PvlanSetupCommand) is sent for setting up PVLAN for vms. Currently it's focus on OVS implementation. Need to be more abstruct and add vSwitch part. --- .../cloud/agent/api/PvlanSetupCommand.java | 130 ++++++++++++++ .../xen/resource/CitrixResourceBase.java | 46 ++++- scripts/vm/hypervisor/xenserver/ovs-pvlan | 168 ++++++++++++++++++ .../vm/hypervisor/xenserver/xenserver60/patch | 6 +- scripts/vm/network/ovs-pvlan-cleanup.sh | 23 +++ scripts/vm/network/ovs-pvlan-dhcp-host.sh | 104 +++++++++++ .../vm/network/ovs-pvlan-vm-in-dhcp-host.sh | 88 +++++++++ scripts/vm/network/ovs-pvlan-vm.sh | 90 ++++++++++ .../network/element/VirtualRouterElement.java | 11 ++ .../VirtualNetworkApplianceManager.java | 4 + .../VirtualNetworkApplianceManagerImpl.java | 87 ++++++++- .../src/com/cloud/vm/UserVmManagerImpl.java | 45 +++++ ...MockVpcVirtualNetworkApplianceManager.java | 7 + 13 files changed, 804 insertions(+), 5 deletions(-) create mode 100644 api/src/com/cloud/agent/api/PvlanSetupCommand.java create mode 100755 scripts/vm/hypervisor/xenserver/ovs-pvlan create mode 100755 scripts/vm/network/ovs-pvlan-cleanup.sh create mode 100755 scripts/vm/network/ovs-pvlan-dhcp-host.sh create mode 100755 scripts/vm/network/ovs-pvlan-vm-in-dhcp-host.sh create mode 100755 scripts/vm/network/ovs-pvlan-vm.sh diff --git a/api/src/com/cloud/agent/api/PvlanSetupCommand.java b/api/src/com/cloud/agent/api/PvlanSetupCommand.java new file mode 100644 index 00000000000..22a828afa8b --- /dev/null +++ b/api/src/com/cloud/agent/api/PvlanSetupCommand.java @@ -0,0 +1,130 @@ +// 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; + +import java.net.URI; + +import com.cloud.utils.net.NetUtils; + +public class PvlanSetupCommand extends Command { + public enum Type { + DHCP, + VM, + VM_IN_DHCP_HOST + } + private String op; + private String bridge; + private String primary; + private String isolated; + private String vmMac; + private String dhcpMac; + private String dhcpIp; + private boolean strict; + private Type type; + + protected PvlanSetupCommand() {} + + protected PvlanSetupCommand(Type type, String op, String bridge, URI uri) + { + this.type = type; + this.op = op; + this.bridge = bridge; + this.primary = NetUtils.getPrimaryPvlanFromUri(uri); + this.isolated = NetUtils.getIsolatedPvlanFromUri(uri); + this.strict = true; + } + + static public PvlanSetupCommand createDhcpSetup(String op, String bridge, URI uri, String dhcpMac, String dhcpIp) + { + PvlanSetupCommand cmd = new PvlanSetupCommand(Type.DHCP, op, bridge, uri); + cmd.setDhcpMac(dhcpMac); + cmd.setDhcpIp(dhcpIp); + return cmd; + } + + static public PvlanSetupCommand createVmSetup(String op, String bridge, URI uri, String vmMac) + { + PvlanSetupCommand cmd = new PvlanSetupCommand(Type.VM, op, bridge, uri); + cmd.setVmMac(vmMac); + return cmd; + } + + static public PvlanSetupCommand createVmInDhcpHostSetup(String op, String bridge, URI uri, String dhcpMac, String vmMac) + { + PvlanSetupCommand cmd = new PvlanSetupCommand(Type.VM_IN_DHCP_HOST, op, bridge, uri); + cmd.setDhcpMac(dhcpMac); + cmd.setVmMac(vmMac); + return cmd; + } + + @Override + public boolean executeInSequence() { + return true; + } + + public String getOp() { + return op; + } + + public String getBridge() { + return bridge; + } + + public String getPrimary() { + return primary; + } + + public String getIsolated() { + return isolated; + } + + public String getVmMac() { + return vmMac; + } + + protected void setVmMac(String vmMac) { + this.vmMac = vmMac; + } + + public String getDhcpMac() { + return dhcpMac; + } + + protected void setDhcpMac(String dhcpMac) { + this.dhcpMac = dhcpMac; + } + + public String getDhcpIp() { + return dhcpIp; + } + + protected void setDhcpIp(String dhcpIp) { + this.dhcpIp = dhcpIp; + } + + public Type getType() { + return type; + } + + public boolean isStrict() { + return strict; + } + + public void setStrict(boolean strict) { + this.strict = strict; + } +} 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 176dc00ec0e..34b590e40c9 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 @@ -604,6 +604,8 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return execute((NetworkRulesVmSecondaryIpCommand)cmd); } else if (clazz == ScaleVmCommand.class) { return execute((ScaleVmCommand) cmd); + } else if (clazz == PvlanSetupCommand.class) { + return execute((PvlanSetupCommand) cmd); } else { return Answer.createUnsupportedCommandAnswer(cmd); } @@ -1054,7 +1056,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe vifr = vif.getRecord(conn); s_logger.debug("Created a vif " + vifr.uuid + " on " + nic.getDeviceId()); } - + return vif; } @@ -1465,6 +1467,48 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } } } + + private Answer execute(PvlanSetupCommand cmd) { + Connection conn = getConnection(); + + String primaryPvlan = cmd.getPrimary(); + String isolatedPvlan = cmd.getIsolated(); + String op = cmd.getOp(); + String bridge = cmd.getBridge(); + String result = null; + String dhcpMac = cmd.getDhcpMac(); + String dhcpIp = cmd.getDhcpIp(); + String vmMac = cmd.getVmMac(); + if (cmd.getType() == PvlanSetupCommand.Type.DHCP) { + result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-dhcp", "op", op, "bridge", bridge, + "primary-pvlan", primaryPvlan, "isolated-pvlan", isolatedPvlan, "dhcp-ip", dhcpIp, "dhcp-mac", dhcpMac); + if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) { + s_logger.warn("Failed to program pvlan for dhcp server with mac " + dhcpMac); + return new Answer(cmd, false, result); + } else { + s_logger.info("Programmed pvlan for dhcp server with mac " + dhcpMac); + } + } else if (cmd.getType() == PvlanSetupCommand.Type.VM) { + result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-vm-alone", "op", op, "bridge", bridge, + "primary-pvlan", primaryPvlan, "isolated-pvlan", isolatedPvlan, "vm-mac", vmMac); + if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) { + s_logger.warn("Failed to program pvlan for vm with mac " + vmMac); + return new Answer(cmd, false, result); + } else { + s_logger.info("Programmed pvlan for vm with mac " + vmMac); + } + } else if (cmd.getType() == PvlanSetupCommand.Type.VM_IN_DHCP_HOST) { + result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-vm-dhcp", "op", op, "bridge", bridge, + "primary-pvlan", primaryPvlan, "isolated-pvlan", isolatedPvlan, "vm-mac", vmMac, "dhcp-mac", dhcpMac); + if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) { + s_logger.warn("Failed to program pvlan for vm in dhcp host with mac " + vmMac); + return new Answer(cmd, false, result); + } else { + s_logger.info("Programmed pvlan for vm in dhcp host with mac " + vmMac); + } + } + return new Answer(cmd, true, result); + } @Override public StartAnswer execute(StartCommand cmd) { diff --git a/scripts/vm/hypervisor/xenserver/ovs-pvlan b/scripts/vm/hypervisor/xenserver/ovs-pvlan new file mode 100755 index 00000000000..2c1e3af8f77 --- /dev/null +++ b/scripts/vm/hypervisor/xenserver/ovs-pvlan @@ -0,0 +1,168 @@ +#!/usr/bin/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. + + +import cloudstack_pluginlib as lib +import logging +import os +import sys +import subprocess +import time +import XenAPIPlugin + +sys.path.append("/opt/xensource/sm/") +import util + +from time import localtime as _localtime, asctime as _asctime + +xePath = "/opt/xensource/bin/xe" +lib.setup_logging("/var/log/ovs-pvlan.log") +dhcpSetupPath = "/opt/xensource/bin/ovs-pvlan-dhcp-host.sh" +vmAloneSetupPath = "/opt/xensource/bin/ovs-pvlan-vm.sh" +vmDhcpSetupPath = "/opt/xensource/bin/ovs-pvlan-vm-in-dhcp-host.sh" +pvlanCleanupPath = "/opt/xensource/bin/ovs-pvlan-cleanup.sh" + +def echo(fn): + def wrapped(*v, **k): + name = fn.__name__ + util.SMlog("#### VMOPS enter %s ####" % name) + res = fn(*v, **k) + util.SMlog("#### VMOPS exit %s ####" % name) + return res + return wrapped + + +@echo +def setup_pvlan_dhcp(session, args): + op = args.pop("op") + bridge = args.pop("bridge") + primary = args.pop("primary-pvlan") + isolated = args.pop("isolated-pvlan") + dhcp_ip = args.pop("dhcp-ip"); + dhcp_mac = args.pop("dhcp-mac"); + + res = lib.check_switch() + if res != "SUCCESS": + return "FAILURE:%s" % res + + if op == "add": + logging.debug("About to setup dhcp vm on the switch:%s" % bridge) + res = lib.do_cmd([dhcpSetupPath, "-A", "-b", bridge, "-p", primary, + "-i", isolated, "-d", dhcp_ip, "-m", dhcp_mac]) + if res: + result = "FAILURE:%s" % res + return result; + logging.debug("Setup dhcp vm on switch program done") + elif op == "delete": + logging.debug("About to remove dhcp the switch:%s" % bridge) + res = lib.do_cmd([dhcpSetupPath, "-D", "-b", bridge, "-p", primary, + "-i", isolated, "-d", dhcp_ip, "-m", dhcp_mac]) + if res: + result = "FAILURE:%s" % res + return result; + logging.debug("Remove DHCP on switch program done") + + result = "true" + logging.debug("Setup_pvlan_dhcp completed with result:%s" % result) + return result + +@echo +def setup_pvlan_vm_alone(session, args): + op = args.pop("op") + bridge = args.pop("bridge") + isolated = args.pop("isolated-pvlan") + vm_mac = args.pop("vm-mac") + trunk_port = 1 + + res = lib.check_switch() + if res != "SUCCESS": + return "FAILURE:%s" % res + + if op == "add": + logging.debug("About to setup vm alone on the switch:%s" % bridge) + res = lib.do_cmd([vmAloneSetupPath, "-A", "-b", bridge, "-i", isolated, "-v", vm_mac]) + if res: + result = "FAILURE:%s" % res + return result; + logging.debug("Setup vm alone on switch program done") + elif op == "delete": + logging.debug("About to remove vm alone on the switch:%s" % bridge) + res = lib.do_cmd([vmAloneSetupPath, "-D", "-b", bridge, "-i", isolated, "-v", vm_mac]) + if res: + result = "FAILURE:%s" % res + return result; + logging.debug("Remove vm alone on switch program done") + + result = "true" + logging.debug("Setup_pvlan_vm_alone completed with result:%s" % result) + return result + +@echo +def setup_pvlan_vm_dhcp(session, args): + op = args.pop("op") + bridge = args.pop("bridge") + isolated = args.pop("isolated-pvlan") + vm_mac = args.pop("vm-mac") + dhcp_mac = args.pop("dhcp-mac"); + trunk_port = 1 + + res = lib.check_switch() + if res != "SUCCESS": + return "FAILURE:%s" % res + + if op == "add": + logging.debug("About to setup vm dhcp on the switch:%s" % bridge) + res = lib.do_cmd([vmDhcpSetupPath, "-A", "-b", bridge, "-i", isolated, + "-v", vm_mac, "-m", dhcp_mac]) + if res: + result = "FAILURE:%s" % res + return result; + logging.debug("Setup vm dhcp on switch program done") + elif op == "delete": + logging.debug("About to remove vm dhcp on the switch:%s" % bridge) + res = lib.do_cmd([vmDhcpSetupPath, "-D", "-b", bridge, "-i", isolated, + "-v", vm_mac, "-m", dhcp_mac]) + if res: + result = "FAILURE:%s" % res + return result; + logging.debug("Remove vm dhcp on switch program done") + + result = "true" + logging.debug("Setup_pvlan_vm_dhcp completed with result:%s" % result) + return result + +@echo +def cleanup(session, args): + res = lib.check_switch() + if res != "SUCCESS": + return "FAILURE:%s" % res + + res = lib.do_cmd([pvlanCleanUpPath]) + if res: + result = "FAILURE:%s" % res + return result; + + result = "true" + logging.debug("Setup_pvlan_vm_dhcp completed with result:%s" % result) + return result + +if __name__ == "__main__": + XenAPIPlugin.dispatch({"setup-pvlan-dhcp": setup_pvlan_dhcp, + "setup-pvlan-vm-alone": setup_pvlan_vm_alone, + "setup-pvlan-vm-dhcp": setup_pvlan_vm_dhcp, + "cleanup":cleanup}) diff --git a/scripts/vm/hypervisor/xenserver/xenserver60/patch b/scripts/vm/hypervisor/xenserver/xenserver60/patch index c9125f4c5b2..c767f1af7df 100644 --- a/scripts/vm/hypervisor/xenserver/xenserver60/patch +++ b/scripts/vm/hypervisor/xenserver/xenserver60/patch @@ -67,4 +67,8 @@ bumpUpPriority.sh=../../../../network/domr/,0755,/opt/xensource/bin swift=..,0755,/opt/xensource/bin swiftxen=..,0755,/etc/xapi.d/plugins s3xen=..,0755,/etc/xapi.d/plugins - +ovs-pvlan=..,0755,/etc/xapi.d/plugins +ovs-pvlan-dhcp-host.sh=../../../network,0755,/opt/xensource/bin +ovs-pvlan-vm-in-dhcp-host.sh=../../../network,0755,/opt/xensource/bin +ovs-pvlan-vm.sh=../../../network,0755,/opt/xensource/bin +ovs-pvlan-cleanup.sh=../../../network,0755,/opt/xensource/bin diff --git a/scripts/vm/network/ovs-pvlan-cleanup.sh b/scripts/vm/network/ovs-pvlan-cleanup.sh new file mode 100755 index 00000000000..7493bedeff6 --- /dev/null +++ b/scripts/vm/network/ovs-pvlan-cleanup.sh @@ -0,0 +1,23 @@ +#!/bin/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. + +#!/bin/bash + +ovs-ofctl del-flows xenbr0 +ovs-ofctl add-flow xenbr0 priority=0,actions=NORMAL + diff --git a/scripts/vm/network/ovs-pvlan-dhcp-host.sh b/scripts/vm/network/ovs-pvlan-dhcp-host.sh new file mode 100755 index 00000000000..e12fbce0f18 --- /dev/null +++ b/scripts/vm/network/ovs-pvlan-dhcp-host.sh @@ -0,0 +1,104 @@ +#!/bin/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. + +usage() { + printf "Usage: %s: (-A|-D) -b -p -i -d -m -v -h \n" $(basename $0) >&2 + exit 2 +} + +br= +pri_vlan= +sec_iso_vlan= +dhcp_ip= +dhcp_mac= +vm_mac= +op= + +while getopts 'ADb:p:i:d:m:v:h' OPTION +do + case $OPTION in + A) op="add" + ;; + D) op="del" + ;; + b) br="$OPTARG" + ;; + p) pri_vlan="$OPTARG" + ;; + i) sec_iso_vlan="$OPTARG" + ;; + d) dhcp_ip="$OPTARG" + ;; + m) dhcp_mac="$OPTARG" + ;; + v) vm_mac="$OPTARG" + ;; + h) usage + exit 1 + ;; + esac +done + +if [ -z "$op" ] +then + echo Missing operation pararmeter! + exit 1 +fi + +if [ -z "$br" ] +then + echo Missing parameter bridge! + exit 1 +fi + +if [ -z "$pri_vlan" ] +then + echo Missing parameter primary vlan! + exit 1 +fi + +if [ -z "$sec_iso_vlan" ] +then + echo Missing parameter secondary isolate vlan! + exit 1 +fi + +if [ -z "$dhcp_ip" ] +then + echo Missing parameter DHCP IP! + exit 1 +fi + +if [ -z "$dhcp_mac" ] +then + echo Missing parameter DHCP MAC! + exit 1 +fi + +if [ "$op" == "add" ] +then + ovs-ofctl add-flow $br priority=200,arp,dl_vlan=$sec_iso_vlan,nw_dst=$dhcp_ip,actions=mod_vlan_vid:$pri_vlan,NORMAL + ovs-ofctl add-flow $br priority=180,arp,nw_dst=$dhcp_ip,actions=NORMAL + ovs-ofctl add-flow $br priority=150,dl_vlan=$sec_iso_vlan,dl_dst=$dhcp_mac,actions=mod_vlan_vid:$pri_vlan,NORMAL + ovs-ofctl add-flow $br priority=100,udp,dl_vlan=$sec_iso_vlan,nw_dst=255.255.255.255,tp_dst=67,actions=mod_vlan_vid:$pri_vlan,NORMAL +else + ovs-ofctl del-flows --strict $br priority=200,arp,dl_vlan=$sec_iso_vlan,nw_dst=$dhcp_ip + ovs-ofctl del-flows --strict $br priority=180,arp,nw_dst=$dhcp_ip + ovs-ofctl del-flows --strict $br priority=150,dl_vlan=$sec_iso_vlan,dl_dst=$dhcp_mac + ovs-ofctl del-flows --strict $br priority=100,udp,dl_vlan=$sec_iso_vlan,nw_dst=255.255.255.255,tp_dst=67 +fi diff --git a/scripts/vm/network/ovs-pvlan-vm-in-dhcp-host.sh b/scripts/vm/network/ovs-pvlan-vm-in-dhcp-host.sh new file mode 100755 index 00000000000..de37882159c --- /dev/null +++ b/scripts/vm/network/ovs-pvlan-vm-in-dhcp-host.sh @@ -0,0 +1,88 @@ +#!/bin/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. + +usage() { + printf "Usage: %s: (-A|-D) -b -p -i -d -m -v -h \n" $(basename $0) >&2 + exit 2 +} + +br= +pri_vlan= +sec_iso_vlan= +dhcp_ip= +dhcp_mac= +vm_mac= +op= + +while getopts 'ADb:p:i:d:m:v:h' OPTION +do + case $OPTION in + A) op="add" + ;; + D) op="del" + ;; + b) br="$OPTARG" + ;; + p) pri_vlan="$OPTARG" + ;; + i) sec_iso_vlan="$OPTARG" + ;; + d) dhcp_ip="$OPTARG" + ;; + m) dhcp_mac="$OPTARG" + ;; + v) vm_mac="$OPTARG" + ;; + h) usage + exit 1 + ;; + esac +done + +if [ -z "$op" ] +then + echo Missing operation pararmeter! + exit 1 +fi + +if [ -z "$br" ] +then + echo Missing parameter bridge! + exit 1 +fi + +if [ -z "$vm_mac" ] +then + echo Missing parameter VM MAC! + exit 1 +fi + +if [ -z "$dhcp_mac" ] +then + echo Missing parameter DHCP MAC! + exit 1 +fi + +if [ "$op" == "add" ] +then + ovs-ofctl add-flow $br priority=120,dl_src=$vm_mac,dl_dst=$dhcp_mac,actions=NORMAL + ovs-ofctl add-flow $br priority=80,udp,dl_src=$vm_mac,nw_dst=255.255.255.255,tp_dst=67,actions=NORMAL +else + ovs-ofctl del-flows --strict $br priority=120,dl_src=$vm_mac,dl_dst=$dhcp_mac + ovs-ofctl del-flows --strict $br priority=80,udp,dl_src=$vm_mac,nw_dst=255.255.255.255,tp_dst=67 +fi diff --git a/scripts/vm/network/ovs-pvlan-vm.sh b/scripts/vm/network/ovs-pvlan-vm.sh new file mode 100755 index 00000000000..8ac20df5ad1 --- /dev/null +++ b/scripts/vm/network/ovs-pvlan-vm.sh @@ -0,0 +1,90 @@ +#!/bin/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. + +usage() { + printf "Usage: %s: (-A|-D) -b -p -i -d -m -v -h \n" $(basename $0) >&2 + exit 2 +} + +br= +pri_vlan= +sec_iso_vlan= +dhcp_ip= +dhcp_mac= +vm_mac= +op= + +while getopts 'ADb:p:i:d:m:v:h' OPTION +do + case $OPTION in + A) op="add" + ;; + D) op="del" + ;; + b) br="$OPTARG" + ;; + p) pri_vlan="$OPTARG" + ;; + i) sec_iso_vlan="$OPTARG" + ;; + d) dhcp_ip="$OPTARG" + ;; + m) dhcp_mac="$OPTARG" + ;; + v) vm_mac="$OPTARG" + ;; + h) usage + exit 1 + ;; + esac +done + +if [ -z "$op" ] +then + echo Missing operation pararmeter! + exit 1 +fi + +if [ -z "$br" ] +then + echo Missing parameter bridge! + exit 1 +fi + +if [ -z "$vm_mac" ] +then + echo Missing parameter VM MAC! + exit 1 +fi + +if [ -z "$sec_iso_vlan" ] +then + echo Missing parameter secondary isolate vlan! + exit 1 +fi + +trunk_port=1 + +if [ "$op" == "add" ] +then + ovs-ofctl add-flow $br priority=50,dl_src=$vm_mac,actions=mod_vlan_vid:$sec_iso_vlan,output:$trunk_port +else + # it would delete any rule related to this vm, not only the rule added above + ovs-ofctl del-flows $br dl_src=$vm_mac +fi + diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java index f601f4fa2e4..d9c43567d06 100755 --- a/server/src/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VirtualRouterElement.java @@ -31,6 +31,7 @@ import org.apache.cloudstack.api.command.admin.router.CreateVirtualRouterElement import org.apache.cloudstack.api.command.admin.router.ListVirtualRouterElementsCmd; import org.apache.log4j.Logger; +import com.cloud.agent.api.PvlanSetupCommand; import com.cloud.agent.api.to.LoadBalancerTO; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.dao.ConfigurationDao; @@ -48,6 +49,7 @@ 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.BroadcastDomainType; import com.cloud.network.Networks.TrafficType; import com.cloud.network.PhysicalNetworkServiceProvider; import com.cloud.network.PublicIpAddress; @@ -214,6 +216,15 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl DataCenter.class, network.getDataCenterId()); } + // Setup PVlan for vm if necessary + if (network.getTrafficType() == TrafficType.Guest && network.getBroadcastDomainType() == BroadcastDomainType.Pvlan) { + assert routers.size() == 1; + DomainRouterVO router = routers.get(0); + if (router.getHostId() == dest.getHost().getId()) { + _routerMgr.setupVmWithDhcpHostForPvlan(true, router, nic); + } + } + return true; } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java index f49ab79b500..4dfd78c2a52 100644 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java @@ -19,6 +19,7 @@ package com.cloud.network.router; import java.util.List; import java.util.Map; +import com.cloud.agent.api.PvlanSetupCommand; import com.cloud.deploy.DeployDestination; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; @@ -35,6 +36,7 @@ import com.cloud.user.User; import com.cloud.uservm.UserVm; import com.cloud.utils.component.Manager; import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; import com.cloud.vm.VirtualMachineProfile; @@ -103,4 +105,6 @@ public interface VirtualNetworkApplianceManager extends Manager, VirtualNetworkA boolean applyUserData(Network config, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, List routers) throws ResourceUnavailableException; + + void setupVmWithDhcpHostForPvlan(boolean add, DomainRouterVO router, NicProfile profile) throws ResourceUnavailableException; } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 6620e0a6379..bb31e1cf5e8 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -62,6 +62,7 @@ import com.cloud.agent.api.GetDomRVersionCmd; import com.cloud.agent.api.ModifySshKeysCommand; import com.cloud.agent.api.NetworkUsageAnswer; import com.cloud.agent.api.NetworkUsageCommand; +import com.cloud.agent.api.PvlanSetupCommand; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StopAnswer; import com.cloud.agent.api.check.CheckSshAnswer; @@ -2210,6 +2211,72 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V return dhcpRange; } + private boolean setupDhcpForPvlanOnHost(boolean add, DomainRouterVO router, Nic routerNic) { + if (!routerNic.getBroadcastUri().getScheme().equals("pvlan")) { + return false; + } + setupDhcpForPvlan(add, router, routerNic); + Long hostId = router.getHostId(); + List vms = _userVmDao.listByHostId(hostId); + for (UserVmVO vm : vms) { + if (vm.getState() != State.Running) { + continue; + } + List nics = _nicDao.listByVmId(vm.getId()); + for (NicVO nic : nics) { + if (nic.getNetworkId() == routerNic.getNetworkId()) { + try { + Network network = _networkDao.findById(routerNic.getNetworkId()); + NicProfile profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), + null, _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vm.getHypervisorType(), network)); + setupVmWithDhcpHostForPvlan(add, router, profile); + } catch (ResourceUnavailableException e) { + s_logger.warn("Fail to program pvlan on nic " + nic.getMacAddress(), e); + return false; + } + } + } + } + return true; + } + + private boolean setupDhcpForPvlan(boolean add, DomainRouterVO router, Nic nic) { + if (!nic.getBroadcastUri().getScheme().equals("pvlan")) { + return false; + } + String op = "add"; + if (!add) { + op = "delete"; + } + PvlanSetupCommand cmd = PvlanSetupCommand.createDhcpSetup(op, "xenbr0", nic.getBroadcastUri(), nic.getMacAddress(), nic.getIp4Address()); + Commands cmds = new Commands(cmd); + // In fact we send command to the host of router, we're not programming router but the host + try { + sendCommandsToRouter(router, cmds); + } catch (AgentUnavailableException e) { + s_logger.warn("Agent Unavailable ", e); + return false; + } + return true; + } + + @Override + public void setupVmWithDhcpHostForPvlan(boolean add, DomainRouterVO router, NicProfile profile) throws ResourceUnavailableException + { + if (!profile.getBroadCastUri().getScheme().equals("pvlan")) { + return; + } + String op = "add"; + if (!add) { + op = "delete"; + } + NicVO routerNic = _nicDao.findByInstanceIdAndNetworkId(profile.getNetworkId(), router.getId()); + PvlanSetupCommand cmd = PvlanSetupCommand.createVmInDhcpHostSetup(op, "xenbr0", profile.getBroadCastUri(), routerNic.getMacAddress(), profile.getMacAddress()); + Commands cmds = new Commands(cmd); + // In fact we send command to the host of router, we're not programming router but the host + sendCommandsToRouter(router, cmds); + } + @Override public boolean finalizeDeployment(Commands cmds, VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException { @@ -2505,11 +2572,18 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V List guestNetworks = new ArrayList(); List routerNics = _nicDao.listByVmId(profile.getId()); - for (Nic routerNic : routerNics) { - Network network = _networkModel.getNetwork(routerNic.getNetworkId()); + for (Nic nic : routerNics) { + Network network = _networkModel.getNetwork(nic.getNetworkId()); if (network.getTrafficType() == TrafficType.Guest) { guestNetworks.add(network); - } + if (nic.getBroadcastUri().getScheme().equals("pvlan")) { + result = setupDhcpForPvlanOnHost(true, router, nic); + } + } + } + + if (!result) { + return result; } answer = cmds.getAnswer("getDomRVersion"); @@ -2537,6 +2611,13 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V VMInstanceVO vm = profile.getVirtualMachine(); DomainRouterVO domR = _routerDao.findById(vm.getId()); processStopOrRebootAnswer(domR, answer); + List routerNics = _nicDao.listByVmId(profile.getId()); + for (Nic nic : routerNics) { + Network network = _networkModel.getNetwork(nic.getNetworkId()); + if (network.getTrafficType() == TrafficType.Guest && nic.getBroadcastUri().getScheme().equals("pvlan")) { + setupDhcpForPvlanOnHost(false, domR, nic); + } + } } } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 8f2d103d343..7a9fc4731e7 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -69,6 +69,7 @@ import com.cloud.agent.api.GetVmStatsAnswer; import com.cloud.agent.api.GetVmStatsCommand; import com.cloud.agent.api.PlugNicAnswer; import com.cloud.agent.api.PlugNicCommand; +import com.cloud.agent.api.PvlanSetupCommand; import com.cloud.agent.api.StartAnswer; import com.cloud.agent.api.StopAnswer; import com.cloud.agent.api.UnPlugNicAnswer; @@ -2751,6 +2752,34 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use return true; } + private boolean setupVmForPvlan(boolean add, Long hostId, NicVO nic) { + if (!nic.getBroadcastUri().getScheme().equals("pvlan")) { + return false; + } + String op = "add"; + if (!add) { + // "delete" would remove all the rules(if using ovs) related to this vm + op = "delete"; + } + PvlanSetupCommand cmd = PvlanSetupCommand.createVmSetup(op, "xenbr0", nic.getBroadcastUri(), nic.getMacAddress()); + Answer answer = null; + try { + answer = _agentMgr.send(hostId, cmd); + } catch (OperationTimedoutException e) { + s_logger.warn("Timed Out", e); + return false; + } catch (AgentUnavailableException e) { + s_logger.warn("Agent Unavailable ", e); + return false; + } + + boolean result = true; + if (answer == null || !answer.getResult()) { + result = false; + } + return result; + } + @Override public boolean finalizeDeployment(Commands cmds, VirtualMachineProfile profile, DeployDestination dest, @@ -2812,6 +2841,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use originalIp = nic.getIp4Address(); guestNic = nic; guestNetwork = network; + if (nic.getBroadcastUri().getScheme().equals("pvlan")) { + if (!setupVmForPvlan(true, hostId, nic)) { + return false; + } + } } } boolean ipChanged = false; @@ -2942,6 +2976,17 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use + " stop due to exception ", ex); } } + + VMInstanceVO vm = profile.getVirtualMachine(); + List nics = _nicDao.listByVmId(vm.getId()); + for (NicVO nic : nics) { + NetworkVO network = _networkDao.findById(nic.getNetworkId()); + if (network.getTrafficType() == TrafficType.Guest) { + if (nic.getBroadcastUri().getScheme().equals("pvlan")) { + setupVmForPvlan(false, vm.getHostId(), nic); + } + } + } } public String generateRandomPassword() { diff --git a/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java b/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java index ef5478bb1f8..5278b339e19 100644 --- a/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java +++ b/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java @@ -402,4 +402,11 @@ VpcVirtualNetworkApplianceService { return null; } + @Override + public void setupVmWithDhcpHostForPvlan(boolean add, + DomainRouterVO router, NicProfile nic) throws ResourceUnavailableException { + // TODO Auto-generated method stub + + } + } From 05885457ecc32e4714914056c11244e0d021bf50 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Wed, 1 May 2013 13:23:08 -0700 Subject: [PATCH 03/59] PVLAN: Simplify OVS policy We can resubmit the packet against the flow table to get simplier result. Now we don't need to check if VM is in the same host as DHCP server or not. --- .../cloud/agent/api/PvlanSetupCommand.java | 25 ++---- .../xen/resource/CitrixResourceBase.java | 18 ++-- .../hypervisor/xenserver/ovs-get-dhcp-port.sh | 26 ++++++ scripts/vm/hypervisor/xenserver/ovs-pvlan | 68 ++++---------- .../vm/hypervisor/xenserver/xenserver60/patch | 2 +- scripts/vm/network/ovs-pvlan-dhcp-host.sh | 34 +++++-- .../vm/network/ovs-pvlan-vm-in-dhcp-host.sh | 88 ------------------- scripts/vm/network/ovs-pvlan-vm.sh | 15 +++- .../network/element/VirtualRouterElement.java | 10 --- .../VirtualNetworkApplianceManager.java | 2 - .../VirtualNetworkApplianceManagerImpl.java | 53 +---------- ...MockVpcVirtualNetworkApplianceManager.java | 8 -- 12 files changed, 104 insertions(+), 245 deletions(-) create mode 100644 scripts/vm/hypervisor/xenserver/ovs-get-dhcp-port.sh delete mode 100755 scripts/vm/network/ovs-pvlan-vm-in-dhcp-host.sh diff --git a/api/src/com/cloud/agent/api/PvlanSetupCommand.java b/api/src/com/cloud/agent/api/PvlanSetupCommand.java index 22a828afa8b..e5d4da09003 100644 --- a/api/src/com/cloud/agent/api/PvlanSetupCommand.java +++ b/api/src/com/cloud/agent/api/PvlanSetupCommand.java @@ -23,17 +23,16 @@ import com.cloud.utils.net.NetUtils; public class PvlanSetupCommand extends Command { public enum Type { DHCP, - VM, - VM_IN_DHCP_HOST + VM } private String op; private String bridge; private String primary; private String isolated; private String vmMac; + private String dhcpName; private String dhcpMac; private String dhcpIp; - private boolean strict; private Type type; protected PvlanSetupCommand() {} @@ -45,12 +44,12 @@ public class PvlanSetupCommand extends Command { this.bridge = bridge; this.primary = NetUtils.getPrimaryPvlanFromUri(uri); this.isolated = NetUtils.getIsolatedPvlanFromUri(uri); - this.strict = true; } - static public PvlanSetupCommand createDhcpSetup(String op, String bridge, URI uri, String dhcpMac, String dhcpIp) + static public PvlanSetupCommand createDhcpSetup(String op, String bridge, URI uri, String dhcpName, String dhcpMac, String dhcpIp) { PvlanSetupCommand cmd = new PvlanSetupCommand(Type.DHCP, op, bridge, uri); + cmd.setDhcpName(dhcpName); cmd.setDhcpMac(dhcpMac); cmd.setDhcpIp(dhcpIp); return cmd; @@ -63,14 +62,6 @@ public class PvlanSetupCommand extends Command { return cmd; } - static public PvlanSetupCommand createVmInDhcpHostSetup(String op, String bridge, URI uri, String dhcpMac, String vmMac) - { - PvlanSetupCommand cmd = new PvlanSetupCommand(Type.VM_IN_DHCP_HOST, op, bridge, uri); - cmd.setDhcpMac(dhcpMac); - cmd.setVmMac(vmMac); - return cmd; - } - @Override public boolean executeInSequence() { return true; @@ -120,11 +111,11 @@ public class PvlanSetupCommand extends Command { return type; } - public boolean isStrict() { - return strict; + public String getDhcpName() { + return dhcpName; } - public void setStrict(boolean strict) { - this.strict = strict; + public void setDhcpName(String dhcpName) { + this.dhcpName = dhcpName; } } 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 34b590e40c9..933f4d33eff 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 @@ -1475,13 +1475,16 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe String isolatedPvlan = cmd.getIsolated(); String op = cmd.getOp(); String bridge = cmd.getBridge(); - String result = null; + String dhcpName = cmd.getDhcpName(); String dhcpMac = cmd.getDhcpMac(); String dhcpIp = cmd.getDhcpIp(); String vmMac = cmd.getVmMac(); + + String result = null; if (cmd.getType() == PvlanSetupCommand.Type.DHCP) { result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-dhcp", "op", op, "bridge", bridge, - "primary-pvlan", primaryPvlan, "isolated-pvlan", isolatedPvlan, "dhcp-ip", dhcpIp, "dhcp-mac", dhcpMac); + "primary-pvlan", primaryPvlan, "isolated-pvlan", isolatedPvlan, "dhcp-name", dhcpName, + "dhcp-ip", dhcpIp, "dhcp-mac", dhcpMac); if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) { s_logger.warn("Failed to program pvlan for dhcp server with mac " + dhcpMac); return new Answer(cmd, false, result); @@ -1489,7 +1492,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe s_logger.info("Programmed pvlan for dhcp server with mac " + dhcpMac); } } else if (cmd.getType() == PvlanSetupCommand.Type.VM) { - result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-vm-alone", "op", op, "bridge", bridge, + result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-vm", "op", op, "bridge", bridge, "primary-pvlan", primaryPvlan, "isolated-pvlan", isolatedPvlan, "vm-mac", vmMac); if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) { s_logger.warn("Failed to program pvlan for vm with mac " + vmMac); @@ -1497,15 +1500,6 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } else { s_logger.info("Programmed pvlan for vm with mac " + vmMac); } - } else if (cmd.getType() == PvlanSetupCommand.Type.VM_IN_DHCP_HOST) { - result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-vm-dhcp", "op", op, "bridge", bridge, - "primary-pvlan", primaryPvlan, "isolated-pvlan", isolatedPvlan, "vm-mac", vmMac, "dhcp-mac", dhcpMac); - if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) { - s_logger.warn("Failed to program pvlan for vm in dhcp host with mac " + vmMac); - return new Answer(cmd, false, result); - } else { - s_logger.info("Programmed pvlan for vm in dhcp host with mac " + vmMac); - } } return new Answer(cmd, true, result); } diff --git a/scripts/vm/hypervisor/xenserver/ovs-get-dhcp-port.sh b/scripts/vm/hypervisor/xenserver/ovs-get-dhcp-port.sh new file mode 100644 index 00000000000..a30b180bed0 --- /dev/null +++ b/scripts/vm/hypervisor/xenserver/ovs-get-dhcp-port.sh @@ -0,0 +1,26 @@ +#!/bin/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. + +#!/bin/bash + +bridge=$1 +dhcp_name=$2 +dom_id=`xe vm-list is-control-domain=false power-state=running params=dom-id name-label=$dhcp_name|cut -d ':' -f 2 |tr -d ' ' ` +iface="vif${dom_id}.0" +port=`ovs-ofctl show $bridge|grep $iface|cut -d '(' -f 1|tr -d ' '` +echo $port diff --git a/scripts/vm/hypervisor/xenserver/ovs-pvlan b/scripts/vm/hypervisor/xenserver/ovs-pvlan index 2c1e3af8f77..372d3c8d05b 100755 --- a/scripts/vm/hypervisor/xenserver/ovs-pvlan +++ b/scripts/vm/hypervisor/xenserver/ovs-pvlan @@ -33,8 +33,8 @@ from time import localtime as _localtime, asctime as _asctime xePath = "/opt/xensource/bin/xe" lib.setup_logging("/var/log/ovs-pvlan.log") dhcpSetupPath = "/opt/xensource/bin/ovs-pvlan-dhcp-host.sh" -vmAloneSetupPath = "/opt/xensource/bin/ovs-pvlan-vm.sh" -vmDhcpSetupPath = "/opt/xensource/bin/ovs-pvlan-vm-in-dhcp-host.sh" +vmSetupPath = "/opt/xensource/bin/ovs-pvlan-vm.sh" +getDhcpPortPath = "/opt/xensource/bin/ovs-get-dhcp-port.sh" pvlanCleanupPath = "/opt/xensource/bin/ovs-pvlan-cleanup.sh" def echo(fn): @@ -53,17 +53,21 @@ def setup_pvlan_dhcp(session, args): bridge = args.pop("bridge") primary = args.pop("primary-pvlan") isolated = args.pop("isolated-pvlan") - dhcp_ip = args.pop("dhcp-ip"); - dhcp_mac = args.pop("dhcp-mac"); + dhcp_name = args.pop("dhcp-name") + dhcp_ip = args.pop("dhcp-ip") + dhcp_mac = args.pop("dhcp-mac") res = lib.check_switch() if res != "SUCCESS": return "FAILURE:%s" % res if op == "add": + logging.debug("Try to get dhcp vm %s port on the switch:%s" % (dhcp_name, bridge)) + dhcp_port = lib.do_cmd([getDhcpPortPath, bridge, dhcp_name]) logging.debug("About to setup dhcp vm on the switch:%s" % bridge) res = lib.do_cmd([dhcpSetupPath, "-A", "-b", bridge, "-p", primary, - "-i", isolated, "-d", dhcp_ip, "-m", dhcp_mac]) + "-i", isolated, "-n", dhcp_name, "-d", dhcp_ip, "-m", dhcp_mac, + "-P", dhcp_port]) if res: result = "FAILURE:%s" % res return result; @@ -71,7 +75,7 @@ def setup_pvlan_dhcp(session, args): elif op == "delete": logging.debug("About to remove dhcp the switch:%s" % bridge) res = lib.do_cmd([dhcpSetupPath, "-D", "-b", bridge, "-p", primary, - "-i", isolated, "-d", dhcp_ip, "-m", dhcp_mac]) + "-i", isolated, "-n", dhcp_name, "-d", dhcp_ip, "-m", dhcp_mac]) if res: result = "FAILURE:%s" % res return result; @@ -82,9 +86,10 @@ def setup_pvlan_dhcp(session, args): return result @echo -def setup_pvlan_vm_alone(session, args): +def setup_pvlan_vm(session, args): op = args.pop("op") bridge = args.pop("bridge") + primary = args.pop("primary-pvlan") isolated = args.pop("isolated-pvlan") vm_mac = args.pop("vm-mac") trunk_port = 1 @@ -94,58 +99,24 @@ def setup_pvlan_vm_alone(session, args): return "FAILURE:%s" % res if op == "add": - logging.debug("About to setup vm alone on the switch:%s" % bridge) - res = lib.do_cmd([vmAloneSetupPath, "-A", "-b", bridge, "-i", isolated, "-v", vm_mac]) + logging.debug("About to setup vm on the switch:%s" % bridge) + res = lib.do_cmd([vmSetupPath, "-A", "-b", bridge, "-p", primary, "-i", isolated, "-v", vm_mac]) if res: result = "FAILURE:%s" % res return result; - logging.debug("Setup vm alone on switch program done") + logging.debug("Setup vm on switch program done") elif op == "delete": - logging.debug("About to remove vm alone on the switch:%s" % bridge) - res = lib.do_cmd([vmAloneSetupPath, "-D", "-b", bridge, "-i", isolated, "-v", vm_mac]) + logging.debug("About to remove vm on the switch:%s" % bridge) + res = lib.do_cmd([vmSetupPath, "-D", "-b", bridge, "-p", primary, "-i", isolated, "-v", vm_mac]) if res: result = "FAILURE:%s" % res return result; - logging.debug("Remove vm alone on switch program done") + logging.debug("Remove vm on switch program done") result = "true" logging.debug("Setup_pvlan_vm_alone completed with result:%s" % result) return result -@echo -def setup_pvlan_vm_dhcp(session, args): - op = args.pop("op") - bridge = args.pop("bridge") - isolated = args.pop("isolated-pvlan") - vm_mac = args.pop("vm-mac") - dhcp_mac = args.pop("dhcp-mac"); - trunk_port = 1 - - res = lib.check_switch() - if res != "SUCCESS": - return "FAILURE:%s" % res - - if op == "add": - logging.debug("About to setup vm dhcp on the switch:%s" % bridge) - res = lib.do_cmd([vmDhcpSetupPath, "-A", "-b", bridge, "-i", isolated, - "-v", vm_mac, "-m", dhcp_mac]) - if res: - result = "FAILURE:%s" % res - return result; - logging.debug("Setup vm dhcp on switch program done") - elif op == "delete": - logging.debug("About to remove vm dhcp on the switch:%s" % bridge) - res = lib.do_cmd([vmDhcpSetupPath, "-D", "-b", bridge, "-i", isolated, - "-v", vm_mac, "-m", dhcp_mac]) - if res: - result = "FAILURE:%s" % res - return result; - logging.debug("Remove vm dhcp on switch program done") - - result = "true" - logging.debug("Setup_pvlan_vm_dhcp completed with result:%s" % result) - return result - @echo def cleanup(session, args): res = lib.check_switch() @@ -163,6 +134,5 @@ def cleanup(session, args): if __name__ == "__main__": XenAPIPlugin.dispatch({"setup-pvlan-dhcp": setup_pvlan_dhcp, - "setup-pvlan-vm-alone": setup_pvlan_vm_alone, - "setup-pvlan-vm-dhcp": setup_pvlan_vm_dhcp, + "setup-pvlan-vm": setup_pvlan_vm, "cleanup":cleanup}) diff --git a/scripts/vm/hypervisor/xenserver/xenserver60/patch b/scripts/vm/hypervisor/xenserver/xenserver60/patch index c767f1af7df..97595190904 100644 --- a/scripts/vm/hypervisor/xenserver/xenserver60/patch +++ b/scripts/vm/hypervisor/xenserver/xenserver60/patch @@ -69,6 +69,6 @@ swiftxen=..,0755,/etc/xapi.d/plugins s3xen=..,0755,/etc/xapi.d/plugins ovs-pvlan=..,0755,/etc/xapi.d/plugins ovs-pvlan-dhcp-host.sh=../../../network,0755,/opt/xensource/bin -ovs-pvlan-vm-in-dhcp-host.sh=../../../network,0755,/opt/xensource/bin ovs-pvlan-vm.sh=../../../network,0755,/opt/xensource/bin ovs-pvlan-cleanup.sh=../../../network,0755,/opt/xensource/bin +ovs-get-dhcp-port.sh=..,0755,/opt/xensource/bin diff --git a/scripts/vm/network/ovs-pvlan-dhcp-host.sh b/scripts/vm/network/ovs-pvlan-dhcp-host.sh index e12fbce0f18..93f56534beb 100755 --- a/scripts/vm/network/ovs-pvlan-dhcp-host.sh +++ b/scripts/vm/network/ovs-pvlan-dhcp-host.sh @@ -16,20 +16,26 @@ # specific language governing permissions and limitations # under the License. +#!/bin/bash + +source ovs-func.sh + usage() { - printf "Usage: %s: (-A|-D) -b -p -i -d -m -v -h \n" $(basename $0) >&2 + printf "Usage: %s: (-A|-D) -b -p -i -n -d -m -P -v -h \n" $(basename $0) >&2 exit 2 } br= pri_vlan= sec_iso_vlan= +dhcp_name= dhcp_ip= dhcp_mac= +dhcp_port= vm_mac= op= -while getopts 'ADb:p:i:d:m:v:h' OPTION +while getopts 'ADb:p:i:d:m:v:n:P:h' OPTION do case $OPTION in A) op="add" @@ -42,10 +48,14 @@ do ;; i) sec_iso_vlan="$OPTARG" ;; + n) dhcp_name="$OPTARG" + ;; d) dhcp_ip="$OPTARG" ;; m) dhcp_mac="$OPTARG" ;; + P) dhcp_port="$OPTARG" + ;; v) vm_mac="$OPTARG" ;; h) usage @@ -78,6 +88,12 @@ then exit 1 fi +if [ -z "$dhcp_name" ] +then + echo Missing parameter DHCP NAME! + exit 1 +fi + if [ -z "$dhcp_ip" ] then echo Missing parameter DHCP IP! @@ -90,12 +106,18 @@ then exit 1 fi +if [ "$op" == "add" -a -z "$dhcp_port" ] +then + echo Missing parameter DHCP PORT! + exit 1 +fi + if [ "$op" == "add" ] then - ovs-ofctl add-flow $br priority=200,arp,dl_vlan=$sec_iso_vlan,nw_dst=$dhcp_ip,actions=mod_vlan_vid:$pri_vlan,NORMAL - ovs-ofctl add-flow $br priority=180,arp,nw_dst=$dhcp_ip,actions=NORMAL - ovs-ofctl add-flow $br priority=150,dl_vlan=$sec_iso_vlan,dl_dst=$dhcp_mac,actions=mod_vlan_vid:$pri_vlan,NORMAL - ovs-ofctl add-flow $br priority=100,udp,dl_vlan=$sec_iso_vlan,nw_dst=255.255.255.255,tp_dst=67,actions=mod_vlan_vid:$pri_vlan,NORMAL + ovs-ofctl add-flow $br priority=200,arp,dl_vlan=$sec_iso_vlan,nw_dst=$dhcp_ip,actions=strip_vlan,output:$dhcp_port + ovs-ofctl add-flow $br priority=180,arp,nw_dst=$dhcp_ip,actions=strip_vlan,output:$dhcp_port + ovs-ofctl add-flow $br priority=150,dl_vlan=$sec_iso_vlan,dl_dst=$dhcp_mac,actions=strip_vlan,output:$dhcp_port + ovs-ofctl add-flow $br priority=100,udp,dl_vlan=$sec_iso_vlan,nw_dst=255.255.255.255,tp_dst=67,actions=strip_vlan,output:$dhcp_port else ovs-ofctl del-flows --strict $br priority=200,arp,dl_vlan=$sec_iso_vlan,nw_dst=$dhcp_ip ovs-ofctl del-flows --strict $br priority=180,arp,nw_dst=$dhcp_ip diff --git a/scripts/vm/network/ovs-pvlan-vm-in-dhcp-host.sh b/scripts/vm/network/ovs-pvlan-vm-in-dhcp-host.sh deleted file mode 100755 index de37882159c..00000000000 --- a/scripts/vm/network/ovs-pvlan-vm-in-dhcp-host.sh +++ /dev/null @@ -1,88 +0,0 @@ -#!/bin/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. - -usage() { - printf "Usage: %s: (-A|-D) -b -p -i -d -m -v -h \n" $(basename $0) >&2 - exit 2 -} - -br= -pri_vlan= -sec_iso_vlan= -dhcp_ip= -dhcp_mac= -vm_mac= -op= - -while getopts 'ADb:p:i:d:m:v:h' OPTION -do - case $OPTION in - A) op="add" - ;; - D) op="del" - ;; - b) br="$OPTARG" - ;; - p) pri_vlan="$OPTARG" - ;; - i) sec_iso_vlan="$OPTARG" - ;; - d) dhcp_ip="$OPTARG" - ;; - m) dhcp_mac="$OPTARG" - ;; - v) vm_mac="$OPTARG" - ;; - h) usage - exit 1 - ;; - esac -done - -if [ -z "$op" ] -then - echo Missing operation pararmeter! - exit 1 -fi - -if [ -z "$br" ] -then - echo Missing parameter bridge! - exit 1 -fi - -if [ -z "$vm_mac" ] -then - echo Missing parameter VM MAC! - exit 1 -fi - -if [ -z "$dhcp_mac" ] -then - echo Missing parameter DHCP MAC! - exit 1 -fi - -if [ "$op" == "add" ] -then - ovs-ofctl add-flow $br priority=120,dl_src=$vm_mac,dl_dst=$dhcp_mac,actions=NORMAL - ovs-ofctl add-flow $br priority=80,udp,dl_src=$vm_mac,nw_dst=255.255.255.255,tp_dst=67,actions=NORMAL -else - ovs-ofctl del-flows --strict $br priority=120,dl_src=$vm_mac,dl_dst=$dhcp_mac - ovs-ofctl del-flows --strict $br priority=80,udp,dl_src=$vm_mac,nw_dst=255.255.255.255,tp_dst=67 -fi diff --git a/scripts/vm/network/ovs-pvlan-vm.sh b/scripts/vm/network/ovs-pvlan-vm.sh index 8ac20df5ad1..4bad11c7624 100755 --- a/scripts/vm/network/ovs-pvlan-vm.sh +++ b/scripts/vm/network/ovs-pvlan-vm.sh @@ -16,6 +16,8 @@ # specific language governing permissions and limitations # under the License. +#!/bin/bash + usage() { printf "Usage: %s: (-A|-D) -b -p -i -d -m -v -h \n" $(basename $0) >&2 exit 2 @@ -72,6 +74,12 @@ then exit 1 fi +if [ -z "$pri_vlan" ] +then + echo Missing parameter secondary isolate vlan! + exit 1 +fi + if [ -z "$sec_iso_vlan" ] then echo Missing parameter secondary isolate vlan! @@ -82,9 +90,10 @@ trunk_port=1 if [ "$op" == "add" ] then - ovs-ofctl add-flow $br priority=50,dl_src=$vm_mac,actions=mod_vlan_vid:$sec_iso_vlan,output:$trunk_port + ovs-ofctl add-flow $br priority=50,dl_vlan=0xffff,dl_src=$vm_mac,actions=mod_vlan_vid:$sec_iso_vlan,resubmit:$trunk_port + ovs-ofctl add-flow $br priority=60,dl_vlan=$sec_iso_vlan,dl_src=$vm_mac,actions=output:1 else - # it would delete any rule related to this vm, not only the rule added above - ovs-ofctl del-flows $br dl_src=$vm_mac + ovs-ofctl del-flows --strict $br priority=50,dl_vlan=0xffff,dl_src=$vm_mac + ovs-ofctl del-flows --strict $br priority=60,dl_vlan=$sec_iso_vlan,dl_src=$vm_mac fi diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java index d9c43567d06..5c73bcdd80e 100755 --- a/server/src/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VirtualRouterElement.java @@ -215,16 +215,6 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl throw new ResourceUnavailableException("Can't find at least one running router!", DataCenter.class, network.getDataCenterId()); } - - // Setup PVlan for vm if necessary - if (network.getTrafficType() == TrafficType.Guest && network.getBroadcastDomainType() == BroadcastDomainType.Pvlan) { - assert routers.size() == 1; - DomainRouterVO router = routers.get(0); - if (router.getHostId() == dest.getHost().getId()) { - _routerMgr.setupVmWithDhcpHostForPvlan(true, router, nic); - } - } - return true; } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java index 4dfd78c2a52..075b014cb0b 100644 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManager.java @@ -105,6 +105,4 @@ public interface VirtualNetworkApplianceManager extends Manager, VirtualNetworkA boolean applyUserData(Network config, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, List routers) throws ResourceUnavailableException; - - void setupVmWithDhcpHostForPvlan(boolean add, DomainRouterVO router, NicProfile profile) throws ResourceUnavailableException; } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index bb31e1cf5e8..d22c7fc6d31 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -2211,35 +2211,6 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V return dhcpRange; } - private boolean setupDhcpForPvlanOnHost(boolean add, DomainRouterVO router, Nic routerNic) { - if (!routerNic.getBroadcastUri().getScheme().equals("pvlan")) { - return false; - } - setupDhcpForPvlan(add, router, routerNic); - Long hostId = router.getHostId(); - List vms = _userVmDao.listByHostId(hostId); - for (UserVmVO vm : vms) { - if (vm.getState() != State.Running) { - continue; - } - List nics = _nicDao.listByVmId(vm.getId()); - for (NicVO nic : nics) { - if (nic.getNetworkId() == routerNic.getNetworkId()) { - try { - Network network = _networkDao.findById(routerNic.getNetworkId()); - NicProfile profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), - null, _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vm.getHypervisorType(), network)); - setupVmWithDhcpHostForPvlan(add, router, profile); - } catch (ResourceUnavailableException e) { - s_logger.warn("Fail to program pvlan on nic " + nic.getMacAddress(), e); - return false; - } - } - } - } - return true; - } - private boolean setupDhcpForPvlan(boolean add, DomainRouterVO router, Nic nic) { if (!nic.getBroadcastUri().getScheme().equals("pvlan")) { return false; @@ -2248,7 +2219,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V if (!add) { op = "delete"; } - PvlanSetupCommand cmd = PvlanSetupCommand.createDhcpSetup(op, "xenbr0", nic.getBroadcastUri(), nic.getMacAddress(), nic.getIp4Address()); + PvlanSetupCommand cmd = PvlanSetupCommand.createDhcpSetup(op, "xenbr0", nic.getBroadcastUri(), router.getInstanceName(), nic.getMacAddress(), nic.getIp4Address()); Commands cmds = new Commands(cmd); // In fact we send command to the host of router, we're not programming router but the host try { @@ -2260,23 +2231,6 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V return true; } - @Override - public void setupVmWithDhcpHostForPvlan(boolean add, DomainRouterVO router, NicProfile profile) throws ResourceUnavailableException - { - if (!profile.getBroadCastUri().getScheme().equals("pvlan")) { - return; - } - String op = "add"; - if (!add) { - op = "delete"; - } - NicVO routerNic = _nicDao.findByInstanceIdAndNetworkId(profile.getNetworkId(), router.getId()); - PvlanSetupCommand cmd = PvlanSetupCommand.createVmInDhcpHostSetup(op, "xenbr0", profile.getBroadCastUri(), routerNic.getMacAddress(), profile.getMacAddress()); - Commands cmds = new Commands(cmd); - // In fact we send command to the host of router, we're not programming router but the host - sendCommandsToRouter(router, cmds); - } - @Override public boolean finalizeDeployment(Commands cmds, VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException { @@ -2577,7 +2531,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V if (network.getTrafficType() == TrafficType.Guest) { guestNetworks.add(network); if (nic.getBroadcastUri().getScheme().equals("pvlan")) { - result = setupDhcpForPvlanOnHost(true, router, nic); + result = setupDhcpForPvlan(true, router, nic); } } } @@ -2615,9 +2569,10 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V for (Nic nic : routerNics) { Network network = _networkModel.getNetwork(nic.getNetworkId()); if (network.getTrafficType() == TrafficType.Guest && nic.getBroadcastUri().getScheme().equals("pvlan")) { - setupDhcpForPvlanOnHost(false, domR, nic); + setupDhcpForPvlan(false, domR, nic); } } + } } diff --git a/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java b/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java index 5278b339e19..e86fc09ce2c 100644 --- a/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java +++ b/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java @@ -401,12 +401,4 @@ VpcVirtualNetworkApplianceService { // TODO Auto-generated method stub return null; } - - @Override - public void setupVmWithDhcpHostForPvlan(boolean add, - DomainRouterVO router, NicProfile nic) throws ResourceUnavailableException { - // TODO Auto-generated method stub - - } - } From 142f3b30f44f279b34ce845ffaec853ef68be36d Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Wed, 1 May 2013 13:23:08 -0700 Subject: [PATCH 04/59] PVLAN: Remove bridge parameter in PvlanSetupCommand Bridge is hypervisor dependent, shouldn't appear in PvlanSetupCommand. --- .../com/cloud/agent/api/PvlanSetupCommand.java | 16 +++++----------- .../xen/resource/CitrixResourceBase.java | 2 +- .../VirtualNetworkApplianceManagerImpl.java | 2 +- server/src/com/cloud/vm/UserVmManagerImpl.java | 2 +- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/api/src/com/cloud/agent/api/PvlanSetupCommand.java b/api/src/com/cloud/agent/api/PvlanSetupCommand.java index e5d4da09003..0426219def2 100644 --- a/api/src/com/cloud/agent/api/PvlanSetupCommand.java +++ b/api/src/com/cloud/agent/api/PvlanSetupCommand.java @@ -26,7 +26,6 @@ public class PvlanSetupCommand extends Command { VM } private String op; - private String bridge; private String primary; private String isolated; private String vmMac; @@ -37,27 +36,26 @@ public class PvlanSetupCommand extends Command { protected PvlanSetupCommand() {} - protected PvlanSetupCommand(Type type, String op, String bridge, URI uri) + protected PvlanSetupCommand(Type type, String op, URI uri) { this.type = type; this.op = op; - this.bridge = bridge; this.primary = NetUtils.getPrimaryPvlanFromUri(uri); this.isolated = NetUtils.getIsolatedPvlanFromUri(uri); } - static public PvlanSetupCommand createDhcpSetup(String op, String bridge, URI uri, String dhcpName, String dhcpMac, String dhcpIp) + static public PvlanSetupCommand createDhcpSetup(String op, URI uri, String dhcpName, String dhcpMac, String dhcpIp) { - PvlanSetupCommand cmd = new PvlanSetupCommand(Type.DHCP, op, bridge, uri); + PvlanSetupCommand cmd = new PvlanSetupCommand(Type.DHCP, op, uri); cmd.setDhcpName(dhcpName); cmd.setDhcpMac(dhcpMac); cmd.setDhcpIp(dhcpIp); return cmd; } - static public PvlanSetupCommand createVmSetup(String op, String bridge, URI uri, String vmMac) + static public PvlanSetupCommand createVmSetup(String op, URI uri, String vmMac) { - PvlanSetupCommand cmd = new PvlanSetupCommand(Type.VM, op, bridge, uri); + PvlanSetupCommand cmd = new PvlanSetupCommand(Type.VM, op, uri); cmd.setVmMac(vmMac); return cmd; } @@ -71,10 +69,6 @@ public class PvlanSetupCommand extends Command { return op; } - public String getBridge() { - return bridge; - } - public String getPrimary() { return primary; } 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 933f4d33eff..d25938f1f57 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 @@ -1474,12 +1474,12 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe String primaryPvlan = cmd.getPrimary(); String isolatedPvlan = cmd.getIsolated(); String op = cmd.getOp(); - String bridge = cmd.getBridge(); String dhcpName = cmd.getDhcpName(); String dhcpMac = cmd.getDhcpMac(); String dhcpIp = cmd.getDhcpIp(); String vmMac = cmd.getVmMac(); + String bridge = "xenbr0"; String result = null; if (cmd.getType() == PvlanSetupCommand.Type.DHCP) { result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-dhcp", "op", op, "bridge", bridge, diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index d22c7fc6d31..59a9f057162 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -2219,7 +2219,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V if (!add) { op = "delete"; } - PvlanSetupCommand cmd = PvlanSetupCommand.createDhcpSetup(op, "xenbr0", nic.getBroadcastUri(), router.getInstanceName(), nic.getMacAddress(), nic.getIp4Address()); + PvlanSetupCommand cmd = PvlanSetupCommand.createDhcpSetup(op, nic.getBroadcastUri(), router.getInstanceName(), nic.getMacAddress(), nic.getIp4Address()); Commands cmds = new Commands(cmd); // In fact we send command to the host of router, we're not programming router but the host try { diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 7a9fc4731e7..6ea295259a9 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2761,7 +2761,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use // "delete" would remove all the rules(if using ovs) related to this vm op = "delete"; } - PvlanSetupCommand cmd = PvlanSetupCommand.createVmSetup(op, "xenbr0", nic.getBroadcastUri(), nic.getMacAddress()); + PvlanSetupCommand cmd = PvlanSetupCommand.createVmSetup(op, nic.getBroadcastUri(), nic.getMacAddress()); Answer answer = null; try { answer = _agentMgr.send(hostId, cmd); From 40386fc4cb6841c8cc6b8458c9ebd80d4c8ffb4f Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Wed, 1 May 2013 13:23:09 -0700 Subject: [PATCH 05/59] PVLAN: Add network label parameter to PvlanSetupCommand We need it to find the real bridge/switch to program on the OVS. --- .../cloud/agent/api/PvlanSetupCommand.java | 16 +++++++---- .../xen/resource/CitrixResourceBase.java | 19 ++++++++++--- .../vm/hypervisor/xenserver/ovs-get-bridge.sh | 27 +++++++++++++++++++ .../hypervisor/xenserver/ovs-get-dhcp-port.sh | 0 scripts/vm/hypervisor/xenserver/ovs-pvlan | 13 ++++++--- .../vm/hypervisor/xenserver/xenserver60/patch | 1 + .../VirtualNetworkApplianceManagerImpl.java | 4 ++- .../src/com/cloud/vm/UserVmManagerImpl.java | 5 +++- 8 files changed, 72 insertions(+), 13 deletions(-) create mode 100755 scripts/vm/hypervisor/xenserver/ovs-get-bridge.sh mode change 100644 => 100755 scripts/vm/hypervisor/xenserver/ovs-get-dhcp-port.sh diff --git a/api/src/com/cloud/agent/api/PvlanSetupCommand.java b/api/src/com/cloud/agent/api/PvlanSetupCommand.java index 0426219def2..ee1f046d6d9 100644 --- a/api/src/com/cloud/agent/api/PvlanSetupCommand.java +++ b/api/src/com/cloud/agent/api/PvlanSetupCommand.java @@ -33,29 +33,31 @@ public class PvlanSetupCommand extends Command { private String dhcpMac; private String dhcpIp; private Type type; + private String networkTag; protected PvlanSetupCommand() {} - protected PvlanSetupCommand(Type type, String op, URI uri) + protected PvlanSetupCommand(Type type, String op, URI uri, String networkTag) { this.type = type; this.op = op; this.primary = NetUtils.getPrimaryPvlanFromUri(uri); this.isolated = NetUtils.getIsolatedPvlanFromUri(uri); + this.networkTag = networkTag; } - static public PvlanSetupCommand createDhcpSetup(String op, URI uri, String dhcpName, String dhcpMac, String dhcpIp) + static public PvlanSetupCommand createDhcpSetup(String op, URI uri, String networkTag, String dhcpName, String dhcpMac, String dhcpIp) { - PvlanSetupCommand cmd = new PvlanSetupCommand(Type.DHCP, op, uri); + PvlanSetupCommand cmd = new PvlanSetupCommand(Type.DHCP, op, uri, networkTag); cmd.setDhcpName(dhcpName); cmd.setDhcpMac(dhcpMac); cmd.setDhcpIp(dhcpIp); return cmd; } - static public PvlanSetupCommand createVmSetup(String op, URI uri, String vmMac) + static public PvlanSetupCommand createVmSetup(String op, URI uri, String networkTag, String vmMac) { - PvlanSetupCommand cmd = new PvlanSetupCommand(Type.VM, op, uri); + PvlanSetupCommand cmd = new PvlanSetupCommand(Type.VM, op, uri, networkTag); cmd.setVmMac(vmMac); return cmd; } @@ -112,4 +114,8 @@ public class PvlanSetupCommand extends Command { public void setDhcpName(String dhcpName) { this.dhcpName = dhcpName; } + + public String getNetworkTag() { + return networkTag; + } } 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 d25938f1f57..d616e1bcd58 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 @@ -1478,11 +1478,24 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe String dhcpMac = cmd.getDhcpMac(); String dhcpIp = cmd.getDhcpIp(); String vmMac = cmd.getVmMac(); + String networkTag = cmd.getNetworkTag(); + + XsLocalNetwork nw = null; + String nwNameLabel = null; + try { + nw = getNativeNetworkForTraffic(conn, TrafficType.Guest, networkTag); + nwNameLabel = nw.getNetwork().getNameLabel(conn); + } catch (XenAPIException e) { + s_logger.warn("Fail to get network", e); + return new Answer(cmd, false, e.toString()); + } catch (XmlRpcException e) { + s_logger.warn("Fail to get network", e); + return new Answer(cmd, false, e.toString()); + } - String bridge = "xenbr0"; String result = null; if (cmd.getType() == PvlanSetupCommand.Type.DHCP) { - result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-dhcp", "op", op, "bridge", bridge, + result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-dhcp", "op", op, "nw-label", nwNameLabel, "primary-pvlan", primaryPvlan, "isolated-pvlan", isolatedPvlan, "dhcp-name", dhcpName, "dhcp-ip", dhcpIp, "dhcp-mac", dhcpMac); if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) { @@ -1492,7 +1505,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe s_logger.info("Programmed pvlan for dhcp server with mac " + dhcpMac); } } else if (cmd.getType() == PvlanSetupCommand.Type.VM) { - result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-vm", "op", op, "bridge", bridge, + result = callHostPlugin(conn, "ovs-pvlan", "setup-pvlan-vm", "op", op, "nw-label", nwNameLabel, "primary-pvlan", primaryPvlan, "isolated-pvlan", isolatedPvlan, "vm-mac", vmMac); if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) { s_logger.warn("Failed to program pvlan for vm with mac " + vmMac); diff --git a/scripts/vm/hypervisor/xenserver/ovs-get-bridge.sh b/scripts/vm/hypervisor/xenserver/ovs-get-bridge.sh new file mode 100755 index 00000000000..f56ddf9020f --- /dev/null +++ b/scripts/vm/hypervisor/xenserver/ovs-get-bridge.sh @@ -0,0 +1,27 @@ +#!/bin/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. + +nw_label=$1 +br=`xe network-list name-label="$nw_label" params=bridge |cut -d ':' -f 2 |tr -d ' ' ` +pbr=`ovs-vsctl br-to-parent $br` +while [ "$br" != "$pbr" ] +do + br=$pbr + pbr=`ovs-vsctl br-to-parent $br` +done +echo $pbr diff --git a/scripts/vm/hypervisor/xenserver/ovs-get-dhcp-port.sh b/scripts/vm/hypervisor/xenserver/ovs-get-dhcp-port.sh old mode 100644 new mode 100755 diff --git a/scripts/vm/hypervisor/xenserver/ovs-pvlan b/scripts/vm/hypervisor/xenserver/ovs-pvlan index 372d3c8d05b..956ea6d7978 100755 --- a/scripts/vm/hypervisor/xenserver/ovs-pvlan +++ b/scripts/vm/hypervisor/xenserver/ovs-pvlan @@ -36,6 +36,7 @@ dhcpSetupPath = "/opt/xensource/bin/ovs-pvlan-dhcp-host.sh" vmSetupPath = "/opt/xensource/bin/ovs-pvlan-vm.sh" getDhcpPortPath = "/opt/xensource/bin/ovs-get-dhcp-port.sh" pvlanCleanupPath = "/opt/xensource/bin/ovs-pvlan-cleanup.sh" +getBridgePath = "/opt/xensource/bin/ovs-get-bridge.sh" def echo(fn): def wrapped(*v, **k): @@ -46,11 +47,10 @@ def echo(fn): return res return wrapped - @echo def setup_pvlan_dhcp(session, args): op = args.pop("op") - bridge = args.pop("bridge") + nw_label = args.pop("nw-label") primary = args.pop("primary-pvlan") isolated = args.pop("isolated-pvlan") dhcp_name = args.pop("dhcp-name") @@ -61,6 +61,10 @@ def setup_pvlan_dhcp(session, args): if res != "SUCCESS": return "FAILURE:%s" % res + logging.debug("Network is:%s" % (nw_label)) + bridge = lib.do_cmd([getBridgePath, nw_label]) + logging.debug("Determine bridge/switch is :%s" % (bridge)) + if op == "add": logging.debug("Try to get dhcp vm %s port on the switch:%s" % (dhcp_name, bridge)) dhcp_port = lib.do_cmd([getDhcpPortPath, bridge, dhcp_name]) @@ -88,7 +92,7 @@ def setup_pvlan_dhcp(session, args): @echo def setup_pvlan_vm(session, args): op = args.pop("op") - bridge = args.pop("bridge") + nw_label = args.pop("nw-label") primary = args.pop("primary-pvlan") isolated = args.pop("isolated-pvlan") vm_mac = args.pop("vm-mac") @@ -98,6 +102,9 @@ def setup_pvlan_vm(session, args): if res != "SUCCESS": return "FAILURE:%s" % res + bridge = lib.do_cmd([getBridgePath, nw_label]) + logging.debug("Determine bridge/switch is :%s" % (bridge)) + if op == "add": logging.debug("About to setup vm on the switch:%s" % bridge) res = lib.do_cmd([vmSetupPath, "-A", "-b", bridge, "-p", primary, "-i", isolated, "-v", vm_mac]) diff --git a/scripts/vm/hypervisor/xenserver/xenserver60/patch b/scripts/vm/hypervisor/xenserver/xenserver60/patch index 97595190904..fe36ba9cb84 100644 --- a/scripts/vm/hypervisor/xenserver/xenserver60/patch +++ b/scripts/vm/hypervisor/xenserver/xenserver60/patch @@ -72,3 +72,4 @@ ovs-pvlan-dhcp-host.sh=../../../network,0755,/opt/xensource/bin ovs-pvlan-vm.sh=../../../network,0755,/opt/xensource/bin ovs-pvlan-cleanup.sh=../../../network,0755,/opt/xensource/bin ovs-get-dhcp-port.sh=..,0755,/opt/xensource/bin +ovs-get-bridge.sh=..,0755,/opt/xensource/bin diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 59a9f057162..a5098aeabd8 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -2219,7 +2219,9 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V if (!add) { op = "delete"; } - PvlanSetupCommand cmd = PvlanSetupCommand.createDhcpSetup(op, nic.getBroadcastUri(), router.getInstanceName(), nic.getMacAddress(), nic.getIp4Address()); + Network network = _networkDao.findById(nic.getNetworkId()); + String networkTag = _networkModel.getNetworkTag(router.getHypervisorType(), network); + PvlanSetupCommand cmd = PvlanSetupCommand.createDhcpSetup(op, nic.getBroadcastUri(), networkTag, router.getInstanceName(), nic.getMacAddress(), nic.getIp4Address()); Commands cmds = new Commands(cmd); // In fact we send command to the host of router, we're not programming router but the host try { diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 6ea295259a9..683f0daa1ee 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2761,7 +2761,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use // "delete" would remove all the rules(if using ovs) related to this vm op = "delete"; } - PvlanSetupCommand cmd = PvlanSetupCommand.createVmSetup(op, nic.getBroadcastUri(), nic.getMacAddress()); + Network network = _networkDao.findById(nic.getNetworkId()); + Host host = _hostDao.findById(hostId); + String networkTag = _networkModel.getNetworkTag(host.getHypervisorType(), network); + PvlanSetupCommand cmd = PvlanSetupCommand.createVmSetup(op, nic.getBroadcastUri(), networkTag, nic.getMacAddress()); Answer answer = null; try { answer = _agentMgr.send(hostId, cmd); From 3c3d67769b9b82c04ed670754fda8e36b7afc66a Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Wed, 1 May 2013 13:23:09 -0700 Subject: [PATCH 06/59] PVLAN: PvlanSetupCommand for KVM support --- .../resource/LibvirtComputingResource.java | 76 +++++++++++++++++++ .../hypervisor/kvm/resource/OvsVifDriver.java | 2 +- ...get-dhcp-port.sh => ovs-get-dhcp-iface.sh} | 3 +- scripts/vm/hypervisor/xenserver/ovs-pvlan | 6 +- .../vm/hypervisor/xenserver/xenserver60/patch | 2 +- scripts/vm/network/ovs-pvlan-dhcp-host.sh | 15 ++-- 6 files changed, 89 insertions(+), 15 deletions(-) rename scripts/vm/hypervisor/xenserver/{ovs-get-dhcp-port.sh => ovs-get-dhcp-iface.sh} (92%) 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..dc8bf9d86f7 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 @@ -125,6 +125,7 @@ import com.cloud.agent.api.PlugNicAnswer; import com.cloud.agent.api.PlugNicCommand; import com.cloud.agent.api.PrepareForMigrationAnswer; import com.cloud.agent.api.PrepareForMigrationCommand; +import com.cloud.agent.api.PvlanSetupCommand; import com.cloud.agent.api.ReadyAnswer; import com.cloud.agent.api.ReadyCommand; import com.cloud.agent.api.RebootAnswer; @@ -267,6 +268,8 @@ ServerResource { private String _createTmplPath; private String _heartBeatPath; private String _securityGroupPath; + private String _ovsPvlanDhcpHostPath; + private String _ovsPvlanVmPath; private String _routerProxyPath; private String _host; private String _dcId; @@ -587,6 +590,18 @@ ServerResource { "Unable to find the router_proxy.sh"); } + _ovsPvlanDhcpHostPath = Script.findScript(networkScriptsDir, "ovs-pvlan-dhcp-host.sh"); + if ( _ovsPvlanDhcpHostPath == null) { + throw new ConfigurationException( + "Unable to find the ovs-pvlan-dhcp-host.sh"); + } + + _ovsPvlanVmPath = Script.findScript(networkScriptsDir, "ovs-pvlan-vm.sh"); + if ( _ovsPvlanVmPath == null) { + throw new ConfigurationException( + "Unable to find the ovs-pvlan-vm.sh"); + } + String value = (String) params.get("developer"); boolean isDeveloper = Boolean.parseBoolean(value); @@ -1202,6 +1217,8 @@ ServerResource { return execute((CheckNetworkCommand) cmd); } else if (cmd instanceof NetworkRulesVmSecondaryIpCommand) { return execute((NetworkRulesVmSecondaryIpCommand) cmd); + } else if (cmd instanceof PvlanSetupCommand) { + return execute((PvlanSetupCommand) cmd); } else { s_logger.warn("Unsupported command "); return Answer.createUnsupportedCommandAnswer(cmd); @@ -1517,6 +1534,65 @@ ServerResource { } } + private Answer execute(PvlanSetupCommand cmd) { + String primaryPvlan = cmd.getPrimary(); + String isolatedPvlan = cmd.getIsolated(); + String op = cmd.getOp(); + String dhcpName = cmd.getDhcpName(); + String dhcpMac = cmd.getDhcpMac(); + String dhcpIp = cmd.getDhcpIp(); + String vmMac = cmd.getVmMac(); + boolean add = true; + + String opr = "-A"; + if (op.equals("delete")) { + opr = "-D"; + add = false; + } + + String result = null; + Connect conn; + try { + if (cmd.getType() == PvlanSetupCommand.Type.DHCP) { + Script script = new Script(_ovsPvlanDhcpHostPath, _timeout, s_logger); + if (add) { + conn = LibvirtConnection.getConnectionByVmName(dhcpName); + List ifaces = getInterfaces(conn, dhcpName); + InterfaceDef guestNic = ifaces.get(0); + script.add(opr, "-b", _guestBridgeName, + "-p", primaryPvlan, "-i", isolatedPvlan, "-n", dhcpName, + "-d", dhcpIp, "-m", dhcpMac, "-I", guestNic.getDevName()); + } else { + script.add(opr, "-b", _guestBridgeName, + "-p", primaryPvlan, "-i", isolatedPvlan, "-n", dhcpName, + "-d", dhcpIp, "-m", dhcpMac); + } + result = script.execute(); + if (result != null) { + s_logger.warn("Failed to program pvlan for dhcp server with mac " + dhcpMac); + return new Answer(cmd, false, result); + } else { + s_logger.info("Programmed pvlan for dhcp server with mac " + dhcpMac); + } + } else if (cmd.getType() == PvlanSetupCommand.Type.VM) { + Script script = new Script(_ovsPvlanVmPath, _timeout, s_logger); + script.add(opr, "-b", _guestBridgeName, + "-p", primaryPvlan, "-i", isolatedPvlan, "-v", vmMac); + result = script.execute(); + if (result != null) { + s_logger.warn("Failed to program pvlan for vm with mac " + vmMac); + return new Answer(cmd, false, result); + } else { + s_logger.info("Programmed pvlan for vm with mac " + vmMac); + } + } + } catch (LibvirtException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return new Answer(cmd, true, result); + } + private void VifHotPlug(Connect conn, String vmName, String vlanId, String macAddr) throws InternalErrorException, LibvirtException { NicTO nicTO = new NicTO(); diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java index 37761aa5555..ac226e212e5 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java @@ -79,7 +79,7 @@ public class OvsVifDriver extends VifDriverBase { } String trafficLabel = nic.getName(); if (nic.getType() == Networks.TrafficType.Guest) { - if (nic.getBroadcastType() == Networks.BroadcastDomainType.Vlan + if ((nic.getBroadcastType() == Networks.BroadcastDomainType.Vlan || nic.getBroadcastType() == Networks.BroadcastDomainType.Pvlan) && !vlanId.equalsIgnoreCase("untagged")) { if(trafficLabel != null && !trafficLabel.isEmpty()) { s_logger.debug("creating a vlan dev and bridge for guest traffic per traffic label " + trafficLabel); diff --git a/scripts/vm/hypervisor/xenserver/ovs-get-dhcp-port.sh b/scripts/vm/hypervisor/xenserver/ovs-get-dhcp-iface.sh similarity index 92% rename from scripts/vm/hypervisor/xenserver/ovs-get-dhcp-port.sh rename to scripts/vm/hypervisor/xenserver/ovs-get-dhcp-iface.sh index a30b180bed0..6b30ee62a06 100755 --- a/scripts/vm/hypervisor/xenserver/ovs-get-dhcp-port.sh +++ b/scripts/vm/hypervisor/xenserver/ovs-get-dhcp-iface.sh @@ -22,5 +22,4 @@ bridge=$1 dhcp_name=$2 dom_id=`xe vm-list is-control-domain=false power-state=running params=dom-id name-label=$dhcp_name|cut -d ':' -f 2 |tr -d ' ' ` iface="vif${dom_id}.0" -port=`ovs-ofctl show $bridge|grep $iface|cut -d '(' -f 1|tr -d ' '` -echo $port +echo $iface diff --git a/scripts/vm/hypervisor/xenserver/ovs-pvlan b/scripts/vm/hypervisor/xenserver/ovs-pvlan index 956ea6d7978..c821870d64d 100755 --- a/scripts/vm/hypervisor/xenserver/ovs-pvlan +++ b/scripts/vm/hypervisor/xenserver/ovs-pvlan @@ -34,7 +34,7 @@ xePath = "/opt/xensource/bin/xe" lib.setup_logging("/var/log/ovs-pvlan.log") dhcpSetupPath = "/opt/xensource/bin/ovs-pvlan-dhcp-host.sh" vmSetupPath = "/opt/xensource/bin/ovs-pvlan-vm.sh" -getDhcpPortPath = "/opt/xensource/bin/ovs-get-dhcp-port.sh" +getDhcpIfacePath = "/opt/xensource/bin/ovs-get-dhcp-iface.sh" pvlanCleanupPath = "/opt/xensource/bin/ovs-pvlan-cleanup.sh" getBridgePath = "/opt/xensource/bin/ovs-get-bridge.sh" @@ -67,11 +67,11 @@ def setup_pvlan_dhcp(session, args): if op == "add": logging.debug("Try to get dhcp vm %s port on the switch:%s" % (dhcp_name, bridge)) - dhcp_port = lib.do_cmd([getDhcpPortPath, bridge, dhcp_name]) + dhcp_iface = lib.do_cmd([getDhcpIfacePath, bridge, dhcp_name]) logging.debug("About to setup dhcp vm on the switch:%s" % bridge) res = lib.do_cmd([dhcpSetupPath, "-A", "-b", bridge, "-p", primary, "-i", isolated, "-n", dhcp_name, "-d", dhcp_ip, "-m", dhcp_mac, - "-P", dhcp_port]) + "-I", dhcp_iface]) if res: result = "FAILURE:%s" % res return result; diff --git a/scripts/vm/hypervisor/xenserver/xenserver60/patch b/scripts/vm/hypervisor/xenserver/xenserver60/patch index fe36ba9cb84..9af32b1457a 100644 --- a/scripts/vm/hypervisor/xenserver/xenserver60/patch +++ b/scripts/vm/hypervisor/xenserver/xenserver60/patch @@ -71,5 +71,5 @@ ovs-pvlan=..,0755,/etc/xapi.d/plugins ovs-pvlan-dhcp-host.sh=../../../network,0755,/opt/xensource/bin ovs-pvlan-vm.sh=../../../network,0755,/opt/xensource/bin ovs-pvlan-cleanup.sh=../../../network,0755,/opt/xensource/bin -ovs-get-dhcp-port.sh=..,0755,/opt/xensource/bin +ovs-get-dhcp-iface.sh=..,0755,/opt/xensource/bin ovs-get-bridge.sh=..,0755,/opt/xensource/bin diff --git a/scripts/vm/network/ovs-pvlan-dhcp-host.sh b/scripts/vm/network/ovs-pvlan-dhcp-host.sh index 93f56534beb..73d735f822e 100755 --- a/scripts/vm/network/ovs-pvlan-dhcp-host.sh +++ b/scripts/vm/network/ovs-pvlan-dhcp-host.sh @@ -18,10 +18,8 @@ #!/bin/bash -source ovs-func.sh - usage() { - printf "Usage: %s: (-A|-D) -b -p -i -n -d -m -P -v -h \n" $(basename $0) >&2 + printf "Usage: %s: (-A|-D) -b -p -i -n -d -m -I -v -h \n" $(basename $0) >&2 exit 2 } @@ -31,11 +29,11 @@ sec_iso_vlan= dhcp_name= dhcp_ip= dhcp_mac= -dhcp_port= vm_mac= +iface= op= -while getopts 'ADb:p:i:d:m:v:n:P:h' OPTION +while getopts 'ADb:p:i:d:m:v:n:I:h' OPTION do case $OPTION in A) op="add" @@ -54,7 +52,7 @@ do ;; m) dhcp_mac="$OPTARG" ;; - P) dhcp_port="$OPTARG" + I) iface="$OPTARG" ;; v) vm_mac="$OPTARG" ;; @@ -106,14 +104,15 @@ then exit 1 fi -if [ "$op" == "add" -a -z "$dhcp_port" ] +if [ "$op" == "add" -a -z "$iface" ] then - echo Missing parameter DHCP PORT! + echo Missing parameter DHCP VM interface! exit 1 fi if [ "$op" == "add" ] then + dhcp_port=`ovs-ofctl show $br | grep $iface | cut -d '(' -f 1|tr -d ' '` ovs-ofctl add-flow $br priority=200,arp,dl_vlan=$sec_iso_vlan,nw_dst=$dhcp_ip,actions=strip_vlan,output:$dhcp_port ovs-ofctl add-flow $br priority=180,arp,nw_dst=$dhcp_ip,actions=strip_vlan,output:$dhcp_port ovs-ofctl add-flow $br priority=150,dl_vlan=$sec_iso_vlan,dl_dst=$dhcp_mac,actions=strip_vlan,output:$dhcp_port From 70da1b3be3b80d1bcc1ae652d9be81d26d3ef807 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Thu, 2 May 2013 16:32:07 -0700 Subject: [PATCH 07/59] PVLAN: Fix KVM ovs driver cannot get vlan id issue --- .../kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java index ac226e212e5..eac32485e53 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java @@ -76,6 +76,8 @@ public class OvsVifDriver extends VifDriverBase { } else if (nic.getBroadcastType() == Networks.BroadcastDomainType.Lswitch) { logicalSwitchUuid = nic.getBroadcastUri().getSchemeSpecificPart(); + } else if (nic.getBroadcastType() == Networks.BroadcastDomainType.Pvlan) { + vlanId = NetUtils.getPrimaryPvlanFromUri(nic.getBroadcastUri()); } String trafficLabel = nic.getName(); if (nic.getType() == Networks.TrafficType.Guest) { From 87b7a8450742b28183bc3e3245ba791959ce4e98 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Mon, 6 May 2013 12:14:19 -0700 Subject: [PATCH 08/59] CLOUDSTACK-2348: PVLAN - UI - infrastructure menu - create guest network - add new field Private VLAN ID. --- ui/scripts/system.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 7aa0566fbef..5eb88e0cf20 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -1375,7 +1375,10 @@ label: 'label.vlan.id', docID: 'helpGuestNetworkZoneVLANID' }, - + isolatedpvlanId: { + label: 'Private VLAN ID' + }, + scope: { label: 'label.scope', docID: 'helpGuestNetworkZoneScope', @@ -1589,11 +1592,15 @@ if(this.id == selectedNetworkOfferingId) { if(this.specifyvlan == false) { $form.find('.form-item[rel=vlanId]').hide(); - cloudStack.dialog.createFormField.validation.required.remove($form.find('.form-item[rel=vlanId]')); //make vlanId optional + cloudStack.dialog.createFormField.validation.required.remove($form.find('.form-item[rel=vlanId]')); //make vlanId optional + + $form.find('.form-item[rel=isolatedpvlanId]').hide(); } else { $form.find('.form-item[rel=vlanId]').css('display', 'inline-block'); - cloudStack.dialog.createFormField.validation.required.add($form.find('.form-item[rel=vlanId]')); //make vlanId required + cloudStack.dialog.createFormField.validation.required.add($form.find('.form-item[rel=vlanId]')); //make vlanId required + + $form.find('.form-item[rel=isolatedpvlanId]').css('display', 'inline-block'); } return false; //break each loop } @@ -1679,7 +1686,10 @@ if(($form.find('.form-item[rel=vlanId]').css("display") != "none") && (args.data.vlanId != null && args.data.vlanId.length > 0)) array1.push("&vlan=" + todb(args.data.vlanId)); - + + if(($form.find('.form-item[rel=isolatedpvlanId]').css("display") != "none") && (args.data.isolatedpvlanId != null && args.data.isolatedpvlanId.length > 0)) + array1.push("&isolatedpvlan=" + todb(args.data.isolatedpvlanId)); + if($form.find('.form-item[rel=domainId]').css("display") != "none") { array1.push("&domainId=" + args.data.domainId); From 0c7bd0777b9a5a5ec326b0d15fb0b3ef584235ab Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Mon, 6 May 2013 17:51:33 -0700 Subject: [PATCH 09/59] PVLAN: Optimize pvlan scripts --- scripts/vm/network/ovs-pvlan-dhcp-host.sh | 2 -- scripts/vm/network/ovs-pvlan-vm.sh | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/vm/network/ovs-pvlan-dhcp-host.sh b/scripts/vm/network/ovs-pvlan-dhcp-host.sh index 73d735f822e..64565ff45d1 100755 --- a/scripts/vm/network/ovs-pvlan-dhcp-host.sh +++ b/scripts/vm/network/ovs-pvlan-dhcp-host.sh @@ -114,12 +114,10 @@ if [ "$op" == "add" ] then dhcp_port=`ovs-ofctl show $br | grep $iface | cut -d '(' -f 1|tr -d ' '` ovs-ofctl add-flow $br priority=200,arp,dl_vlan=$sec_iso_vlan,nw_dst=$dhcp_ip,actions=strip_vlan,output:$dhcp_port - ovs-ofctl add-flow $br priority=180,arp,nw_dst=$dhcp_ip,actions=strip_vlan,output:$dhcp_port ovs-ofctl add-flow $br priority=150,dl_vlan=$sec_iso_vlan,dl_dst=$dhcp_mac,actions=strip_vlan,output:$dhcp_port ovs-ofctl add-flow $br priority=100,udp,dl_vlan=$sec_iso_vlan,nw_dst=255.255.255.255,tp_dst=67,actions=strip_vlan,output:$dhcp_port else ovs-ofctl del-flows --strict $br priority=200,arp,dl_vlan=$sec_iso_vlan,nw_dst=$dhcp_ip - ovs-ofctl del-flows --strict $br priority=180,arp,nw_dst=$dhcp_ip ovs-ofctl del-flows --strict $br priority=150,dl_vlan=$sec_iso_vlan,dl_dst=$dhcp_mac ovs-ofctl del-flows --strict $br priority=100,udp,dl_vlan=$sec_iso_vlan,nw_dst=255.255.255.255,tp_dst=67 fi diff --git a/scripts/vm/network/ovs-pvlan-vm.sh b/scripts/vm/network/ovs-pvlan-vm.sh index 4bad11c7624..fd384814cc4 100755 --- a/scripts/vm/network/ovs-pvlan-vm.sh +++ b/scripts/vm/network/ovs-pvlan-vm.sh @@ -91,7 +91,7 @@ trunk_port=1 if [ "$op" == "add" ] then ovs-ofctl add-flow $br priority=50,dl_vlan=0xffff,dl_src=$vm_mac,actions=mod_vlan_vid:$sec_iso_vlan,resubmit:$trunk_port - ovs-ofctl add-flow $br priority=60,dl_vlan=$sec_iso_vlan,dl_src=$vm_mac,actions=output:1 + ovs-ofctl add-flow $br priority=60,dl_vlan=$sec_iso_vlan,dl_src=$vm_mac,actions=output:$trunk_port else ovs-ofctl del-flows --strict $br priority=50,dl_vlan=0xffff,dl_src=$vm_mac ovs-ofctl del-flows --strict $br priority=60,dl_vlan=$sec_iso_vlan,dl_src=$vm_mac From 25e992dc8e1f2c202fba9c845d5913e2308ded90 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Tue, 7 May 2013 13:02:41 -0700 Subject: [PATCH 10/59] CLOUDSTACK-2348: PVLAN - UI - Infrastructure menu - guest network - add broadcast URI field to listView and detailView. --- ui/scripts/system.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 5eb88e0cf20..022f29995f3 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -1340,6 +1340,7 @@ name: { label: 'label.name' }, type: { label: 'label.type' }, vlan: { label: 'label.vlan.id' }, + broadcasturi: { label: 'broadcast URI' }, cidr: { label: 'IPv4 CIDR' }, ip6cidr: { label: 'IPv6 CIDR'} //scope: { label: 'label.scope' } @@ -2057,6 +2058,7 @@ } }, vlan: { label: 'label.vlan.id' }, + broadcasturi: { label: 'broadcast URI' }, scope: { label: 'label.scope' }, networkofferingdisplaytext: { label: 'label.network.offering' }, networkofferingid: { From 065d2561b9532c6f7536d22ce067d6085238a76b Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Mon, 13 May 2013 11:40:40 -0700 Subject: [PATCH 11/59] CLOUDSTACK-2392: Not allow create pvlan network with ipv6 --- server/src/com/cloud/network/NetworkServiceImpl.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 7c4d7027c6b..ebada5c3fc3 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -1019,6 +1019,10 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { throw new InvalidParameterValueException("Can only support create Private VLAN network with advance shared network!"); } + if (isolatedPvlan != null && ipv6) { + throw new InvalidParameterValueException("Can only support create Private VLAN network with IPv4!"); + } + // Regular user can create Guest Isolated Source Nat enabled network only if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL && (ntwkOff.getTrafficType() != TrafficType.Guest || ntwkOff.getGuestType() != Network.GuestType.Isolated From 2bcf71638dba9a252378c251bbd32e6f72f74028 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Thu, 9 May 2013 19:44:14 -0700 Subject: [PATCH 12/59] PVLAN: Add integration test --- test/integration/smoke/test_pvlan.py | 86 ++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 test/integration/smoke/test_pvlan.py diff --git a/test/integration/smoke/test_pvlan.py b/test/integration/smoke/test_pvlan.py new file mode 100644 index 00000000000..4eb76e1cdb7 --- /dev/null +++ b/test/integration/smoke/test_pvlan.py @@ -0,0 +1,86 @@ +# 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. +""" test for private vlan isolation +""" +#Import Local Modules +import marvin +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin 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 telnetlib + +#Import System modules +import time +_multiprocess_shared_ = True + +class TestPVLAN(cloudstackTestCase): + + zoneId = 1 + networkOfferingId = 7 + vlan = 1234 + isolatedpvlan = 567 + + def setUp(self): + self.apiClient = self.testClient.getApiClient() + + def test_create_pvlan_network(self): + self.debug("Test create pvlan network") + createNetworkCmd = createNetwork.createNetworkCmd() + createNetworkCmd.name = "pvlan network" + createNetworkCmd.displaytext = "pvlan network" + createNetworkCmd.netmask = "255.255.255.0" + createNetworkCmd.gateway = "10.10.10.1" + createNetworkCmd.startip = "10.10.10.10" + createNetworkCmd.gateway = "10.10.10.20" + createNetworkCmd.vlan = "1234" + createNetworkCmd.isolatedpvlan = "567" + createNetworkCmd.zoneid = self.zoneId + createNetworkCmd.networkofferingid = self.networkOfferingId + createNetworkResponse = self.apiClient.createNetwork(createNetworkCmd) + self.networkId = createNetworkResponse.id + self.broadcasttype = createNetworkResponse.broadcastdomaintype + self.broadcasturi = createNetworkResponse.broadcasturi + + self.assertIsNotNone(createNetworkResponse.id, "Network failed to create") + self.assertTrue(createNetworkResponse.broadcastdomaintype, "Pvlan") + self.assertTrue(createNetworkResponse.broadcasturi, "pvlan://1234-i567") + + self.debug("Clean up test pvlan network") + deleteNetworkCmd = deleteNetwork.deleteNetworkCmd() + deleteNetworkCmd.id = self.networkId; + self.apiClient.deleteNetwork(deleteNetworkCmd) + + #Test invalid parameter + + # CLOUDSTACK-2392: Should not allow create pvlan with ipv6 + createNetworkCmd.ip6gateway="fc00:1234::1" + createNetworkCmd.ip6cidr="fc00:1234::/64" + createNetworkCmd.startipv6="fc00:1234::10" + createNetworkCmd.endipv6="fc00:1234::20" + err = 0; + try: + createNetworkResponse = self.apiClient.createNetwork(createNetworkCmd) + except Exception as e: + err = 1; + self.debug("Try alloc with ipv6, got:%s" % e) + self.assertEqual(err, 1, "Shouldn't allow create PVLAN network with IPv6"); + + From 3388b77156e93ff8de5f08737dd66023ed0089f2 Mon Sep 17 00:00:00 2001 From: Kishan Kavala Date: Wed, 15 May 2013 12:51:08 +0530 Subject: [PATCH 13/59] CLOUDSTACK-2487: Show error while adding acl_item to default ACL --- .../src/com/cloud/network/vpc/NetworkACLServiceImpl.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/server/src/com/cloud/network/vpc/NetworkACLServiceImpl.java b/server/src/com/cloud/network/vpc/NetworkACLServiceImpl.java index ac59fab7ba2..00c90d5164e 100644 --- a/server/src/com/cloud/network/vpc/NetworkACLServiceImpl.java +++ b/server/src/com/cloud/network/vpc/NetworkACLServiceImpl.java @@ -216,8 +216,8 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ throw new InvalidParameterValueException("Network ACL can be created just for networks of type " + Networks.TrafficType.Guest); } - if(aclId != NetworkACL.DEFAULT_DENY) { - //ACL is not default DENY + if(aclId != NetworkACL.DEFAULT_DENY && aclId != NetworkACL.DEFAULT_ALLOW) { + //ACL is not default DENY/ALLOW // ACL should be associated with a VPC Vpc vpc = _vpcMgr.getVpc(acl.getVpcId()); if(vpc == null){ @@ -254,6 +254,10 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ throw new InvalidParameterValueException("Unable to find specified ACL"); } + if((aclId == NetworkACL.DEFAULT_DENY) || (aclId == NetworkACL.DEFAULT_ALLOW)){ + throw new InvalidParameterValueException("Default ACL cannot be modified"); + } + Vpc vpc = _vpcMgr.getVpc(acl.getVpcId()); if(vpc == null){ throw new InvalidParameterValueException("Unable to find Vpc associated with the NetworkACL"); From 39caa0ebdd183f54b2f2b7b635c40f70f1a51d01 Mon Sep 17 00:00:00 2001 From: Kishan Kavala Date: Wed, 15 May 2013 14:20:29 +0530 Subject: [PATCH 14/59] Updated network acl service test to avoid default ACL modification --- server/test/com/cloud/vpc/NetworkACLServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/test/com/cloud/vpc/NetworkACLServiceTest.java b/server/test/com/cloud/vpc/NetworkACLServiceTest.java index 7cc7200718a..9a368b94ae4 100644 --- a/server/test/com/cloud/vpc/NetworkACLServiceTest.java +++ b/server/test/com/cloud/vpc/NetworkACLServiceTest.java @@ -83,7 +83,7 @@ public class NetworkACLServiceTest extends TestCase{ createACLItemCmd = new CreateNetworkACLCmd(){ @Override public Long getACLId(){ - return 1L; + return 3L; } @Override From 24cdddbf5e645da92855f3f19c8d81b1ddf57e06 Mon Sep 17 00:00:00 2001 From: Nitin Mehta Date: Wed, 15 May 2013 14:25:39 +0530 Subject: [PATCH 15/59] CLOUDSTACK-2459 Fix the scale vm tests --- server/test/com/cloud/vm/UserVmManagerTest.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/server/test/com/cloud/vm/UserVmManagerTest.java b/server/test/com/cloud/vm/UserVmManagerTest.java index 939ecdcc185..6a9711401c9 100755 --- a/server/test/com/cloud/vm/UserVmManagerTest.java +++ b/server/test/com/cloud/vm/UserVmManagerTest.java @@ -246,8 +246,8 @@ public class UserVmManagerTest { } - // Test scaleVm on incompatible HV. - //@Test(expected=InvalidParameterValueException.class) + // Test scaleVm on equal service offerings. + @Test(expected=InvalidParameterValueException.class) public void testScaleVMF2() throws Exception { ScaleVMCmd cmd = new ScaleVMCmd(); @@ -261,14 +261,11 @@ public class UserVmManagerTest { serviceOfferingIdField.setAccessible(true); serviceOfferingIdField.set(cmd, 1L); - //UserContext.current().setEventDetails("Vm Id: "+getId()); - // Account account = (Account) new AccountVO("testaccount", 1L, "networkdomain", (short) 0, 1); - //AccountVO(String accountName, long domainId, String networkDomain, short type, int regionId) - // UserContext.registerContext(1, account, null, true); when(_vmInstanceDao.findById(anyLong())).thenReturn(_vmInstance); doReturn(Hypervisor.HypervisorType.XenServer).when(_vmInstance).getHypervisorType(); + doReturn(VirtualMachine.State.Running).when(_vmInstance).getState(); doNothing().when(_accountMgr).checkAccess(_account, null, true, _templateMock); @@ -285,8 +282,8 @@ public class UserVmManagerTest { } - // Test scaleVm for Stopped vm. Full positive test. - //@Test + // Test scaleVm for Stopped vm. + @Test(expected=InvalidParameterValueException.class) public void testScaleVMF3() throws Exception { ScaleVMCmd cmd = new ScaleVMCmd(); @@ -316,10 +313,12 @@ public class UserVmManagerTest { when(_configMgr.getServiceOffering(1L)).thenReturn(so1); doReturn(VirtualMachine.State.Stopped).when(_vmInstance).getState(); + when(_vmDao.findById(anyLong())).thenReturn(null); + doReturn(true).when(_itMgr).upgradeVmDb(anyLong(),anyLong()); - when(_vmDao.findById(anyLong())).thenReturn(_vmMock); + //when(_vmDao.findById(anyLong())).thenReturn(_vmMock); _userVmMgr.upgradeVirtualMachine(cmd); From b17be94cf5592e9cfd5d346b3d678f31f0a8e374 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Wed, 15 May 2013 14:51:37 +0530 Subject: [PATCH 16/59] don't let requests logs requests logs to the logger making it hard to distinguish marvin logs from http logs. Signed-off-by: Prasanna Santhanam --- tools/marvin/marvin/cloudstackConnection.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/marvin/marvin/cloudstackConnection.py b/tools/marvin/marvin/cloudstackConnection.py index 803911721e9..b5ff5bf7b3f 100644 --- a/tools/marvin/marvin/cloudstackConnection.py +++ b/tools/marvin/marvin/cloudstackConnection.py @@ -20,6 +20,7 @@ import urllib import base64 import hmac import hashlib +import logging import time import cloudstackException from cloudstackAPI import * @@ -37,6 +38,7 @@ class cloudConnection(object): apiKey=None, securityKey=None, asyncTimeout=3600, logging=None, scheme='http', path='client/api'): + self.loglevel() #Turn off requests logs self.apiKey = apiKey self.securityKey = securityKey self.mgtSvr = mgtSvr @@ -65,6 +67,13 @@ class cloudConnection(object): self.asyncTimeout, self.logging, self.protocol, self.path) + def loglevel(self, lvl=logging.WARNING): + """ + Turns off the INFO/DEBUG logs from `requests` + """ + requests_log = logging.getLogger("requests") + requests_log.setLevel(lvl) + def poll(self, jobid, response): """ polls the completion of a given jobid From 9542f105927ceba39a4da0e2f63c85f21f1e43a1 Mon Sep 17 00:00:00 2001 From: Sanjay Tripathi Date: Fri, 26 Apr 2013 16:47:56 +0530 Subject: [PATCH 17/59] CLOUDSTACK-1904: API : UI : Admin can not delete Events/Archive from other accounts --- .../command/user/event/DeleteEventsCmd.java | 1 - .../src/com/cloud/domain/dao/DomainDao.java | 9 ++++--- .../com/cloud/domain/dao/DomainDaoImpl.java | 18 +++++++++++-- .../src/com/cloud/event/dao/EventDao.java | 2 +- .../src/com/cloud/event/dao/EventDaoImpl.java | 27 ++++++++++--------- .../src/com/cloud/user/dao/AccountDao.java | 1 + .../com/cloud/user/dao/AccountDaoImpl.java | 19 +++++++++++-- .../cloud/server/ManagementServerImpl.java | 24 +++++++++++++++-- .../cloud/event/EventControlsUnitTest.java | 3 +-- 9 files changed, 77 insertions(+), 27 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/command/user/event/DeleteEventsCmd.java b/api/src/org/apache/cloudstack/api/command/user/event/DeleteEventsCmd.java index 55ca92a5dfe..a03e6d9f7df 100644 --- a/api/src/org/apache/cloudstack/api/command/user/event/DeleteEventsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/event/DeleteEventsCmd.java @@ -25,7 +25,6 @@ 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.AlertResponse; import org.apache.cloudstack.api.response.EventResponse; import org.apache.cloudstack.api.response.SuccessResponse; import org.apache.log4j.Logger; diff --git a/engine/schema/src/com/cloud/domain/dao/DomainDao.java b/engine/schema/src/com/cloud/domain/dao/DomainDao.java index afeb0f462f4..cb1c1f2c4be 100644 --- a/engine/schema/src/com/cloud/domain/dao/DomainDao.java +++ b/engine/schema/src/com/cloud/domain/dao/DomainDao.java @@ -26,9 +26,10 @@ public interface DomainDao extends GenericDao { public DomainVO create(DomainVO domain); public DomainVO findDomainByPath(String domainPath); public boolean isChildDomain(Long parentId, Long childId); - DomainVO findImmediateChildForParent(Long parentId); - List findImmediateChildrenForParent(Long parentId); - List findAllChildren(String path, Long parentId); - List findInactiveDomains(); + DomainVO findImmediateChildForParent(Long parentId); + List findImmediateChildrenForParent(Long parentId); + List findAllChildren(String path, Long parentId); + List findInactiveDomains(); Set getDomainParentIds(long domainId); + List getDomainChildrenIds(String path); } diff --git a/engine/schema/src/com/cloud/domain/dao/DomainDaoImpl.java b/engine/schema/src/com/cloud/domain/dao/DomainDaoImpl.java index c30ca5ef49a..9460a73dc57 100644 --- a/engine/schema/src/com/cloud/domain/dao/DomainDaoImpl.java +++ b/engine/schema/src/com/cloud/domain/dao/DomainDaoImpl.java @@ -32,6 +32,7 @@ import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.utils.db.DB; 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.Transaction; @@ -46,6 +47,7 @@ public class DomainDaoImpl extends GenericDaoBase implements Dom protected SearchBuilder DomainPairSearch; protected SearchBuilder ImmediateChildDomainSearch; protected SearchBuilder FindAllChildrenSearch; + protected GenericSearchBuilder FindIdsOfAllChildrenSearch; protected SearchBuilder AllFieldsSearch; public DomainDaoImpl () { @@ -70,7 +72,12 @@ public class DomainDaoImpl extends GenericDaoBase implements Dom FindAllChildrenSearch.and("path", FindAllChildrenSearch.entity().getPath(), SearchCriteria.Op.LIKE); FindAllChildrenSearch.and("id", FindAllChildrenSearch.entity().getId(), SearchCriteria.Op.NEQ); FindAllChildrenSearch.done(); - + + FindIdsOfAllChildrenSearch = createSearchBuilder(Long.class); + FindIdsOfAllChildrenSearch.selectField(FindIdsOfAllChildrenSearch.entity().getId()); + FindIdsOfAllChildrenSearch.and("path", FindIdsOfAllChildrenSearch.entity().getPath(), SearchCriteria.Op.LIKE); + FindIdsOfAllChildrenSearch.done(); + AllFieldsSearch = createSearchBuilder(); AllFieldsSearch.and("name", AllFieldsSearch.entity().getName(), SearchCriteria.Op.EQ); AllFieldsSearch.and("state", AllFieldsSearch.entity().getState(), SearchCriteria.Op.EQ); @@ -221,7 +228,14 @@ public class DomainDaoImpl extends GenericDaoBase implements Dom sc.setParameters("id", parentId); return listBy(sc); } - + + @Override + public List getDomainChildrenIds(String path){ + SearchCriteria sc = FindIdsOfAllChildrenSearch.create(); + sc.setParameters("path", path+"%"); + return customSearch(sc, null); + } + @Override public boolean isChildDomain(Long parentId, Long childId) { if ((parentId == null) || (childId == null)) { diff --git a/engine/schema/src/com/cloud/event/dao/EventDao.java b/engine/schema/src/com/cloud/event/dao/EventDao.java index da5f47a90b4..9454ce717de 100644 --- a/engine/schema/src/com/cloud/event/dao/EventDao.java +++ b/engine/schema/src/com/cloud/event/dao/EventDao.java @@ -31,7 +31,7 @@ public interface EventDao extends GenericDao { EventVO findCompletedEvent(long startId); - public List listToArchiveOrDeleteEvents(List ids, String type, Date olderThan, Long accountId); + public List listToArchiveOrDeleteEvents(List ids, String type, Date olderThan, List accountIds); public void archiveEvents(List events); diff --git a/engine/schema/src/com/cloud/event/dao/EventDaoImpl.java b/engine/schema/src/com/cloud/event/dao/EventDaoImpl.java index 6ba59c56b0a..0d3d38a0204 100644 --- a/engine/schema/src/com/cloud/event/dao/EventDaoImpl.java +++ b/engine/schema/src/com/cloud/event/dao/EventDaoImpl.java @@ -49,7 +49,7 @@ public class EventDaoImpl extends GenericDaoBase implements Event ToArchiveOrDeleteEventSearch = createSearchBuilder(); ToArchiveOrDeleteEventSearch.and("id", ToArchiveOrDeleteEventSearch.entity().getId(), Op.IN); ToArchiveOrDeleteEventSearch.and("type", ToArchiveOrDeleteEventSearch.entity().getType(), Op.EQ); - ToArchiveOrDeleteEventSearch.and("accountId", ToArchiveOrDeleteEventSearch.entity().getAccountId(), Op.EQ); + ToArchiveOrDeleteEventSearch.and("accountIds", ToArchiveOrDeleteEventSearch.entity().getAccountId(), Op.IN); ToArchiveOrDeleteEventSearch.and("createDateL", ToArchiveOrDeleteEventSearch.entity().getCreateDate(), Op.LT); ToArchiveOrDeleteEventSearch.done(); } @@ -76,7 +76,7 @@ public class EventDaoImpl extends GenericDaoBase implements Event } @Override - public List listToArchiveOrDeleteEvents(List ids, String type, Date olderThan, Long accountId) { + public List listToArchiveOrDeleteEvents(List ids, String type, Date olderThan, List accountIds) { SearchCriteria sc = ToArchiveOrDeleteEventSearch.create(); if (ids != null) { sc.setParameters("id", ids.toArray(new Object[ids.size()])); @@ -87,23 +87,24 @@ public class EventDaoImpl extends GenericDaoBase implements Event if (olderThan != null) { sc.setParameters("createDateL", olderThan); } - if (accountId != null) { - sc.setParameters("accountId", accountId); + if (accountIds != null && !accountIds.isEmpty()) { + sc.setParameters("accountIds", accountIds.toArray(new Object[accountIds.size()])); } return search(sc, null); } @Override public void archiveEvents(List events) { - - Transaction txn = Transaction.currentTxn(); - txn.start(); - for (EventVO event : events) { - event = lockRow(event.getId(), true); - event.setArchived(true); - update(event.getId(), event); - txn.commit(); + if (events != null && !events.isEmpty()) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + for (EventVO event : events) { + event = lockRow(event.getId(), true); + event.setArchived(true); + update(event.getId(), event); + txn.commit(); + } + txn.close(); } - txn.close(); } } diff --git a/engine/schema/src/com/cloud/user/dao/AccountDao.java b/engine/schema/src/com/cloud/user/dao/AccountDao.java index 3b7fa66434e..204da394a69 100644 --- a/engine/schema/src/com/cloud/user/dao/AccountDao.java +++ b/engine/schema/src/com/cloud/user/dao/AccountDao.java @@ -49,4 +49,5 @@ public interface AccountDao extends GenericDao { //returns only non-removed account Account findActiveAccount(String accountName, Long domainId); Account findActiveNonProjectAccount(String accountName, Long domainId); + List getAccountIdsForDomains(List ids); } diff --git a/engine/schema/src/com/cloud/user/dao/AccountDaoImpl.java b/engine/schema/src/com/cloud/user/dao/AccountDaoImpl.java index 892fdcd548d..aa67e86bf70 100755 --- a/engine/schema/src/com/cloud/user/dao/AccountDaoImpl.java +++ b/engine/schema/src/com/cloud/user/dao/AccountDaoImpl.java @@ -35,8 +35,10 @@ import com.cloud.utils.Pair; import com.cloud.utils.crypt.DBEncryptionUtil; import com.cloud.utils.db.Filter; 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.Op; import com.cloud.utils.db.Transaction; @Component @@ -54,7 +56,8 @@ public class AccountDaoImpl extends GenericDaoBase implements A protected final SearchBuilder CleanupForRemovedAccountsSearch; protected final SearchBuilder CleanupForDisabledAccountsSearch; protected final SearchBuilder NonProjectAccountSearch; - + protected final GenericSearchBuilder AccountIdsSearch; + public AccountDaoImpl() { AllFieldsSearch = createSearchBuilder(); AllFieldsSearch.and("accountName", AllFieldsSearch.entity().getAccountName(), SearchCriteria.Op.EQ); @@ -91,6 +94,11 @@ public class AccountDaoImpl extends GenericDaoBase implements A NonProjectAccountSearch.and("state", NonProjectAccountSearch.entity().getState(), SearchCriteria.Op.EQ); NonProjectAccountSearch.and("type", NonProjectAccountSearch.entity().getType(), SearchCriteria.Op.NEQ); NonProjectAccountSearch.done(); + + AccountIdsSearch = createSearchBuilder(Long.class); + AccountIdsSearch.selectField(AccountIdsSearch.entity().getId()); + AccountIdsSearch.and("ids", AccountIdsSearch.entity().getDomainId(), Op.IN); + AccountIdsSearch.done(); } @Override @@ -263,5 +271,12 @@ public class AccountDaoImpl extends GenericDaoBase implements A } } } - + + @Override + public List getAccountIdsForDomains(List domainIds) { + SearchCriteria sc = AccountIdsSearch.create(); + sc.setParameters("ids", domainIds.toArray(new Object[domainIds.size()])); + return customSearch(sc, null); + } + } diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 425ecf080f8..137f07e1527 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -887,10 +887,20 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe @Override public boolean archiveEvents(ArchiveEventsCmd cmd) { + Account caller = UserContext.current().getCaller(); List ids = cmd.getIds(); boolean result =true; + List permittedAccountIds = new ArrayList(); - List events = _eventDao.listToArchiveOrDeleteEvents(ids, cmd.getType(), cmd.getOlderThan(), cmd.getEntityOwnerId()); + if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL && caller.getType() == Account.ACCOUNT_TYPE_PROJECT) { + permittedAccountIds.add(caller.getId()); + } else { + DomainVO domain = _domainDao.findById(caller.getDomainId()); + List permittedDomainIds = _domainDao.getDomainChildrenIds(domain.getPath()); + permittedAccountIds = _accountDao.getAccountIdsForDomains(permittedDomainIds); + } + + List events = _eventDao.listToArchiveOrDeleteEvents(ids, cmd.getType(), cmd.getOlderThan(), permittedAccountIds); ControlledEntity[] sameOwnerEvents = events.toArray(new ControlledEntity[events.size()]); _accountMgr.checkAccess(UserContext.current().getCaller(), null, true, sameOwnerEvents); @@ -904,10 +914,20 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe @Override public boolean deleteEvents(DeleteEventsCmd cmd) { + Account caller = UserContext.current().getCaller(); List ids = cmd.getIds(); boolean result =true; + List permittedAccountIds = new ArrayList(); - List events = _eventDao.listToArchiveOrDeleteEvents(ids, cmd.getType(), cmd.getOlderThan(), cmd.getEntityOwnerId()); + if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL || caller.getType() == Account.ACCOUNT_TYPE_PROJECT) { + permittedAccountIds.add(caller.getId()); + } else { + DomainVO domain = _domainDao.findById(caller.getDomainId()); + List permittedDomainIds = _domainDao.getDomainChildrenIds(domain.getPath()); + permittedAccountIds = _accountDao.getAccountIdsForDomains(permittedDomainIds); + } + + List events = _eventDao.listToArchiveOrDeleteEvents(ids, cmd.getType(), cmd.getOlderThan(), permittedAccountIds); ControlledEntity[] sameOwnerEvents = events.toArray(new ControlledEntity[events.size()]); _accountMgr.checkAccess(UserContext.current().getCaller(), null, true, sameOwnerEvents); diff --git a/server/test/com/cloud/event/EventControlsUnitTest.java b/server/test/com/cloud/event/EventControlsUnitTest.java index 3c2527565c9..e2a86cdb4be 100644 --- a/server/test/com/cloud/event/EventControlsUnitTest.java +++ b/server/test/com/cloud/event/EventControlsUnitTest.java @@ -18,7 +18,6 @@ package com.cloud.event; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyList; -import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.when; @@ -58,7 +57,7 @@ public class EventControlsUnitTest extends TestCase{ _mgmtServer._eventDao = _eventDao; _mgmtServer._accountMgr = _accountMgr; doNothing().when(_accountMgr).checkAccess(any(Account.class), any(AccessType.class), any(Boolean.class), any(ControlledEntity.class)); - when(_eventDao.listToArchiveOrDeleteEvents(anyList(), anyString(), any(Date.class), anyLong())).thenReturn(_events); + when(_eventDao.listToArchiveOrDeleteEvents(anyList(), anyString(), any(Date.class), anyList())).thenReturn(_events); } @After From ffe90c00599917bfbe5e22e369fd248358074600 Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Wed, 15 May 2013 16:00:25 +0530 Subject: [PATCH 18/59] CLOUDSTACK-2085: VM weight on xen remain same as before vmscaleup ;because "Add-To-VCPUs-Params-Live.sh" is not getting copied on xs host Fixed by updating the patch files that has entries to copy scipts on xenserver. Here we added Add-To-VCPUs-Params-Live.sh Added a check on Host params whether host restricts Dynamic memory control(DMC) to able to allow scale up VM. If DMC is not enabled then static max and min are set to SO. Signed Off by - Nitin Mehta --- .../hypervisor/xen/resource/CitrixResourceBase.java | 8 +++++++- .../xen/resource/XenServer56FP1Resource.java | 13 +++++++++++-- .../xen/resource/CitrixResourceBaseTest.java | 8 ++++---- ...s-Params-Live.sh => add_to_vcpus_params_live.sh} | 0 scripts/vm/hypervisor/xenserver/vmops | 2 +- scripts/vm/hypervisor/xenserver/xcpserver/patch | 1 + scripts/vm/hypervisor/xenserver/xenserver56/patch | 1 + .../vm/hypervisor/xenserver/xenserver56fp1/patch | 1 + scripts/vm/hypervisor/xenserver/xenserver60/patch | 1 + 9 files changed, 27 insertions(+), 8 deletions(-) rename scripts/vm/hypervisor/xenserver/{Add-To-VCPUs-Params-Live.sh => add_to_vcpus_params_live.sh} (100%) 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 7bb25ef81bb..734f72fe01a 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 @@ -639,7 +639,8 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe if (vmSpec.getLimitCpuUse()) { long utilization = 0; // max CPU cap, default is unlimited utilization = ((long)speed * 100 * vmSpec.getCpus()) / _host.speed ; - vm.addToVCPUsParamsLive(conn, "cap", Long.toString(utilization)); + //vm.addToVCPUsParamsLive(conn, "cap", Long.toString(utilization)); currently xenserver doesnot support Xapi to add VCPUs params live. + callHostPlugin(conn, "vmops", "add_to_VCPUs_params_live", "key", "cap", "value", Long.toString(utilization), "vmname", vmSpec.getName() ); } //vm.addToVCPUsParamsLive(conn, "weight", Integer.toString(cpuWeight)); callHostPlugin(conn, "vmops", "add_to_VCPUs_params_live", "key", "weight", "value", Integer.toString(cpuWeight), "vmname", vmSpec.getName() ); @@ -672,6 +673,11 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe for (VM vm : vms) { VM.Record vmr = vm.getRecord(conn); try { + Map hostParams = new HashMap(); + hostParams = host.getLicenseParams(conn); + if (hostParams.get("restrict_dmc").equalsIgnoreCase("true")) { + throw new CloudRuntimeException("Host "+ _host.uuid + " does not support Dynamic Memory Control, so we cannot scale up the vm"); + } scaleVM(conn, vm, vmSpec, host); } catch (Exception e) { diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java index 96a90a61fff..24cb75cbf93 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java @@ -139,8 +139,17 @@ public class XenServer56FP1Resource extends XenServer56Resource { record.actionsAfterShutdown = Types.OnNormalExit.DESTROY; record.memoryDynamicMax = vmSpec.getMaxRam(); record.memoryDynamicMin = vmSpec.getMinRam(); - record.memoryStaticMax = 8589934592L; //128GB - record.memoryStaticMin = 134217728L; //128MB + Map hostParams = new HashMap(); + hostParams = host.getLicenseParams(conn); + if (hostParams.get("restrict_dmc").equalsIgnoreCase("false")) { + record.memoryStaticMax = 8589934592L; //8GB + record.memoryStaticMin = 134217728L; //128MB + } else { + s_logger.warn("Host "+ _host.uuid + " does not support Dynamic Memory Control, so we cannot scale up the vm"); + record.memoryStaticMax = vmSpec.getMaxRam(); + record.memoryStaticMin = vmSpec.getMinRam(); + } + if (guestOsTypeName.toLowerCase().contains("windows")) { record.VCPUsMax = (long) vmSpec.getCpus(); } else { diff --git a/plugins/hypervisors/xen/test/com/cloud/hypervisor/xen/resource/CitrixResourceBaseTest.java b/plugins/hypervisors/xen/test/com/cloud/hypervisor/xen/resource/CitrixResourceBaseTest.java index 7392cb1d53e..877e3bc5120 100644 --- a/plugins/hypervisors/xen/test/com/cloud/hypervisor/xen/resource/CitrixResourceBaseTest.java +++ b/plugins/hypervisors/xen/test/com/cloud/hypervisor/xen/resource/CitrixResourceBaseTest.java @@ -110,7 +110,7 @@ public class CitrixResourceBaseTest { @Test public void testScaleVMF2() throws Types.XenAPIException, XmlRpcException { - doReturn(null).when(vm).setMemoryDynamicRangeAsync(conn, 536870912L, 536870912L); + doNothing().when(vm).setMemoryDynamicRange(conn, 536870912L, 536870912L); doReturn(1).when(vmSpec).getCpus(); doNothing().when(vm).setVCPUsNumberLive(conn, 1L); doReturn(500).when(vmSpec).getSpeed(); @@ -129,12 +129,12 @@ public class CitrixResourceBaseTest { @Test public void testScaleVMF3() throws Types.XenAPIException, XmlRpcException { - doReturn(null).when(vm).setMemoryDynamicRangeAsync(conn, 536870912L, 536870912L); + doNothing().when(vm).setMemoryDynamicRange(conn, 536870912L, 536870912L); doReturn(1).when(vmSpec).getCpus(); doNothing().when(vm).setVCPUsNumberLive(conn, 1L); doReturn(500).when(vmSpec).getSpeed(); doReturn(true).when(vmSpec).getLimitCpuUse(); - doNothing().when(vm).addToVCPUsParamsLive(conn, "cap", "100"); + doReturn(null).when(_resource).callHostPlugin(conn, "vmops", "add_to_VCPUs_params_live", "key", "cap", "value", "100", "vmname", "i-2-3-VM"); Map args = (Map)mock(HashMap.class); when(host.callPlugin(conn, "vmops", "add_to_VCPUs_params_live", args)).thenReturn("Success"); doReturn(null).when(_resource).callHostPlugin(conn, "vmops", "add_to_VCPUs_params_live", "key", "weight", "value", "253", "vmname", "i-2-3-VM"); @@ -143,6 +143,6 @@ public class CitrixResourceBaseTest { verify(vmSpec, times(1)).getLimitCpuUse(); verify(_resource, times(1)).callHostPlugin(conn, "vmops", "add_to_VCPUs_params_live", "key", "weight", "value", "253", "vmname", "i-2-3-VM"); - verify(vm, times(1)).addToVCPUsParamsLive(conn, "cap", "100"); + verify(_resource, times(1)).callHostPlugin(conn, "vmops", "add_to_VCPUs_params_live", "key", "cap", "value", "100", "vmname", "i-2-3-VM"); } } \ No newline at end of file diff --git a/scripts/vm/hypervisor/xenserver/Add-To-VCPUs-Params-Live.sh b/scripts/vm/hypervisor/xenserver/add_to_vcpus_params_live.sh similarity index 100% rename from scripts/vm/hypervisor/xenserver/Add-To-VCPUs-Params-Live.sh rename to scripts/vm/hypervisor/xenserver/add_to_vcpus_params_live.sh diff --git a/scripts/vm/hypervisor/xenserver/vmops b/scripts/vm/hypervisor/xenserver/vmops index 60fb8ab0b21..d18eca836b8 100755 --- a/scripts/vm/hypervisor/xenserver/vmops +++ b/scripts/vm/hypervisor/xenserver/vmops @@ -48,7 +48,7 @@ def add_to_VCPUs_params_live(session, args): value = args['value'] vmname = args['vmname'] try: - cmd = ["bash", "/opt/xensource/bin/Add-To-VCPUs-Params-Live.sh", vmname, key, value] + cmd = ["bash", "/opt/xensource/bin/add_to_vcpus_params_live.sh", vmname, key, value] txt = util.pread2(cmd) except: return 'false' diff --git a/scripts/vm/hypervisor/xenserver/xcpserver/patch b/scripts/vm/hypervisor/xenserver/xcpserver/patch index bfecd0c8e04..a275df4a48b 100644 --- a/scripts/vm/hypervisor/xenserver/xcpserver/patch +++ b/scripts/vm/hypervisor/xenserver/xcpserver/patch @@ -64,3 +64,4 @@ cloud-prepare-upgrade.sh=..,0755,/opt/xensource/bin getRouterStatus.sh=../../../../network/domr/,0755,/opt/xensource/bin bumpUpPriority.sh=../../../../network/domr/,0755,/opt/xensource/bin getDomRVersion.sh=../../../../network/domr/,0755,/opt/xensource/bin +add_to_vcpus_params_live.sh=..,0755,/opt/xensource/bin diff --git a/scripts/vm/hypervisor/xenserver/xenserver56/patch b/scripts/vm/hypervisor/xenserver/xenserver56/patch index 1be14ea62db..5c4673df247 100644 --- a/scripts/vm/hypervisor/xenserver/xenserver56/patch +++ b/scripts/vm/hypervisor/xenserver/xenserver56/patch @@ -65,4 +65,5 @@ bumpUpPriority.sh=../../../../network/domr/,0755,/opt/xensource/bin swift=..,0755,/opt/xensource/bin swiftxen=..,0755,/etc/xapi.d/plugins s3xen=..,0755,/etc/xapi.d/plugins +add_to_vcpus_params_live.sh=..,0755,/opt/xensource/bin diff --git a/scripts/vm/hypervisor/xenserver/xenserver56fp1/patch b/scripts/vm/hypervisor/xenserver/xenserver56fp1/patch index dd31e441b4f..c7c58b98374 100644 --- a/scripts/vm/hypervisor/xenserver/xenserver56fp1/patch +++ b/scripts/vm/hypervisor/xenserver/xenserver56fp1/patch @@ -64,4 +64,5 @@ bumpUpPriority.sh=../../../../network/domr/,0755,/opt/xensource/bin swift=..,0755,/opt/xensource/bin swiftxen=..,0755,/etc/xapi.d/plugins s3xen=..,0755,/etc/xapi.d/plugins +add_to_vcpus_params_live.sh=..,0755,/opt/xensource/bin diff --git a/scripts/vm/hypervisor/xenserver/xenserver60/patch b/scripts/vm/hypervisor/xenserver/xenserver60/patch index 787f474739a..6d819791d3d 100644 --- a/scripts/vm/hypervisor/xenserver/xenserver60/patch +++ b/scripts/vm/hypervisor/xenserver/xenserver60/patch @@ -69,4 +69,5 @@ bumpUpPriority.sh=../../../../network/domr/,0755,/opt/xensource/bin swift=..,0755,/opt/xensource/bin swiftxen=..,0755,/etc/xapi.d/plugins s3xen=..,0755,/etc/xapi.d/plugins +add_to_vcpus_params_live.sh=..,0755,/opt/xensource/bin From 737063891592af1d896f150cca02ff3d63a0198c Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 15 May 2013 15:53:36 +0530 Subject: [PATCH 19/59] CLOUDSTACK:685 Fix user stat collection in PrepareStop part of VirtualNetworkApplianceImpl --- .../VirtualNetworkApplianceManagerImpl.java | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index f6057e8dcc3..522b90ec4fb 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -3888,26 +3888,29 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V String privateIP = router.getPrivateIpAddress(); if (privateIP != null) { + boolean forVpc = router.getVpcId() != null; List routerNics = _nicDao.listByVmId(router.getId()); for (Nic routerNic : routerNics) { Network network = _networkModel.getNetwork(routerNic.getNetworkId()); - if (network.getTrafficType() == TrafficType.Public) { - boolean forVpc = router.getVpcId() != null; + //Send network usage command for public nic in VPC VR + //Send network usage command for isolated guest nic of non VPC VR + if ((forVpc && network.getTrafficType() == TrafficType.Public) || (!forVpc && network.getTrafficType() == TrafficType.Guest && network.getGuestType() == Network.GuestType.Isolated)) { final NetworkUsageCommand usageCmd = new NetworkUsageCommand(privateIP, router.getHostName(), forVpc, routerNic.getIp4Address()); + String routerType = router.getType().toString(); UserStatisticsVO previousStats = _userStatsDao.findBy(router.getAccountId(), - router.getDataCenterId(), network.getId(), null, router.getId(), router.getType().toString()); + router.getDataCenterId(), network.getId(), (forVpc ? routerNic.getIp4Address() : null), router.getId(), routerType); NetworkUsageAnswer answer = null; try { answer = (NetworkUsageAnswer) _agentMgr.easySend(router.getHostId(), usageCmd); } catch (Exception e) { - s_logger.warn("Error while collecting network stats from router: "+router.getInstanceName()+" from host: "+router.getHostId(), e); + s_logger.warn("Error while collecting network stats from router: " + router.getInstanceName() + " from host: " + router.getHostId(), e); continue; } if (answer != null) { if (!answer.getResult()) { - s_logger.warn("Error while collecting network stats from router: "+router.getInstanceName()+" from host: "+router.getHostId() + "; details: " + answer.getDetails()); + s_logger.warn("Error while collecting network stats from router: " + router.getInstanceName() + " from host: " + router.getHostId() + "; details: " + answer.getDetails()); continue; } Transaction txn = Transaction.open(Transaction.CLOUD_DB); @@ -3918,26 +3921,26 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V } txn.start(); UserStatisticsVO stats = _userStatsDao.lock(router.getAccountId(), - router.getDataCenterId(), network.getId(), null, router.getId(), router.getType().toString()); + router.getDataCenterId(), network.getId(), (forVpc ? routerNic.getIp4Address() : null), router.getId(), routerType); if (stats == null) { s_logger.warn("unable to find stats for account: " + router.getAccountId()); continue; } - if(previousStats != null - && ((previousStats.getCurrentBytesReceived() != stats.getCurrentBytesReceived()) - || (previousStats.getCurrentBytesSent() != stats.getCurrentBytesSent()))){ + if (previousStats != null + && ((previousStats.getCurrentBytesReceived() != stats.getCurrentBytesReceived()) + || (previousStats.getCurrentBytesSent() != stats.getCurrentBytesSent()))){ s_logger.debug("Router stats changed from the time NetworkUsageCommand was sent. " + - "Ignoring current answer. Router: "+answer.getRouterName()+" Rcvd: " + - answer.getBytesReceived()+ "Sent: " +answer.getBytesSent()); + "Ignoring current answer. Router: " + answer.getRouterName() + " Rcvd: " + + answer.getBytesReceived() + "Sent: " + answer.getBytesSent()); continue; } if (stats.getCurrentBytesReceived() > answer.getBytesReceived()) { if (s_logger.isDebugEnabled()) { s_logger.debug("Received # of bytes that's less than the last one. " + - "Assuming something went wrong and persisting it. Router: " + - answer.getRouterName()+" Reported: " + answer.getBytesReceived() + "Assuming something went wrong and persisting it. Router: " + + answer.getRouterName() + " Reported: " + answer.getBytesReceived() + " Stored: " + stats.getCurrentBytesReceived()); } stats.setNetBytesReceived(stats.getNetBytesReceived() + stats.getCurrentBytesReceived()); @@ -3946,8 +3949,8 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V if (stats.getCurrentBytesSent() > answer.getBytesSent()) { if (s_logger.isDebugEnabled()) { s_logger.debug("Received # of bytes that's less than the last one. " + - "Assuming something went wrong and persisting it. Router: " + - answer.getRouterName()+" Reported: " + answer.getBytesSent() + "Assuming something went wrong and persisting it. Router: " + + answer.getRouterName() + " Reported: " + answer.getBytesSent() + " Stored: " + stats.getCurrentBytesSent()); } stats.setNetBytesSent(stats.getNetBytesSent() + stats.getCurrentBytesSent()); From 9b6513466f5826d4932bf69dcf3a531f05ac625c Mon Sep 17 00:00:00 2001 From: Jayapal Date: Wed, 15 May 2013 15:40:23 +0530 Subject: [PATCH 20/59] CLOUDSTACK-2369 fixed adding same private gw twice --- .../src/com/cloud/network/vpc/dao/PrivateIpDao.java | 3 ++- .../com/cloud/network/vpc/dao/PrivateIpDaoImpl.java | 11 ++++++++++- server/src/com/cloud/network/NetworkServiceImpl.java | 4 +++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/engine/schema/src/com/cloud/network/vpc/dao/PrivateIpDao.java b/engine/schema/src/com/cloud/network/vpc/dao/PrivateIpDao.java index 02df92e9c67..ff8c26a9571 100644 --- a/engine/schema/src/com/cloud/network/vpc/dao/PrivateIpDao.java +++ b/engine/schema/src/com/cloud/network/vpc/dao/PrivateIpDao.java @@ -70,6 +70,7 @@ public interface PrivateIpDao extends GenericDao{ */ PrivateIpVO findByIpAndVpcId(long vpcId, String ip4Address); - + + PrivateIpVO findByIpAndSourceNetworkIdAndVpcId(long networkId, String ip4Address, long vpcId); } diff --git a/engine/schema/src/com/cloud/network/vpc/dao/PrivateIpDaoImpl.java b/engine/schema/src/com/cloud/network/vpc/dao/PrivateIpDaoImpl.java index ecab3bb6625..fe435c05175 100644 --- a/engine/schema/src/com/cloud/network/vpc/dao/PrivateIpDaoImpl.java +++ b/engine/schema/src/com/cloud/network/vpc/dao/PrivateIpDaoImpl.java @@ -114,7 +114,16 @@ public class PrivateIpDaoImpl extends GenericDaoBase implemen sc.setParameters("networkId", networkId); return findOneBy(sc); } - + + @Override + public PrivateIpVO findByIpAndSourceNetworkIdAndVpcId(long networkId, String ip4Address, long vpcId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("ip", ip4Address); + sc.setParameters("networkId", networkId); + sc.setParameters("vpcId", vpcId); + return findOneBy(sc); + } + @Override public PrivateIpVO findByIpAndVpcId(long vpcId, String ip4Address) { SearchCriteria sc = AllFieldsSearch.create(); diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index f3ec253d631..d3ef320a981 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -3813,10 +3813,12 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { s_logger.debug("Created private network " + privateNetwork); } else { s_logger.debug("Private network already exists: " + privateNetwork); + throw new InvalidParameterValueException("Private network for the vlan: " + vlan + " and cidr "+ cidr +" already exists " + + " in zone " + _configMgr.getZone(pNtwk.getDataCenterId()).getName()); } //add entry to private_ip_address table - PrivateIpVO privateIp = _privateIpDao.findByIpAndSourceNetworkId(privateNetwork.getId(), startIp); + PrivateIpVO privateIp = _privateIpDao.findByIpAndSourceNetworkIdAndVpcId(privateNetwork.getId(), startIp, vpcId); if (privateIp != null) { throw new InvalidParameterValueException("Private ip address " + startIp + " already used for private gateway" + " in zone " + _configMgr.getZone(pNtwk.getDataCenterId()).getName()); From 68a428f84dea9c051456882d6762f419c40d90db Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Wed, 15 May 2013 13:57:58 +0200 Subject: [PATCH 21/59] CLOUDSTACK-2515: Verify if the targetPath isn't null before comparing --- .../cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java index 8f58719e7be..e7e4bbf2c30 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java @@ -465,7 +465,8 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { StoragePool p = conn.storagePoolLookupByName(poolname); LibvirtStoragePoolDef pdef = getStoragePoolDef(conn, p); - if (pdef.getTargetPath().equals(path)) { + String targetPath = pdef.getTargetPath(); + if (targetPath != null && targetPath.equals(path)) { s_logger.debug("Storage pool utilizing path '" + path + "' already exists as pool " + poolname + ", undefining so we can re-define with correct name " + name); if (p.isPersistent() == 1) { From 6d6887533ff6270335b2b64bd5b9fc453c41182f Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Wed, 15 May 2013 18:01:10 +0530 Subject: [PATCH 22/59] CLOUDSTACK-2491:NTier: Creation of ACL Rule for protocol AH (51) and ESP (50) Fails --- ui/scripts/vpc.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/ui/scripts/vpc.js b/ui/scripts/vpc.js index 5d436f3536a..0c4a446485b 100644 --- a/ui/scripts/vpc.js +++ b/ui/scripts/vpc.js @@ -94,8 +94,8 @@ }, 'protocolnumber': {label:'Protocol Number',isDisabled:true,isHidden:true,edit:true}, - 'startport': { edit: true, label: 'label.start.port' }, - 'endport': { edit: true, label: 'label.end.port' }, + 'startport': { edit: true, label: 'label.start.port' , isOptional:true }, + 'endport': { edit: true, label: 'label.end.port' , isOptional:true}, 'networkid': { label: 'Select Tier', select: function(args) { @@ -165,7 +165,18 @@ else delete args.data.protocolnumber; + + if((args.data.protocol == 'tcp' || args.data.protocol == 'udp' || args.data.protocol == 'all') && (args.data.startport=="" || args.data.startport == undefined)){ + cloudStack.dialog.notice({message:_l('Start Port or End Port value should not be blank')}); + $(window).trigger('cloudStack.fullRefresh'); + } + else if((args.data.protocol == 'tcp' || args.data.protocol == 'udp' || args.data.protocol == 'all') && (args.data.endport=="" || args.data.endport == undefined)){ + cloudStack.dialog.notice({message:_l('Start Port or End Port value should not be blank')}); + $(window).trigger('cloudStack.fullRefresh'); + } + + else{ $.ajax({ url: createURL('createNetworkACL'), data: $.extend(args.data, { @@ -202,6 +213,7 @@ } }); } + } }, actions: { destroy: { From f893aa8a786a071ebf108bad0368d148755ce233 Mon Sep 17 00:00:00 2001 From: Likitha Shetty Date: Tue, 14 May 2013 14:24:47 +0530 Subject: [PATCH 23/59] CLOUDSTACK-2116 Public IP addresses resource count of an account - number of ip addresses dedicated to an account plus the number of ip addresses belonging to the system that have been allocated to the account --- .../schema/src/com/cloud/dc/dao/VlanDao.java | 2 ++ .../src/com/cloud/dc/dao/VlanDaoImpl.java | 15 ++++++++++++ .../ConfigurationManagerImpl.java | 10 +++++++- .../com/cloud/network/NetworkManagerImpl.java | 16 ++++++------- .../ResourceLimitManagerImpl.java | 23 ++++++++++++++++++- 5 files changed, 56 insertions(+), 10 deletions(-) diff --git a/engine/schema/src/com/cloud/dc/dao/VlanDao.java b/engine/schema/src/com/cloud/dc/dao/VlanDao.java index 605fb2020df..39fa818e26f 100755 --- a/engine/schema/src/com/cloud/dc/dao/VlanDao.java +++ b/engine/schema/src/com/cloud/dc/dao/VlanDao.java @@ -54,4 +54,6 @@ public interface VlanDao extends GenericDao { List listZoneWideNonDedicatedVlans(long zoneId); List listVlansByNetworkIdAndGateway(long networkid, String gateway); + + List listDedicatedVlans(long accountId); } diff --git a/engine/schema/src/com/cloud/dc/dao/VlanDaoImpl.java b/engine/schema/src/com/cloud/dc/dao/VlanDaoImpl.java index e8c68b18a6b..eb3bde9d005 100755 --- a/engine/schema/src/com/cloud/dc/dao/VlanDaoImpl.java +++ b/engine/schema/src/com/cloud/dc/dao/VlanDaoImpl.java @@ -58,6 +58,7 @@ public class VlanDaoImpl extends GenericDaoBase implements VlanDao protected SearchBuilder PhysicalNetworkVlanSearch; protected SearchBuilder ZoneWideNonDedicatedVlanSearch; protected SearchBuilder VlanGatewaysearch; + protected SearchBuilder DedicatedVlanSearch; protected SearchBuilder AccountVlanMapSearch; @@ -213,6 +214,13 @@ public class VlanDaoImpl extends GenericDaoBase implements VlanDao ZoneWideNonDedicatedVlanSearch.done(); AccountVlanMapSearch.done(); + DedicatedVlanSearch = createSearchBuilder(); + AccountVlanMapSearch = _accountVlanMapDao.createSearchBuilder(); + AccountVlanMapSearch.and("accountId", AccountVlanMapSearch.entity().getAccountId(), SearchCriteria.Op.EQ); + DedicatedVlanSearch.join("AccountVlanMapSearch", AccountVlanMapSearch, DedicatedVlanSearch.entity().getId(), AccountVlanMapSearch.entity().getVlanDbId(), JoinBuilder.JoinType.LEFTOUTER); + DedicatedVlanSearch.done(); + AccountVlanMapSearch.done(); + return result; } @@ -343,4 +351,11 @@ public class VlanDaoImpl extends GenericDaoBase implements VlanDao return listBy(sc); } + @Override + public List listDedicatedVlans(long accountId) { + SearchCriteria sc = DedicatedVlanSearch.create(); + sc.setJoinParameters("AccountVlanMapSearch", "accountId", accountId); + return listBy(sc); + } + } diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 55e7b7ed4d9..e1aaa5050f9 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -2853,6 +2853,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati ip.getDataCenterId(), ip.getId(), ip.getAddress().toString(), ip.isSourceNat(), vlan.getVlanType().toString(), ip.getSystem(), ip.getClass().getName(), ip.getUuid()); } + // increment resource count for dedicated public ip's + _resourceLimitMgr.incrementResourceCount(vlanOwner.getId(), ResourceType.public_ip, new Long(ips.size())); } else if (podId != null) { // This VLAN is pod-wide, so create a PodVlanMapVO entry PodVlanMapVO podVlanMapVO = new PodVlanMapVO(podId, vlan.getId()); @@ -3124,6 +3126,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati ip.getDataCenterId(), ip.getId(), ip.getAddress().toString(), ip.isSourceNat(), vlan.getVlanType().toString(), ip.getSystem(), ip.getClass().getName(), ip.getUuid()); } + + // increment resource count for dedicated public ip's + _resourceLimitMgr.incrementResourceCount(vlanOwner.getId(), ResourceType.public_ip, new Long(ips.size())); + return vlan; } @@ -3187,10 +3193,12 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati 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(), + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_RELEASE, acctVln.get(0).getAccountId(), ip.getDataCenterId(), ip.getId(), ip.getAddress().toString(), ip.isSourceNat(), vlan.getVlanType().toString(), ip.getSystem(), ip.getClass().getName(), ip.getUuid()); } + // decrement resource count for dedicated public ip's + _resourceLimitMgr.decrementResourceCount(acctVln.get(0).getAccountId(), ResourceType.public_ip, new Long(ips.size())); return true; } else { return false; diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 4ce54401618..9440286cb8e 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -394,8 +394,8 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L 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) { + // don't increment resource count for direct and dedicated ip addresses + if (addr.getAssociatedWithNetworkId() != null && !isIpDedicated(addr)) { _resourceLimitMgr.incrementResourceCount(owner.getId(), ResourceType.public_ip); } } @@ -640,10 +640,6 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L s_logger.debug("Associate IP address lock acquired"); } - // Check that the maximum number of public IPs for the given - // accountId will not be exceeded - _resourceLimitMgr.checkResourceLimit(accountToLock, ResourceType.public_ip); - txn.start(); // If account has dedicated Public IP ranges, allocate IP from the dedicated range @@ -668,6 +664,10 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L } if (!allocateFromDedicatedRange) { + // Check that the maximum number of public IPs for the given + // accountId will not be exceeded + _resourceLimitMgr.checkResourceLimit(accountToLock, ResourceType.public_ip); + List nonDedicatedVlans = _vlanDao.listZoneWideNonDedicatedVlans(zone.getId()); for (VlanVO nonDedicatedVlan : nonDedicatedVlans) { nonDedicatedVlanDbIds.add(nonDedicatedVlan.getId()); @@ -2964,8 +2964,8 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L if (ip.getState() != State.Releasing) { txn.start(); - // don't decrement resource count for direct ips - if (ip.getAssociatedWithNetworkId() != null) { + // don't decrement resource count for direct and dedicated ips + if (ip.getAssociatedWithNetworkId() != null && !isIpDedicated(ip)) { _resourceLimitMgr.decrementResourceCount(_ipAddressDao.findById(addrId).getAllocatedToAccountId(), ResourceType.public_ip); } diff --git a/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java b/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java index 5bb770871ca..6d929c6438b 100755 --- a/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java +++ b/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java @@ -46,6 +46,8 @@ import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.configuration.dao.ResourceCountDao; import com.cloud.configuration.dao.ResourceLimitDao; import com.cloud.dao.EntityManager; +import com.cloud.dc.VlanVO; +import com.cloud.dc.dao.VlanDao; import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; @@ -53,6 +55,7 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.NetworkDao; import com.cloud.network.vpc.dao.VpcDao; import com.cloud.projects.Project; @@ -141,6 +144,8 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim private ServiceOfferingDao _serviceOfferingDao; @Inject private VMTemplateHostDao _vmTemplateHostDao; + @Inject + private VlanDao _vlanDao; protected GenericSearchBuilder templateSizeSearch; @@ -814,7 +819,7 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim } else if (type == Resource.ResourceType.snapshot) { newCount = _snapshotDao.countSnapshotsForAccount(accountId); } else if (type == Resource.ResourceType.public_ip) { - newCount = _ipAddressDao.countAllocatedIPsForAccount(accountId); + newCount = calculatePublicIpForAccount(accountId); } else if (type == Resource.ResourceType.template) { newCount = _vmTemplateDao.countTemplatesForAccount(accountId); } else if (type == Resource.ResourceType.project) { @@ -906,6 +911,22 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim return totalVolumesSize + totalSnapshotsSize + totalTemplatesSize; } + private long calculatePublicIpForAccount(long accountId) { + Long dedicatedCount = 0L; + Long allocatedCount = 0L; + + List dedicatedVlans = _vlanDao.listDedicatedVlans(accountId); + for (VlanVO dedicatedVlan : dedicatedVlans) { + List ips = _ipAddressDao.listByVlanId(dedicatedVlan.getId()); + dedicatedCount += new Long(ips.size()); + } + allocatedCount = _ipAddressDao.countAllocatedIPsForAccount(accountId); + if (dedicatedCount > allocatedCount) + return dedicatedCount; + else + return allocatedCount; + } + @Override public long getResourceCount(Account account, ResourceType type) { return _resourceCountDao.getResourceCount(account.getId(), ResourceOwnerType.Account, type); From 36a312d4b24908cad107c2ae351c2c686890b995 Mon Sep 17 00:00:00 2001 From: Jayapal Date: Thu, 25 Apr 2013 12:56:38 +0530 Subject: [PATCH 24/59] CLOUDSTACK-2134 updated acl checks for aquiring nic secondary ip --- .../com/cloud/network/NetworkServiceImpl.java | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index d3ef320a981..5f51a30d389 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -610,18 +610,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { throw new InvalidParameterValueException("Invalid network id is given"); } - Network network = _networksDao.findById(networkId); - if (network == null) { - throw new InvalidParameterValueException("Invalid network id is given"); - } - accountId = network.getAccountId(); - domainId = network.getDomainId(); - - // Validate network offering - NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(network.getNetworkOfferingId()); - - // verify permissions - _accountMgr.checkAccess(ipOwner, null, true, network); + Account caller = UserContext.current().getCaller(); //check whether the nic belongs to user vm. NicVO nicVO = _nicDao.findById(nicId); @@ -633,6 +622,25 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { throw new InvalidParameterValueException("The nic is not belongs to user vm"); } + Nic nic = _nicDao.findById(nicId); + VirtualMachine vm = _userVmDao.findById(nicVO.getInstanceId()); + if (vm == null) { + throw new InvalidParameterValueException("There is no vm with the nic"); + } + // verify permissions + _accountMgr.checkAccess(ipOwner, null, true, vm); + + + Network network = _networksDao.findById(networkId); + if (network == null) { + throw new InvalidParameterValueException("Invalid network id is given"); + } + accountId = network.getAccountId(); + domainId = network.getDomainId(); + + // Validate network offering + NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(network.getNetworkOfferingId()); + DataCenter dc = _dcDao.findById(network.getDataCenterId()); Long id = nicVO.getInstanceId(); @@ -649,14 +657,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { throw new InvalidParameterValueException("Allocating guest ip for nic failed"); } } else if (dc.getNetworkType() == NetworkType.Basic || ntwkOff.getGuestType() == Network.GuestType.Shared) { - Account caller = UserContext.current().getCaller(); - long callerUserId = UserContext.current().getCallerUserId(); - _accountMgr.checkAccess(caller, SecurityChecker.AccessType.UseNetwork, false, network); //handle the basic networks here - VirtualMachine vm = _userVmDao.findById(nicVO.getInstanceId()); - if (vm == null) { - throw new InvalidParameterValueException("There is no vm with the nic"); - } VMInstanceVO vmi = (VMInstanceVO)vm; Long podId = vmi.getPodIdToDeployIn(); if (podId == null) { @@ -718,6 +719,13 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { throw new InvalidParameterValueException("Unable to find ip address by id"); } + VirtualMachine vm = _userVmDao.findById(secIpVO.getVmId()); + if (vm == null) { + throw new InvalidParameterValueException("There is no vm with the nic"); + } + // verify permissions + _accountMgr.checkAccess(caller, null, true, vm); + Network network = _networksDao.findById(secIpVO.getNetworkId()); if (network == null) { @@ -727,9 +735,6 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { // Validate network offering NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(network.getNetworkOfferingId()); - // verify permissions - _accountMgr.checkAccess(caller, null, true, network); - Long nicId = secIpVO.getNicId(); s_logger.debug("ip id = " + ipAddressId + " nic id = " + nicId); //check is this the last secondary ip for NIC From 987c3427dd26f36a060571d022efb7043d0ee473 Mon Sep 17 00:00:00 2001 From: Joe Mills Date: Wed, 15 May 2013 17:47:58 +0900 Subject: [PATCH 25/59] Midonet Plugin bugfixes * Updated SQL upgrade scripts to include midonet configs. * Fixed bug where default ICMP allow rule was missing on static NAT creation, keeping VMs from being able to ping the gateway. * Changed the filter in the MidoNetElement callbacks to allow calls when Midonet is configured. Signed-off-by: Hugo Trippaers --- .../cloud/network/element/MidoNetElement.java | 113 +++++++++++------- .../network/guru/MidoNetGuestNetworkGuru.java | 13 +- .../guru/MidoNetPublicNetworkGuru.java | 9 +- .../network/element/MidoNetElementTest.java | 31 +++-- setup/db/db/schema-410to420.sql | 2 + 5 files changed, 107 insertions(+), 61 deletions(-) diff --git a/plugins/network-elements/midonet/src/com/cloud/network/element/MidoNetElement.java b/plugins/network-elements/midonet/src/com/cloud/network/element/MidoNetElement.java index d07fa5624c5..ab6a6def405 100644 --- a/plugins/network-elements/midonet/src/com/cloud/network/element/MidoNetElement.java +++ b/plugins/network-elements/midonet/src/com/cloud/network/element/MidoNetElement.java @@ -36,7 +36,6 @@ import com.cloud.network.NetworkModel; import com.cloud.network.Networks; import com.cloud.network.PhysicalNetworkServiceProvider; import com.cloud.network.PublicIpAddress; -import com.cloud.network.dao.NetworkServiceMapDao; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.StaticNat; @@ -47,6 +46,8 @@ import com.cloud.utils.Pair; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.PluggableService; import com.cloud.utils.net.NetUtils; +import com.cloud.user.AccountVO; +import com.cloud.user.dao.AccountDao; import com.cloud.vm.NicProfile; import com.cloud.vm.NicVO; import com.cloud.vm.ReservationContext; @@ -131,14 +132,14 @@ public class MidoNetElement extends AdapterBase implements @Inject AccountManager _accountMgr; @Inject - NetworkServiceMapDao _ntwkSrvcDao; + AccountDao _accountDao; public void setMidonetApi(MidonetApi api) { this.api = api; } - public void setNtwkSrvcDao(NetworkServiceMapDao ntwkSrvcDao){ - this._ntwkSrvcDao = ntwkSrvcDao; + public void setAccountDao(AccountDao aDao) { + this._accountDao = aDao; } @Override @@ -172,10 +173,13 @@ public class MidoNetElement extends AdapterBase implements } public boolean midoInNetwork(Network network) { - for (String pname : _ntwkSrvcDao.getDistinctProviders(network.getId())) { - if (pname.equals(getProvider().getName())) { - return true; - } + if((network.getTrafficType() == Networks.TrafficType.Public) && + (network.getBroadcastDomainType() == Networks.BroadcastDomainType.Mido)){ + return true; + } + if((network.getTrafficType() == Networks.TrafficType.Guest) && + (network.getBroadcastDomainType() == Networks.BroadcastDomainType.Mido)){ + return true; } return false; } @@ -280,6 +284,11 @@ public class MidoNetElement extends AdapterBase implements post.addRule().type(DtoRule.RevDNAT).flowAction(DtoRule.Accept).create(); } + public String getAccountUuid(Network network) { + AccountVO acc = _accountDao.findById(network.getAccountId()); + return acc.getUuid(); + } + public boolean associatePublicIP(Network network, final List ipAddress) throws ResourceUnavailableException { @@ -316,7 +325,7 @@ public class MidoNetElement extends AdapterBase implements tenantUplink = ports[0]; providerDownlink = ports[1]; - accountIdStr = String.valueOf(network.getAccountId()); + accountIdStr = getAccountUuid(network); boolean isVpc = getIsVpc(network); long id = getRouterId(network, isVpc); routerName = getRouterName(isVpc, id); @@ -611,7 +620,7 @@ public class MidoNetElement extends AdapterBase implements RuleChain preNat = null; RuleChain post = null; - String accountIdStr = String.valueOf(network.getAccountId()); + String accountIdStr = getAccountUuid(network); String networkUUIDStr = String.valueOf(network.getId()); for (StaticNat rule : rules) { @@ -659,7 +668,7 @@ public class MidoNetElement extends AdapterBase implements return false; } if (canHandle(config, Service.Firewall)) { - String accountIdStr = String.valueOf(config.getAccountId()); + String accountIdStr = getAccountUuid(config); String networkUUIDStr = String.valueOf(config.getId()); RuleChain preFilter = getChain(accountIdStr, networkUUIDStr, RuleChainCode.TR_PREFILTER); RuleChain preNat = getChain(accountIdStr, networkUUIDStr, RuleChainCode.TR_PRENAT); @@ -947,7 +956,7 @@ public class MidoNetElement extends AdapterBase implements return false; } - String accountIdStr = String.valueOf(network.getAccountId()); + String accountIdStr = getAccountUuid(network); String networkUUIDStr = String.valueOf(network.getId()); RuleChain preNat = getChain(accountIdStr, networkUUIDStr, RuleChainCode.TR_PRENAT); RuleChain postNat = getChain(accountIdStr, networkUUIDStr, RuleChainCode.TR_POST); @@ -1170,16 +1179,16 @@ public class MidoNetElement extends AdapterBase implements return routerName + "-tenantrouter-" + chain; } - protected RuleChain getChain(String accountID, String routerName, RuleChainCode chainCode){ - return getChain("", accountID, routerName, chainCode); + protected RuleChain getChain(String accountUuid, String routerName, RuleChainCode chainCode){ + return getChain("", accountUuid, routerName, chainCode); } - protected RuleChain getChain(String networkId, String accountID, + protected RuleChain getChain(String networkId, String accountUuid, String routerName, RuleChainCode chainCode){ String chainName = getChainName(networkId, routerName, chainCode); MultivaluedMap findChain = new MultivaluedMapImpl(); - findChain.add("tenant_id", accountID); + findChain.add("tenant_id", accountUuid); ResourceCollection ruleChains = api.getChains(findChain); @@ -1303,7 +1312,7 @@ public class MidoNetElement extends AdapterBase implements String routerName = getRouterName(isVpc, id); RuleChain egressChain = getChain(String.valueOf(network.getId()), - String.valueOf(network.getAccountId()), + getAccountUuid(network), routerName, RuleChainCode.ACL_EGRESS); @@ -1325,7 +1334,7 @@ public class MidoNetElement extends AdapterBase implements String routerName = getRouterName(isVpc, id); RuleChain egressChain = getChain(String.valueOf(network.getId()), - String.valueOf(network.getAccountId()), + getAccountUuid(network), routerName, RuleChainCode.ACL_EGRESS); @@ -1355,6 +1364,14 @@ public class MidoNetElement extends AdapterBase implements .position(pos++) .create(); + // If it is ICMP to the router, accept that + egressChain.addRule().type(DtoRule.Accept) + .nwProto(SimpleFirewallRule.stringToProtocolNumber("icmp")) + .nwDstAddress(network.getGateway()) + .nwDstLength(32) + .position(pos++) + .create(); + // Everything else gets dropped egressChain.addRule() .type(DtoRule.Drop) @@ -1369,7 +1386,7 @@ public class MidoNetElement extends AdapterBase implements boolean isVpc = getIsVpc(network); long id = getRouterId(network, isVpc); String routerName = getRouterName(isVpc, id); - String accountIdStr = String.valueOf(network.getAccountId()); + String accountIdStr = getAccountUuid(network); // Add interior port on bridge side BridgePort bridgePort = netBridge.addInteriorPort().create(); @@ -1406,6 +1423,14 @@ public class MidoNetElement extends AdapterBase implements .position(pos++) .create(); + // If it is ICMP to the router, accept that + inc.addRule().type(DtoRule.Accept) + .nwProto(SimpleFirewallRule.stringToProtocolNumber("icmp")) + .nwDstAddress(network.getGateway()) + .nwDstLength(32) + .position(pos++) + .create(); + // If it is connection tracked, accept that as well inc.addRule().type(DtoRule.Accept) .matchReturnFlow(true) @@ -1449,27 +1474,25 @@ public class MidoNetElement extends AdapterBase implements private Bridge getOrCreateNetworkBridge(Network network){ // Find the single bridge for this network, create if doesn't exist - return getOrCreateNetworkBridge(network.getId(), network.getAccountId()); + return getOrCreateNetworkBridge(network.getId(), getAccountUuid(network)); } - private Bridge getOrCreateNetworkBridge(long networkID, long accountID){ - Bridge netBridge = getNetworkBridge(networkID, accountID); + private Bridge getOrCreateNetworkBridge(long networkID, String accountUuid){ + Bridge netBridge = getNetworkBridge(networkID, accountUuid); if(netBridge == null){ - String accountIdStr = String.valueOf(accountID); String networkUUIDStr = String.valueOf(networkID); - netBridge = api.addBridge().tenantId(accountIdStr).name(networkUUIDStr).create(); + netBridge = api.addBridge().tenantId(accountUuid).name(networkUUIDStr).create(); } return netBridge; } - private Bridge getNetworkBridge(long networkID, long accountID){ + private Bridge getNetworkBridge(long networkID, String accountUuid){ MultivaluedMap qNetBridge = new MultivaluedMapImpl(); - String accountIdStr = String.valueOf(accountID); String networkUUIDStr = String.valueOf(networkID); - qNetBridge.add("tenant_id", accountIdStr); + qNetBridge.add("tenant_id", accountUuid); for (Bridge b : this. api.getBridges(qNetBridge)) { if(b.getName().equals(networkUUIDStr)){ @@ -1497,7 +1520,7 @@ public class MidoNetElement extends AdapterBase implements boolean isVpc = getIsVpc(network); long id = getRouterId(network, isVpc); - return getOrCreateGuestNetworkRouter(id, network.getAccountId(), isVpc); + return getOrCreateGuestNetworkRouter(id, getAccountUuid(network), isVpc); } @@ -1509,29 +1532,28 @@ public class MidoNetElement extends AdapterBase implements } } - protected Router createRouter(long id, long accountID, boolean isVpc) { + protected Router createRouter(long id, String accountUuid, boolean isVpc) { - String accountIdStr = String.valueOf(accountID); String routerName = getRouterName(isVpc, id); //Set up rule chains RuleChain pre = api.addChain() .name(getChainName(routerName, RuleChainCode.TR_PRE)) - .tenantId(accountIdStr) + .tenantId(accountUuid) .create(); RuleChain post = api.addChain() .name(getChainName(routerName, RuleChainCode.TR_POST)) - .tenantId(accountIdStr) + .tenantId(accountUuid) .create(); // Set up NAT and filter chains for pre-routing RuleChain preFilter = api.addChain() .name(getChainName(routerName, RuleChainCode.TR_PREFILTER)) - .tenantId(accountIdStr) + .tenantId(accountUuid) .create(); RuleChain preNat = api.addChain() .name(getChainName(routerName, RuleChainCode.TR_PRENAT)) - .tenantId(accountIdStr) + .tenantId(accountUuid) .create(); // Hook the chains in - first jump to Filter chain, then jump to Nat chain @@ -1545,28 +1567,27 @@ public class MidoNetElement extends AdapterBase implements .create(); return api.addRouter() - .tenantId(accountIdStr) + .tenantId(accountUuid) .name(routerName) .inboundFilterId(pre.getId()) .outboundFilterId(post.getId()) .create(); } - private Router getOrCreateGuestNetworkRouter(long id, long accountID, boolean isVpc) { - Router tenantRouter = getGuestNetworkRouter(id, accountID, isVpc); + private Router getOrCreateGuestNetworkRouter(long id, String accountUuid, boolean isVpc) { + Router tenantRouter = getGuestNetworkRouter(id, accountUuid, isVpc); if(tenantRouter == null){ - tenantRouter = createRouter(id, accountID, isVpc); + tenantRouter = createRouter(id, accountUuid, isVpc); } return tenantRouter; } - private Router getGuestNetworkRouter(long id, long accountID, boolean isVpc){ + private Router getGuestNetworkRouter(long id, String accountUuid, boolean isVpc){ MultivaluedMap qNetRouter = new MultivaluedMapImpl(); - String accountIdStr = String.valueOf(accountID); String routerName = getRouterName(isVpc, id); - qNetRouter.add("tenant_id", accountIdStr); + qNetRouter.add("tenant_id", accountUuid); for (Router router : api.getRouters(qNetRouter)) { if(router.getName().equals(routerName)){ @@ -1613,10 +1634,10 @@ public class MidoNetElement extends AdapterBase implements } private void deleteNetworkBridges(Network network){ - long accountID = network.getAccountId(); + String accountUuid = getAccountUuid(network); long networkID = network.getId(); - Bridge netBridge = getNetworkBridge(networkID, accountID); + Bridge netBridge = getNetworkBridge(networkID, accountUuid); if(netBridge != null){ cleanBridge(netBridge); @@ -1632,11 +1653,11 @@ public class MidoNetElement extends AdapterBase implements } private void deleteGuestNetworkRouters(Network network){ - long accountID = network.getAccountId(); + String accountUuid = getAccountUuid(network); boolean isVpc = getIsVpc(network); long id = getRouterId(network, isVpc); - Router tenantRouter = getGuestNetworkRouter(id, accountID, isVpc); + Router tenantRouter = getGuestNetworkRouter(id, accountUuid, isVpc); // Delete any peer ports corresponding to this router for(Port peerPort : tenantRouter.getPeerPorts((new MultivaluedMapImpl()))){ @@ -1677,7 +1698,7 @@ public class MidoNetElement extends AdapterBase implements } // Remove inbound and outbound filter chains - String accountIdStr = String.valueOf(accountID); + String accountIdStr = String.valueOf(accountUuid); String routerName = getRouterName(isVpc, id); RuleChain pre = api.getChain(tenantRouter.getInboundFilterId()); diff --git a/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java b/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java index 20b74b9e491..d57affc5827 100644 --- a/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java +++ b/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java @@ -30,6 +30,8 @@ import com.cloud.network.*; import com.cloud.network.PhysicalNetwork; import com.cloud.offering.NetworkOffering; import com.cloud.user.Account; +import com.cloud.user.AccountVO; +import com.cloud.user.dao.AccountDao; import com.cloud.vm.*; import com.midokura.midonet.client.resource.Bridge; import com.cloud.utils.net.NetUtils; @@ -46,12 +48,16 @@ import com.cloud.vm.Nic.ReservationStrategy; import javax.ejb.Local; import java.util.UUID; +import javax.inject.Inject; @Component @Local(value = NetworkGuru.class) public class MidoNetGuestNetworkGuru extends GuestNetworkGuru { private static final Logger s_logger = Logger.getLogger(MidoNetGuestNetworkGuru.class); + @Inject + AccountDao _accountDao; + public MidoNetGuestNetworkGuru() { super(); _isolationMethods = new PhysicalNetwork.IsolationMethod[] { PhysicalNetwork.IsolationMethod.MIDO }; @@ -118,7 +124,8 @@ public class MidoNetGuestNetworkGuru extends GuestNetworkGuru { implemented.setCidr(network.getCidr()); } - String accountIdStr = String.valueOf(network.getAccountId()); + AccountVO acc = _accountDao.findById(network.getAccountId()); + String accountUUIDStr = acc.getUuid(); String routerName = ""; if (network.getVpcId() != null) { routerName = "VPC" + String.valueOf(network.getVpcId()); @@ -126,7 +133,9 @@ public class MidoNetGuestNetworkGuru extends GuestNetworkGuru { routerName = String.valueOf(network.getId()); } - String broadcastUriStr = accountIdStr + "." + String.valueOf(network.getId()) + ":" + routerName; + String broadcastUriStr = accountUUIDStr + "." + + String.valueOf(network.getId()) + + ":" + routerName; implemented.setBroadcastUri(Networks.BroadcastDomainType.Mido.toUri(broadcastUriStr)); s_logger.debug("Broadcast URI set to " + broadcastUriStr); diff --git a/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetPublicNetworkGuru.java b/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetPublicNetworkGuru.java index 7e93edbcd99..1daf0bad040 100644 --- a/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetPublicNetworkGuru.java +++ b/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetPublicNetworkGuru.java @@ -34,6 +34,8 @@ import com.cloud.utils.db.DB; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; +import com.cloud.user.AccountVO; +import com.cloud.user.dao.AccountDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.IPAddressVO; import com.cloud.vm.*; @@ -50,6 +52,8 @@ public class MidoNetPublicNetworkGuru extends PublicNetworkGuru { // Inject any stuff we need to use (DAOs etc) @Inject NetworkModel _networkModel; + @Inject + AccountDao _accountDao; // Don't need to change traffic type stuff, public is fine @@ -228,9 +232,10 @@ public class MidoNetPublicNetworkGuru extends PublicNetworkGuru { } private URI generateBroadcastUri(Network network){ - String accountIdStr = String.valueOf(network.getAccountId()); + AccountVO acc = _accountDao.findById(network.getAccountId()); + String accountUUIDStr = acc.getUuid(); String networkUUIDStr = String.valueOf(network.getId()); - return Networks.BroadcastDomainType.Mido.toUri(accountIdStr + + return Networks.BroadcastDomainType.Mido.toUri(accountUUIDStr + "." + networkUUIDStr + ":" + diff --git a/plugins/network-elements/midonet/test/com/cloud/network/element/MidoNetElementTest.java b/plugins/network-elements/midonet/test/com/cloud/network/element/MidoNetElementTest.java index aec9c2d9ef9..baf99b908d4 100644 --- a/plugins/network-elements/midonet/test/com/cloud/network/element/MidoNetElementTest.java +++ b/plugins/network-elements/midonet/test/com/cloud/network/element/MidoNetElementTest.java @@ -18,12 +18,13 @@ */ import com.cloud.network.element.MidoNetElement; +import com.cloud.user.AccountVO; +import com.cloud.user.dao.AccountDao; import junit.framework.TestCase; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.*; import com.midokura.midonet.client.MidonetApi; import com.midokura.midonet.client.resource.*; -import com.cloud.network.dao.NetworkServiceMapDao; import com.sun.jersey.core.util.MultivaluedMapImpl; import com.cloud.network.*; import com.cloud.vm.*; @@ -46,10 +47,6 @@ public class MidoNetElementTest extends TestCase { //mockMgmt MidonetApi api = mock(MidonetApi.class, RETURNS_DEEP_STUBS); - ArrayList arr = new ArrayList(); - arr.add("MidoNet"); - NetworkServiceMapDao mockNSMD = mock(NetworkServiceMapDao.class); - when(mockNSMD.getDistinctProviders(anyLong())).thenReturn(arr); //mockDhcpHost DhcpHost mockDhcpHost = mock(DhcpHost.class); @@ -82,6 +79,14 @@ public class MidoNetElementTest extends TestCase { when(mockNetwork.getGateway()).thenReturn("1.2.3.4"); when(mockNetwork.getCidr()).thenReturn("1.2.3.0/24"); when(mockNetwork.getId()).thenReturn((long)2); + when(mockNetwork.getBroadcastDomainType()).thenReturn(Networks.BroadcastDomainType.Mido); + when(mockNetwork.getTrafficType()).thenReturn(Networks.TrafficType.Guest); + + //mockAccountDao + AccountDao mockAccountDao = mock(AccountDao.class); + AccountVO mockAccountVO = mock(AccountVO.class); + when(mockAccountDao.findById(anyLong())).thenReturn(mockAccountVO); + when(mockAccountVO.getUuid()).thenReturn("1"); //mockNic NicProfile mockNic = mock(NicProfile.class); @@ -96,8 +101,8 @@ public class MidoNetElementTest extends TestCase { when(mockVm.getType()).thenReturn(VirtualMachine.Type.User); MidoNetElement elem = new MidoNetElement(); - elem.setNtwkSrvcDao(mockNSMD); elem.setMidonetApi(api); + elem.setAccountDao(mockAccountDao); boolean result = false; try { @@ -119,14 +124,16 @@ public class MidoNetElementTest extends TestCase { public void testImplement() { //mock MidonetApi api = mock(MidonetApi.class, RETURNS_DEEP_STUBS); - ArrayList arr = new ArrayList(); - arr.add("MidoNet"); - NetworkServiceMapDao mockNSMD = mock(NetworkServiceMapDao.class); - when(mockNSMD.getDistinctProviders(anyLong())).thenReturn(arr); + //mockAccountDao + AccountDao mockAccountDao = mock(AccountDao.class); + AccountVO mockAccountVO = mock(AccountVO.class); + when(mockAccountDao.findById(anyLong())).thenReturn(mockAccountVO); + when(mockAccountVO.getUuid()).thenReturn("1"); MidoNetElement elem = new MidoNetElement(); - elem.setNtwkSrvcDao(mockNSMD); + elem.setMidonetApi(api); + elem.setAccountDao(mockAccountDao); //mockRPort RouterPort mockRPort = mock(RouterPort.class); @@ -161,6 +168,8 @@ public class MidoNetElementTest extends TestCase { when(mockNetwork.getGateway()).thenReturn("1.2.3.4"); when(mockNetwork.getCidr()).thenReturn("1.2.3.0/24"); when(mockNetwork.getId()).thenReturn((long)2); + when(mockNetwork.getBroadcastDomainType()).thenReturn(Networks.BroadcastDomainType.Mido); + when(mockNetwork.getTrafficType()).thenReturn(Networks.TrafficType.Public); boolean result = false; try { diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index 9e1a871e835..334aae76f33 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -29,6 +29,8 @@ INSERT IGNORE INTO `cloud`.`hypervisor_capabilities`(hypervisor_type, hypervisor INSERT IGNORE INTO `cloud`.`hypervisor_capabilities`(hypervisor_type, hypervisor_version, max_guests_limit, security_group_enabled, max_hosts_per_cluster) VALUES ('VMware', '5.1', 128, 0, 32); DELETE FROM `cloud`.`configuration` where name='vmware.percluster.host.max'; INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'AgentManager', 'xen.nics.max', '7', 'Maximum allowed nics for Vms created on Xen'); +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`.`load_balancer_vm_map` ADD state VARCHAR(40) NULL COMMENT 'service status updated by LB healthcheck manager'; alter table storage_pool change storage_provider_id storage_provider_name varchar(255); From 8f7a51ee5f5d745026d51b9ca3b2746a39f00bf2 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 15 May 2013 15:54:03 +0100 Subject: [PATCH 26/59] CLOUDSTACK-962: Because of the same reason to this (CLOUDSTACK-685) https://reviews.apache.org/r/11157/ Signed-off-by: Chip Childers --- .../network/router/VirtualNetworkApplianceManagerImpl.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 522b90ec4fb..29ef0d59f55 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -3956,6 +3956,11 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V stats.setNetBytesSent(stats.getNetBytesSent() + stats.getCurrentBytesSent()); } stats.setCurrentBytesSent(answer.getBytesSent()); + if (! _dailyOrHourly) { + //update agg bytes + stats.setAggBytesSent(stats.getNetBytesSent() + stats.getCurrentBytesSent()); + stats.setAggBytesReceived(stats.getNetBytesReceived() + stats.getCurrentBytesReceived()); + } _userStatsDao.update(stats.getId(), stats); txn.commit(); } catch (Exception e) { From bfc5887a1bf6b41e88dd7a8f9987fcee8d3d9175 Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Wed, 15 May 2013 10:36:22 -0600 Subject: [PATCH 27/59] Summary: Use hypervisor as clock source for system vms BUG-ID: CLOUDSTACK-2492 Bugfix-for: 4.1,master Signed-off-by: Marcus Sorensen 1368635782 -0600 --- .../cloud/hypervisor/kvm/resource/LibvirtComputingResource.java | 2 ++ 1 file changed, 2 insertions(+) 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 b8c6f0900b6..01476825b7b 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 @@ -3152,6 +3152,8 @@ ServerResource { if (vmTO.getOs().startsWith("Windows")) { clock.setClockOffset(ClockDef.ClockOffset.LOCALTIME); clock.setTimer("rtc", "catchup", null); + } else if (vmTO.getType() != VirtualMachine.Type.User) { + clock.setTimer("kvmclock", "catchup", null); } vm.addComp(clock); From dbb223e4de54bdff4b805407d6d2ce3ea043f170 Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Wed, 15 May 2013 10:32:32 -0700 Subject: [PATCH 28/59] Fixed applyLbRules for Netscaler. --- .../src/com/cloud/network/element/NetscalerElement.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 60d6674fdb4..cc2bcc17a43 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 @@ -240,7 +240,7 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl return false; } - if (canHandleLbRules(rules)) { + if (!canHandleLbRules(rules)) { return false; } From 7e0006a3e5584e0f89873ebfddf77c0bbcd4c222 Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Wed, 15 May 2013 11:01:43 -0700 Subject: [PATCH 29/59] CLOUDSTACK-747: internalLb in VPC - UI - create tier dialog - only one tier is allowed to have PublicLb in a VPC. --- ui/scripts/sharedFunctions.js | 34 +++++++++++----------------------- ui/scripts/vpc.js | 9 +++++---- 2 files changed, 16 insertions(+), 27 deletions(-) diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js index a01840637e3..035299059c2 100644 --- a/ui/scripts/sharedFunctions.js +++ b/ui/scripts/sharedFunctions.js @@ -122,34 +122,22 @@ function createURL(apiName, options) { return urlString; } -/* -function fromdb(val) { - return sanitizeXSS(noNull(val)); -} -*/ - function todb(val) { return encodeURIComponent(val); } -/* -function noNull(val) { - if(val == null) - return ""; - else - return val; -} -*/ +//LB provider map +var lbProviderMap = { + "publicLb": { + "non-vpc": ["VirtualRouter", "Netscaler", "F5"], + "vpc": ["VpcVirtualRouter", "Netscaler"] + }, + "internalLb": { + "non-vpc": [], + "vpc": ["InternalLbVm"] + } +}; -/* -function sanitizeXSS(val) { // Prevent cross-site-script(XSS) attack - if(val == null || typeof(val) != "string") - return val; - val = val.replace(//g, ">"); //replace > whose unicode is \u003e - return unescape(val); -} -*/ // Role Functions function isAdmin() { diff --git a/ui/scripts/vpc.js b/ui/scripts/vpc.js index 0c4a446485b..4890dcc6ee9 100644 --- a/ui/scripts/vpc.js +++ b/ui/scripts/vpc.js @@ -2344,15 +2344,16 @@ var items; if(networkSupportingLbExists == true) { items = $.grep(networkOfferings, function(networkOffering) { - var includingLbService = false; + var includingPublicLbService = false; $(networkOffering.service).each(function(){ var thisService = this; - if(thisService.name == "Lb") { - includingLbService = true; + //only one tier is allowed to have PublicLb provider in a VPC + if(thisService.name == "Lb" && lbProviderMap.publicLb.vpc.indexOf(thisService.provider[0].name) != -1) { + includingPublicLbService = true; return false; //break $.each() loop } }); - return !includingLbService; + return !includingPublicLbService; }); } else { From a13dd59d167e70b3991ea666b83bdd240aa5e786 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Tue, 14 May 2013 14:43:15 -0700 Subject: [PATCH 30/59] CLOUDSTACK-2486: Deleting the host_details and inserting them back can lead to mysql deadlock - Instead of using separate delete and insert, we will use ON DUPLICATE KEY UPDATE to avoid the MySQL deadlock --- .../entity/api/db/dao/HostDetailsDaoImpl.java | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/datacenter/entity/api/db/dao/HostDetailsDaoImpl.java b/engine/orchestration/src/org/apache/cloudstack/engine/datacenter/entity/api/db/dao/HostDetailsDaoImpl.java index 02f8c2c546c..e0ae778911c 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/datacenter/entity/api/db/dao/HostDetailsDaoImpl.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/datacenter/entity/api/db/dao/HostDetailsDaoImpl.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.engine.datacenter.entity.api.db.dao; +import java.sql.PreparedStatement; +import java.sql.SQLException; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -30,18 +32,19 @@ 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(value="EngineHostDetailsDao") @Local(value=HostDetailsDao.class) public class HostDetailsDaoImpl extends GenericDaoBase implements HostDetailsDao { protected final SearchBuilder HostSearch; protected final SearchBuilder DetailSearch; - + public HostDetailsDaoImpl() { HostSearch = createSearchBuilder(); HostSearch.and("hostId", HostSearch.entity().getHostId(), SearchCriteria.Op.EQ); HostSearch.done(); - + DetailSearch = createSearchBuilder(); DetailSearch.and("hostId", DetailSearch.entity().getHostId(), SearchCriteria.Op.EQ); DetailSearch.and("name", DetailSearch.entity().getName(), SearchCriteria.Op.EQ); @@ -53,7 +56,7 @@ public class HostDetailsDaoImpl extends GenericDaoBase implement SearchCriteria sc = DetailSearch.create(); sc.setParameters("hostId", hostId); sc.setParameters("name", name); - + DetailVO detail = findOneIncludingRemovedBy(sc); if("password".equals(name) && detail != null){ detail.setValue(DBEncryptionUtil.decrypt(detail.getValue())); @@ -65,7 +68,7 @@ public class HostDetailsDaoImpl extends GenericDaoBase implement public Map findDetails(long hostId) { SearchCriteria sc = HostSearch.create(); sc.setParameters("hostId", hostId); - + List results = search(sc, null); Map details = new HashMap(results.size()); for (DetailVO result : results) { @@ -77,12 +80,12 @@ public class HostDetailsDaoImpl extends GenericDaoBase implement } return details; } - + @Override public void deleteDetails(long hostId) { SearchCriteria sc = HostSearch.create(); sc.setParameters("hostId", hostId); - + List results = search(sc, null); for (DetailVO result : results) { remove(result.getId()); @@ -91,19 +94,27 @@ public class HostDetailsDaoImpl extends GenericDaoBase implement @Override public void persist(long hostId, Map details) { + final String InsertOrUpdateSql = "INSERT INTO `cloud`.`host_details` (host_id, name, value) VALUES (?,?,?) ON DUPLICATE KEY UPDATE value=?"; + Transaction txn = Transaction.currentTxn(); txn.start(); - SearchCriteria sc = HostSearch.create(); - sc.setParameters("hostId", hostId); - expunge(sc); - + for (Map.Entry detail : details.entrySet()) { - String value = detail.getValue(); - if("password".equals(detail.getKey())){ - value = DBEncryptionUtil.encrypt(value); - } - DetailVO vo = new DetailVO(hostId, detail.getKey(), value); - persist(vo); + String value = detail.getValue(); + if ("password".equals(detail.getKey())) { + value = DBEncryptionUtil.encrypt(value); + } + try { + PreparedStatement pstmt = txn.prepareAutoCloseStatement(InsertOrUpdateSql); + pstmt.setLong(1, hostId); + pstmt.setString(2, detail.getKey()); + pstmt.setString(3, value); + pstmt.setString(4, value); + pstmt.executeUpdate(); + } catch (SQLException e) { + throw new CloudRuntimeException("Unable to persist the host_details key: " + detail.getKey() + + " for host id: " + hostId, e); + } } txn.commit(); } From d31217f3be2786951363e0859ef62d3c0b8c3643 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Tue, 14 May 2013 17:29:13 -0700 Subject: [PATCH 31/59] CLOUDSTACK-2486: Deleting the host_details and inserting them back can lead to mysql deadlock - Added the index found missing after upgrade Contained in branches: master Contained in no tag --- .../cloud/upgrade/dao/Upgrade410to420.java | 69 ++++++++++++++----- 1 file changed, 51 insertions(+), 18 deletions(-) diff --git a/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java index 1bd9abe780e..ff5e0fb0f88 100644 --- a/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java @@ -73,9 +73,10 @@ public class Upgrade410to420 implements DbUpgrade { upgradeDefaultVpcOffering(conn); upgradePhysicalNtwksWithInternalLbProvider(conn); updateNetworkACLs(conn); + addHostDetailsIndex(conn); } - - private void updateSystemVmTemplates(Connection conn) { + + private void updateSystemVmTemplates(Connection conn) { PreparedStatement sql = null; try { sql = conn.prepareStatement("update vm_template set image_data_store_id = 1 where type = 'SYSTEM' or type = 'BUILTIN'"); @@ -91,7 +92,7 @@ public class Upgrade410to420 implements DbUpgrade { } } } - + private void updatePrimaryStore(Connection conn) { PreparedStatement sql = null; PreparedStatement sql2 = null; @@ -100,7 +101,7 @@ public class Upgrade410to420 implements DbUpgrade { sql.setString(1, "ancient primary data store provider"); sql.setString(2, "HOST"); sql.executeUpdate(); - + sql2 = conn.prepareStatement("update storage_pool set storage_provider_name = ? , scope = ? where pool_type != 'Filesystem' and pool_type != 'LVM'"); sql2.setString(1, "ancient primary data store provider"); sql2.setString(2, "CLUSTER"); @@ -114,7 +115,7 @@ public class Upgrade410to420 implements DbUpgrade { } catch (SQLException e) { } } - + if (sql2 != null) { try { sql2.close(); @@ -242,7 +243,7 @@ public class Upgrade410to420 implements DbUpgrade { } } } - + private void createPlaceHolderNics(Connection conn) { PreparedStatement pstmt = null; ResultSet rs = null; @@ -263,7 +264,7 @@ public class Upgrade410to420 implements DbUpgrade { pstmt.setLong(4, networkId); pstmt.executeUpdate(); s_logger.debug("Created placeholder nic for the ipAddress " + ip); - + } } catch (SQLException e) { throw new CloudRuntimeException("Unable to create placeholder nics", e); @@ -279,8 +280,8 @@ public class Upgrade410to420 implements DbUpgrade { } } } - - + + private void updateRemoteAccessVpn(Connection conn) { PreparedStatement pstmt = null; ResultSet rs = null; @@ -560,8 +561,8 @@ public class Upgrade410to420 implements DbUpgrade { } } } - - + + private void upgradeDefaultVpcOffering(Connection conn) { PreparedStatement pstmt = null; @@ -579,7 +580,7 @@ public class Upgrade410to420 implements DbUpgrade { 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 { @@ -594,9 +595,9 @@ public class Upgrade410to420 implements DbUpgrade { } } } - - - + + + private void upgradePhysicalNtwksWithInternalLbProvider(Connection conn) { PreparedStatement pstmt = null; @@ -615,7 +616,7 @@ public class Upgrade410to420 implements DbUpgrade { 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'"); @@ -629,7 +630,7 @@ public class Upgrade410to420 implements DbUpgrade { pstmt1.executeUpdate(); } } - + } catch (SQLException e) { throw new CloudRuntimeException("Unable existing physical networks with internal lb provider", e); } finally { @@ -643,6 +644,38 @@ public class Upgrade410to420 implements DbUpgrade { } catch (SQLException e) { } } - + + } + + private void addHostDetailsIndex(Connection conn) { + s_logger.debug("Checking if host_details index exists, if not we will add it"); + PreparedStatement pstmt = null; + ResultSet rs = null; + try { + pstmt = conn.prepareStatement("SHOW INDEX FROM `cloud`.`host_details` where KEY_NAME = 'fk_host_details__host_id'"); + rs = pstmt.executeQuery(); + if (rs.next()) { + s_logger.debug("Index already exists on host_details - not adding new one"); + } else { + // add the index + PreparedStatement pstmtUpdate = conn.prepareStatement("ALTER IGNORE TABLE `cloud`.`host_details` ADD INDEX `fk_host_details__host_id` (`host_id`)"); + pstmtUpdate.executeUpdate(); + s_logger.debug("Index did not exist on host_details - added new one"); + pstmtUpdate.close(); + } + } catch (SQLException e) { + throw new CloudRuntimeException("Failed to check/update the host_details index ", e); + } finally { + try { + if (rs != null) { + rs.close(); + } + + if (pstmt != null) { + pstmt.close(); + } + } catch (SQLException e) { + } + } } } From 73030f43729f408acd8c6325541db2f184757e80 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Wed, 15 May 2013 11:58:13 -0700 Subject: [PATCH 32/59] CLOUDSTACK-2486: Deleting the host_details and inserting them back can lead to mysql deadlock - Changing the correct details dao. Instead of using separate delete and insert, we will use ON DUPLICATE KEY UPDATE to avoid the MySQL deadlock --- .../cloud/host/dao/HostDetailsDaoImpl.java | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/engine/schema/src/com/cloud/host/dao/HostDetailsDaoImpl.java b/engine/schema/src/com/cloud/host/dao/HostDetailsDaoImpl.java index b6a9cef9ee9..47cdeb30633 100644 --- a/engine/schema/src/com/cloud/host/dao/HostDetailsDaoImpl.java +++ b/engine/schema/src/com/cloud/host/dao/HostDetailsDaoImpl.java @@ -16,6 +16,8 @@ // under the License. package com.cloud.host.dao; +import java.sql.PreparedStatement; +import java.sql.SQLException; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -30,18 +32,19 @@ 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=HostDetailsDao.class) public class HostDetailsDaoImpl extends GenericDaoBase implements HostDetailsDao { protected final SearchBuilder HostSearch; protected final SearchBuilder DetailSearch; - + public HostDetailsDaoImpl() { HostSearch = createSearchBuilder(); HostSearch.and("hostId", HostSearch.entity().getHostId(), SearchCriteria.Op.EQ); HostSearch.done(); - + DetailSearch = createSearchBuilder(); DetailSearch.and("hostId", DetailSearch.entity().getHostId(), SearchCriteria.Op.EQ); DetailSearch.and("name", DetailSearch.entity().getName(), SearchCriteria.Op.EQ); @@ -53,7 +56,7 @@ public class HostDetailsDaoImpl extends GenericDaoBase implement SearchCriteria sc = DetailSearch.create(); sc.setParameters("hostId", hostId); sc.setParameters("name", name); - + DetailVO detail = findOneIncludingRemovedBy(sc); if("password".equals(name) && detail != null){ detail.setValue(DBEncryptionUtil.decrypt(detail.getValue())); @@ -65,7 +68,7 @@ public class HostDetailsDaoImpl extends GenericDaoBase implement public Map findDetails(long hostId) { SearchCriteria sc = HostSearch.create(); sc.setParameters("hostId", hostId); - + List results = search(sc, null); Map details = new HashMap(results.size()); for (DetailVO result : results) { @@ -77,12 +80,12 @@ public class HostDetailsDaoImpl extends GenericDaoBase implement } return details; } - + @Override public void deleteDetails(long hostId) { SearchCriteria sc = HostSearch.create(); sc.setParameters("hostId", hostId); - + List results = search(sc, null); for (DetailVO result : results) { remove(result.getId()); @@ -91,19 +94,27 @@ public class HostDetailsDaoImpl extends GenericDaoBase implement @Override public void persist(long hostId, Map details) { + final String InsertOrUpdateSql = "INSERT INTO `cloud`.`host_details` (host_id, name, value) VALUES (?,?,?) ON DUPLICATE KEY UPDATE value=?"; + Transaction txn = Transaction.currentTxn(); txn.start(); - SearchCriteria sc = HostSearch.create(); - sc.setParameters("hostId", hostId); - expunge(sc); - + for (Map.Entry detail : details.entrySet()) { - String value = detail.getValue(); - if("password".equals(detail.getKey())){ - value = DBEncryptionUtil.encrypt(value); - } - DetailVO vo = new DetailVO(hostId, detail.getKey(), value); - persist(vo); + String value = detail.getValue(); + if ("password".equals(detail.getKey())) { + value = DBEncryptionUtil.encrypt(value); + } + try { + PreparedStatement pstmt = txn.prepareAutoCloseStatement(InsertOrUpdateSql); + pstmt.setLong(1, hostId); + pstmt.setString(2, detail.getKey()); + pstmt.setString(3, value); + pstmt.setString(4, value); + pstmt.executeUpdate(); + } catch (SQLException e) { + throw new CloudRuntimeException("Unable to persist the host_details key: " + detail.getKey() + + " for host id: " + hostId, e); + } } txn.commit(); } From 9f59c618e277f4b9ce7e3cdd4156012b1d538471 Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Wed, 15 May 2013 12:08:34 -0700 Subject: [PATCH 33/59] CLOUDSTACK-2517: fixed private gateway creation. Following fixes went in: 1) Only PrivateNetworkGuru handles network creation for the private gateway. Exluded Guest Network Guru from this list (was mistakenly included as a part of merge for Nicira integration) 2) Pass vpc_id to createNetwork call when the network is created as a part of private gateway creation 3) Fixed VPC restart when there are multiple private gateways present (have to grab all the private gateways when creating nic profiles for the VPC router that is being re-created) 4) 41-42 db upgarde: set vpc_id for the private networks of the existing VPCs --- .../src/com/cloud/network/dao/NetworkDao.java | 2 ++ .../com/cloud/network/dao/NetworkDaoImpl.java | 13 +++++++++ .../cloud/upgrade/dao/Upgrade410to420.java | 27 ++++++++++++++++++- .../com/cloud/network/NetworkServiceImpl.java | 2 +- .../guru/ExternalGuestNetworkGuru.java | 2 +- ...VpcVirtualNetworkApplianceManagerImpl.java | 14 +++++----- .../src/com/cloud/network/vpc/VpcManager.java | 2 +- .../com/cloud/network/vpc/VpcManagerImpl.java | 11 ++++---- .../com/cloud/vpc/MockVpcManagerImpl.java | 2 +- .../com/cloud/vpc/dao/MockNetworkDaoImpl.java | 5 ++++ 10 files changed, 64 insertions(+), 16 deletions(-) diff --git a/engine/schema/src/com/cloud/network/dao/NetworkDao.java b/engine/schema/src/com/cloud/network/dao/NetworkDao.java index 43cabe751f6..d0a1a256efc 100644 --- a/engine/schema/src/com/cloud/network/dao/NetworkDao.java +++ b/engine/schema/src/com/cloud/network/dao/NetworkDao.java @@ -113,4 +113,6 @@ public interface NetworkDao extends GenericDao , StateDao listRedundantNetworks(); List listByAclId(long aclId); + + int getNonSystemNetworkCountByVpcId(long vpcId); } diff --git a/engine/schema/src/com/cloud/network/dao/NetworkDaoImpl.java b/engine/schema/src/com/cloud/network/dao/NetworkDaoImpl.java index 5b3b526b640..c55cf28273a 100644 --- a/engine/schema/src/com/cloud/network/dao/NetworkDaoImpl.java +++ b/engine/schema/src/com/cloud/network/dao/NetworkDaoImpl.java @@ -162,6 +162,9 @@ public class NetworkDaoImpl extends GenericDaoBase implements N CountBy.and("offeringId", CountBy.entity().getNetworkOfferingId(), Op.EQ); CountBy.and("vpcId", CountBy.entity().getVpcId(), Op.EQ); CountBy.and("removed", CountBy.entity().getRemoved(), Op.NULL); + SearchBuilder ntwkOffJoin = _ntwkOffDao.createSearchBuilder(); + ntwkOffJoin.and("isSystem", ntwkOffJoin.entity().isSystemOnly(), Op.EQ); + CountBy.join("offerings", ntwkOffJoin, CountBy.entity().getNetworkOfferingId(), ntwkOffJoin.entity().getId(), JoinBuilder.JoinType.INNER); CountBy.done(); PhysicalNetworkSearch = createSearchBuilder(); @@ -627,4 +630,14 @@ public class NetworkDaoImpl extends GenericDaoBase implements N return listBy(sc, null); } + + + @Override + public int getNonSystemNetworkCountByVpcId(long vpcId) { + SearchCriteria sc = CountBy.create(); + sc.setParameters("vpcId", vpcId); + sc.setJoinParameters("offerings", "isSystem", false); + List results = customSearch(sc, null); + return results.get(0); + } } diff --git a/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java index ff5e0fb0f88..1d35c8981fa 100644 --- a/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java @@ -74,6 +74,7 @@ public class Upgrade410to420 implements DbUpgrade { upgradePhysicalNtwksWithInternalLbProvider(conn); updateNetworkACLs(conn); addHostDetailsIndex(conn); + updateNetworksForPrivateGateways(conn); } private void updateSystemVmTemplates(Connection conn) { @@ -564,7 +565,6 @@ public class Upgrade410to420 implements DbUpgrade { private void upgradeDefaultVpcOffering(Connection conn) { - PreparedStatement pstmt = null; ResultSet rs = null; @@ -678,4 +678,29 @@ public class Upgrade410to420 implements DbUpgrade { } } } + + + private void updateNetworksForPrivateGateways(Connection conn) { + + PreparedStatement pstmt = null; + ResultSet rs = null; + + try { + //1) get all non removed gateways + pstmt = conn.prepareStatement("SELECT network_id, vpc_id FROM `cloud`.`vpc_gateways` WHERE type='Private' AND removed IS null"); + rs = pstmt.executeQuery(); + while (rs.next()) { + Long networkId = rs.getLong(1); + Long vpcId = rs.getLong(2); + //2) Update networks with vpc_id if its set to NULL + pstmt = conn.prepareStatement("UPDATE `cloud`.`networks` set vpc_id=? where id=? and vpc_id is NULL and removed is NULL"); + pstmt.setLong(1, vpcId); + pstmt.setLong(2, networkId); + pstmt.executeUpdate(); + + } + } catch (SQLException e) { + throw new CloudRuntimeException("Failed to update private networks with VPC id.", e); + } + } } diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 5f51a30d389..8b11819577e 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -3813,7 +3813,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, true); + null, owner, null, pNtwk, pNtwk.getDataCenterId(), ACLType.Account, null, vpcId, null, null, true); s_logger.debug("Created private network " + privateNetwork); } else { diff --git a/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java b/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java index fe9e01f558d..eb1b3dc4b24 100644 --- a/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java +++ b/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java @@ -83,7 +83,7 @@ public class ExternalGuestNetworkGuru extends GuestNetworkGuru { if (networkType == NetworkType.Advanced && isMyTrafficType(offering.getTrafficType()) && offering.getGuestType() == Network.GuestType.Isolated - && isMyIsolationMethod(physicalNetwork)) { + && isMyIsolationMethod(physicalNetwork) && !offering.isSystemOnly()) { return true; } else { s_logger.trace("We only take care of Guest networks of type " diff --git a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java index 915e2d8afe9..70073741433 100644 --- a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java @@ -1236,12 +1236,14 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian //1) allocate nic for control and source nat public ip networks = super.createRouterNetworks(owner, isRedundant, plan, null, sourceNatIp); - //2) allocate nic for private gateway if needed - PrivateGateway privateGateway = _vpcMgr.getVpcPrivateGateway(vpcId); - if (privateGateway != null) { - NicProfile privateNic = createPrivateNicProfileForGateway(privateGateway); - Network privateNetwork = _networkModel.getNetwork(privateGateway.getNetworkId()); - networks.add(new Pair((NetworkVO) privateNetwork, privateNic)); + //2) allocate nic for private gateways if needed + List privateGateways = _vpcMgr.getVpcPrivateGateways(vpcId); + if (privateGateways != null && !privateGateways.isEmpty()) { + for (PrivateGateway privateGateway : privateGateways) { + NicProfile privateNic = createPrivateNicProfileForGateway(privateGateway); + Network privateNetwork = _networkModel.getNetwork(privateGateway.getNetworkId()); + networks.add(new Pair((NetworkVO) privateNetwork, privateNic)); + } } //3) allocate nic for guest gateway if needed diff --git a/server/src/com/cloud/network/vpc/VpcManager.java b/server/src/com/cloud/network/vpc/VpcManager.java index e8db8d3fd5c..f22e7e4bf83 100644 --- a/server/src/com/cloud/network/vpc/VpcManager.java +++ b/server/src/com/cloud/network/vpc/VpcManager.java @@ -166,5 +166,5 @@ public interface VpcManager extends VpcService{ */ void validateNtwkOffForNtwkInVpc(Long networkId, long newNtwkOffId, String newCidr, String newNetworkDomain, Vpc vpc, String gateway, Account networkOwner); - List getVpcPrivateGateways(long id); + List getVpcPrivateGateways(long vpcId); } diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index f01d81be392..2335416e9fc 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -711,8 +711,9 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis public boolean destroyVpc(Vpc vpc, Account caller, Long callerUserId) throws ConcurrentOperationException, ResourceUnavailableException { s_logger.debug("Destroying vpc " + vpc); - //don't allow to delete vpc if it's in use by existing networks - int networksCount = _ntwkDao.getNetworkCountByVpcId(vpc.getId()); + //don't allow to delete vpc if it's in use by existing non system networks (system networks are networks of a private gateway of the VPC, + //and they will get removed as a part of VPC cleanup + int networksCount = _ntwkDao.getNonSystemNetworkCountByVpcId(vpc.getId()); if (networksCount > 0) { throw new InvalidParameterValueException("Can't delete VPC " + vpc + " as its used by " + networksCount + " networks"); } @@ -1235,7 +1236,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis return false; } - //4) Delete private gateway + //4) Delete private gateways List gateways = getVpcPrivateGateways(vpcId); if (gateways != null) { for (PrivateGateway gateway: gateways) { @@ -1299,8 +1300,8 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis @Override - public List getVpcPrivateGateways(long id) { - List gateways = _vpcGatewayDao.listByVpcIdAndType(id, VpcGateway.Type.Private); + public List getVpcPrivateGateways(long vpcId) { + List gateways = _vpcGatewayDao.listByVpcIdAndType(vpcId, VpcGateway.Type.Private); if (gateways != null) { List pvtGateway = new ArrayList(); diff --git a/server/test/com/cloud/vpc/MockVpcManagerImpl.java b/server/test/com/cloud/vpc/MockVpcManagerImpl.java index 9812750e479..921321f52da 100644 --- a/server/test/com/cloud/vpc/MockVpcManagerImpl.java +++ b/server/test/com/cloud/vpc/MockVpcManagerImpl.java @@ -379,7 +379,7 @@ public class MockVpcManagerImpl extends ManagerBase implements VpcManager { } @Override - public List getVpcPrivateGateways(long id) { + public List getVpcPrivateGateways(long vpcId) { return null; } diff --git a/server/test/com/cloud/vpc/dao/MockNetworkDaoImpl.java b/server/test/com/cloud/vpc/dao/MockNetworkDaoImpl.java index 4747e702e65..ec1a0173aa8 100644 --- a/server/test/com/cloud/vpc/dao/MockNetworkDaoImpl.java +++ b/server/test/com/cloud/vpc/dao/MockNetworkDaoImpl.java @@ -367,4 +367,9 @@ public class MockNetworkDaoImpl extends GenericDaoBase implemen return null; } + + @Override + public int getNonSystemNetworkCountByVpcId(long vpcId) { + return 0; + } } From ddd7cfd71c45c708012d30a0b7858db9d74c90f4 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Wed, 15 May 2013 12:19:33 -0700 Subject: [PATCH 34/59] CLOUDSTACK-2519: VMs on local storage incorrectly destroyed when removing another host using deleteHost API - For DeleteHost API: Search for Volumes in READY state on the local storage of the host to find VM's in 'Running' State - For PrepareForMaintenance API: Search for Volumes not in Destroy or Expunging state to check if the Local Storage on the host is being used. --- .../com/cloud/storage/StorageManagerImpl.java | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 1d4dcefad92..a67397ec460 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -423,6 +423,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C SearchCriteria.Op.EQ); volumeSB.and("removed", volumeSB.entity().getRemoved(), SearchCriteria.Op.NULL); + volumeSB.and("state", volumeSB.entity().getState(), SearchCriteria.Op.NIN); SearchBuilder activeVmSB = _vmInstanceDao .createSearchBuilder(); @@ -434,6 +435,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C SearchCriteria volumeSC = volumeSB.create(); volumeSC.setParameters("poolId", PrimaryDataStoreVO.getId()); + volumeSC.setParameters("state", Volume.State.Expunging, Volume.State.Destroy); volumeSC.setJoinParameters("activeVmSB", "state", State.Starting, State.Running, State.Stopping, State.Migrating); @@ -456,13 +458,13 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C VirtualMachineProfile profile = new VirtualMachineProfileImpl( vm); for (StoragePoolAllocator allocator : _storagePoolAllocators) { - + ExcludeList avoidList = new ExcludeList(); for(StoragePool pool : avoid){ avoidList.addPool(pool.getId()); } DataCenterDeployment plan = new DataCenterDeployment(dc.getId(), pod.getId(), clusterId, hostId, null, null); - + final List poolList = allocator.allocateToPool(dskCh, profile, plan, avoidList, 1); if (poolList != null && !poolList.isEmpty()) { return (StoragePool)this.dataStoreMgr.getDataStore(poolList.get(0).getId(), DataStoreRole.Primary); @@ -629,6 +631,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C SearchCriteria.Op.EQ); volumeSearch.and("poolId", volumeSearch.entity().getPoolId(), SearchCriteria.Op.EQ); + volumeSearch.and("state", volumeSearch.entity().getState(), SearchCriteria.Op.EQ); StoragePoolSearch.join("vmVolume", volumeSearch, volumeSearch.entity() .getInstanceId(), StoragePoolSearch.entity().getId(), JoinBuilder.JoinType.INNER); @@ -651,7 +654,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C return true; } - + @Override public String getStoragePoolTags(long poolId) { return _configMgr.listToCsvTags(_storagePoolDao @@ -680,7 +683,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C return true; } - + @DB @Override public DataStore createLocalStorage(Host host, StoragePoolInfo pInfo) throws ConnectionException { @@ -694,7 +697,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C StoragePoolVO pool = _storagePoolDao.findPoolByHostPath(host.getDataCenterId(), host.getPodId(), pInfo.getHost(), pInfo.getHostPath(), pInfo.getUuid()); if(pool == null && host.getHypervisorType() == HypervisorType.VMware) { // perform run-time upgrade. In versions prior to 2.2.12, there is a bug that we don't save local datastore info (host path is empty), this will cause us - // not able to distinguish multiple local datastores that may be available on the host, to support smooth migration, we + // not able to distinguish multiple local datastores that may be available on the host, to support smooth migration, we // need to perform runtime upgrade here if(pInfo.getHostPath().length() > 0) { pool = _storagePoolDao.findPoolByHostPath(host.getDataCenterId(), host.getPodId(), pInfo.getHost(), "", pInfo.getUuid()); @@ -714,13 +717,13 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C params.put("details", pInfo.getDetails()); params.put("uuid", pInfo.getUuid()); params.put("providerName", provider.getName()); - + store = lifeCycle.initialize(params); } else { store = (DataStore) dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary); } - + HostScope scope = new HostScope(host.getId()); lifeCycle.attachHost(store, scope, pInfo); } catch (Exception e) { @@ -990,7 +993,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } CapacityState capacityState = (allocationState == AllocationState.Disabled) ? CapacityState.Disabled : CapacityState.Enabled; - + capacity.setCapacityState(capacityState); _capacityDao.persist(capacity); } else { @@ -1130,7 +1133,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C }finally { scanLock.unlock(); } - } + } }finally { scanLock.releaseRef(); } @@ -1462,7 +1465,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C DataStore store = dataStoreMgr.getDataStore( primaryStorage.getId(), DataStoreRole.Primary); lifeCycle.cancelMaintain(store); - + return (PrimaryDataStoreInfo) dataStoreMgr.getDataStore( primaryStorage.getId(), DataStoreRole.Primary); } @@ -1610,7 +1613,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C DataStoreRole.Primary); } - + @Override @DB @@ -1618,6 +1621,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C SearchCriteria sc = StoragePoolSearch.create(); sc.setJoinParameters("vmVolume", "volumeType", Volume.Type.ROOT); sc.setJoinParameters("vmVolume", "poolId", storagePoolId); + sc.setJoinParameters("vmVolume", "state", Volume.State.Ready); return _vmInstanceDao.search(sc, null); } @@ -1691,7 +1695,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C return secHost; } - + @Override public HypervisorType getHypervisorTypeFromFormat(ImageFormat format) { From c8af438e64abea2c4138fab13c1d4d5ab669ada0 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Wed, 15 May 2013 14:27:27 -0700 Subject: [PATCH 35/59] CLOUDSTACK-2522: While processing agents behind on ping, we may fail to process a host that is already in 'Down' state Changes: - Added a transition for DOWN -> DOWN state on PING TIMEOUT so that transition will set mgmt_server_id in the host table to null. --- api/src/com/cloud/host/Status.java | 1 + 1 file changed, 1 insertion(+) diff --git a/api/src/com/cloud/host/Status.java b/api/src/com/cloud/host/Status.java index 97b151dc723..dd49122c13b 100755 --- a/api/src/com/cloud/host/Status.java +++ b/api/src/com/cloud/host/Status.java @@ -147,6 +147,7 @@ public enum Status { s_fsm.addTransition(Status.Down, Event.Remove, Status.Removed); s_fsm.addTransition(Status.Down, Event.ManagementServerDown, Status.Down); s_fsm.addTransition(Status.Down, Event.AgentDisconnected, Status.Down); + s_fsm.addTransition(Status.Down, Event.PingTimeout, Status.Down); s_fsm.addTransition(Status.Alert, Event.AgentConnected, Status.Connecting); s_fsm.addTransition(Status.Alert, Event.Ping, Status.Up); s_fsm.addTransition(Status.Alert, Event.Remove, Status.Removed); From 076c32db9a1733146a542cb23eb0515176bd5d0b Mon Sep 17 00:00:00 2001 From: Chiradeep Vittal Date: Wed, 15 May 2013 15:00:19 -0700 Subject: [PATCH 36/59] CLOUDSTACK-2492: enable time sync on vmware if ntp is not installed --- .../systemvm/debian/config/etc/init.d/cloud-early-config | 6 ++++++ 1 file changed, 6 insertions(+) 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 a457f228653..893a2455bc4 100755 --- a/patches/systemvm/debian/config/etc/init.d/cloud-early-config +++ b/patches/systemvm/debian/config/etc/init.d/cloud-early-config @@ -434,6 +434,12 @@ setup_common() { ping -n -c 3 $MGMT_GW & sleep 3 pkill ping + + fi + + local hyp=$(hypervisor) + if [ "$hyp" == "vmware" ]; then + ntpq -p &> /dev/null || vmware-toolbox-cmd timesync enable fi } From 521e156520a3ca9514478c6871cde23d3e8e91f0 Mon Sep 17 00:00:00 2001 From: Chiradeep Vittal Date: Wed, 15 May 2013 15:33:57 -0700 Subject: [PATCH 37/59] CLOUDSTACK-2521: auto download ISO if not present --- tools/appliance/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/appliance/build.sh b/tools/appliance/build.sh index c39d38a4e76..0216c067a45 100644 --- a/tools/appliance/build.sh +++ b/tools/appliance/build.sh @@ -34,7 +34,7 @@ bundle # Clean and start building the appliance veewee vbox destroy $appliance -veewee vbox build $appliance --nogui +veewee vbox build $appliance --nogui --auto veewee vbox halt $appliance while [[ `vboxmanage list runningvms | grep $appliance | wc -l` -ne 0 ]]; From 5511eb241af775efa59d4fdeb597d2b335b50739 Mon Sep 17 00:00:00 2001 From: Koushik Das Date: Thu, 16 May 2013 09:20:41 +0530 Subject: [PATCH 38/59] CLOUDSTACK-2509: [Cisco VNMC]No way to block incoming traffic as ACL created with PF/Static Nat is Source is Any No longer creating firewall rule as part of PF/Static NAT rule creation. Now firewall rule needs to be configured separately. Also made some changes to exception handling. --- .../network/cisco/create-egress-acl-rule.xml | 10 +- ...te-generic-egress-acl-no-protocol-rule.xml | 10 +- .../cisco/create-generic-egress-acl-rule.xml | 10 +- .../network/cisco/CiscoVnmcConnection.java | 4 +- .../cisco/CiscoVnmcConnectionImpl.java | 12 +- .../network/resource/CiscoVnmcResource.java | 149 ++++++++---------- 6 files changed, 88 insertions(+), 107 deletions(-) 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 05c066d6d53..f283ffeb333 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 @@ -80,7 +80,7 @@ under the License. @@ -93,7 +93,7 @@ under the License. name="" placement="begin" status="created" - value="%deststartip%"/> + value="%sourcestartip%"/> + value="%sourceendip%"/> @@ -161,8 +161,8 @@ under the License. descr=value actiontype="drop" or "permit" protocolvalue = "TCP" or "UDP" - deststartip="destination start ip" - destendip="destination end ip" + sourcestartip="source start ip" + sourceendip="source end 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 index 17cfa54a34e..e6f4cfb63d1 100755 --- 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 @@ -54,7 +54,7 @@ under the License. @@ -67,7 +67,7 @@ under the License. name="" placement="begin" status="created" - value="%deststartip%"/> + value="%sourcestartip%"/> + value="%sourceendip%"/> @@ -89,6 +89,6 @@ under the License. aclrulename="dummy" descr=value actiontype="drop" or "permit" - deststartip="destination start ip" - destendip="destination end ip" + sourcestartip="source start ip" + sourceendip="source end ip" --!> 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 436e3eae790..55edd1fa728 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 @@ -80,7 +80,7 @@ under the License. @@ -93,7 +93,7 @@ under the License. name="" placement="begin" status="created" - value="%deststartip%"/> + value="%sourcestartip%"/> + value="%sourceendip%"/> @@ -116,6 +116,6 @@ under the License. descr=value actiontype="drop" or "permit" protocolvalue = "TCP" or "UDP" or "ICMP" - deststartip="destination start ip" - destendip="destination end ip" + sourcestartip="source start ip" + sourceendip="source end ip" --!> 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 fed6724418d..28e2535ca91 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 @@ -150,13 +150,13 @@ public interface CiscoVnmcConnection { public boolean createTenantVDCEgressAclRule(String tenantName, String identifier, String policyIdentifier, - String protocol, String destStartIp, String destEndIp, + String protocol, String sourceStartIp, String sourceEndIp, String destStartPort, String destEndPort) throws ExecutionException; public boolean createTenantVDCEgressAclRule(String tenantName, String identifier, String policyIdentifier, - String protocol, String destStartIp, String destEndIp) + String protocol, String sourceStartIp, String sourceEndIp) 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 0e57cae6ddc..a9e8cf633f9 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 @@ -729,7 +729,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { @Override public boolean createTenantVDCEgressAclRule(String tenantName, String identifier, String policyIdentifier, - String protocol, String destStartIp, String destEndIp, + String protocol, String sourceStartIp, String sourceEndIp, String destStartPort, String destEndPort) throws ExecutionException { String xml = VnmcXml.CREATE_EGRESS_ACL_RULE.getXml(); String service = VnmcXml.CREATE_EGRESS_ACL_RULE.getService(); @@ -740,8 +740,8 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { 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); + xml = replaceXmlValue(xml, "sourcestartip", sourceStartIp); + xml = replaceXmlValue(xml, "sourceendip", sourceEndIp); xml = replaceXmlValue(xml, "deststartport", destStartPort); xml = replaceXmlValue(xml, "destendport", destEndPort); @@ -759,7 +759,7 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { @Override public boolean createTenantVDCEgressAclRule(String tenantName, String identifier, String policyIdentifier, - String protocol, String destStartIp, String destEndIp) throws ExecutionException { + String protocol, String sourceStartIp, String sourceEndIp) 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 @@ -773,8 +773,8 @@ public class CiscoVnmcConnectionImpl implements CiscoVnmcConnection { 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, "deststartip", destStartIp); - xml = replaceXmlValue(xml, "destendip", destEndIp); + xml = replaceXmlValue(xml, "sourcestartip", sourceStartIp); + xml = replaceXmlValue(xml, "sourceendip", sourceEndIp); List rules = listChildren(getDnForAclPolicy(tenantName, policyIdentifier)); int order = 100; 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 176fdc45062..29bbbe67a31 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 @@ -60,6 +60,7 @@ import com.cloud.utils.Pair; import com.cloud.utils.cisco.n1kv.vsm.NetconfHelper; import com.cloud.utils.cisco.n1kv.vsm.VsmCommand.OperationType; import com.cloud.utils.cisco.n1kv.vsm.VsmCommand.SwitchPortMode; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.ExecutionException; import com.cloud.utils.net.NetUtils; @@ -280,30 +281,30 @@ public class CiscoVnmcResource implements ServerResource { String policyIdentifier = cmd.getIpAddress().getPublicIp().replace('.', '-'); try { if (!_connection.createTenantVDCNatPolicySet(tenant)) { - throw new Exception("Failed to create NAT policy set in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create NAT policy set in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCSourceNatPolicy(tenant, policyIdentifier)) { - throw new Exception("Failed to create source NAT policy in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create source NAT policy in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCSourceNatPolicyRef(tenant, policyIdentifier)) { - throw new Exception("Failed to associate source NAT policy with NAT policy set in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to associate source NAT policy with NAT policy set in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCSourceNatIpPool(tenant, policyIdentifier, cmd.getIpAddress().getPublicIp())) { - throw new Exception("Failed to create source NAT ip pool in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create source NAT ip pool in VNMC for guest network with vlan " + vlanId); } String[] ipRange = getIpRangeFromCidr(cmd.getContextParam(NetworkElementCommand.GUEST_NETWORK_CIDR)); if (!_connection.createTenantVDCSourceNatRule(tenant, policyIdentifier, ipRange[0], ipRange[1])) { - throw new Exception("Failed to create source NAT rule in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create source NAT rule in VNMC for guest network with vlan " + vlanId); } if (!_connection.associateNatPolicySet(tenant)) { - throw new Exception("Failed to associate source NAT policy set with edge security profile in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to associate source NAT policy set with edge security profile in VNMC for guest network with vlan " + vlanId); } - } catch (Throwable e) { + } catch (ExecutionException e) { String msg = "SetSourceNatCommand failed due to " + e.getMessage(); s_logger.error(msg, e); return new Answer(cmd, false, msg); @@ -337,29 +338,29 @@ public class CiscoVnmcResource implements ServerResource { try { if (!_connection.createTenantVDCAclPolicySet(tenant, true)) { - throw new Exception("Failed to create ACL ingress policy set in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create ACL ingress policy set in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCAclPolicySet(tenant, false)) { - throw new Exception("Failed to create ACL egress policy set in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create ACL egress policy set in VNMC for guest network with vlan " + vlanId); } for (String publicIp : publicIpRulesMap.keySet()) { String policyIdentifier = publicIp.replace('.', '-'); if (!_connection.createTenantVDCAclPolicy(tenant, policyIdentifier)) { - throw new Exception("Failed to create ACL policy in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create ACL policy in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCAclPolicyRef(tenant, policyIdentifier, true)) { - throw new Exception("Failed to associate ACL policy with ACL ingress policy set in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to associate ACL policy with ACL ingress policy set in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCAclPolicyRef(tenant, policyIdentifier, false)) { - throw new Exception("Failed to associate ACL policy with ACL egress policy set in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to associate ACL policy with ACL egress policy set in VNMC for guest network with vlan " + vlanId); } for (FirewallRuleTO rule : publicIpRulesMap.get(publicIp)) { if (rule.revoked()) { if (!_connection.deleteTenantVDCAclRule(tenant, Long.toString(rule.getId()), policyIdentifier)) { - throw new Exception("Failed to delete ACL rule in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to delete ACL rule in VNMC for guest network with vlan " + vlanId); } } else { String[] externalIpRange = getIpRangeFromCidr(rule.getSourceCidrList().get(0)); @@ -370,13 +371,13 @@ public class CiscoVnmcResource implements ServerResource { Long.toString(rule.getId()), policyIdentifier, rule.getProtocol().toUpperCase(), externalIpRange[0], externalIpRange[1], 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); + throw new ExecutionException("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])) { - throw new Exception("Failed to create ACL ingress rule in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create ACL ingress rule in VNMC for guest network with vlan " + vlanId); } } } else { @@ -387,13 +388,13 @@ public class CiscoVnmcResource implements ServerResource { rule.getProtocol().toUpperCase(), 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); + throw new ExecutionException("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(), externalIpRange[0], externalIpRange[1])) { - throw new Exception("Failed to create ACL egress rule in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create ACL egress rule in VNMC for guest network with vlan " + vlanId); } } } @@ -402,9 +403,9 @@ public class CiscoVnmcResource implements ServerResource { } if (!_connection.associateAclPolicySet(tenant)) { - throw new Exception("Failed to associate ACL policy set with edge security profile in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to associate ACL policy set with edge security profile in VNMC for guest network with vlan " + vlanId); } - } catch (Throwable e) { + } catch (ExecutionException e) { String msg = "SetFirewallRulesCommand failed due to " + e.getMessage(); s_logger.error(msg, e); return new Answer(cmd, false, msg); @@ -438,69 +439,60 @@ public class CiscoVnmcResource implements ServerResource { try { if (!_connection.createTenantVDCNatPolicySet(tenant)) { - throw new Exception("Failed to create NAT policy set in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create NAT policy set in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCAclPolicySet(tenant, true)) { - throw new Exception("Failed to create ACL ingress policy set in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create ACL ingress policy set in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCAclPolicySet(tenant, false)) { - throw new Exception("Failed to create ACL egress policy set in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create ACL egress policy set in VNMC for guest network with vlan " + vlanId); } for (String publicIp : publicIpRulesMap.keySet()) { String policyIdentifier = publicIp.replace('.', '-'); if (!_connection.createTenantVDCDNatPolicy(tenant, policyIdentifier)) { - throw new Exception("Failed to create DNAT policy in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create DNAT policy in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCDNatPolicyRef(tenant, policyIdentifier)) { - throw new Exception("Failed to associate DNAT policy with NAT policy set in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to associate DNAT policy with NAT policy set in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCAclPolicy(tenant, policyIdentifier)) { - throw new Exception("Failed to create ACL policy in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create ACL policy in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCAclPolicyRef(tenant, policyIdentifier, true)) { - throw new Exception("Failed to associate ACL policy with ACL ingress policy set in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to associate ACL policy with ACL ingress policy set in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCAclPolicyRef(tenant, policyIdentifier, false)) { - throw new Exception("Failed to associate ACL policy with ACL egress policy set in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to associate ACL policy with ACL egress policy set in VNMC for guest network with vlan " + vlanId); } for (StaticNatRuleTO rule : publicIpRulesMap.get(publicIp)) { if (rule.revoked()) { if (!_connection.deleteTenantVDCDNatRule(tenant, Long.toString(rule.getId()), policyIdentifier)) { - throw new Exception("Failed to delete DNAT rule in VNMC for guest network with vlan " + vlanId); - } - - if (!_connection.deleteTenantVDCAclRule(tenant, Long.toString(rule.getId()), policyIdentifier)) { - throw new Exception("Failed to delete ACL ingress rule for DNAT in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to delete DNAT rule in VNMC for guest network with vlan " + vlanId); } } else { if (!_connection.createTenantVDCDNatIpPool(tenant, Long.toString(rule.getId()), rule.getDstIp())) { - throw new Exception("Failed to create DNAT ip pool in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create DNAT ip pool in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCDNatRule(tenant, Long.toString(rule.getId()), policyIdentifier, rule.getSrcIp())) { - throw new Exception("Failed to create DNAT rule in VNMC for guest network with vlan " + vlanId); - } - - if (!_connection.createTenantVDCAclRuleForDNat(tenant, - Long.toString(rule.getId()), policyIdentifier, rule.getDstIp())) { - throw new Exception("Failed to create ACL rule for DNAT in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create DNAT rule in VNMC for guest network with vlan " + vlanId); } } } } if (!_connection.associateAclPolicySet(tenant)) { - throw new Exception("Failed to associate source NAT policy set with edge security profile in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to associate source NAT policy set with edge security profile in VNMC for guest network with vlan " + vlanId); } - } catch (Throwable e) { - String msg = "SetSourceNatCommand failed due to " + e.getMessage(); + } catch (ExecutionException e) { + String msg = "SetStaticNatRulesCommand failed due to " + e.getMessage(); s_logger.error(msg, e); return new Answer(cmd, false, msg); } @@ -533,77 +525,66 @@ public class CiscoVnmcResource implements ServerResource { try { if (!_connection.createTenantVDCNatPolicySet(tenant)) { - throw new Exception("Failed to create NAT policy set in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create NAT policy set in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCAclPolicySet(tenant, true)) { - throw new Exception("Failed to create ACL ingress policy set in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create ACL ingress policy set in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCAclPolicySet(tenant, false)) { - throw new Exception("Failed to create ACL egress policy set in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create ACL egress policy set in VNMC for guest network with vlan " + vlanId); } for (String publicIp : publicIpRulesMap.keySet()) { String policyIdentifier = publicIp.replace('.', '-'); if (!_connection.createTenantVDCPFPolicy(tenant, policyIdentifier)) { - throw new Exception("Failed to create PF policy in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create PF policy in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCPFPolicyRef(tenant, policyIdentifier)) { - throw new Exception("Failed to associate PF policy with NAT policy set in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to associate PF policy with NAT policy set in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCAclPolicy(tenant, policyIdentifier)) { - throw new Exception("Failed to create ACL policy in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create ACL policy in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCAclPolicyRef(tenant, policyIdentifier, true)) { - throw new Exception("Failed to associate ACL policy with ACL ingress policy set in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to associate ACL policy with ACL ingress policy set in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCAclPolicyRef(tenant, policyIdentifier, false)) { - throw new Exception("Failed to associate ACL policy with ACL egress policy set in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to associate ACL policy with ACL egress policy set in VNMC for guest network with vlan " + vlanId); } for (PortForwardingRuleTO rule : publicIpRulesMap.get(publicIp)) { if (rule.revoked()) { if (!_connection.deleteTenantVDCPFRule(tenant, Long.toString(rule.getId()), policyIdentifier)) { - throw new Exception("Failed to delete PF rule in VNMC for guest network with vlan " + vlanId); - } - - if (!_connection.deleteTenantVDCAclRule(tenant, Long.toString(rule.getId()), policyIdentifier)) { - throw new Exception("Failed to delete ACL ingress rule for PF in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to delete PF rule in VNMC for guest network with vlan " + vlanId); } } else { if (!_connection.createTenantVDCPFIpPool(tenant, Long.toString(rule.getId()), rule.getDstIp())) { - throw new Exception("Failed to create PF ip pool in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create PF ip pool in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCPFPortPool(tenant, Long.toString(rule.getId()), Integer.toString(rule.getDstPortRange()[0]), Integer.toString(rule.getDstPortRange()[1]))) { - throw new Exception("Failed to create PF port pool in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create PF port pool in VNMC for guest network with vlan " + vlanId); } if (!_connection.createTenantVDCPFRule(tenant, Long.toString(rule.getId()), policyIdentifier, rule.getProtocol().toUpperCase(), rule.getSrcIp(), Integer.toString(rule.getSrcPortRange()[0]), Integer.toString(rule.getSrcPortRange()[1]))) { - throw new Exception("Failed to create PF rule in VNMC for guest network with vlan " + vlanId); - } - - if (!_connection.createTenantVDCAclRuleForPF(tenant, - Long.toString(rule.getId()), policyIdentifier, - rule.getProtocol().toUpperCase(), rule.getDstIp(), - Integer.toString(rule.getDstPortRange()[0]), Integer.toString(rule.getDstPortRange()[1]))) { - throw new Exception("Failed to create ACL rule for PF in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create PF rule in VNMC for guest network with vlan " + vlanId); } } } } if (!_connection.associateAclPolicySet(tenant)) { - throw new Exception("Failed to associate source NAT policy set with edge security profile in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to associate source NAT policy set with edge security profile in VNMC for guest network with vlan " + vlanId); } - } catch (Throwable e) { - String msg = "SetSourceNatCommand failed due to " + e.getMessage(); + } catch (ExecutionException e) { + String msg = "SetPortForwardingRulesCommand failed due to " + e.getMessage(); s_logger.error(msg, e); return new Answer(cmd, false, msg); } @@ -619,24 +600,24 @@ public class CiscoVnmcResource implements ServerResource { return execute(cmd, _numRetries); } - private void createEdgeDeviceProfile(String tenant, List gateways, Long vlanId) throws Exception { + private void createEdgeDeviceProfile(String tenant, List gateways, Long vlanId) throws ExecutionException { // create edge device profile if (!_connection.createTenantVDCEdgeDeviceProfile(tenant)) - throw new Exception("Failed to create tenant edge device profile in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create tenant edge device profile in VNMC for guest network with vlan " + vlanId); // create edge static route policy if (!_connection.createTenantVDCEdgeStaticRoutePolicy(tenant)) - throw new Exception("Failed to create tenant edge static route policy in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create tenant edge static route policy in VNMC for guest network with vlan " + vlanId); // create edge static route for all gateways for (String gateway : gateways) { if (!_connection.createTenantVDCEdgeStaticRoute(tenant, gateway, "0.0.0.0", "0.0.0.0")) - throw new Exception("Failed to create tenant edge static route in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to create tenant edge static route in VNMC for guest network with vlan " + vlanId); } // associate edge if (!_connection.associateTenantVDCEdgeStaticRoutePolicy(tenant)) - throw new Exception("Failed to associate edge static route policy with edge device profile in VNMC for guest network with vlan " + vlanId); + throw new ExecutionException("Failed to associate edge static route policy with edge device profile in VNMC for guest network with vlan " + vlanId); } private Answer execute(CreateLogicalEdgeFirewallCommand cmd, int numRetries) { @@ -644,23 +625,23 @@ public class CiscoVnmcResource implements ServerResource { try { // create tenant if (!_connection.createTenant(tenant)) - throw new Exception("Failed to create tenant in VNMC for guest network with vlan " + cmd.getVlanId()); + throw new ExecutionException("Failed to create tenant in VNMC for guest network with vlan " + cmd.getVlanId()); // create tenant VDC if (!_connection.createTenantVDC(tenant)) - throw new Exception("Failed to create tenant VDC in VNMC for guest network with vlan " + cmd.getVlanId()); + throw new ExecutionException("Failed to create tenant VDC in VNMC for guest network with vlan " + cmd.getVlanId()); // create edge security profile if (!_connection.createTenantVDCEdgeSecurityProfile(tenant)) - throw new Exception("Failed to create tenant edge security profile in VNMC for guest network with vlan " + cmd.getVlanId()); + throw new ExecutionException("Failed to create tenant edge security profile in VNMC for guest network with vlan " + cmd.getVlanId()); // create edge device profile and associated route createEdgeDeviceProfile(tenant, cmd.getPublicGateways(), cmd.getVlanId()); // create logical edge firewall if (!_connection.createEdgeFirewall(tenant, cmd.getPublicIp(), cmd.getInternalIp(), cmd.getPublicSubnet(), cmd.getInternalSubnet())) - throw new Exception("Failed to create edge firewall in VNMC for guest network with vlan " + cmd.getVlanId()); - } catch (Throwable e) { + throw new ExecutionException("Failed to create edge firewall in VNMC for guest network with vlan " + cmd.getVlanId()); + } catch (ExecutionException e) { String msg = "CreateLogicalEdgeFirewallCommand failed due to " + e.getMessage(); s_logger.error(msg, e); return new Answer(cmd, false, msg); @@ -688,7 +669,7 @@ public class CiscoVnmcResource implements ServerResource { s_logger.debug("Created vservice node for ASA appliance in Cisco VSM for vlan " + vlanId); helper.updatePortProfile(cmd.getAsaInPortProfile(), SwitchPortMode.access, params); s_logger.debug("Updated inside port profile for ASA appliance in Cisco VSM with new vlan " + vlanId); - } catch (Throwable e) { + } catch (CloudRuntimeException e) { String msg = "ConfigureVSMForASACommand failed due to " + e.getMessage(); s_logger.error(msg, e); return new Answer(cmd, false, msg); @@ -711,18 +692,18 @@ public class CiscoVnmcResource implements ServerResource { try { Map availableAsaAppliances = _connection.listUnAssocAsa1000v(); if (availableAsaAppliances.isEmpty()) { - throw new Exception("No ASA 1000v available to associate with logical edge firewall for guest vlan " + cmd.getVlanId()); + throw new ExecutionException("No ASA 1000v available to associate with logical edge firewall for guest vlan " + cmd.getVlanId()); } String asaInstanceDn = availableAsaAppliances.get(cmd.getAsaMgmtIp()); if (asaInstanceDn == null) { - throw new Exception("Requested ASA 1000v (" + cmd.getAsaMgmtIp() + ") is not available"); + throw new ExecutionException("Requested ASA 1000v (" + cmd.getAsaMgmtIp() + ") is not available"); } if (!_connection.assignAsa1000v(tenant, asaInstanceDn)) { - throw new Exception("Failed to associate ASA 1000v (" + cmd.getAsaMgmtIp() + ") with logical edge firewall for guest vlan " + cmd.getVlanId()); + throw new ExecutionException("Failed to associate ASA 1000v (" + cmd.getAsaMgmtIp() + ") with logical edge firewall for guest vlan " + cmd.getVlanId()); } - } catch (Throwable e) { + } catch (ExecutionException e) { String msg = "AssociateAsaWithLogicalEdgeFirewallCommand failed due to " + e.getMessage(); s_logger.error(msg, e); return new Answer(cmd, false, msg); @@ -743,7 +724,7 @@ public class CiscoVnmcResource implements ServerResource { String tenant = "vlan-" + cmd.getVlanId(); try { _connection.deleteTenant(tenant); - } catch (Throwable e) { + } catch (ExecutionException e) { String msg = "CleanupLogicalEdgeFirewallCommand failed due to " + e.getMessage(); s_logger.error(msg, e); return new Answer(cmd, false, msg); From a37fa39fe75925716c2b9998d40d4e95e78bbcdd Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Wed, 15 May 2013 16:45:56 +0530 Subject: [PATCH 39/59] multiple fixes to regression tests - remove references to account.account - remove ostypeid references - correct zone.networktype - correct storage_motion assert. skip on invalid environmetn Signed-off-by: Prasanna Santhanam --- test/integration/component/test_accounts.py | 71 ++++---- .../component/test_resource_limits.py | 154 +++++++++--------- .../component/test_storage_motion.py | 6 + .../component/test_vm_passwdenabled.py | 2 +- 4 files changed, 119 insertions(+), 114 deletions(-) diff --git a/test/integration/component/test_accounts.py b/test/integration/component/test_accounts.py index 9cbefe55fdb..b2038a9bd3b 100644 --- a/test/integration/component/test_accounts.py +++ b/test/integration/component/test_accounts.py @@ -78,7 +78,6 @@ class Services: "template": { "displaytext": "Public Template", "name": "Public template", - "ostypeid": 'bc66ada0-99e7-483b-befc-8fb0c2129b70', "url": "http://download.cloud.com/releases/2.0.0/UbuntuServer-10-04-64bit.vhd.bz2", "hypervisor": 'XenServer', "format": 'VHD', @@ -243,7 +242,7 @@ class TestRemoveUserFromAccount(cloudstackTestCase): cls.template = get_template( cls.api_client, cls.zone.id, - cls.services["ostypeid"] + cls.services["ostype"] ) cls.services["virtual_machine"]["zoneid"] = cls.zone.id cls.services["virtual_machine"]["template"] = cls.template.id @@ -568,7 +567,7 @@ class TestNonRootAdminsPrivileges(cloudstackTestCase): self.apiclient, self.services["account"] ) - self.debug("Created account: %s" % account_2.account.name) + self.debug("Created account: %s" % account_2.name) self.cleanup.append(account_2) accounts_response = list_accounts( @@ -886,7 +885,7 @@ class TesttemplateHierarchy(cloudstackTestCase): cls.template = Template.register( cls.api_client, cls.services["template"], - account=cls.account_1.account.name, + account=cls.account_1.name, domainid=cls.domain_1.id ) cls._cleanup = [ @@ -935,7 +934,7 @@ class TesttemplateHierarchy(cloudstackTestCase): templates = list_templates( self.apiclient, templatefilter='self', - account=self.account_1.account.name, + account=self.account_1.name, domainid=self.domain_1.id ) self.assertEqual( @@ -960,7 +959,7 @@ class TesttemplateHierarchy(cloudstackTestCase): templates = list_templates( self.apiclient, templatefilter='self', - account=self.account_2.account.name, + account=self.account_2.name, domainid=self.domain_2.id ) self.assertEqual( @@ -1033,15 +1032,15 @@ class TestAddVmToSubDomain(cloudstackTestCase): cls.template = get_template( cls.api_client, cls.zone.id, - cls.services["ostypeid"] + cls.services["ostype"] ) cls.services["virtual_machine"]["zoneid"] = cls.zone.id cls.vm_1 = VirtualMachine.create( cls.api_client, cls.services["virtual_machine"], templateid=cls.template.id, - accountid=cls.account_1.account.name, - domainid=cls.account_1.account.domainid, + accountid=cls.account_1.name, + domainid=cls.account_1.domainid, serviceofferingid=cls.service_offering.id ) @@ -1049,8 +1048,8 @@ class TestAddVmToSubDomain(cloudstackTestCase): cls.api_client, cls.services["virtual_machine"], templateid=cls.template.id, - accountid=cls.account_2.account.name, - domainid=cls.account_2.account.domainid, + accountid=cls.account_2.name, + domainid=cls.account_2.domainid, serviceofferingid=cls.service_offering.id ) cls._cleanup = [ @@ -1625,7 +1624,7 @@ class TestDomainForceRemove(cloudstackTestCase): cls.template = get_template( cls.api_client, cls.zone.id, - cls.services["ostypeid"] + cls.services["ostype"] ) cls.services["virtual_machine"]["zoneid"] = cls.zone.id @@ -1719,31 +1718,31 @@ class TestDomainForceRemove(cloudstackTestCase): ) self.debug("Deploying virtual machine in account 1: %s" % - self.account_1.account.name) + self.account_1.name) vm_1 = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], templateid=self.template.id, - accountid=self.account_1.account.name, - domainid=self.account_1.account.domainid, + accountid=self.account_1.name, + domainid=self.account_1.domainid, serviceofferingid=self.service_offering.id ) self.debug("Deploying virtual machine in account 2: %s" % - self.account_2.account.name) + self.account_2.name) vm_2 = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], templateid=self.template.id, - accountid=self.account_2.account.name, - domainid=self.account_2.account.domainid, + accountid=self.account_2.name, + domainid=self.account_2.domainid, serviceofferingid=self.service_offering.id ) networks = Network.list( self.apiclient, - account=self.account_1.account.name, - domainid=self.account_1.account.domainid, + account=self.account_1.name, + domainid=self.account_1.domainid, listall=True ) self.assertEqual( @@ -1753,13 +1752,13 @@ class TestDomainForceRemove(cloudstackTestCase): ) network_1 = networks[0] self.debug("Default network in account 1: %s is %s" % ( - self.account_1.account.name, + self.account_1.name, network_1.name)) src_nat_list = PublicIPAddress.list( self.apiclient, associatednetworkid=network_1.id, - account=self.account_1.account.name, - domainid=self.account_1.account.domainid, + account=self.account_1.name, + domainid=self.account_1.domainid, listall=True, issourcenat=True, ) @@ -1823,8 +1822,8 @@ class TestDomainForceRemove(cloudstackTestCase): self.debug("Checking if the resources in domain are deleted or not..") accounts = Account.list( self.apiclient, - name=self.account_1.account.name, - domainid=self.account_1.account.domainid, + name=self.account_1.name, + domainid=self.account_1.domainid, listall=True ) @@ -1894,31 +1893,31 @@ class TestDomainForceRemove(cloudstackTestCase): self.cleanup.append(self.service_offering) self.debug("Deploying virtual machine in account 1: %s" % - self.account_1.account.name) + self.account_1.name) vm_1 = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], templateid=self.template.id, - accountid=self.account_1.account.name, - domainid=self.account_1.account.domainid, + accountid=self.account_1.name, + domainid=self.account_1.domainid, serviceofferingid=self.service_offering.id ) self.debug("Deploying virtual machine in account 2: %s" % - self.account_2.account.name) + self.account_2.name) vm_2 = VirtualMachine.create( self.apiclient, self.services["virtual_machine"], templateid=self.template.id, - accountid=self.account_2.account.name, - domainid=self.account_2.account.domainid, + accountid=self.account_2.name, + domainid=self.account_2.domainid, serviceofferingid=self.service_offering.id ) networks = Network.list( self.apiclient, - account=self.account_1.account.name, - domainid=self.account_1.account.domainid, + account=self.account_1.name, + domainid=self.account_1.domainid, listall=True ) self.assertEqual( @@ -1928,13 +1927,13 @@ class TestDomainForceRemove(cloudstackTestCase): ) network_1 = networks[0] self.debug("Default network in account 1: %s is %s" % ( - self.account_1.account.name, + self.account_1.name, network_1.name)) src_nat_list = PublicIPAddress.list( self.apiclient, associatednetworkid=network_1.id, - account=self.account_1.account.name, - domainid=self.account_1.account.domainid, + account=self.account_1.name, + domainid=self.account_1.domainid, listall=True, issourcenat=True, ) diff --git a/test/integration/component/test_resource_limits.py b/test/integration/component/test_resource_limits.py index 1d876b6195f..ea79c07c376 100644 --- a/test/integration/component/test_resource_limits.py +++ b/test/integration/component/test_resource_limits.py @@ -191,25 +191,25 @@ class TestResourceLimitsAccount(cloudstackTestCase): self.debug( "Updating instance resource limit for account: %s" % - self.account_1.account.name) + self.account_1.name) # Set usage_vm=1 for Account 1 update_resource_limit( self.apiclient, 0, # Instance - account=self.account_1.account.name, - domainid=self.account_1.account.domainid, + account=self.account_1.name, + domainid=self.account_1.domainid, max=1 ) self.debug( "Deploying VM instance in account: %s" % - self.account_1.account.name) + self.account_1.name) virtual_machine = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, - accountid=self.account_1.account.name, - domainid=self.account_1.account.domainid, + accountid=self.account_1.name, + domainid=self.account_1.domainid, serviceofferingid=self.service_offering.id ) self.cleanup.append(virtual_machine) @@ -227,20 +227,20 @@ class TestResourceLimitsAccount(cloudstackTestCase): self.apiclient, self.services["server"], templateid=self.template.id, - accountid=self.account_1.account.name, - domainid=self.account_1.account.domainid, + accountid=self.account_1.name, + domainid=self.account_1.domainid, serviceofferingid=self.service_offering.id ) self.debug( "Deploying VM instance in account: %s" % - self.account_2.account.name) + self.account_2.name) # Start 2 instances for account_2 virtual_machine_1 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, - accountid=self.account_2.account.name, - domainid=self.account_2.account.domainid, + accountid=self.account_2.name, + domainid=self.account_2.domainid, serviceofferingid=self.service_offering.id ) self.cleanup.append(virtual_machine_1) @@ -253,13 +253,13 @@ class TestResourceLimitsAccount(cloudstackTestCase): self.debug( "Deploying VM instance in account: %s" % - self.account_2.account.name) + self.account_2.name) virtual_machine_2 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, - accountid=self.account_2.account.name, - domainid=self.account_2.account.domainid, + accountid=self.account_2.name, + domainid=self.account_2.domainid, serviceofferingid=self.service_offering.id ) self.cleanup.append(virtual_machine_2) @@ -287,25 +287,25 @@ class TestResourceLimitsAccount(cloudstackTestCase): self.debug( "Updating public IP resource limit for account: %s" % - self.account_1.account.name) + self.account_1.name) # Set usage_vm=1 for Account 1 update_resource_limit( self.apiclient, 1, # Public Ip - account=self.account_1.account.name, - domainid=self.account_1.account.domainid, + account=self.account_1.name, + domainid=self.account_1.domainid, max=2 ) self.debug( "Deploying VM instance in account: %s" % - self.account_1.account.name) + self.account_1.name) virtual_machine_1 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, - accountid=self.account_1.account.name, - domainid=self.account_1.account.domainid, + accountid=self.account_1.name, + domainid=self.account_1.domainid, serviceofferingid=self.service_offering.id ) self.cleanup.append(virtual_machine_1) @@ -318,14 +318,14 @@ class TestResourceLimitsAccount(cloudstackTestCase): self.debug( "Deploying VM instance in account: %s" % - self.account_2.account.name) + self.account_2.name) # Create VM for second account virtual_machine_2 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, - accountid=self.account_2.account.name, - domainid=self.account_2.account.domainid, + accountid=self.account_2.name, + domainid=self.account_2.domainid, serviceofferingid=self.service_offering.id ) self.cleanup.append(virtual_machine_2) @@ -431,25 +431,25 @@ class TestResourceLimitsAccount(cloudstackTestCase): self.debug( "Updating public IP resource limit for account: %s" % - self.account_1.account.name) + self.account_1.name) # Set usage_vm=1 for Account 1 update_resource_limit( self.apiclient, 3, # Snapshot - account=self.account_1.account.name, - domainid=self.account_1.account.domainid, + account=self.account_1.name, + domainid=self.account_1.domainid, max=1 ) self.debug( "Deploying VM instance in account: %s" % - self.account_1.account.name) + self.account_1.name) virtual_machine_1 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, - accountid=self.account_1.account.name, - domainid=self.account_1.account.domainid, + accountid=self.account_1.name, + domainid=self.account_1.domainid, serviceofferingid=self.service_offering.id ) self.cleanup.append(virtual_machine_1) @@ -462,14 +462,14 @@ class TestResourceLimitsAccount(cloudstackTestCase): self.debug( "Deploying VM instance in account: %s" % - self.account_1.account.name) + self.account_1.name) # Create VM for second account virtual_machine_2 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, - accountid=self.account_2.account.name, - domainid=self.account_2.account.domainid, + accountid=self.account_2.name, + domainid=self.account_2.domainid, serviceofferingid=self.service_offering.id ) self.cleanup.append(virtual_machine_2) @@ -498,8 +498,8 @@ class TestResourceLimitsAccount(cloudstackTestCase): # Create a snapshot from the ROOTDISK (Account 1) snapshot_1 = Snapshot.create(self.apiclient, volumes[0].id, - account=self.account_1.account.name, - domainid=self.account_1.account.domainid, + account=self.account_1.name, + domainid=self.account_1.domainid, ) self.cleanup.append(snapshot_1) # Verify Snapshot state @@ -516,8 +516,8 @@ class TestResourceLimitsAccount(cloudstackTestCase): with self.assertRaises(Exception): Snapshot.create(self.apiclient, volumes[0].id, - account=self.account_1.account.name, - domainid=self.account_1.account.domainid, + account=self.account_1.name, + domainid=self.account_1.domainid, ) # Get the Root disk of VM @@ -538,8 +538,8 @@ class TestResourceLimitsAccount(cloudstackTestCase): # Create a snapshot from the ROOTDISK (Account 2) snapshot_2 = Snapshot.create(self.apiclient, volumes[0].id, - account=self.account_2.account.name, - domainid=self.account_2.account.domainid, + account=self.account_2.name, + domainid=self.account_2.domainid, ) self.cleanup.append(snapshot_2) # Verify Snapshot state @@ -556,8 +556,8 @@ class TestResourceLimitsAccount(cloudstackTestCase): # Create a second snapshot from the ROOTDISK (Account 2) snapshot_3 = Snapshot.create(self.apiclient, volumes[0].id, - account=self.account_2.account.name, - domainid=self.account_2.account.domainid, + account=self.account_2.name, + domainid=self.account_2.domainid, ) self.cleanup.append(snapshot_3) # Verify Snapshot state @@ -587,25 +587,25 @@ class TestResourceLimitsAccount(cloudstackTestCase): self.debug( "Updating volume resource limit for account: %s" % - self.account_1.account.name) + self.account_1.name) # Set usage_vm=1 for Account 1 update_resource_limit( self.apiclient, 2, # Volume - account=self.account_1.account.name, - domainid=self.account_1.account.domainid, + account=self.account_1.name, + domainid=self.account_1.domainid, max=2 ) self.debug( - "Deploying VM for account: %s" % self.account_1.account.name) + "Deploying VM for account: %s" % self.account_1.name) virtual_machine_1 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, - accountid=self.account_1.account.name, - domainid=self.account_1.account.domainid, + accountid=self.account_1.name, + domainid=self.account_1.domainid, serviceofferingid=self.service_offering.id ) self.cleanup.append(virtual_machine_1) @@ -617,15 +617,15 @@ class TestResourceLimitsAccount(cloudstackTestCase): ) self.debug( - "Deploying VM for account: %s" % self.account_2.account.name) + "Deploying VM for account: %s" % self.account_2.name) # Create VM for second account virtual_machine_2 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, - accountid=self.account_2.account.name, - domainid=self.account_2.account.domainid, + accountid=self.account_2.name, + domainid=self.account_2.domainid, serviceofferingid=self.service_offering.id ) self.cleanup.append(virtual_machine_2) @@ -637,13 +637,13 @@ class TestResourceLimitsAccount(cloudstackTestCase): ) self.debug( - "Create a data volume for account: %s" % self.account_1.account.name) + "Create a data volume for account: %s" % self.account_1.name) volume_1 = Volume.create( self.apiclient, self.services["volume"], zoneid=self.zone.id, - account=self.account_1.account.name, - domainid=self.account_1.account.domainid, + account=self.account_1.name, + domainid=self.account_1.domainid, diskofferingid=self.disk_offering.id ) self.cleanup.append(volume_1) @@ -663,20 +663,20 @@ class TestResourceLimitsAccount(cloudstackTestCase): self.apiclient, self.services["volume"], zoneid=self.zone.id, - account=self.account_1.account.name, - domainid=self.account_1.account.domainid, + account=self.account_1.name, + domainid=self.account_1.domainid, diskofferingid=self.disk_offering.id ) self.debug( - "Create a data volume for account: %s" % self.account_2.account.name) + "Create a data volume for account: %s" % self.account_2.name) # Create volume for Account 2 volume_2 = Volume.create( self.apiclient, self.services["volume"], zoneid=self.zone.id, - account=self.account_2.account.name, - domainid=self.account_2.account.domainid, + account=self.account_2.name, + domainid=self.account_2.domainid, diskofferingid=self.disk_offering.id ) self.cleanup.append(volume_2) @@ -691,14 +691,14 @@ class TestResourceLimitsAccount(cloudstackTestCase): ) self.debug( - "Create a data volume for account: %s" % self.account_2.account.name) + "Create a data volume for account: %s" % self.account_2.name) # Create a second volume from the ROOTDISK (Account 2) volume_3 = Volume.create( self.apiclient, self.services["volume"], zoneid=self.zone.id, - account=self.account_2.account.name, - domainid=self.account_2.account.domainid, + account=self.account_2.name, + domainid=self.account_2.domainid, diskofferingid=self.disk_offering.id ) self.cleanup.append(volume_3) @@ -727,25 +727,25 @@ class TestResourceLimitsAccount(cloudstackTestCase): self.debug( "Updating template resource limit for account: %s" % - self.account_1.account.name) + self.account_1.name) # Set usage_vm=1 for Account 1 update_resource_limit( self.apiclient, 4, # Template - account=self.account_1.account.name, - domainid=self.account_1.account.domainid, + account=self.account_1.name, + domainid=self.account_1.domainid, max=1 ) self.debug( "Updating volume resource limit for account: %s" % - self.account_1.account.name) + self.account_1.name) virtual_machine_1 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, - accountid=self.account_1.account.name, - domainid=self.account_1.account.domainid, + accountid=self.account_1.name, + domainid=self.account_1.domainid, serviceofferingid=self.service_offering.id ) self.cleanup.append(virtual_machine_1) @@ -758,14 +758,14 @@ class TestResourceLimitsAccount(cloudstackTestCase): self.debug( "Deploying virtual machine for account: %s" % - self.account_2.account.name) + self.account_2.name) # Create VM for second account virtual_machine_2 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, - accountid=self.account_2.account.name, - domainid=self.account_2.account.domainid, + accountid=self.account_2.name, + domainid=self.account_2.domainid, serviceofferingid=self.service_offering.id ) self.cleanup.append(virtual_machine_2) @@ -798,8 +798,8 @@ class TestResourceLimitsAccount(cloudstackTestCase): self.apiclient, self.services["template"], volumeid=volume.id, - account=self.account_1.account.name, - domainid=self.account_1.account.domainid, + account=self.account_1.name, + domainid=self.account_1.domainid, ) self.cleanup.append(template_1) @@ -816,8 +816,8 @@ class TestResourceLimitsAccount(cloudstackTestCase): self.apiclient, self.services["template"], volumeid=volume.id, - account=self.account_1.account.name, - domainid=self.account_1.account.domainid, + account=self.account_1.name, + domainid=self.account_1.domainid, ) virtual_machine_2.stop(self.apiclient) # Get the Root disk of VM @@ -841,8 +841,8 @@ class TestResourceLimitsAccount(cloudstackTestCase): self.apiclient, self.services["template"], volumeid=volume.id, - account=self.account_2.account.name, - domainid=self.account_2.account.domainid, + account=self.account_2.name, + domainid=self.account_2.domainid, ) self.cleanup.append(template_2) @@ -859,8 +859,8 @@ class TestResourceLimitsAccount(cloudstackTestCase): self.apiclient, self.services["template"], volumeid=volume.id, - account=self.account_2.account.name, - domainid=self.account_2.account.domainid, + account=self.account_2.name, + domainid=self.account_2.domainid, ) self.cleanup.append(template_3) diff --git a/test/integration/component/test_storage_motion.py b/test/integration/component/test_storage_motion.py index c05d79e6861..cf110d34e61 100644 --- a/test/integration/component/test_storage_motion.py +++ b/test/integration/component/test_storage_motion.py @@ -178,6 +178,12 @@ class TestStorageMotion(cloudstackTestCase): # Migrate to a host that requires storage motion hosts[:] = [host for host in hosts if host.requiresStorageMotion] + self.assert_(hosts is not None, msg="No valid hosts for storage motion") + self.assert_(len(hosts)>0, msg="No valid hosts for storage motion. Skipping") + if hosts is None or len(hosts) == 0: + self.skipTest("No valid hosts for storage motion. Skipping") + + host = hosts[0] self.debug("Migrating VM-ID: %s to Host: %s" % ( self.virtual_machine.id, diff --git a/test/integration/component/test_vm_passwdenabled.py b/test/integration/component/test_vm_passwdenabled.py index 65b068dc2d2..e89253c407a 100644 --- a/test/integration/component/test_vm_passwdenabled.py +++ b/test/integration/component/test_vm_passwdenabled.py @@ -83,7 +83,7 @@ class TestVMPasswordEnabled(cloudstackTestCase): # Get Zone, Domain and templates domain = get_domain(cls.api_client, cls.services) zone = get_zone(cls.api_client, cls.services) - cls.services['mode'] = cls.zone.networktype + cls.services['mode'] = zone.networktype template = get_template( cls.api_client, zone.id, From e26081731898e2b3de53fdfb9f58d6fdb017f09f Mon Sep 17 00:00:00 2001 From: Saksham Srivastava Date: Tue, 14 May 2013 10:39:20 +0530 Subject: [PATCH 40/59] CLOUDSTACK-2130: UpdateDefaultNicForVirtualMachine api should also create usage events for updating new default network Signed-off-by: Mice Xia --- server/src/com/cloud/vm/UserVmManagerImpl.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 8b1a9af0341..f2c44a419da 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -1024,6 +1024,13 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use throw new CloudRuntimeException("Failed to find a nic profile for the existing default network. This is bad and probably means some sort of configuration corruption"); } + Network oldDefaultNetwork = null; + oldDefaultNetwork = _networkModel.getDefaultNetworkForVm(vmId); + long oldNetworkOfferingId = -1L; + + if(oldDefaultNetwork!=null) { + oldNetworkOfferingId = oldDefaultNetwork.getNetworkOfferingId(); + } NicVO existingVO = _nicDao.findById(existing.id); Integer chosenID = nic.getDeviceId(); Integer existingID = existing.getDeviceId(); @@ -1055,6 +1062,16 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use throw new CloudRuntimeException("Failed to change default nic to " + nic + " and now we have no default"); } else if (newdefault.getId() == nic.getNetworkId()) { s_logger.debug("successfully set default network to " + network + " for " + vmInstance); + String nicIdString = Long.toString(nic.getId()); + long newNetworkOfferingId = network.getNetworkOfferingId(); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_REMOVE, vmInstance.getAccountId(), vmInstance.getDataCenterId(), + vmInstance.getId(), nicIdString, oldNetworkOfferingId, null, 1L, VirtualMachine.class.getName(), vmInstance.getUuid()); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_ASSIGN, vmInstance.getAccountId(), vmInstance.getDataCenterId(), + vmInstance.getId(), nicIdString, newNetworkOfferingId, null, 1L, VirtualMachine.class.getName(), vmInstance.getUuid()); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_REMOVE, vmInstance.getAccountId(), vmInstance.getDataCenterId(), + vmInstance.getId(), nicIdString, newNetworkOfferingId, null, 0L, VirtualMachine.class.getName(), vmInstance.getUuid()); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_ASSIGN, vmInstance.getAccountId(), vmInstance.getDataCenterId(), + vmInstance.getId(), nicIdString, oldNetworkOfferingId, null, 0L, VirtualMachine.class.getName(), vmInstance.getUuid()); return _vmDao.findById(vmInstance.getId()); } From e7fef86c8086a3bad3a5f3aacaa39dd5ddef3ab4 Mon Sep 17 00:00:00 2001 From: Mice Xia Date: Thu, 16 May 2013 15:19:05 +0800 Subject: [PATCH 41/59] CLOUDSTACK-2456 usage:usage parser throws runtime exception while parsing networkoffering usage --- .../com/cloud/usage/dao/UsageNetworkOfferingDaoImpl.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/engine/schema/src/com/cloud/usage/dao/UsageNetworkOfferingDaoImpl.java b/engine/schema/src/com/cloud/usage/dao/UsageNetworkOfferingDaoImpl.java index c3fc5a6f6c1..4ed7c27d491 100644 --- a/engine/schema/src/com/cloud/usage/dao/UsageNetworkOfferingDaoImpl.java +++ b/engine/schema/src/com/cloud/usage/dao/UsageNetworkOfferingDaoImpl.java @@ -118,18 +118,18 @@ public class UsageNetworkOfferingDaoImpl extends GenericDaoBase Date: Thu, 16 May 2013 16:00:02 +0800 Subject: [PATCH 42/59] instead of using '==', use equals() to test Long value equality --- server/src/com/cloud/api/ApiDispatcher.java | 2 +- server/src/com/cloud/api/query/QueryManagerImpl.java | 2 +- server/src/com/cloud/capacity/CapacityManagerImpl.java | 2 +- .../AgentBasedStandaloneConsoleProxyManager.java | 2 +- server/src/com/cloud/network/NetworkServiceImpl.java | 2 +- server/src/com/cloud/network/vpc/NetworkACLServiceImpl.java | 4 ++-- server/src/com/cloud/server/ManagementServerImpl.java | 6 +++--- server/src/com/cloud/template/TemplateManagerImpl.java | 6 +++--- server/src/com/cloud/vm/UserVmManagerImpl.java | 2 +- server/src/com/cloud/vm/VirtualMachineManagerImpl.java | 2 +- 10 files changed, 15 insertions(+), 15 deletions(-) diff --git a/server/src/com/cloud/api/ApiDispatcher.java b/server/src/com/cloud/api/ApiDispatcher.java index b4437ce6193..b7d08e2c872 100755 --- a/server/src/com/cloud/api/ApiDispatcher.java +++ b/server/src/com/cloud/api/ApiDispatcher.java @@ -168,7 +168,7 @@ public class ApiDispatcher { pageSize = Long.valueOf((String) pageSizeObj); } - if ((unpackedParams.get(ApiConstants.PAGE) == null) && (pageSize != null && pageSize != BaseListCmd.PAGESIZE_UNLIMITED)) { + if ((unpackedParams.get(ApiConstants.PAGE) == null) && (pageSize != null && !pageSize.equals(BaseListCmd.PAGESIZE_UNLIMITED))) { ServerApiException ex = new ServerApiException(ApiErrorCode.PARAM_ERROR, "\"page\" parameter is required when \"pagesize\" is specified"); ex.setCSErrorCode(CSExceptionErrorCode.getCSErrCode(ex.getClass().getName())); throw ex; diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index 9872c3a53ef..a126925e5f0 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -2346,7 +2346,7 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { // offerings private boolean isPermissible(Long accountDomainId, Long offeringDomainId) { - if (accountDomainId == offeringDomainId) { + if (accountDomainId.equals(offeringDomainId)) { return true; // account and service offering in same domain } diff --git a/server/src/com/cloud/capacity/CapacityManagerImpl.java b/server/src/com/cloud/capacity/CapacityManagerImpl.java index 1eb2fa5894a..e7101c6755b 100755 --- a/server/src/com/cloud/capacity/CapacityManagerImpl.java +++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java @@ -681,7 +681,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, if ((newState == State.Starting || newState == State.Migrating || event == Event.AgentReportMigrated) && vm.getHostId() != null) { boolean fromLastHost = false; - if (vm.getLastHostId() == vm.getHostId()) { + if (vm.getLastHostId().equals(vm.getHostId())) { s_logger.debug("VM starting again on the last host it was stopped on"); fromLastHost = true; } diff --git a/server/src/com/cloud/consoleproxy/AgentBasedStandaloneConsoleProxyManager.java b/server/src/com/cloud/consoleproxy/AgentBasedStandaloneConsoleProxyManager.java index 3cfdf22bf08..23663334dbd 100644 --- a/server/src/com/cloud/consoleproxy/AgentBasedStandaloneConsoleProxyManager.java +++ b/server/src/com/cloud/consoleproxy/AgentBasedStandaloneConsoleProxyManager.java @@ -57,7 +57,7 @@ AgentBasedConsoleProxyManager { if (allocatedHost == null) { /*Is there a consoleproxy agent running in the same pod?*/ for (HostVO hv : hosts) { - if (hv.getType() == Host.Type.ConsoleProxy && hv.getPodId() == host.getPodId()) { + if (hv.getType() == Host.Type.ConsoleProxy && hv.getPodId().equals(host.getPodId())) { allocatedHost = hv; break; } diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 2bc3913a99e..ed9a8c4ece7 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -1264,7 +1264,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { throw new InvalidParameterValueException("Unable to find specified NetworkACL"); } - if(vpcId != acl.getVpcId()){ + if(!vpcId.equals(acl.getVpcId())){ throw new InvalidParameterValueException("ACL: "+aclId+" do not belong to the VPC"); } } diff --git a/server/src/com/cloud/network/vpc/NetworkACLServiceImpl.java b/server/src/com/cloud/network/vpc/NetworkACLServiceImpl.java index 00c90d5164e..4d5d98192fa 100644 --- a/server/src/com/cloud/network/vpc/NetworkACLServiceImpl.java +++ b/server/src/com/cloud/network/vpc/NetworkACLServiceImpl.java @@ -182,7 +182,7 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ throw new InvalidParameterValueException("Unable to find Vpc associated with the NetworkACL"); } _accountMgr.checkAccess(caller, null, true, vpc); - if(gateway.getVpcId() != acl.getVpcId()){ + if(!gateway.getVpcId().equals(acl.getVpcId())){ throw new InvalidParameterValueException("private gateway: "+privateGatewayId+" and ACL: "+aclId+" do not belong to the same VPC"); } } @@ -225,7 +225,7 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ } _accountMgr.checkAccess(caller, null, true, vpc); - if(network.getVpcId() != acl.getVpcId()){ + if(!network.getVpcId().equals(acl.getVpcId())){ throw new InvalidParameterValueException("Network: "+networkId+" and ACL: "+aclId+" do not belong to the same VPC"); } } diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 137f07e1527..bc3728203bc 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -1152,7 +1152,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe if (volumePools.isEmpty()) { allHosts.remove(host); } else { - if (host.getClusterId() != srcHost.getClusterId() || usesLocal) { + if (!host.getClusterId().equals(srcHost.getClusterId()) || usesLocal) { requiresStorageMotion.put(host, true); } } @@ -1887,7 +1887,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe } // Don't allow to modify system template - if (id == Long.valueOf(1)) { + if (id.equals(Long.valueOf(1))) { InvalidParameterValueException ex = new InvalidParameterValueException("Unable to update template/iso of specified id"); ex.addProxyObject(template, id, "templateId"); throw ex; @@ -2414,7 +2414,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe public int compare(SummedCapacity arg0, SummedCapacity arg1) { if (arg0.getPercentUsed() < arg1.getPercentUsed()) { return 1; - } else if (arg0.getPercentUsed() == arg1.getPercentUsed()) { + } else if (arg0.getPercentUsed().equals(arg1.getPercentUsed())) { return 0; } return -1; diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index a8729e1490a..d4976cdc357 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -993,7 +993,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } //Verify parameters - if (sourceZoneId == destZoneId) { + if (sourceZoneId.equals(destZoneId)) { throw new InvalidParameterValueException("Please specify different source and destination zones."); } @@ -1522,7 +1522,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, Account caller = UserContext.current().getCaller(); Long id = cmd.getId(); - if (id == Long.valueOf(1)) { + if (id.equals(Long.valueOf(1))) { throw new PermissionDeniedException("unable to list permissions for " + cmd.getMediaType() + " with id " + id); } @@ -1614,7 +1614,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, throw new InvalidParameterValueException("unable to update permissions for " + mediaType + " with id " + id + " as it is removed "); } - if (id == Long.valueOf(1)) { + if (id.equals(Long.valueOf(1))) { throw new InvalidParameterValueException("unable to update permissions for " + mediaType + " with id " + id); } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index f2c44a419da..fe80d2cb7e6 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -3708,7 +3708,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use List vmVolumes = _volsDao.findUsableVolumesForInstance(vm.getId()); Map volToPoolObjectMap = new HashMap(); - if (!isVMUsingLocalStorage(vm) && destinationHost.getClusterId() == srcHost.getClusterId()) { + if (!isVMUsingLocalStorage(vm) && destinationHost.getClusterId().equals(srcHost.getClusterId())) { if (volumeToPool.isEmpty()) { // If the destination host is in the same cluster and volumes do not have to be migrated across pools // then fail the call. migrateVirtualMachine api should have been used. diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index 521b5e0c582..d153bb2cafe 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -1322,7 +1322,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac if (migrationResult) { //if the vm is migrated to different pod in basic mode, need to reallocate ip - if (vm.getPodIdToDeployIn() != destPool.getPodId()) { + if (!vm.getPodIdToDeployIn().equals(destPool.getPodId())) { DataCenterDeployment plan = new DataCenterDeployment(vm.getDataCenterId(), destPool.getPodId(), null, null, null, null); VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vm, null, null, null, null); _networkMgr.reallocate(vmProfile, plan); From e26442f7d0abd9cf7cfefc85585fdd669af395a6 Mon Sep 17 00:00:00 2001 From: Mice Xia Date: Thu, 16 May 2013 16:18:53 +0800 Subject: [PATCH 43/59] instead of '==', use equals() to compare two strings in cloud-server --- .../src/com/cloud/configuration/ConfigurationManagerImpl.java | 2 +- server/src/com/cloud/test/DatabaseConfig.java | 4 ++-- server/src/com/cloud/vm/UserVmManagerImpl.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 96145a2d3b3..887878254b3 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -2491,7 +2491,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if ( vlans != null && vlans.size() > 0 ) { if ( vlanId == null ) { vlanId = vlan.getVlanTag(); - } else if ( vlan.getVlanTag() != vlanId ) { + } else if (!vlan.getVlanTag().equals(vlanId)) { throw new InvalidParameterValueException("there is already one vlan " + vlan.getVlanTag() + " on network :" + + network.getId() + ", only one vlan is allowed on guest network"); } diff --git a/server/src/com/cloud/test/DatabaseConfig.java b/server/src/com/cloud/test/DatabaseConfig.java index 7c10f98abf4..70c81781959 100755 --- a/server/src/com/cloud/test/DatabaseConfig.java +++ b/server/src/com/cloud/test/DatabaseConfig.java @@ -792,14 +792,14 @@ public class DatabaseConfig { } // If a netmask was provided, check that the startIP, endIP, and gateway all belong to the same subnet - if (netmask != null && netmask != "") { + if (netmask != null && !netmask.equals("")) { if (endIP != null) { if (!IPRangeConfig.sameSubnet(startIP, endIP, netmask)) { printError("Start and end IPs for the public IP range must be in the same subnet, as per the provided netmask."); } } - if (gateway != null && gateway != "") { + if (gateway != null && !gateway.equals("")) { if (!IPRangeConfig.sameSubnet(startIP, gateway, netmask)) { printError("The start IP for the public IP range must be in the same subnet as the gateway, as per the provided netmask."); } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index fe80d2cb7e6..7416cae61de 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -1673,7 +1673,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use String description = ""; - if (displayName != vmInstance.getDisplayName()) { + if (!displayName.equals(vmInstance.getDisplayName())) { description += "New display name: " + displayName + ". "; } From b4903ebbead34d02ba9ee445522473467d295519 Mon Sep 17 00:00:00 2001 From: Gavin Lee Date: Thu, 16 May 2013 16:19:11 +0800 Subject: [PATCH 44/59] $PRODUCT; should be &PRODUCT; to represent entity CloudStack --- docs/en-US/build-rpm.xml | 8 ++++---- docs/en-US/deployment-architecture-overview.xml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/en-US/build-rpm.xml b/docs/en-US/build-rpm.xml index 574065833ff..7caf924bfe4 100644 --- a/docs/en-US/build-rpm.xml +++ b/docs/en-US/build-rpm.xml @@ -41,9 +41,9 @@ under the License. You probably want to ensure that your environment variables will survive a logout/reboot. Be sure to update ~/.bashrc with the PATH and JAVA_HOME variables. - Building RPMs for $PRODUCT; is fairly simple. Assuming you already have the source downloaded and have uncompressed the tarball into a local directory, you're going to be able to generate packages in just a few minutes. + Building RPMs for &PRODUCT; is fairly simple. Assuming you already have the source downloaded and have uncompressed the tarball into a local directory, you're going to be able to generate packages in just a few minutes. Packaging has Changed - If you've created packages for $PRODUCT; previously, you should be aware that the process has changed considerably since the project has moved to using Apache Maven. Please be sure to follow the steps in this section closely. + If you've created packages for &PRODUCT; previously, you should be aware that the process has changed considerably since the project has moved to using Apache Maven. Please be sure to follow the steps in this section closely.
Generating RPMS @@ -69,7 +69,7 @@ under the License. Configuring your systems to use your new yum repository Now that your yum repository is populated with RPMs and metadata - we need to configure the machines that need to install $PRODUCT;. + we need to configure the machines that need to install &PRODUCT;. Create a file named /etc/yum.repos.d/cloudstack.repo with this information: [apache-cloudstack] @@ -79,7 +79,7 @@ under the License. gpgcheck=0 - Completing this step will allow you to easily install $PRODUCT; on a number of machines across the network. + Completing this step will allow you to easily install &PRODUCT; on a number of machines across the network.
diff --git a/docs/en-US/deployment-architecture-overview.xml b/docs/en-US/deployment-architecture-overview.xml index e3103c52c1c..835898ced7f 100644 --- a/docs/en-US/deployment-architecture-overview.xml +++ b/docs/en-US/deployment-architecture-overview.xml @@ -49,7 +49,7 @@ multi-node Management Server installation and up to tens of thousands of hosts using any of several advanced networking setups. For information about deployment options, see the "Choosing a Deployment Architecture" - section of the $PRODUCT; Installation Guide. + section of the &PRODUCT; Installation Guide. From 6ae6c2b8b603fc8d44d6bec57caf765d843ca27d Mon Sep 17 00:00:00 2001 From: Gavin Lee Date: Thu, 16 May 2013 17:19:22 +0800 Subject: [PATCH 45/59] A space char needed after &PRODUCT; entity representation --- docs/en-US/event-framework.xml | 2 +- docs/en-US/gslb.xml | 2 +- docs/en-US/ipv6-support.xml | 2 +- docs/en-US/vmware-cluster-config-dvswitch.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/en-US/event-framework.xml b/docs/en-US/event-framework.xml index 88c45c9033d..0f62fac1407 100644 --- a/docs/en-US/event-framework.xml +++ b/docs/en-US/event-framework.xml @@ -24,7 +24,7 @@ Event notification framework provides a means for the Management Server components to publish and subscribe to &PRODUCT; events. Event notification is achieved by implementing the concept of event bus abstraction in the Management Server. An event bus is introduced in the - Management Server that allows the &PRODUCT;components and extension plug-ins to subscribe to the + Management Server that allows the &PRODUCT; components and extension plug-ins to subscribe to the events by using the Advanced Message Queuing Protocol (AMQP) client. In &PRODUCT;, a default implementation of event bus is provided as a plug-in that uses the RabbitMQ AMQP client. The AMQP client pushes the published events to a compatible AMQP server. Therefore all the &PRODUCT; diff --git a/docs/en-US/gslb.xml b/docs/en-US/gslb.xml index d5d2d203265..968e8e2cefa 100644 --- a/docs/en-US/gslb.xml +++ b/docs/en-US/gslb.xml @@ -45,7 +45,7 @@ A typical GSLB environment is comprised of the following components: - GSLB Site: In &PRODUCT;terminology, GSLB sites are + 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 diff --git a/docs/en-US/ipv6-support.xml b/docs/en-US/ipv6-support.xml index c7f7744393e..bc14c8eab0e 100644 --- a/docs/en-US/ipv6-support.xml +++ b/docs/en-US/ipv6-support.xml @@ -21,7 +21,7 @@ -->
IPv6 Support in &PRODUCT; - &PRODUCT;supports Internet Protocol version 6 (IPv6), the recent version of the Internet + &PRODUCT; supports Internet Protocol version 6 (IPv6), the recent version of the Internet Protocol (IP) that defines routing the network traffic. IPv6 uses a 128-bit address that exponentially expands the current address space that is available to the users. IPv6 addresses consist of eight groups of four hexadecimal digits separated by colons, for example, diff --git a/docs/en-US/vmware-cluster-config-dvswitch.xml b/docs/en-US/vmware-cluster-config-dvswitch.xml index 3468c1bea4e..a3250f4f380 100644 --- a/docs/en-US/vmware-cluster-config-dvswitch.xml +++ b/docs/en-US/vmware-cluster-config-dvswitch.xml @@ -21,7 +21,7 @@ -->
Configuring a vSphere Cluster with VMware Distributed Virtual Switch - &PRODUCT;supports VMware vNetwork Distributed Switch (VDS) for virtual network configuration + &PRODUCT; supports VMware vNetwork Distributed Switch (VDS) for virtual network configuration in a VMware vSphere environment. This section helps you configure VMware VDS in a &PRODUCT; deployment. Each vCenter server instance can support up to 128 VDS instances and each VDS instance can manage up to 500 VMware hosts. From 3c51c4e7adb717b5cee3bd01be716d75e288aa0c Mon Sep 17 00:00:00 2001 From: Murali Reddy Date: Thu, 16 May 2013 12:26:23 +0530 Subject: [PATCH 46/59] CLOUDSTACK-2461: createGSLBRule API is failing to pick the default algorithm "round robin" for parameter "gslblbmethod" fix defaults to round robin when parameter not specified --- .../region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java index b08b6aeff17..07d3274b335 100644 --- a/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java @@ -85,7 +85,11 @@ public class CreateGlobalLoadBalancerRuleCmd extends BaseAsyncCreateCmd { } public String getAlgorithm() { - return algorithm; + if (algorithm != null) { + return algorithm; + } else { + return GlobalLoadBalancerRule.Algorithm.RoundRobin.name(); + } } public String getGslbMethod() { From 565d829c006609251c18883b1007175b6a1d2f79 Mon Sep 17 00:00:00 2001 From: Murali Reddy Date: Thu, 16 May 2013 14:25:14 +0530 Subject: [PATCH 47/59] CLOUDSTACK-2460: fix the event descriptions for create/delete/update/assign global load balancer rule apis --- api/src/com/cloud/event/EventTypes.java | 1 + .../AssignToGlobalLoadBalancerRuleCmd.java | 2 +- .../gslb/CreateGlobalLoadBalancerRuleCmd.java | 2 +- .../gslb/DeleteGlobalLoadBalancerRuleCmd.java | 4 +-- .../gslb/UpdateGlobalLoadBalancerRuleCmd.java | 28 +++++++++++++++---- 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index d272c99bc02..e317a8fbf1c 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -134,6 +134,7 @@ public class EventTypes { public static final String EVENT_REMOVE_FROM_GLOBAL_LOAD_BALANCER_RULE = "GLOBAL.LB.REMOVE"; public static final String EVENT_GLOBAL_LOAD_BALANCER_CREATE = "GLOBAL.LB.CREATE"; public static final String EVENT_GLOBAL_LOAD_BALANCER_DELETE = "GLOBAL.LB.DELETE"; + public static final String EVENT_GLOBAL_LOAD_BALANCER_UPDATE = "GLOBAL.LB.UPDATE"; // Account events public static final String EVENT_ACCOUNT_ENABLE = "ACCOUNT.ENABLE"; diff --git a/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/AssignToGlobalLoadBalancerRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/AssignToGlobalLoadBalancerRuleCmd.java index 1c07a0aad53..1575cd34d07 100644 --- a/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/AssignToGlobalLoadBalancerRuleCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/AssignToGlobalLoadBalancerRuleCmd.java @@ -95,7 +95,7 @@ public class AssignToGlobalLoadBalancerRuleCmd extends BaseAsyncCmd { @Override public String getEventDescription() { - return "applying load balancer rules " + StringUtils.join(getLoadBalancerRulesIds(), ",") + + return "assign load balancer rules " + StringUtils.join(getLoadBalancerRulesIds(), ",") + " to global load balancer rule " + getGlobalLoadBalancerRuleId(); } diff --git a/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java index 07d3274b335..ac3349516df 100644 --- a/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/CreateGlobalLoadBalancerRuleCmd.java @@ -162,7 +162,7 @@ public class CreateGlobalLoadBalancerRuleCmd extends BaseAsyncCreateCmd { @Override public String getEventDescription() { - return "creating a global load balancer: " + getName() + " for account: " + getAccountName(); + return "creating a global load balancer rule Id: " + getEntityId(); } diff --git a/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/DeleteGlobalLoadBalancerRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/DeleteGlobalLoadBalancerRuleCmd.java index 424b1072887..fe5decdf5fc 100644 --- a/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/DeleteGlobalLoadBalancerRuleCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/DeleteGlobalLoadBalancerRuleCmd.java @@ -77,12 +77,12 @@ public class DeleteGlobalLoadBalancerRuleCmd extends BaseAsyncCmd { @Override public String getEventType() { - return EventTypes.EVENT_LOAD_BALANCER_DELETE; + return EventTypes.EVENT_GLOBAL_LOAD_BALANCER_DELETE; } @Override public String getEventDescription() { - return "deleting global load balancer: " + getGlobalLoadBalancerId(); + return "deleting global load balancer rule: " + getGlobalLoadBalancerId(); } @Override diff --git a/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/UpdateGlobalLoadBalancerRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/UpdateGlobalLoadBalancerRuleCmd.java index 10694e1633e..4e2c0fd0fb9 100644 --- a/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/UpdateGlobalLoadBalancerRuleCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/region/ha/gslb/UpdateGlobalLoadBalancerRuleCmd.java @@ -17,11 +17,11 @@ package org.apache.cloudstack.api.command.user.region.ha.gslb; +import com.cloud.event.EventTypes; +import com.cloud.region.ha.GlobalLoadBalancerRule; import com.cloud.region.ha.GlobalLoadBalancingRulesService; -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 com.cloud.user.Account; +import org.apache.cloudstack.api.*; import org.apache.cloudstack.api.response.GlobalLoadBalancerResponse; import org.apache.cloudstack.api.response.LoadBalancerResponse; import org.apache.log4j.Logger; @@ -29,7 +29,7 @@ import org.apache.log4j.Logger; import javax.inject.Inject; @APICommand(name = "updateGlobalLoadBalancerRule", description = "update global load balancer rules.", responseObject = LoadBalancerResponse.class) -public class UpdateGlobalLoadBalancerRuleCmd extends BaseListTaggedResourcesCmd { +public class UpdateGlobalLoadBalancerRuleCmd extends BaseAsyncCmd { public static final Logger s_logger = Logger.getLogger(GlobalLoadBalancerResponse.class.getName()); private static final String s_name = "updategloballoadbalancerruleresponse"; @@ -88,9 +88,27 @@ public class UpdateGlobalLoadBalancerRuleCmd extends BaseListTaggedResourcesCmd return s_name; } + @Override + public long getEntityOwnerId() { + GlobalLoadBalancerRule lb = _entityMgr.findById(GlobalLoadBalancerRule.class, getId()); + if (lb != null) { + return lb.getAccountId(); + } + return Account.ACCOUNT_ID_SYSTEM; + } + @Override public void execute() { _gslbService.updateGlobalLoadBalancerRule(this); } + @Override + public String getEventType() { + return EventTypes.EVENT_GLOBAL_LOAD_BALANCER_UPDATE; + } + + @Override + public String getEventDescription() { + return null; + } } From d2d0398e3321b819756a537c0b1fab0491e5a3e6 Mon Sep 17 00:00:00 2001 From: Murali Reddy Date: Thu, 16 May 2013 14:45:49 +0530 Subject: [PATCH 48/59] CLOUDSTACK-2529: GlobalLoadBalancerResponse should have the full FQDN for the global load balanced service --- server/src/com/cloud/api/ApiDBUtils.java | 5 +++++ server/src/com/cloud/api/ApiResponseHelper.java | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index 94c873ee9fb..1afedac5144 100755 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -1668,4 +1668,9 @@ public class ApiDBUtils { public static List listSiteLoadBalancers(long gslbRuleId) { return _gslbService.listSiteLoadBalancers(gslbRuleId); } + + public static String getDnsNameConfiguredForGslb() { + String providerDnsName = _configDao.getValue(Config.CloudDnsName.key()); + return providerDnsName; + } } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 9a70d95e0bc..482594dd8f1 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -787,7 +787,8 @@ public class ApiResponseHelper implements ResponseGenerator { response.setAlgorithm(globalLoadBalancerRule.getAlgorithm()); response.setStickyMethod(globalLoadBalancerRule.getPersistence()); response.setServiceType(globalLoadBalancerRule.getServiceType()); - response.setServiceDomainName(globalLoadBalancerRule.getGslbDomain()); + response.setServiceDomainName(globalLoadBalancerRule.getGslbDomain() + "." + + ApiDBUtils.getDnsNameConfiguredForGslb()); response.setName(globalLoadBalancerRule.getName()); response.setDescription(globalLoadBalancerRule.getDescription()); response.setRegionIdId(globalLoadBalancerRule.getRegion()); From 33e683915c3083ac60a578fc90a7d90a64cb028e Mon Sep 17 00:00:00 2001 From: Murali Reddy Date: Thu, 16 May 2013 15:18:02 +0530 Subject: [PATCH 49/59] CLOUDSTACK-2462: Failed to create GSLB rule with "proximity" algorithm add RTT as load balancing method for GSLB vserver --- .../com/cloud/network/resource/NetscalerResource.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) 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 98e14618248..c0d4599dc0c 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 @@ -1095,7 +1095,15 @@ public class NetscalerResource implements ServerResource { } vserver.set_name(vserverName); - vserver.set_lbmethod(lbMethod); + if ("RoundRobin".equalsIgnoreCase(lbMethod)) { + vserver.set_lbmethod("ROUNDROBIN"); + } else if ("LeastConn".equalsIgnoreCase(lbMethod)) { + vserver.set_lbmethod("LEASTCONNECTION"); + } else if ("Proximity".equalsIgnoreCase(lbMethod)) { + vserver.set_lbmethod("RTT"); + } else { + throw new ExecutionException("Unsupported LB method"); + } vserver.set_persistencetype(persistenceType); if ("SOURCEIP".equalsIgnoreCase(persistenceType)) { vserver.set_persistenceid(persistenceId); From f441582e1b7747bba1385ecb48a7b7b34a9dded1 Mon Sep 17 00:00:00 2001 From: Murali Reddy Date: Thu, 16 May 2013 18:26:14 +0530 Subject: [PATCH 50/59] CLOUDSTACK-2378: assignToGSLBRule or removeFromGlobalLoadBalancerRule APIs are failing when there are multiple physical network in a zone adding support for deployments where multiple physical networks are configured for guest traffic in a zone --- .../network/element/NetscalerElement.java | 39 ++++++++++++------- .../GlobalLoadBalancingRulesServiceImpl.java | 37 ++++++++++-------- .../region/gslb/GslbServiceProvider.java | 8 ++-- ...obalLoadBalancingRulesServiceImplTest.java | 3 ++ 4 files changed, 52 insertions(+), 35 deletions(-) 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 cc2bcc17a43..850962d05ee 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 @@ -923,13 +923,13 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl } @Override - public boolean applyGlobalLoadBalancerRule(long zoneId, GlobalLoadBalancerConfigCommand gslbConfigCmd) + public boolean applyGlobalLoadBalancerRule(long zoneId, long physicalNetworkId, GlobalLoadBalancerConfigCommand gslbConfigCmd) throws ResourceUnavailableException { long zoneGslbProviderHosId = 0; // find the NetScaler device configured as gslb service provider in the zone - ExternalLoadBalancerDeviceVO nsGslbProvider = findGslbProvider(zoneId); + ExternalLoadBalancerDeviceVO nsGslbProvider = findGslbProvider(zoneId, physicalNetworkId); if (nsGslbProvider == null) { String msg = "Unable to find a NetScaler configured as gslb service provider in zone " + zoneId; s_logger.debug(msg); @@ -950,28 +950,37 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl return true; } - private ExternalLoadBalancerDeviceVO findGslbProvider(long zoneId) { + private ExternalLoadBalancerDeviceVO findGslbProvider(long zoneId, long physicalNetworkId) { List pNtwks = _physicalNetworkDao.listByZoneAndTrafficType(zoneId, TrafficType.Guest); - if (pNtwks.isEmpty() || pNtwks.size() > 1) { - throw new InvalidParameterValueException("Unable to get physical network in zone id = " + zoneId); + + if (pNtwks == null || pNtwks.isEmpty()) { + throw new InvalidParameterValueException("Unable to get physical network: " + physicalNetworkId + + " in zone id = " + zoneId); + } else { + for (PhysicalNetwork physicalNetwork : pNtwks) { + if (physicalNetwork.getId() == physicalNetworkId) { + PhysicalNetworkVO physNetwork = pNtwks.get(0); + ExternalLoadBalancerDeviceVO nsGslbProvider = _externalLoadBalancerDeviceDao.findGslbServiceProvider( + physNetwork.getId(), Provider.Netscaler.getName()); + return nsGslbProvider; + } + } } - PhysicalNetworkVO physNetwork = pNtwks.get(0); - ExternalLoadBalancerDeviceVO nsGslbProvider = _externalLoadBalancerDeviceDao.findGslbServiceProvider( - physNetwork.getId(), Provider.Netscaler.getName()); - return nsGslbProvider; + + return null; } @Override - public boolean isServiceEnabledInZone(long zoneId) { + public boolean isServiceEnabledInZone(long zoneId, long physicalNetworkId) { - ExternalLoadBalancerDeviceVO nsGslbProvider = findGslbProvider(zoneId); + ExternalLoadBalancerDeviceVO nsGslbProvider = findGslbProvider(zoneId, physicalNetworkId); //return true if a NetScaler device is configured in the zone return (nsGslbProvider != null); } @Override - public String getZoneGslbProviderPublicIp(long zoneId) { - ExternalLoadBalancerDeviceVO nsGslbProvider = findGslbProvider(zoneId); + public String getZoneGslbProviderPublicIp(long zoneId, long physicalNetworkId) { + ExternalLoadBalancerDeviceVO nsGslbProvider = findGslbProvider(zoneId, physicalNetworkId); if (nsGslbProvider != null) { return nsGslbProvider.getGslbSitePublicIP(); } @@ -979,8 +988,8 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl } @Override - public String getZoneGslbProviderPrivateIp(long zoneId) { - ExternalLoadBalancerDeviceVO nsGslbProvider = findGslbProvider(zoneId); + public String getZoneGslbProviderPrivateIp(long zoneId, long physicalNetworkId) { + ExternalLoadBalancerDeviceVO nsGslbProvider = findGslbProvider(zoneId, physicalNetworkId); if (nsGslbProvider != null) { return nsGslbProvider.getGslbSitePrivateIP(); } diff --git a/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancingRulesServiceImpl.java b/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancingRulesServiceImpl.java index 56c46b01c79..0622f77f750 100644 --- a/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancingRulesServiceImpl.java +++ b/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancingRulesServiceImpl.java @@ -35,6 +35,7 @@ import com.cloud.region.ha.GlobalLoadBalancingRulesService; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.UserContext; +import com.cloud.utils.Pair; import com.cloud.utils.db.DB; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; @@ -173,6 +174,7 @@ public class GlobalLoadBalancingRulesServiceImpl implements GlobalLoadBalancingR List oldLbRuleIds = new ArrayList(); List oldZones = new ArrayList(); List newZones = new ArrayList(oldZones); + List> physcialNetworks = new ArrayList>(); // get the list of load balancer rules id's that are assigned currently to GSLB rule and corresponding zone id's List gslbLbMapVos = _gslbLbMapDao.listByGslbRuleId(gslbRuleId); @@ -217,12 +219,14 @@ public class GlobalLoadBalancingRulesServiceImpl implements GlobalLoadBalancingR } newZones.add(network.getDataCenterId()); + physcialNetworks.add(new Pair(network.getDataCenterId(), network.getPhysicalNetworkId())); } - // check each of the zone has a GSLB service provider configured - for (Long zoneId: newZones) { - if (!checkGslbServiceEnabledInZone(zoneId)) { - throw new InvalidParameterValueException("GSLB service is not enabled in the Zone"); + // for each of the physical network check if GSLB service provider configured + for (Pair physicalNetwork: physcialNetworks) { + if (!checkGslbServiceEnabledInZone(physicalNetwork.first(), physicalNetwork.second())) { + throw new InvalidParameterValueException("GSLB service is not enabled in the Zone:" + + physicalNetwork.first() + " and physical network " + physicalNetwork.second()); } } @@ -543,8 +547,8 @@ public class GlobalLoadBalancingRulesServiceImpl implements GlobalLoadBalancingR GlobalLoadBalancerConfigCommand gslbConfigCmd = new GlobalLoadBalancerConfigCommand(gslbFqdn, lbMethod, persistenceMethod, serviceType, gslbRuleId, revoke); - // list of the zones participating in global load balancing - List gslbSiteIds = new ArrayList(); + // list of the physical network participating in global load balancing + List> gslbSiteIds = new ArrayList>(); // map of the zone and info corresponding to the load balancer configured in the zone Map zoneSiteLoadbalancerMap = new HashMap(); @@ -559,37 +563,38 @@ public class GlobalLoadBalancingRulesServiceImpl implements GlobalLoadBalancingR LoadBalancerVO loadBalancer = _lbDao.findById(gslbLbMapVo.getLoadBalancerId()); Network network = _networkDao.findById(loadBalancer.getNetworkId()); long dataCenterId = network.getDataCenterId(); + long physicalNetworkId = network.getPhysicalNetworkId(); - gslbSiteIds.add(dataCenterId); + gslbSiteIds.add(new Pair(dataCenterId, physicalNetworkId)); IPAddressVO ip = _ipAddressDao.findById(loadBalancer.getSourceIpAddressId()); SiteLoadBalancerConfig siteLb = new SiteLoadBalancerConfig(gslbLbMapVo.isRevoke(), serviceType, ip.getAddress().addr(), Integer.toString(loadBalancer.getDefaultPortStart()), dataCenterId); - siteLb.setGslbProviderPublicIp(_gslbProvider.getZoneGslbProviderPublicIp(dataCenterId)); - siteLb.setGslbProviderPrivateIp(_gslbProvider.getZoneGslbProviderPrivateIp(dataCenterId)); + siteLb.setGslbProviderPublicIp(_gslbProvider.getZoneGslbProviderPublicIp(dataCenterId, physicalNetworkId)); + siteLb.setGslbProviderPrivateIp(_gslbProvider.getZoneGslbProviderPrivateIp(dataCenterId, physicalNetworkId)); zoneSiteLoadbalancerMap.put(network.getDataCenterId(), siteLb); } // loop through all the zones, participating in GSLB, and send GSLB config command // to the corresponding GSLB service provider in that zone - for (long zoneId: gslbSiteIds) { + for (Pair zoneId: gslbSiteIds) { List slbs = new ArrayList(); // set site as 'local' for the site in that zone - for (long innerLoopZoneId: gslbSiteIds) { - SiteLoadBalancerConfig siteLb = zoneSiteLoadbalancerMap.get(innerLoopZoneId); - siteLb.setLocal(zoneId == innerLoopZoneId); + for (Pair innerLoopZoneId: gslbSiteIds) { + SiteLoadBalancerConfig siteLb = zoneSiteLoadbalancerMap.get(innerLoopZoneId.first()); + siteLb.setLocal(zoneId.first() == innerLoopZoneId.first()); slbs.add(siteLb); } gslbConfigCmd.setSiteLoadBalancers(slbs); try { - _gslbProvider.applyGlobalLoadBalancerRule(zoneId, gslbConfigCmd); + _gslbProvider.applyGlobalLoadBalancerRule(zoneId.first(), zoneId.second(), gslbConfigCmd); } catch (ResourceUnavailableException e) { s_logger.warn("Failed to configure GSLB rul in the zone " + zoneId + " due to " + e.getMessage()); throw new CloudRuntimeException("Failed to configure GSLB rul in the zone"); @@ -599,13 +604,13 @@ public class GlobalLoadBalancingRulesServiceImpl implements GlobalLoadBalancingR return true; } - private boolean checkGslbServiceEnabledInZone(long zoneId) { + private boolean checkGslbServiceEnabledInZone(long zoneId, long physicalNetworkId) { if (_gslbProvider == null) { throw new CloudRuntimeException("No GSLB provider is available"); } - return _gslbProvider.isServiceEnabledInZone(zoneId); + return _gslbProvider.isServiceEnabledInZone(zoneId, physicalNetworkId); } @Override diff --git a/server/src/org/apache/cloudstack/region/gslb/GslbServiceProvider.java b/server/src/org/apache/cloudstack/region/gslb/GslbServiceProvider.java index 4338d65eff2..0413edff978 100755 --- a/server/src/org/apache/cloudstack/region/gslb/GslbServiceProvider.java +++ b/server/src/org/apache/cloudstack/region/gslb/GslbServiceProvider.java @@ -24,13 +24,13 @@ import org.apache.cloudstack.region.RegionServiceProvider; public interface GslbServiceProvider extends RegionServiceProvider { - public boolean isServiceEnabledInZone(long zoneId); + public boolean isServiceEnabledInZone(long zoneId, long physicalNetworkId); - public String getZoneGslbProviderPublicIp(long zoneId); + public String getZoneGslbProviderPublicIp(long zoneId, long physicalNetworkId); - public String getZoneGslbProviderPrivateIp(long zoneId); + public String getZoneGslbProviderPrivateIp(long zoneId, long physicalNetworkId); - public boolean applyGlobalLoadBalancerRule(long zoneId, GlobalLoadBalancerConfigCommand gslbConfigCmd) + public boolean applyGlobalLoadBalancerRule(long zoneId, long physicalNetworkId, GlobalLoadBalancerConfigCommand gslbConfigCmd) throws ResourceUnavailableException; } diff --git a/server/test/org/apache/cloudstack/region/gslb/GlobalLoadBalancingRulesServiceImplTest.java b/server/test/org/apache/cloudstack/region/gslb/GlobalLoadBalancingRulesServiceImplTest.java index 700fe8f7dde..1c281a08bed 100644 --- a/server/test/org/apache/cloudstack/region/gslb/GlobalLoadBalancingRulesServiceImplTest.java +++ b/server/test/org/apache/cloudstack/region/gslb/GlobalLoadBalancingRulesServiceImplTest.java @@ -730,6 +730,9 @@ public class GlobalLoadBalancingRulesServiceImplTest extends TestCase { Field dcID = NetworkVO.class.getDeclaredField("dataCenterId"); dcID.setAccessible(true); dcID.set(networkVo, new Long(1)); + Field phyNetworkId = NetworkVO.class.getDeclaredField("physicalNetworkId"); + phyNetworkId.setAccessible(true); + phyNetworkId.set(networkVo, new Long(200)); when(gslbServiceImpl._networkDao.findById(new Long(1))).thenReturn(networkVo); GlobalLoadBalancerLbRuleMapVO gslbLbMap = new GlobalLoadBalancerLbRuleMapVO(1, 1); From d078f921671d0f28d9291fa2bffa8a7eab53cda7 Mon Sep 17 00:00:00 2001 From: Kishan Kavala Date: Thu, 16 May 2013 19:12:42 +0530 Subject: [PATCH 51/59] CLOUDSTACK-2544: Fix NPE while comparing lastHostId during capacity calculation --- server/src/com/cloud/capacity/CapacityManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/com/cloud/capacity/CapacityManagerImpl.java b/server/src/com/cloud/capacity/CapacityManagerImpl.java index e7101c6755b..b2419893cf7 100755 --- a/server/src/com/cloud/capacity/CapacityManagerImpl.java +++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java @@ -681,7 +681,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, if ((newState == State.Starting || newState == State.Migrating || event == Event.AgentReportMigrated) && vm.getHostId() != null) { boolean fromLastHost = false; - if (vm.getLastHostId().equals(vm.getHostId())) { + if (vm.getHostId().equals(vm.getLastHostId())) { s_logger.debug("VM starting again on the last host it was stopped on"); fromLastHost = true; } From a29e39365aab0ff4024ff5ff4b04fccb7abc2885 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Thu, 16 May 2013 22:07:03 +0100 Subject: [PATCH 52/59] CLOUDSTACK-2545: Change unit of network statistics from 1000 to 1024 for KVM Signed-off-by: Chip Childers --- .../hypervisor/kvm/resource/LibvirtComputingResource.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 f3ae33365c3..c3140d3921a 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 @@ -2842,7 +2842,7 @@ ServerResource { Pair nicStats = getNicStats(_publicBridgeName); HostStatsEntry hostStats = new HostStatsEntry(cmd.getHostId(), cpuUtil, - nicStats.first() / 1000, nicStats.second() / 1000, "host", + nicStats.first() / 1024, nicStats.second() / 1024, "host", totMem, freeMem, 0, 0); return new GetHostStatsAnswer(cmd, hostStats); } @@ -4561,10 +4561,10 @@ ServerResource { if (oldStats != null) { long deltarx = rx - oldStats._rx; if (deltarx > 0) - stats.setNetworkReadKBs(deltarx / 1000); + stats.setNetworkReadKBs(deltarx / 1024); long deltatx = tx - oldStats._tx; if (deltatx > 0) - stats.setNetworkWriteKBs(deltatx / 1000); + stats.setNetworkWriteKBs(deltatx / 1024); } vmStats newStat = new vmStats(); From 15be97772e1b41801867beef25ae66dfaf286458 Mon Sep 17 00:00:00 2001 From: Vijayendra Bhamidipati Date: Thu, 16 May 2013 08:15:22 -0700 Subject: [PATCH 53/59] PVLAN : Implementing PVLAN deployment capability for VMware deployments in cloudstack. --- .../com/cloud/agent/api/PlugNicCommand.java | 9 +- .../vmware/resource/VmwareResource.java | 121 +++++++++----- .../com/cloud/network/NetworkManagerImpl.java | 2 + ...VpcVirtualNetworkApplianceManagerImpl.java | 45 +++-- .../src/com/cloud/vm/UserVmManagerImpl.java | 5 +- .../vmware/mo/DistributedVirtualSwitchMO.java | 77 +++++++++ .../vmware/mo/HypervisorHostHelper.java | 156 ++++++++++++++++-- 7 files changed, 335 insertions(+), 80 deletions(-) diff --git a/core/src/com/cloud/agent/api/PlugNicCommand.java b/core/src/com/cloud/agent/api/PlugNicCommand.java index b896e4540cb..d10c6808a59 100644 --- a/core/src/com/cloud/agent/api/PlugNicCommand.java +++ b/core/src/com/cloud/agent/api/PlugNicCommand.java @@ -17,11 +17,13 @@ package com.cloud.agent.api; import com.cloud.agent.api.to.NicTO; +import com.cloud.vm.VirtualMachine; public class PlugNicCommand extends Command { NicTO nic; String instanceName; + VirtualMachine.Type vmType; public NicTO getNic() { return nic; @@ -35,12 +37,17 @@ public class PlugNicCommand extends Command { protected PlugNicCommand() { } - public PlugNicCommand(NicTO nic, String instanceName) { + public PlugNicCommand(NicTO nic, String instanceName, VirtualMachine.Type vmtype) { this.nic = nic; this.instanceName = instanceName; + this.vmType = vmtype; } public String getVmName() { return instanceName; } + + public VirtualMachine.Type getVMType() { + return vmType; + } } 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 37ddaa14bd9..be4775452f3 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 @@ -16,6 +16,32 @@ // under the License. package com.cloud.hypervisor.vmware.resource; +import java.io.File; +import java.io.IOException; +import java.net.ConnectException; +import java.net.InetSocketAddress; +import java.net.URI; +import java.nio.channels.SocketChannel; +import java.rmi.RemoteException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.TimeZone; +import java.util.UUID; + +import javax.naming.ConfigurationException; + +import org.apache.log4j.Logger; +import org.apache.log4j.NDC; + import com.cloud.agent.IAgentControl; import com.cloud.agent.api.Answer; import com.cloud.agent.api.AttachIsoCommand; @@ -47,7 +73,6 @@ import com.cloud.agent.api.CreateVolumeFromSnapshotCommand; import com.cloud.agent.api.DeleteStoragePoolCommand; import com.cloud.agent.api.DeleteVMSnapshotAnswer; import com.cloud.agent.api.DeleteVMSnapshotCommand; -import com.cloud.agent.api.UnregisterVMCommand; import com.cloud.agent.api.GetDomRVersionAnswer; import com.cloud.agent.api.GetDomRVersionCmd; import com.cloud.agent.api.GetHostStatsAnswer; @@ -78,6 +103,7 @@ import com.cloud.agent.api.PlugNicCommand; import com.cloud.agent.api.PoolEjectCommand; import com.cloud.agent.api.PrepareForMigrationAnswer; import com.cloud.agent.api.PrepareForMigrationCommand; +import com.cloud.agent.api.PvlanSetupCommand; import com.cloud.agent.api.ReadyAnswer; import com.cloud.agent.api.ReadyCommand; import com.cloud.agent.api.RebootAnswer; @@ -85,8 +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.ScaleVmCommand; import com.cloud.agent.api.SetupAnswer; import com.cloud.agent.api.SetupCommand; import com.cloud.agent.api.SetupGuestNetworkAnswer; @@ -101,6 +127,7 @@ import com.cloud.agent.api.StopCommand; import com.cloud.agent.api.StoragePoolInfo; import com.cloud.agent.api.UnPlugNicAnswer; import com.cloud.agent.api.UnPlugNicCommand; +import com.cloud.agent.api.UnregisterVMCommand; import com.cloud.agent.api.UpgradeSnapshotCommand; import com.cloud.agent.api.ValidateSnapshotAnswer; import com.cloud.agent.api.ValidateSnapshotCommand; @@ -135,14 +162,14 @@ 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; +import com.cloud.agent.api.storage.CreateVolumeOVAAnswer; +import com.cloud.agent.api.storage.CreateVolumeOVACommand; import com.cloud.agent.api.storage.DestroyCommand; +import com.cloud.agent.api.storage.PrepareOVAPackingAnswer; +import com.cloud.agent.api.storage.PrepareOVAPackingCommand; import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer; import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; import com.cloud.agent.api.storage.ResizeVolumeAnswer; @@ -250,30 +277,6 @@ import com.vmware.vim25.VirtualMachineGuestOsIdentifier; import com.vmware.vim25.VirtualMachinePowerState; import com.vmware.vim25.VirtualMachineRuntimeInfo; import com.vmware.vim25.VirtualSCSISharing; -import org.apache.log4j.Logger; -import org.apache.log4j.NDC; - -import javax.naming.ConfigurationException; -import java.io.File; -import java.io.IOException; -import java.net.ConnectException; -import java.net.InetSocketAddress; -import java.net.URI; -import java.nio.channels.SocketChannel; -import java.rmi.RemoteException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.TimeZone; -import java.util.UUID; public class VmwareResource implements StoragePoolResource, ServerResource, VmwareHostService { @@ -495,6 +498,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa return execute((UnregisterVMCommand) cmd); } else if (clz == ScaleVmCommand.class) { return execute((ScaleVmCommand) cmd); + } else if (clz == PvlanSetupCommand.class) { + return execute((PvlanSetupCommand) cmd); } else { answer = Answer.createUnsupportedCommandAnswer(cmd); } @@ -1037,7 +1042,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa String domrGIP = cmd.getAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP); String domrName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME); String gw = cmd.getAccessDetail(NetworkElementCommand.GUEST_NETWORK_GATEWAY); - String cidr = Long.toString(NetUtils.getCidrSize(nic.getNetmask()));; + String cidr = Long.toString(NetUtils.getCidrSize(nic.getNetmask())); String domainName = cmd.getNetworkDomain(); String dns = cmd.getDefaultDns1(); if (dns == null || dns.isEmpty()) { @@ -1376,7 +1381,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa NicTO nicTo = cmd.getNic(); VirtualDevice nic; - Pair networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, false); + Pair networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, false, cmd.getVMType());; if (VmwareHelper.isDvPortGroup(networkInfo.first())) { String dvSwitchUuid; ManagedObjectReference dcMor = hyperHost.getHyperHostDatacenter(); @@ -1643,7 +1648,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa vmMo.getRunningHost(), vlanId, null, null, this._ops_timeout, true); } else { networkInfo = HypervisorHostHelper.prepareNetwork(this._publicTrafficInfo.getVirtualSwitchName(), "cloud.public", - vmMo.getRunningHost(), vlanId, null, null, this._ops_timeout, vSwitchType, _portsPerDvPortGroup, null, false); + vmMo.getRunningHost(), vlanId, null, null, null, this._ops_timeout, vSwitchType, _portsPerDvPortGroup, null, false); } int nicIndex = allocPublicNicIndex(vmMo); @@ -2537,7 +2542,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa s_logger.info("Prepare NIC device based on NicTO: " + _gson.toJson(nicTo)); boolean configureVServiceInNexus = (nicTo.getType() == TrafficType.Guest) && (vmSpec.getDetails().containsKey("ConfigureVServiceInNexus")); - Pair networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, configureVServiceInNexus); + VirtualMachine.Type vmType = cmd.getVirtualMachine().getType(); + Pair networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, configureVServiceInNexus, vmType); if (VmwareHelper.isDvPortGroup(networkInfo.first())) { String dvSwitchUuid; ManagedObjectReference dcMor = hyperHost.getHyperHostDatacenter(); @@ -2719,16 +2725,28 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa return poolMors; } + + private String getPvlanInfo(NicTO nicTo) { + if (nicTo.getBroadcastType() == BroadcastDomainType.Pvlan) { + return NetUtils.getIsolatedPvlanFromUri(nicTo.getBroadcastUri()); + } + return null; + } + private String getVlanInfo(NicTO nicTo, String defaultVlan) { if (nicTo.getBroadcastType() == BroadcastDomainType.Native) { return defaultVlan; } - - if (nicTo.getBroadcastType() == BroadcastDomainType.Vlan) { + if (nicTo.getBroadcastType() == BroadcastDomainType.Vlan || nicTo.getBroadcastType() == BroadcastDomainType.Pvlan) { if (nicTo.getBroadcastUri() != null) { + if (nicTo.getBroadcastType() == BroadcastDomainType.Vlan) + // For vlan, the broadcast uri is of the form vlan:// return nicTo.getBroadcastUri().getHost(); + else + // for pvlan, the broacast uri will be of the form pvlan://-i + return NetUtils.getPrimaryPvlanFromUri(nicTo.getBroadcastUri()); } else { - s_logger.warn("BroadcastType is not claimed as VLAN, but without vlan info in broadcast URI. Use vlan info from labeling: " + defaultVlan); + s_logger.warn("BroadcastType is not claimed as VLAN or PVLAN, but without vlan info in broadcast URI. Use vlan info from labeling: " + defaultVlan); return defaultVlan; } } @@ -2737,7 +2755,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa return defaultVlan; } - private Pair prepareNetworkFromNicInfo(HostMO hostMo, NicTO nicTo, boolean configureVServiceInNexus) throws Exception { + private Pair prepareNetworkFromNicInfo(HostMO hostMo, NicTO nicTo, boolean configureVServiceInNexus, VirtualMachine.Type vmType) throws Exception { Pair switchName; TrafficType trafficType; VirtualSwitchType switchType; @@ -2761,12 +2779,22 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa s_logger.info("Prepare network on " + switchType + " " + switchName + " with name prefix: " + namePrefix); if (VirtualSwitchType.StandardVirtualSwitch == switchType) { - networkInfo = HypervisorHostHelper.prepareNetwork(switchName.first(), namePrefix, hostMo, getVlanInfo(nicTo, switchName.second()), - nicTo.getNetworkRateMbps(), nicTo.getNetworkRateMulticastMbps(), _ops_timeout, + networkInfo = HypervisorHostHelper.prepareNetwork(switchName.first(), namePrefix, + hostMo, getVlanInfo(nicTo, switchName.second()), nicTo.getNetworkRateMbps(), nicTo.getNetworkRateMulticastMbps(), _ops_timeout, !namePrefix.startsWith("cloud.private")); } else { - networkInfo = HypervisorHostHelper.prepareNetwork(switchName.first(), namePrefix, hostMo, getVlanInfo(nicTo, switchName.second()), + String vlanId = getVlanInfo(nicTo, switchName.second()); + String svlanId = null; + boolean pvlannetwork = (getPvlanInfo(nicTo) == null)?false:true; + if (vmType != null && vmType.equals(VirtualMachine.Type.DomainRouter) && pvlannetwork) { + // plumb this network to the promiscuous vlan. + svlanId = vlanId; + } else { + // plumb this network to the isolated vlan. + svlanId = getPvlanInfo(nicTo); + } + networkInfo = HypervisorHostHelper.prepareNetwork(switchName.first(), namePrefix, hostMo, vlanId, svlanId, nicTo.getNetworkRateMbps(), nicTo.getNetworkRateMulticastMbps(), _ops_timeout, switchType, _portsPerDvPortGroup, nicTo.getGateway(), configureVServiceInNexus); } @@ -3253,7 +3281,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa NicTO[] nics = vm.getNics(); for (NicTO nic : nics) { // prepare network on the host - prepareNetworkFromNicInfo(new HostMO(getServiceContext(), _morHyperHost), nic, false); + prepareNetworkFromNicInfo(new HostMO(getServiceContext(), _morHyperHost), nic, false, cmd.getVirtualMachine().getType()); } String secStoreUrl = mgr.getSecondaryStorageStoreUrl(Long.parseLong(_dcId)); @@ -3917,6 +3945,14 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } } + protected Answer execute(PvlanSetupCommand cmd) { + // Pvlan related operations are performed in the start/stop command paths + // for vmware. This function is implemented to support mgmt layer code + // that issue this command. Note that pvlan operations are supported only + // in Distributed Virtual Switch environments for vmware deployments. + return new Answer(cmd, true, "success"); + } + protected Answer execute(UnregisterVMCommand cmd){ if (s_logger.isInfoEnabled()) { s_logger.info("Executing resource UnregisterVMCommand: " + _gson.toJson(cmd)); @@ -4134,6 +4170,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } } + @Override public CreateVolumeOVAAnswer execute(CreateVolumeOVACommand cmd) { if (s_logger.isInfoEnabled()) { s_logger.info("Executing resource CreateVolumeOVACommand: " + _gson.toJson(cmd)); diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 01a0384df5c..c58ef220ea1 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -3004,6 +3004,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L Random _rand = new Random(System.currentTimeMillis()); + @Override public List listVmNics(Long vmId, Long nicId) { List result = null; if (nicId == null) { @@ -3014,6 +3015,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L return result; } + @Override public String allocateGuestIP(Account ipOwner, boolean isSystem, long zoneId, Long networkId, String requestedIp) throws InsufficientAddressCapacityException { String ipaddr = null; diff --git a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java index 70073741433..9992b7ca01e 100644 --- a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java @@ -27,24 +27,6 @@ import java.util.TreeSet; import javax.ejb.Local; import javax.inject.Inject; -import com.cloud.network.vpc.NetworkACLItem; -import com.cloud.network.vpc.NetworkACLItemDao; -import com.cloud.network.vpc.NetworkACLItemVO; -import com.cloud.network.vpc.NetworkACLManager; -import com.cloud.network.vpc.PrivateGateway; -import com.cloud.network.vpc.PrivateIpAddress; -import com.cloud.network.vpc.PrivateIpVO; -import com.cloud.network.vpc.StaticRoute; -import com.cloud.network.vpc.StaticRouteProfile; -import com.cloud.network.vpc.Vpc; -import com.cloud.network.vpc.VpcGateway; -import com.cloud.network.vpc.VpcManager; -import com.cloud.network.vpc.VpcVO; -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 org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -108,6 +90,24 @@ import com.cloud.network.dao.Site2SiteCustomerGatewayVO; import com.cloud.network.dao.Site2SiteVpnConnectionDao; import com.cloud.network.dao.Site2SiteVpnGatewayDao; import com.cloud.network.dao.Site2SiteVpnGatewayVO; +import com.cloud.network.vpc.NetworkACLItem; +import com.cloud.network.vpc.NetworkACLItemDao; +import com.cloud.network.vpc.NetworkACLItemVO; +import com.cloud.network.vpc.NetworkACLManager; +import com.cloud.network.vpc.PrivateGateway; +import com.cloud.network.vpc.PrivateIpAddress; +import com.cloud.network.vpc.PrivateIpVO; +import com.cloud.network.vpc.StaticRoute; +import com.cloud.network.vpc.StaticRouteProfile; +import com.cloud.network.vpc.Vpc; +import com.cloud.network.vpc.VpcGateway; +import com.cloud.network.vpc.VpcManager; +import com.cloud.network.vpc.VpcVO; +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.vpn.Site2SiteVpnManager; import com.cloud.offering.NetworkOffering; import com.cloud.user.Account; @@ -127,7 +127,6 @@ import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.VirtualMachineProfile.Param; import com.cloud.vm.dao.VMInstanceDao; - @Component @Local(value = {VpcVirtualNetworkApplianceManager.class, VpcVirtualNetworkApplianceService.class}) public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplianceManagerImpl implements VpcVirtualNetworkApplianceManager{ @@ -339,7 +338,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian DomainRouterVO router = _routerDao.findById(vm.getId()); if (router.getState() == State.Running) { try { - PlugNicCommand plugNicCmd = new PlugNicCommand(nic, vm.getName()); + PlugNicCommand plugNicCmd = new PlugNicCommand(nic, vm.getName(), vm.getType()); Commands cmds = new Commands(OnError.Stop); cmds.addCommand("plugnic", plugNicCmd); @@ -748,7 +747,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian // if (rule.getSourceCidrList() == null && (rule.getPurpose() == Purpose.Firewall || rule.getPurpose() == Purpose.NetworkACL)) { // _firewallDao.loadSourceCidrs((FirewallRuleVO)rule); // } - NetworkACLTO ruleTO = new NetworkACLTO((NetworkACLItemVO)rule, guestVlan, rule.getTrafficType()); + NetworkACLTO ruleTO = new NetworkACLTO(rule, guestVlan, rule.getTrafficType()); rulesTO.add(ruleTO); } } @@ -828,7 +827,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian _routerDao.update(routerVO.getId(), routerVO); } } - PlugNicCommand plugNicCmd = new PlugNicCommand(getNicTO(router, publicNic.getNetworkId(), publicNic.getBroadcastUri().toString()), router.getInstanceName()); + PlugNicCommand plugNicCmd = new PlugNicCommand(getNicTO(router, publicNic.getNetworkId(), publicNic.getBroadcastUri().toString()), router.getInstanceName(), router.getType()); cmds.addCommand(plugNicCmd); VpcVO vpc = _vpcDao.findById(router.getVpcId()); NetworkUsageCommand netUsageCmd = new NetworkUsageCommand(router.getPrivateIpAddress(), router.getInstanceName(), true, publicNic.getIp4Address(), vpc.getCidr()); @@ -851,7 +850,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian for (Pair nicNtwk : guestNics) { Nic guestNic = nicNtwk.first(); //plug guest nic - PlugNicCommand plugNicCmd = new PlugNicCommand(getNicTO(router, guestNic.getNetworkId(), null), router.getInstanceName()); + PlugNicCommand plugNicCmd = new PlugNicCommand(getNicTO(router, guestNic.getNetworkId(), null), router.getInstanceName(), router.getType()); cmds.addCommand(plugNicCmd); if (!_networkModel.isPrivateGateway(guestNic)) { diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 7416cae61de..aa065294f8c 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2898,6 +2898,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use originalIp = nic.getIp4Address(); guestNic = nic; guestNetwork = network; + // In vmware, we will be effecting pvlan settings in portgroups in StartCommand. + if (profile.getHypervisorType() != HypervisorType.VMware) { if (nic.getBroadcastUri().getScheme().equals("pvlan")) { if (!setupVmForPvlan(true, hostId, nic)) { return false; @@ -2905,6 +2907,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } } } + } boolean ipChanged = false; if (originalIp != null && !originalIp.equalsIgnoreCase(returnedIp)) { if (returnedIp != null && guestNic != null) { @@ -4336,7 +4339,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use UserVmVO vmVO = _vmDao.findById(vm.getId()); if (vmVO.getState() == State.Running) { try { - PlugNicCommand plugNicCmd = new PlugNicCommand(nic,vm.getName()); + PlugNicCommand plugNicCmd = new PlugNicCommand(nic,vm.getName(), vm.getType()); Commands cmds = new Commands(OnError.Stop); cmds.addCommand("plugnic",plugNicCmd); _agentMgr.send(dest.getHost().getId(),cmds); diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/DistributedVirtualSwitchMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/DistributedVirtualSwitchMO.java index 247be2a5fab..b00b97ca3ae 100644 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/DistributedVirtualSwitchMO.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/DistributedVirtualSwitchMO.java @@ -17,13 +17,20 @@ package com.cloud.hypervisor.vmware.mo; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.log4j.Logger; import com.cloud.hypervisor.vmware.util.VmwareContext; import com.vmware.vim25.DVPortgroupConfigSpec; +import com.vmware.vim25.DVSConfigInfo; import com.vmware.vim25.ManagedObjectReference; +import com.vmware.vim25.TaskInfo; +import com.vmware.vim25.VMwareDVSConfigInfo; +import com.vmware.vim25.VMwareDVSConfigSpec; +import com.vmware.vim25.VMwareDVSPvlanMapEntry; public class DistributedVirtualSwitchMO extends BaseMO { private static final Logger s_logger = Logger.getLogger(DistributedVirtualSwitchMO.class); @@ -46,4 +53,74 @@ public class DistributedVirtualSwitchMO extends BaseMO { // TODO(sateesh): Update numPorts _context.getService().reconfigureDVPortgroupTask(dvPortGroupMor, dvPortGroupSpec); } + + public void updateVMWareDVSwitch(ManagedObjectReference dvSwitchMor, VMwareDVSConfigSpec dvsSpec) throws Exception { + _context.getService().reconfigureDvsTask(dvSwitchMor, dvsSpec); + } + + public TaskInfo updateVMWareDVSwitchGetTask(ManagedObjectReference dvSwitchMor, VMwareDVSConfigSpec dvsSpec) throws Exception { + ManagedObjectReference task = _context.getService().reconfigureDvsTask(dvSwitchMor, dvsSpec); + TaskInfo info = (TaskInfo) (_context.getVimClient().getDynamicProperty(task, "info")); + boolean waitvalue = _context.getVimClient().waitForTask(task); + return info; + } + + public String getDVSConfigVersion(ManagedObjectReference dvSwitchMor) throws Exception { + assert (dvSwitchMor != null); + DVSConfigInfo dvsConfigInfo = (DVSConfigInfo)_context.getVimClient().getDynamicProperty(dvSwitchMor, "config"); + return dvsConfigInfo.getConfigVersion(); + } + + public Map retrieveVlanPvlan(int vlanid, int secondaryvlanid, ManagedObjectReference dvSwitchMor) throws Exception { + assert (dvSwitchMor != null); + + Map result = new HashMap(); + + VMwareDVSConfigInfo configinfo = (VMwareDVSConfigInfo)_context.getVimClient().getDynamicProperty(dvSwitchMor, "config"); + List pvlanconfig = null; + pvlanconfig = configinfo.getPvlanConfig(); + + if (null == pvlanconfig || 0 == pvlanconfig.size()) { + return result; + } + // Iterate through the pvlanMapList and check if the specified vlan id and pvlan id exist. If they do, set the fields in result accordingly. + + for (VMwareDVSPvlanMapEntry mapEntry : pvlanconfig) { + int entryVlanid = mapEntry.getPrimaryVlanId(); + int entryPvlanid = mapEntry.getSecondaryVlanId(); + if (entryVlanid == entryPvlanid) { + // promiscuous + if (vlanid == entryVlanid) { + // pvlan type will always be promiscuous in this case. + result.put(vlanid, HypervisorHostHelper.PvlanType.valueOf(mapEntry.getPvlanType())); + } else if ((vlanid != secondaryvlanid) && secondaryvlanid == entryVlanid) { + result.put(secondaryvlanid, HypervisorHostHelper.PvlanType.valueOf(mapEntry.getPvlanType())); + } + } else { + if (vlanid == entryVlanid) { + // vlan id in entry is promiscuous + result.put(vlanid, HypervisorHostHelper.PvlanType.promiscuous); + } else if (vlanid == entryPvlanid) { + result.put(vlanid, HypervisorHostHelper.PvlanType.valueOf(mapEntry.getPvlanType())); + } + if ((vlanid != secondaryvlanid) && secondaryvlanid == entryVlanid) { + //promiscuous + result.put(secondaryvlanid, HypervisorHostHelper.PvlanType.promiscuous); + } else if (secondaryvlanid == entryPvlanid) { + result.put(secondaryvlanid, HypervisorHostHelper.PvlanType.valueOf(mapEntry.getPvlanType())); + } + + } + // If we already know that the vlanid is being used as a non primary vlan, it's futile to + // go over the entire list. Return. + if (result.containsKey(vlanid) && result.get(vlanid) != HypervisorHostHelper.PvlanType.promiscuous) + return result; + + // If we've already found both vlanid and pvlanid, we have enough info to make a decision. Return. + if (result.containsKey(vlanid) && result.containsKey(secondaryvlanid)) + return result; + } + return result; + } + } diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java index 7f323c5e400..20f84784157 100755 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java @@ -39,6 +39,7 @@ import com.cloud.utils.cisco.n1kv.vsm.VsmCommand.SwitchPortMode; import com.cloud.utils.db.GlobalLock; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; +import com.vmware.vim25.AlreadyExistsFaultMsg; import com.vmware.vim25.BoolPolicy; import com.vmware.vim25.DVPortSetting; import com.vmware.vim25.DVPortgroupConfigInfo; @@ -59,7 +60,11 @@ import com.vmware.vim25.ObjectContent; import com.vmware.vim25.OvfCreateImportSpecParams; import com.vmware.vim25.OvfCreateImportSpecResult; import com.vmware.vim25.OvfFileItem; +import com.vmware.vim25.TaskInfo; +import com.vmware.vim25.VMwareDVSConfigSpec; import com.vmware.vim25.VMwareDVSPortSetting; +import com.vmware.vim25.VMwareDVSPvlanConfigSpec; +import com.vmware.vim25.VMwareDVSPvlanMapEntry; import com.vmware.vim25.VirtualDeviceConfigSpec; import com.vmware.vim25.VirtualDeviceConfigSpecOperation; import com.vmware.vim25.VirtualLsiLogicController; @@ -67,6 +72,7 @@ import com.vmware.vim25.VirtualMachineConfigSpec; import com.vmware.vim25.VirtualMachineFileInfo; import com.vmware.vim25.VirtualMachineVideoCard; import com.vmware.vim25.VirtualSCSISharing; +import com.vmware.vim25.VmwareDistributedVirtualSwitchPvlanSpec; import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec; import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanSpec; @@ -124,12 +130,17 @@ public class HypervisorHostHelper { } } - public static String composeCloudNetworkName(String prefix, String vlanId, Integer networkRateMbps, String vSwitchName) { + public static String composeCloudNetworkName(String prefix, String vlanId, String svlanId, Integer networkRateMbps, String vSwitchName) { StringBuffer sb = new StringBuffer(prefix); - if(vlanId == null || UNTAGGED_VLAN_NAME.equalsIgnoreCase(vlanId)) + if(vlanId == null || UNTAGGED_VLAN_NAME.equalsIgnoreCase(vlanId)) { sb.append(".untagged"); - else + } else { sb.append(".").append(vlanId); + if (svlanId != null) { + sb.append(".").append("s" + svlanId); + } + + } if(networkRateMbps != null && networkRateMbps.intValue() > 0) sb.append(".").append(String.valueOf(networkRateMbps)); @@ -412,7 +423,7 @@ public class HypervisorHostHelper { */ public static Pair prepareNetwork(String physicalNetwork, String namePrefix, - HostMO hostMo, String vlanId, Integer networkRateMbps, Integer networkRateMulticastMbps, long timeOutMs, + HostMO hostMo, String vlanId, String secondaryvlanId, Integer networkRateMbps, Integer networkRateMulticastMbps, long timeOutMs, VirtualSwitchType vSwitchType, int numPorts, String gateway, boolean configureVServiceInNexus) throws Exception { ManagedObjectReference morNetwork = null; VmwareContext context = hostMo.getContext(); @@ -428,20 +439,28 @@ public class HypervisorHostHelper { boolean createGCTag = false; String networkName; Integer vid = null; + Integer spvlanid = null; // secondary pvlan id if(vlanId != null && !UNTAGGED_VLAN_NAME.equalsIgnoreCase(vlanId)) { createGCTag = true; vid = Integer.parseInt(vlanId); } - networkName = composeCloudNetworkName(namePrefix, vlanId, networkRateMbps, physicalNetwork); + if (secondaryvlanId != null) { + spvlanid = Integer.parseInt(secondaryvlanId); + } + networkName = composeCloudNetworkName(namePrefix, vlanId, secondaryvlanId, networkRateMbps, physicalNetwork); if (vSwitchType == VirtualSwitchType.VMwareDistributedVirtualSwitch) { + VMwareDVSConfigSpec dvsSpec = null; DVSTrafficShapingPolicy shapingPolicy; - VmwareDistributedVirtualSwitchVlanSpec vlanSpec; + VmwareDistributedVirtualSwitchVlanSpec vlanSpec = null; + VmwareDistributedVirtualSwitchPvlanSpec pvlanSpec = null; + //VMwareDVSPvlanConfigSpec pvlanSpec = null; DVSSecurityPolicy secPolicy; VMwareDVSPortSetting dvsPortSetting; DVPortgroupConfigSpec dvPortGroupSpec; DVPortgroupConfigInfo dvPortgroupInfo; + //DVSConfigInfo dvsInfo; dvSwitchName = physicalNetwork; // TODO(sateesh): Remove this after ensuring proper default value for vSwitchName throughout traffic types @@ -462,13 +481,95 @@ public class HypervisorHostHelper { dvSwitchMo = new DistributedVirtualSwitchMO(context, morDvSwitch); shapingPolicy = getDVSShapingPolicy(networkRateMbps); - if (vid != null) { - vlanSpec = createDVPortVlanIdSpec(vid); - } else { - vlanSpec = createDVPortVlanSpec(); - } secPolicy = createDVSSecurityPolicy(); + + // First, if both vlan id and pvlan id are provided, we need to + // reconfigure the DVSwitch to have a tuple of + // type isolated. + if (vid != null && spvlanid != null) { + // First check if the vlan/pvlan pair already exists on this dvswitch. + + Map vlanmap = dvSwitchMo.retrieveVlanPvlan(vid, spvlanid, morDvSwitch); + if (vlanmap.size() != 0) { + // Then either vid or pvlanid or both are already being used. + if (vlanmap.containsKey(vid) && vlanmap.get(vid) != HypervisorHostHelper.PvlanType.promiscuous) { + // This VLAN ID is already setup as a non-promiscuous vlan id on the DVS. Throw an exception. + String msg = "VLAN ID " + vid + " is already in use as a " + vlanmap.get(vid).toString() + " VLAN on the DVSwitch"; + s_logger.error(msg); + throw new Exception(msg); + } + if ((vid != spvlanid) && vlanmap.containsKey(spvlanid) && vlanmap.get(spvlanid) != HypervisorHostHelper.PvlanType.isolated) { + // This PVLAN ID is already setup as a non-isolated vlan id on the DVS. Throw an exception. + String msg = "PVLAN ID " + spvlanid + " is already in use as a " + vlanmap.get(spvlanid).toString() + " VLAN in the DVSwitch"; + s_logger.error(msg); + throw new Exception(msg); + } + } + + // First create a DVSconfig spec. + dvsSpec = new VMwareDVSConfigSpec(); + // Next, add the required primary and secondary vlan config specs to the dvs config spec. + if (!vlanmap.containsKey(vid)) { + VMwareDVSPvlanConfigSpec ppvlanConfigSpec = createDVPortPvlanConfigSpec(vid, vid, PvlanType.promiscuous, PvlanOperation.add); + dvsSpec.getPvlanConfigSpec().add(ppvlanConfigSpec); + } + if ( !vid.equals(spvlanid) && !vlanmap.containsKey(spvlanid)) { + VMwareDVSPvlanConfigSpec spvlanConfigSpec = createDVPortPvlanConfigSpec(vid, spvlanid, PvlanType.isolated, PvlanOperation.add); + dvsSpec.getPvlanConfigSpec().add(spvlanConfigSpec); + } + + if (dvsSpec.getPvlanConfigSpec().size() > 0) { + // We have something to configure on the DVS... so send it the command. + // When reconfiguring a vmware DVSwitch, we need to send in the configVersion in the spec. + // Let's retrieve this switch's configVersion first. + String dvsConfigVersion = dvSwitchMo.getDVSConfigVersion(morDvSwitch); + dvsSpec.setConfigVersion(dvsConfigVersion); + // Reconfigure the dvs using this spec. + + try { + TaskInfo reconfigTask = dvSwitchMo.updateVMWareDVSwitchGetTask(morDvSwitch, dvsSpec); + } catch (Exception e) { + if(e instanceof AlreadyExistsFaultMsg) { + s_logger.info("Specified vlan id (" + vid + ") private vlan id (" + spvlanid + ") tuple already configured on VMWare DVSwitch"); + // Do nothing, good if the tuple's already configured on the dvswitch. + } else { + // Rethrow the exception + s_logger.error("Failed to configure vlan/pvlan tuple on VMware DVSwitch: " + vid + "/" + spvlanid + ", failure message: " + e.getMessage()); + e.printStackTrace(); + throw e; + } + } + } + // Else the vlan/pvlan pair already exists on the DVSwitch, and we needn't configure it again. + } + + // Next, create the port group. For this, we need to create a VLAN spec. + if (vid == null) { + vlanSpec = createDVPortVlanSpec(); + } else { + if (spvlanid == null) { + // Create vlan spec. + vlanSpec = createDVPortVlanIdSpec(vid); + } else { + // Create a pvlan spec. The pvlan spec is different from the pvlan config spec + // that we created earlier. The pvlan config spec is used to configure the switch + // with a tuple. The pvlan spec is used + // to configure a port group (i.e., a network) with a secondary vlan id. We don't + // need to mention more than the secondary vlan id because one secondary vlan id + // can be associated with only one primary vlan id. Give vCenter the secondary vlan id, + // and it will find out the associated primary vlan id and do the rest of the + // port group configuration. + pvlanSpec = createDVPortPvlanIdSpec(spvlanid); + } + } + + // NOTE - VmwareDistributedVirtualSwitchPvlanSpec extends VmwareDistributedVirtualSwitchVlanSpec. + if (pvlanSpec != null) { + dvsPortSetting = createVmwareDVPortSettingSpec(shapingPolicy, secPolicy, pvlanSpec); + } else { dvsPortSetting = createVmwareDVPortSettingSpec(shapingPolicy, secPolicy, vlanSpec); + } + dvPortGroupSpec = createDvPortGroupSpec(networkName, dvsPortSetting, numPorts); if (!dataCenterMo.hasDvPortGroup(networkName)) { @@ -627,7 +728,6 @@ public class HypervisorHostHelper { dvsPortSetting.setSecurityPolicy(secPolicy); dvsPortSetting.setInShapingPolicy(shapingPolicy); dvsPortSetting.setOutShapingPolicy(shapingPolicy); - return dvsPortSetting; } @@ -658,6 +758,35 @@ public class HypervisorHostHelper { return shapingPolicy; } + public static VmwareDistributedVirtualSwitchPvlanSpec createDVPortPvlanIdSpec(int pvlanId) { + VmwareDistributedVirtualSwitchPvlanSpec pvlanIdSpec = new VmwareDistributedVirtualSwitchPvlanSpec(); + pvlanIdSpec.setPvlanId(pvlanId); + return pvlanIdSpec; + } + + public enum PvlanOperation { + add, + edit, + remove + } + + public enum PvlanType { + promiscuous, + isolated, + community, // We don't use Community + } + + public static VMwareDVSPvlanConfigSpec createDVPortPvlanConfigSpec(int vlanId, int secondaryVlanId, PvlanType pvlantype, PvlanOperation operation) { + VMwareDVSPvlanConfigSpec pvlanConfigSpec = new VMwareDVSPvlanConfigSpec(); + VMwareDVSPvlanMapEntry map = new VMwareDVSPvlanMapEntry(); + map.setPvlanType(pvlantype.toString()); + map.setPrimaryVlanId(vlanId); + map.setSecondaryVlanId(secondaryVlanId); + pvlanConfigSpec.setPvlanEntry(map); + + pvlanConfigSpec.setOperation(operation.toString()); + return pvlanConfigSpec; + } public static VmwareDistributedVirtualSwitchVlanIdSpec createDVPortVlanIdSpec(int vlanId) { VmwareDistributedVirtualSwitchVlanIdSpec vlanIdSpec = new VmwareDistributedVirtualSwitchVlanIdSpec(); vlanIdSpec.setVlanId(vlanId); @@ -706,7 +835,7 @@ public class HypervisorHostHelper { vid = Integer.parseInt(vlanId); } - networkName = composeCloudNetworkName(namePrefix, vlanId, networkRateMbps, vSwitchName); + networkName = composeCloudNetworkName(namePrefix, vlanId, null, networkRateMbps, vSwitchName); HostNetworkSecurityPolicy secPolicy = null; if (namePrefix.equalsIgnoreCase("cloud.private")) { secPolicy = new HostNetworkSecurityPolicy(); @@ -1036,6 +1165,7 @@ public class HypervisorHostHelper { context.uploadVmdkFile(ovfFileItem.isCreate() ? "PUT" : "POST", urlToPost, absoluteFile, bytesAlreadyWritten, new ActionDelegate () { + @Override public void action(Long param) { progressReporter.reportProgress((int)(param * 100 / totalBytes)); } From a2eb7bab1ef67de6589053ccd45515cf410d187c Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Thu, 16 May 2013 14:53:46 -0700 Subject: [PATCH 54/59] CLOUDSTACK-2056: DeploymentPlanner choice via ServiceOffering - Changes merged from planner_reserve branch - Exposing deploymentplanner as an optional parameter while creating a service offering - changes to DeploymentPlanningManagerImpl to make sure host reserve-release happens between conflicting planner usages. --- .../deploy/DeploymentClusterPlanner.java | 45 + .../com/cloud/deploy/DeploymentPlanner.java | 26 +- api/src/com/cloud/event/EventTypes.java | 2 +- .../com/cloud/offering/ServiceOffering.java | 2 + .../com/cloud/resource/ResourceService.java | 4 +- .../com/cloud/server/ManagementService.java | 2 + .../apache/cloudstack/api/ApiConstants.java | 1 + .../config/ListDeploymentPlannersCmd.java | 71 ++ .../admin/host/ReleaseHostReservationCmd.java | 105 ++ .../offering/CreateServiceOfferingCmd.java | 6 + .../api/response/ServiceOfferingResponse.java | 12 + client/tomcatconf/applicationContext.xml.in | 28 +- client/tomcatconf/commands.properties.in | 2 + .../cloud/migration/ServiceOffering21VO.java | 5 + .../com/cloud/service/ServiceOfferingVO.java | 17 + .../cloud/upgrade/dao/Upgrade410to420.java | 60 +- .../src/com/cloud/vm/dao/VMInstanceDao.java | 28 +- .../com/cloud/vm/dao/VMInstanceDaoImpl.java | 147 ++- .../ClusterScopeStoragePoolAllocator.java | 18 +- .../allocator/LocalStoragePoolAllocator.java | 21 +- .../ZoneWideStoragePoolAllocator.java | 25 +- .../deploy/UserConcentratedPodPlanner.java | 34 +- .../cloud/deploy/UserDispersingPlanner.java | 14 +- .../manager/BaremetalPlannerSelector.java | 39 - server/pom.xml | 5 + .../allocator/impl/FirstFitAllocator.java | 110 +- .../query/dao/ServiceOfferingJoinDaoImpl.java | 1 + .../api/query/vo/ServiceOfferingJoinVO.java | 11 + .../cloud/capacity/CapacityManagerImpl.java | 38 + .../src/com/cloud/configuration/Config.java | 3 + .../configuration/ConfigurationManager.java | 3 +- .../ConfigurationManagerImpl.java | 162 +-- .../deploy/AbstractDeployPlannerSelector.java | 84 -- .../deploy/DeploymentPlanningManagerImpl.java | 1032 ++++++++++++++++- .../src/com/cloud/deploy/FirstFitPlanner.java | 617 ++-------- .../deploy/HypervisorVmPlannerSelector.java | 54 - .../deploy/PlannerHostReservationVO.java | 117 ++ .../PlannerHostReservationDao.java} | 54 +- .../dao/PlannerHostReservationDaoImpl.java | 63 + .../cloud/resource/ResourceManagerImpl.java | 43 + .../cloud/server/ManagementServerImpl.java | 125 +- .../src/com/cloud/vm/UserVmManagerImpl.java | 26 +- .../resource/MockResourceManagerImpl.java | 6 + .../vm/DeploymentPlanningManagerImplTest.java | 359 ++++++ .../vpc/MockConfigurationManagerImpl.java | 2 +- .../ChildTestConfiguration.java | 72 +- server/test/resources/affinityContext.xml | 42 + setup/db/db/schema-410to420.sql | 61 +- ...ploy_vms_with_varied_deploymentplanners.py | 164 +++ tools/apidoc/gen_toc.py | 1 + 50 files changed, 2878 insertions(+), 1091 deletions(-) create mode 100644 api/src/com/cloud/deploy/DeploymentClusterPlanner.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/config/ListDeploymentPlannersCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/host/ReleaseHostReservationCmd.java delete mode 100755 plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalPlannerSelector.java delete mode 100755 server/src/com/cloud/deploy/AbstractDeployPlannerSelector.java delete mode 100755 server/src/com/cloud/deploy/HypervisorVmPlannerSelector.java create mode 100644 server/src/com/cloud/deploy/PlannerHostReservationVO.java rename server/src/com/cloud/deploy/{DeployPlannerSelector.java => dao/PlannerHostReservationDao.java} (67%) mode change 100755 => 100644 create mode 100644 server/src/com/cloud/deploy/dao/PlannerHostReservationDaoImpl.java create mode 100644 server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java create mode 100644 server/test/resources/affinityContext.xml create mode 100644 test/integration/smoke/test_deploy_vms_with_varied_deploymentplanners.py diff --git a/api/src/com/cloud/deploy/DeploymentClusterPlanner.java b/api/src/com/cloud/deploy/DeploymentClusterPlanner.java new file mode 100644 index 00000000000..1a19c71dbfa --- /dev/null +++ b/api/src/com/cloud/deploy/DeploymentClusterPlanner.java @@ -0,0 +1,45 @@ +// 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.deploy; + +import java.util.List; + +import com.cloud.exception.InsufficientServerCapacityException; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile; + +/** + */ +public interface DeploymentClusterPlanner extends DeploymentPlanner { + /** + * This is called to determine list of possible clusters where a virtual + * machine can be deployed. + * + * @param vm + * virtual machine. + * @param plan + * deployment plan that tells you where it's being deployed to. + * @param avoid + * avoid these data centers, pods, clusters, or hosts. + * @return DeployDestination for that virtual machine. + */ + List orderClusters(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid) + throws InsufficientServerCapacityException; + + PlannerResourceUsage getResourceUsage(); + +} diff --git a/api/src/com/cloud/deploy/DeploymentPlanner.java b/api/src/com/cloud/deploy/DeploymentPlanner.java index 537dd314733..eb56a591f6b 100644 --- a/api/src/com/cloud/deploy/DeploymentPlanner.java +++ b/api/src/com/cloud/deploy/DeploymentPlanner.java @@ -35,6 +35,7 @@ import com.cloud.vm.VirtualMachineProfile; /** */ public interface DeploymentPlanner extends Adapter { + /** * plan is called to determine where a virtual machine should be running. * @@ -46,6 +47,7 @@ public interface DeploymentPlanner extends Adapter { * avoid these data centers, pods, clusters, or hosts. * @return DeployDestination for that virtual machine. */ + @Deprecated DeployDestination plan(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid) throws InsufficientServerCapacityException; /** @@ -88,6 +90,10 @@ public interface DeploymentPlanner extends Adapter { userconcentratedpod_firstfit; } + public enum PlannerResourceUsage { + Shared, Dedicated; + } + public static class ExcludeList { private Set _dcIds; private Set _podIds; @@ -99,10 +105,22 @@ public interface DeploymentPlanner extends Adapter { } public ExcludeList(Set _dcIds, Set _podIds, Set _clusterIds, Set _hostIds, Set _poolIds) { - this._dcIds = _dcIds; - this._podIds = _podIds; - this._clusterIds = _clusterIds; - this._poolIds = _poolIds; + if (_dcIds != null) { + this._dcIds = new HashSet(_dcIds); + } + if (_podIds != null) { + this._podIds = new HashSet(_podIds); + } + if (_clusterIds != null) { + this._clusterIds = new HashSet(_clusterIds); + } + + if (_hostIds != null) { + this._hostIds = new HashSet(_hostIds); + } + if (_poolIds != null) { + this._poolIds = new HashSet(_poolIds); + } } public boolean add(InsufficientCapacityException e) { diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index e317a8fbf1c..ee7f5b7d89f 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -423,6 +423,7 @@ public class EventTypes { public static final String EVENT_INTERNAL_LB_VM_START = "INTERNALLBVM.START"; public static final String EVENT_INTERNAL_LB_VM_STOP = "INTERNALLBVM.STOP"; + public static final String EVENT_HOST_RESERVATION_RELEASE = "HOST.RESERVATION.RELEASE"; // 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"; @@ -728,7 +729,6 @@ 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()); } diff --git a/api/src/com/cloud/offering/ServiceOffering.java b/api/src/com/cloud/offering/ServiceOffering.java index 165369c5e9b..45d5f38952b 100755 --- a/api/src/com/cloud/offering/ServiceOffering.java +++ b/api/src/com/cloud/offering/ServiceOffering.java @@ -108,4 +108,6 @@ public interface ServiceOffering extends InfrastructureEntity, InternalIdentity, boolean getDefaultUse(); String getSystemVmType(); + + String getDeploymentPlanner(); } diff --git a/api/src/com/cloud/resource/ResourceService.java b/api/src/com/cloud/resource/ResourceService.java index 08e2585d1a7..ce0df635bfe 100755 --- a/api/src/com/cloud/resource/ResourceService.java +++ b/api/src/com/cloud/resource/ResourceService.java @@ -100,11 +100,13 @@ public interface ResourceService { Swift discoverSwift(AddSwiftCmd addSwiftCmd) throws DiscoveryException; S3 discoverS3(AddS3Cmd cmd) throws DiscoveryException; - + List getSupportedHypervisorTypes(long zoneId, boolean forVirtualRouter, Long podId); Pair, Integer> listSwifts(ListSwiftsCmd cmd); List listS3s(ListS3sCmd cmd); + boolean releaseHostReservation(Long hostId); + } diff --git a/api/src/com/cloud/server/ManagementService.java b/api/src/com/cloud/server/ManagementService.java index 22494072648..59b83c9bbce 100755 --- a/api/src/com/cloud/server/ManagementService.java +++ b/api/src/com/cloud/server/ManagementService.java @@ -419,5 +419,7 @@ public interface ManagementService { * @return List of capacities */ List listTopConsumedResources(ListCapacityCmd cmd); + + List listDeploymentPlanners(); } diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index f09a00b98f8..8d7739c13e1 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -496,6 +496,7 @@ public class ApiConstants { public static final String AFFINITY_GROUP_NAMES = "affinitygroupnames"; public static final String ASA_INSIDE_PORT_PROFILE = "insideportprofile"; public static final String AFFINITY_GROUP_ID = "affinitygroupid"; + public static final String DEPLOYMENT_PLANNER = "deploymentplanner"; public static final String ACL_ID = "aclid"; public static final String NUMBER = "number"; diff --git a/api/src/org/apache/cloudstack/api/command/admin/config/ListDeploymentPlannersCmd.java b/api/src/org/apache/cloudstack/api/command/admin/config/ListDeploymentPlannersCmd.java new file mode 100644 index 00000000000..598b620c301 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/config/ListDeploymentPlannersCmd.java @@ -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. +package org.apache.cloudstack.api.command.admin.config; + +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.DeploymentPlannersResponse; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.log4j.Logger; + +@APICommand(name = "listDeploymentPlanners", description = "Lists all DeploymentPlanners available.", responseObject = DeploymentPlannersResponse.class) +public class ListDeploymentPlannersCmd extends BaseListCmd { + public static final Logger s_logger = Logger.getLogger(ListDeploymentPlannersCmd.class.getName()); + + private static final String s_name = "listdeploymentplannersresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public void execute(){ + List planners = _mgr.listDeploymentPlanners(); + ListResponse response = new ListResponse(); + List plannerResponses = new ArrayList(); + + for (String planner : planners) { + DeploymentPlannersResponse plannerResponse = new DeploymentPlannersResponse(); + plannerResponse.setName(planner); + plannerResponse.setObjectName("deploymentPlanner"); + plannerResponses.add(plannerResponse); + } + + response.setResponses(plannerResponses); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/host/ReleaseHostReservationCmd.java b/api/src/org/apache/cloudstack/api/command/admin/host/ReleaseHostReservationCmd.java new file mode 100644 index 00000000000..d09cf38cc50 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/host/ReleaseHostReservationCmd.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.api.command.admin.host; + +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.HostResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.user.Account; +import com.cloud.user.UserContext; + +@APICommand(name = "releaseHostReservation", description = "Releases host reservation.", responseObject = SuccessResponse.class) +public class ReleaseHostReservationCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(ReleaseHostReservationCmd.class.getName()); + + private static final String s_name = "releasehostreservationresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=HostResponse.class, + required=true, description="the host ID") + private Long id; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + Account account = UserContext.current().getCaller(); + if (account != null) { + return account.getId(); + } + + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public String getEventType() { + return EventTypes.EVENT_HOST_RESERVATION_RELEASE; + } + + @Override + public String getEventDescription() { + return "releasing reservation for host: " + getId(); + } + + @Override + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.Host; + } + + @Override + public Long getInstanceId() { + return getId(); + } + + @Override + public void execute(){ + boolean result = _resourceService.releaseHostReservation(getId()); + if (result) { + SuccessResponse response = new SuccessResponse(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to release host reservation"); + } + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java index 0e35276d914..c155b706fc0 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java @@ -84,6 +84,9 @@ public class CreateServiceOfferingCmd extends BaseCmd { @Parameter(name=ApiConstants.NETWORKRATE, type=CommandType.INTEGER, description="data transfer rate in megabits per second allowed. Supported only for non-System offering and system offerings having \"domainrouter\" systemvmtype") private Integer networkRate; + @Parameter(name = ApiConstants.DEPLOYMENT_PLANNER, type = CommandType.STRING, description = "The deployment planner heuristics used to deploy a VM of this offering. If null, value of global config vm.deployment.planner is used") + private String deploymentPlanner; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -148,6 +151,9 @@ public class CreateServiceOfferingCmd extends BaseCmd { return networkRate; } + public String getDeploymentPlanner() { + return deploymentPlanner; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/org/apache/cloudstack/api/response/ServiceOfferingResponse.java b/api/src/org/apache/cloudstack/api/response/ServiceOfferingResponse.java index f35e87e3b0f..08ebbb05887 100644 --- a/api/src/org/apache/cloudstack/api/response/ServiceOfferingResponse.java +++ b/api/src/org/apache/cloudstack/api/response/ServiceOfferingResponse.java @@ -18,6 +18,8 @@ package org.apache.cloudstack.api.response; import java.util.Date; +import javax.persistence.Column; + import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; @@ -82,6 +84,8 @@ public class ServiceOfferingResponse extends BaseResponse { @SerializedName(ApiConstants.NETWORKRATE) @Param(description="data transfer rate in megabits per second allowed.") private Integer networkRate; + @SerializedName(ApiConstants.DEPLOYMENT_PLANNER) @Param(description="deployment strategy used to deploy VM.") + private String deploymentPlanner; public String getId() { return id; @@ -225,4 +229,12 @@ public class ServiceOfferingResponse extends BaseResponse { public void setNetworkRate(Integer networkRate) { this.networkRate = networkRate; } + + public String getDeploymentPlanner() { + return deploymentPlanner; + } + + public void setDeploymentPlanner(String deploymentPlanner) { + this.deploymentPlanner = deploymentPlanner; + } } diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 6406660c814..1d1eca4c191 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -540,15 +540,11 @@ Deployment planners --> - - - + - - - + @@ -605,10 +601,6 @@ - - - - @@ -623,6 +615,7 @@ + @@ -630,9 +623,7 @@ - - - + @@ -833,17 +824,13 @@ - + - - - - @@ -859,6 +846,8 @@ + + @@ -868,4 +857,7 @@ + + + diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index f57cc3c1815..4cd9065b641 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -212,6 +212,7 @@ listConfigurations=1 ldapConfig=1 ldapRemove=1 listCapabilities=15 +listDeploymentPlanners=1 #### pod commands createPod=1 @@ -261,6 +262,7 @@ listHosts=3 findHostsForMigration=1 addSecondaryStorage=1 updateHostPassword=1 +releaseHostReservation=1 #### volume commands attachVolume=15 diff --git a/engine/schema/src/com/cloud/migration/ServiceOffering21VO.java b/engine/schema/src/com/cloud/migration/ServiceOffering21VO.java index d07be6462f1..7a49e63e5b3 100644 --- a/engine/schema/src/com/cloud/migration/ServiceOffering21VO.java +++ b/engine/schema/src/com/cloud/migration/ServiceOffering21VO.java @@ -174,5 +174,10 @@ public class ServiceOffering21VO extends DiskOffering21VO implements ServiceOffe return false; } + @Override + public String getDeploymentPlanner() { + // TODO Auto-generated method stub + return null; + } } diff --git a/engine/schema/src/com/cloud/service/ServiceOfferingVO.java b/engine/schema/src/com/cloud/service/ServiceOfferingVO.java index 94a73515e6a..fd31d301bc3 100755 --- a/engine/schema/src/com/cloud/service/ServiceOfferingVO.java +++ b/engine/schema/src/com/cloud/service/ServiceOfferingVO.java @@ -68,6 +68,9 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering @Column(name="sort_key") int sortKey; + @Column(name = "deployment_planner") + private String deploymentPlanner = null; + protected ServiceOfferingVO() { super(); } @@ -104,6 +107,15 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering this.hostTag = hostTag; } + public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, + boolean offerHA, boolean limitResourceUse, boolean volatileVm, String displayText, boolean useLocalStorage, + boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vm_type, Long domainId, + String hostTag, String deploymentPlanner) { + this(name, cpu, ramSize, speed, rateMbps, multicastRateMbps, offerHA, limitResourceUse, volatileVm, + displayText, useLocalStorage, recreatable, tags, systemUse, vm_type, domainId, hostTag); + this.deploymentPlanner = deploymentPlanner; + } + @Override public boolean getOfferHA() { return offerHA; @@ -208,4 +220,9 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering return volatileVm; } + @Override + public String getDeploymentPlanner() { + return deploymentPlanner; + } + } diff --git a/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java index 1d35c8981fa..c03d377cbe0 100644 --- a/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java @@ -17,6 +17,10 @@ package com.cloud.upgrade.dao; +import com.cloud.deploy.DeploymentPlanner; +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.Date; @@ -25,12 +29,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; import java.util.UUID; - import com.cloud.network.vpc.NetworkACL; -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); @@ -70,6 +69,7 @@ public class Upgrade410to420 implements DbUpgrade { updatePrimaryStore(conn); addEgressFwRulesForSRXGuestNw(conn); upgradeEIPNetworkOfferings(conn); + updateGlobalDeploymentPlanner(conn); upgradeDefaultVpcOffering(conn); upgradePhysicalNtwksWithInternalLbProvider(conn); updateNetworkACLs(conn); @@ -563,6 +563,53 @@ public class Upgrade410to420 implements DbUpgrade { } } + private void updateGlobalDeploymentPlanner(Connection conn) { + PreparedStatement pstmt = null; + ResultSet rs = null; + + try { + pstmt = conn + .prepareStatement("select value from `cloud`.`configuration` where name = 'vm.allocation.algorithm'"); + rs = pstmt.executeQuery(); + while (rs.next()) { + String globalValue = rs.getString(1); + String plannerName = "FirstFitPlanner"; + + if (globalValue != null) { + if (globalValue.equals(DeploymentPlanner.AllocationAlgorithm.random.toString())) { + plannerName = "FirstFitPlanner"; + } else if (globalValue.equals(DeploymentPlanner.AllocationAlgorithm.firstfit.toString())) { + plannerName = "FirstFitPlanner"; + } else if (globalValue.equals(DeploymentPlanner.AllocationAlgorithm.userconcentratedpod_firstfit + .toString())) { + plannerName = "UserConcentratedPodPlanner"; + } else if (globalValue.equals(DeploymentPlanner.AllocationAlgorithm.userconcentratedpod_random + .toString())) { + plannerName = "UserConcentratedPodPlanner"; + } else if (globalValue.equals(DeploymentPlanner.AllocationAlgorithm.userdispersing.toString())) { + plannerName = "UserDispersingPlanner"; + } + } + // update vm.deployment.planner global config + pstmt = conn.prepareStatement("UPDATE `cloud`.`configuration` set value=? where name = 'vm.deployment.planner'"); + pstmt.setString(1, plannerName); + pstmt.executeUpdate(); + } + } catch (SQLException e) { + throw new CloudRuntimeException("Unable to set vm.deployment.planner global config", e); + } finally { + try { + if (rs != null) { + rs.close(); + } + if (pstmt != null) { + pstmt.close(); + } + } catch (SQLException e) { + } + } + } + private void upgradeDefaultVpcOffering(Connection conn) { PreparedStatement pstmt = null; @@ -596,8 +643,6 @@ public class Upgrade410to420 implements DbUpgrade { } } - - private void upgradePhysicalNtwksWithInternalLbProvider(Connection conn) { PreparedStatement pstmt = null; @@ -644,7 +689,6 @@ public class Upgrade410to420 implements DbUpgrade { } catch (SQLException e) { } } - } private void addHostDetailsIndex(Connection conn) { diff --git a/engine/schema/src/com/cloud/vm/dao/VMInstanceDao.java b/engine/schema/src/com/cloud/vm/dao/VMInstanceDao.java index c604027abde..830e4643251 100644 --- a/engine/schema/src/com/cloud/vm/dao/VMInstanceDao.java +++ b/engine/schema/src/com/cloud/vm/dao/VMInstanceDao.java @@ -38,14 +38,14 @@ public interface VMInstanceDao extends GenericDao, StateDao< * @return list of VMInstanceVO running on that host. */ List listByHostId(long hostId); - + /** * List VMs by zone ID * @param zoneId * @return list of VMInstanceVO in the specified zone */ List listByZoneId(long zoneId); - + /** * List VMs by pod ID * @param podId @@ -59,32 +59,32 @@ public interface VMInstanceDao extends GenericDao, StateDao< * @return list of VMInstanceVO in the specified zone, deployed from the specified template, that are not expunged */ public List listNonExpungedByZoneAndTemplate(long zoneId, long templateId); - + /** * Find vm instance with names like. - * + * * @param name name that fits SQL like. * @return list of VMInstanceVO */ List findVMInstancesLike(String name); - + List findVMInTransition(Date time, State... states); List listByTypes(VirtualMachine.Type... types); - + VMInstanceVO findByIdTypes(long id, VirtualMachine.Type... types); - + VMInstanceVO findVMByInstanceName(String name); void updateProxyId(long id, Long proxyId, Date time); List listByHostIdTypes(long hostid, VirtualMachine.Type... types); - + List listUpByHostIdTypes(long hostid, VirtualMachine.Type... types); List listByZoneIdAndType(long zoneId, VirtualMachine.Type type); List listUpByHostId(Long hostId); List listByLastHostId(Long hostId); - + List listByTypeAndState(VirtualMachine.Type type, State state); List listByAccountId(long accountId); @@ -92,9 +92,9 @@ public interface VMInstanceDao extends GenericDao, StateDao< List listByClusterId(long clusterId); // this does not pull up VMs which are starting List listLHByClusterId(long clusterId); // get all the VMs even starting one on this cluster - + List listVmsMigratingFromHost(Long hostId); - + public Long countRunningByHostId(long hostId); Pair, Map> listClusterIdsInZoneByVmCount(long zoneId, long accountId); @@ -106,7 +106,7 @@ public interface VMInstanceDao extends GenericDao, StateDao< List listHostIdsByVmCount(long dcId, Long podId, Long clusterId, long accountId); Long countRunningByAccount(long accountId); - + List listNonRemovedVmsByTypeAndNetwork(long networkId, VirtualMachine.Type... types); /** @@ -116,4 +116,8 @@ public interface VMInstanceDao extends GenericDao, StateDao< */ List listDistinctHostNames(long networkId, VirtualMachine.Type... types); + List findByHostInStates(Long hostId, State... states); + + List listStartingWithNoHostId(); + } diff --git a/engine/schema/src/com/cloud/vm/dao/VMInstanceDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/VMInstanceDaoImpl.java index 7198b7c24e0..ffb1a0b8b3d 100644 --- a/engine/schema/src/com/cloud/vm/dao/VMInstanceDaoImpl.java +++ b/engine/schema/src/com/cloud/vm/dao/VMInstanceDaoImpl.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, @@ -83,30 +83,32 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem protected GenericSearchBuilder CountRunningByAccount; protected SearchBuilder NetworkTypeSearch; protected GenericSearchBuilder DistinctHostNameSearch; - + protected SearchBuilder HostAndStateSearch; + protected SearchBuilder StartingWithNoHostSearch; + @Inject ResourceTagDao _tagsDao; @Inject NicDao _nicDao; - + protected Attribute _updateTimeAttr; - - private static final String ORDER_CLUSTERS_NUMBER_OF_VMS_FOR_ACCOUNT_PART1 = + + private static final String ORDER_CLUSTERS_NUMBER_OF_VMS_FOR_ACCOUNT_PART1 = "SELECT host.cluster_id, SUM(IF(vm.state='Running' AND vm.account_id = ?, 1, 0)) FROM `cloud`.`host` host LEFT JOIN `cloud`.`vm_instance` vm ON host.id = vm.host_id WHERE "; private static final String ORDER_CLUSTERS_NUMBER_OF_VMS_FOR_ACCOUNT_PART2 = " AND host.type = 'Routing' GROUP BY host.cluster_id ORDER BY 2 ASC "; - + private static final String ORDER_PODS_NUMBER_OF_VMS_FOR_ACCOUNT = "SELECT pod.id, SUM(IF(vm.state='Running' AND vm.account_id = ?, 1, 0)) FROM `cloud`.`host_pod_ref` pod LEFT JOIN `cloud`.`vm_instance` vm ON pod.id = vm.pod_id WHERE pod.data_center_id = ? " + " GROUP BY pod.id ORDER BY 2 ASC "; - + private static final String ORDER_HOSTS_NUMBER_OF_VMS_FOR_ACCOUNT = "SELECT host.id, SUM(IF(vm.state='Running' AND vm.account_id = ?, 1, 0)) FROM `cloud`.`host` host LEFT JOIN `cloud`.`vm_instance` vm ON host.id = vm.host_id WHERE host.data_center_id = ? " + " AND host.pod_id = ? AND host.cluster_id = ? AND host.type = 'Routing' " + " GROUP BY host.id ORDER BY 2 ASC "; @Inject protected HostDao _hostDao; - + public VMInstanceDaoImpl() { } - + @PostConstruct protected void init() { @@ -114,14 +116,14 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem IdStatesSearch.and("id", IdStatesSearch.entity().getId(), Op.EQ); IdStatesSearch.and("states", IdStatesSearch.entity().getState(), Op.IN); IdStatesSearch.done(); - + VMClusterSearch = createSearchBuilder(); SearchBuilder hostSearch = _hostDao.createSearchBuilder(); VMClusterSearch.join("hostSearch", hostSearch, hostSearch.entity().getId(), VMClusterSearch.entity().getHostId(), JoinType.INNER); hostSearch.and("clusterId", hostSearch.entity().getClusterId(), SearchCriteria.Op.EQ); VMClusterSearch.done(); - + LHVMClusterSearch = createSearchBuilder(); SearchBuilder hostSearch1 = _hostDao.createSearchBuilder(); LHVMClusterSearch.join("hostSearch1", hostSearch1, hostSearch1.entity().getId(), LHVMClusterSearch.entity().getLastHostId(), JoinType.INNER); @@ -129,7 +131,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem hostSearch1.and("clusterId", hostSearch1.entity().getClusterId(), SearchCriteria.Op.EQ); LHVMClusterSearch.done(); - + AllFieldsSearch = createSearchBuilder(); AllFieldsSearch.and("host", AllFieldsSearch.entity().getHostId(), Op.EQ); AllFieldsSearch.and("lastHost", AllFieldsSearch.entity().getLastHostId(), Op.EQ); @@ -169,23 +171,23 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem IdTypesSearch.and("id", IdTypesSearch.entity().getId(), Op.EQ); IdTypesSearch.and("types", IdTypesSearch.entity().getType(), Op.IN); IdTypesSearch.done(); - + HostIdTypesSearch = createSearchBuilder(); HostIdTypesSearch.and("hostid", HostIdTypesSearch.entity().getHostId(), Op.EQ); HostIdTypesSearch.and("types", HostIdTypesSearch.entity().getType(), Op.IN); HostIdTypesSearch.done(); - + HostIdUpTypesSearch = createSearchBuilder(); HostIdUpTypesSearch.and("hostid", HostIdUpTypesSearch.entity().getHostId(), Op.EQ); HostIdUpTypesSearch.and("types", HostIdUpTypesSearch.entity().getType(), Op.IN); HostIdUpTypesSearch.and("states", HostIdUpTypesSearch.entity().getState(), Op.NIN); HostIdUpTypesSearch.done(); - + HostUpSearch = createSearchBuilder(); HostUpSearch.and("host", HostUpSearch.entity().getHostId(), Op.EQ); HostUpSearch.and("states", HostUpSearch.entity().getState(), Op.IN); HostUpSearch.done(); - + InstanceNameSearch = createSearchBuilder(); InstanceNameSearch.and("instanceName", InstanceNameSearch.entity().getInstanceName(), Op.EQ); InstanceNameSearch.done(); @@ -194,21 +196,31 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem CountVirtualRoutersByAccount.select(null, Func.COUNT, null); CountVirtualRoutersByAccount.and("account", CountVirtualRoutersByAccount.entity().getAccountId(), SearchCriteria.Op.EQ); CountVirtualRoutersByAccount.and("type", CountVirtualRoutersByAccount.entity().getType(), SearchCriteria.Op.EQ); - CountVirtualRoutersByAccount.and("state", CountVirtualRoutersByAccount.entity().getState(), SearchCriteria.Op.NIN); + CountVirtualRoutersByAccount.and("state", CountVirtualRoutersByAccount.entity().getState(), SearchCriteria.Op.NIN); CountVirtualRoutersByAccount.done(); - + CountRunningByHost = createSearchBuilder(Long.class); CountRunningByHost.select(null, Func.COUNT, null); CountRunningByHost.and("host", CountRunningByHost.entity().getHostId(), SearchCriteria.Op.EQ); CountRunningByHost.and("state", CountRunningByHost.entity().getState(), SearchCriteria.Op.EQ); - CountRunningByHost.done(); + CountRunningByHost.done(); CountRunningByAccount = createSearchBuilder(Long.class); CountRunningByAccount.select(null, Func.COUNT, null); CountRunningByAccount.and("account", CountRunningByAccount.entity().getAccountId(), SearchCriteria.Op.EQ); CountRunningByAccount.and("state", CountRunningByAccount.entity().getState(), SearchCriteria.Op.EQ); - CountRunningByAccount.done(); - + CountRunningByAccount.done(); + + HostAndStateSearch = createSearchBuilder(); + HostAndStateSearch.and("host", HostAndStateSearch.entity().getHostId(), Op.EQ); + HostAndStateSearch.and("states", HostAndStateSearch.entity().getState(), Op.IN); + HostAndStateSearch.done(); + + StartingWithNoHostSearch = createSearchBuilder(); + StartingWithNoHostSearch.and("state", StartingWithNoHostSearch.entity().getState(), Op.EQ); + StartingWithNoHostSearch.and("host", StartingWithNoHostSearch.entity().getHostId(), Op.NULL); + StartingWithNoHostSearch.done(); + _updateTimeAttr = _allAttributes.get("updateTime"); assert _updateTimeAttr != null : "Couldn't get this updateTime attribute"; } @@ -219,7 +231,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setParameters("account", accountId); return listBy(sc); } - + @Override public List findVMInstancesLike(String name) { SearchCriteria sc = NameLikeSearch.create(); @@ -234,7 +246,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem return listBy(sc); } - + @Override public List listByZoneId(long zoneId) { SearchCriteria sc = AllFieldsSearch.create(); @@ -242,7 +254,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem return listBy(sc); } - + @Override public List listByPodId(long podId) { SearchCriteria sc = AllFieldsSearch.create(); @@ -263,7 +275,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setJoinParameters("hostSearch1", "clusterId", clusterId); return listBy(sc); } - + @Override public List listByZoneIdAndType(long zoneId, VirtualMachine.Type type) { SearchCriteria sc = AllFieldsSearch.create(); @@ -271,8 +283,8 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setParameters("type", type.toString()); return listBy(sc); } - - + + @Override public List listNonExpungedByZoneAndTemplate(long zoneId, long templateId) { SearchCriteria sc = ZoneTemplateNonExpungedSearch.create(); @@ -310,7 +322,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setParameters("states", new Object[] {State.Destroyed, State.Stopped, State.Expunging}); return listBy(sc); } - + @Override public List listUpByHostId(Long hostId) { SearchCriteria sc = HostUpSearch.create(); @@ -318,14 +330,14 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setParameters("states", new Object[] {State.Starting, State.Running}); return listBy(sc); } - + @Override public List listByTypes(Type... types) { SearchCriteria sc = TypesSearch.create(); sc.setParameters("types", (Object[]) types); return listBy(sc); } - + @Override public List listByTypeAndState(VirtualMachine.Type type, State state) { SearchCriteria sc = AllFieldsSearch.create(); @@ -348,7 +360,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setParameters("instanceName", name); return findOneBy(sc); } - + @Override public void updateProxyId(long id, Long proxyId, Date time) { VMInstanceVO vo = createForUpdate(); @@ -369,12 +381,12 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem @SuppressWarnings("unchecked") Pair hosts = (Pair)opaque; Long newHostId = hosts.second(); - + VMInstanceVO vmi = (VMInstanceVO)vm; Long oldHostId = vmi.getHostId(); Long oldUpdated = vmi.getUpdated(); Date oldUpdateDate = vmi.getUpdateTime(); - + SearchCriteria sc = StateChangeSearch.create(); sc.setParameters("id", vmi.getId()); sc.setParameters("states", oldState); @@ -383,7 +395,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem vmi.incrUpdated(); UpdateBuilder ub = getUpdateBuilder(vmi); - + ub.set(vmi, "state", newState); ub.set(vmi, "hostId", newHostId); ub.set(vmi, "podIdToDeployIn", vmi.getPodIdToDeployIn()); @@ -393,7 +405,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem if (result == 0 && s_logger.isDebugEnabled()) { VMInstanceVO vo = findByIdIncludingRemoved(vm.getId()); - + if (vo != null) { StringBuilder str = new StringBuilder("Unable to update ").append(vo.toString()); str.append(": DB Data={Host=").append(vo.getHostId()).append("; State=").append(vo.getState().toString()).append("; updated=").append(vo.getUpdated()).append("; time=").append(vo.getUpdateTime()); @@ -407,7 +419,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem } return result > 0; } - + @Override public List listByLastHostId(Long hostId) { SearchCriteria sc = AllFieldsSearch.create(); @@ -415,7 +427,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setParameters("state", State.Stopped); return listBy(sc); } - + @Override public Long countAllocatedVirtualRoutersForAccount(long accountId) { SearchCriteria sc = CountVirtualRoutersByAccount.create(); @@ -424,7 +436,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setParameters("state", new Object[] {State.Destroyed, State.Error, State.Expunging}); return customSearch(sc, null).get(0); } - + @Override public List listVmsMigratingFromHost(Long hostId) { SearchCriteria sc = AllFieldsSearch.create(); @@ -432,7 +444,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setParameters("state", State.Migrating); return listBy(sc); } - + @Override public Long countRunningByHostId(long hostId){ SearchCriteria sc = CountRunningByHost.create(); @@ -455,7 +467,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem pstmt = txn.prepareAutoCloseStatement(sql.toString()); pstmt.setLong(1, accountId); pstmt.setLong(2, zoneId); - + ResultSet rs = pstmt.executeQuery(); while (rs.next()) { Long clusterId = rs.getLong(1); @@ -484,11 +496,11 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem pstmt = txn.prepareAutoCloseStatement(sql.toString()); pstmt.setLong(1, accountId); pstmt.setLong(2, podId); - + ResultSet rs = pstmt.executeQuery(); while (rs.next()) { Long clusterId = rs.getLong(1); - result.add(clusterId); + result.add(clusterId); clusterVmCountMap.put(clusterId, rs.getDouble(2)); } return new Pair, Map>(result, clusterVmCountMap); @@ -511,11 +523,11 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem pstmt = txn.prepareAutoCloseStatement(sql); pstmt.setLong(1, accountId); pstmt.setLong(2, dataCenterId); - + ResultSet rs = pstmt.executeQuery(); while (rs.next()) { Long podId = rs.getLong(1); - result.add(podId); + result.add(podId); podVmCountMap.put(podId, rs.getDouble(2)); } return new Pair, Map>(result, podVmCountMap); @@ -523,7 +535,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem throw new CloudRuntimeException("DB Exception on: " + ORDER_PODS_NUMBER_OF_VMS_FOR_ACCOUNT, e); } catch (Throwable e) { throw new CloudRuntimeException("Caught: " + ORDER_PODS_NUMBER_OF_VMS_FOR_ACCOUNT, e); - } + } } @Override @@ -538,7 +550,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem pstmt.setLong(2, dcId); pstmt.setLong(3, podId); pstmt.setLong(4, clusterId); - + ResultSet rs = pstmt.executeQuery(); while (rs.next()) { result.add(rs.getLong(1)); @@ -548,9 +560,9 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem throw new CloudRuntimeException("DB Exception on: " + ORDER_PODS_NUMBER_OF_VMS_FOR_ACCOUNT, e); } catch (Throwable e) { throw new CloudRuntimeException("Caught: " + ORDER_PODS_NUMBER_OF_VMS_FOR_ACCOUNT, e); - } + } } - + @Override public Long countRunningByAccount(long accountId){ SearchCriteria sc = CountRunningByAccount.create(); @@ -558,18 +570,18 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setParameters("state", State.Running); return customSearch(sc, null).get(0); } - + @Override public List listNonRemovedVmsByTypeAndNetwork(long networkId, VirtualMachine.Type... types) { if (NetworkTypeSearch == null) { - + SearchBuilder nicSearch = _nicDao.createSearchBuilder(); nicSearch.and("networkId", nicSearch.entity().getNetworkId(), SearchCriteria.Op.EQ); NetworkTypeSearch = createSearchBuilder(); NetworkTypeSearch.and("types", NetworkTypeSearch.entity().getType(), SearchCriteria.Op.IN); NetworkTypeSearch.and("removed", NetworkTypeSearch.entity().getRemoved(), SearchCriteria.Op.NULL); - NetworkTypeSearch.join("nicSearch", nicSearch, NetworkTypeSearch.entity().getId(), + NetworkTypeSearch.join("nicSearch", nicSearch, NetworkTypeSearch.entity().getId(), nicSearch.entity().getInstanceId(), JoinBuilder.JoinType.INNER); NetworkTypeSearch.done(); } @@ -577,27 +589,27 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem SearchCriteria sc = NetworkTypeSearch.create(); if (types != null && types.length != 0) { sc.setParameters("types", (Object[]) types); - } + } sc.setJoinParameters("nicSearch", "networkId", networkId); return listBy(sc); } - - - + + + @Override public List listDistinctHostNames(long networkId, VirtualMachine.Type... types) { if (DistinctHostNameSearch == null) { - + SearchBuilder nicSearch = _nicDao.createSearchBuilder(); nicSearch.and("networkId", nicSearch.entity().getNetworkId(), SearchCriteria.Op.EQ); DistinctHostNameSearch = createSearchBuilder(String.class); DistinctHostNameSearch.selectField(DistinctHostNameSearch.entity().getHostName()); - + DistinctHostNameSearch.and("types", DistinctHostNameSearch.entity().getType(), SearchCriteria.Op.IN); DistinctHostNameSearch.and("removed", DistinctHostNameSearch.entity().getRemoved(), SearchCriteria.Op.NULL); - DistinctHostNameSearch.join("nicSearch", nicSearch, DistinctHostNameSearch.entity().getId(), + DistinctHostNameSearch.join("nicSearch", nicSearch, DistinctHostNameSearch.entity().getId(), nicSearch.entity().getInstanceId(), JoinBuilder.JoinType.INNER); DistinctHostNameSearch.done(); } @@ -605,12 +617,12 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem SearchCriteria sc = DistinctHostNameSearch.create(); if (types != null && types.length != 0) { sc.setParameters("types", (Object[]) types); - } + } sc.setJoinParameters("nicSearch", "networkId", networkId); return customSearch(sc, null); } - + @Override @DB public boolean remove(Long id) { @@ -625,4 +637,19 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem return result; } + @Override + public List findByHostInStates(Long hostId, State... states) { + SearchCriteria sc = HostAndStateSearch.create(); + sc.setParameters("host", hostId); + sc.setParameters("states", (Object[]) states); + return listBy(sc); + } + + @Override + public List listStartingWithNoHostId() { + SearchCriteria sc = StartingWithNoHostSearch.create(); + sc.setParameters("state", State.Starting); + return listBy(sc); + } + } diff --git a/engine/storage/src/org/apache/cloudstack/storage/allocator/ClusterScopeStoragePoolAllocator.java b/engine/storage/src/org/apache/cloudstack/storage/allocator/ClusterScopeStoragePoolAllocator.java index 0dd55d1d325..5b1f8cd699a 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/allocator/ClusterScopeStoragePoolAllocator.java +++ b/engine/storage/src/org/apache/cloudstack/storage/allocator/ClusterScopeStoragePoolAllocator.java @@ -50,7 +50,7 @@ public class ClusterScopeStoragePoolAllocator extends AbstractStoragePoolAllocat @Override protected List select(DiskProfile dskCh, VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid, int returnUpTo) { - + s_logger.debug("ClusterScopeStoragePoolAllocator looking for storage pool"); List suitablePools = new ArrayList(); @@ -65,6 +65,14 @@ public class ClusterScopeStoragePoolAllocator extends AbstractStoragePoolAllocat } List pools = _storagePoolDao.findPoolsByTags(dcId, podId, clusterId, dskCh.getTags()); + + // add remaining pools in cluster, that did not match tags, to avoid set + List allPools = _storagePoolDao.findPoolsByTags(dcId, podId, clusterId, null); + allPools.removeAll(pools); + for (StoragePoolVO pool : allPools) { + avoid.addPool(pool.getId()); + } + if (pools.size() == 0) { if (s_logger.isDebugEnabled()) { String storageType = dskCh.useLocalStorage() ? ServiceOffering.StorageType.local.toString() : ServiceOffering.StorageType.shared.toString(); @@ -72,7 +80,7 @@ public class ClusterScopeStoragePoolAllocator extends AbstractStoragePoolAllocat } return suitablePools; } - + for (StoragePoolVO pool: pools) { if(suitablePools.size() == returnUpTo){ break; @@ -80,13 +88,15 @@ public class ClusterScopeStoragePoolAllocator extends AbstractStoragePoolAllocat StoragePool pol = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(pool.getId()); if (filter(avoid, pol, dskCh, plan)) { suitablePools.add(pol); + } else { + avoid.addPool(pool.getId()); } } - + if (s_logger.isDebugEnabled()) { s_logger.debug("FirstFitStoragePoolAllocator returning "+suitablePools.size() +" suitable storage pools"); } - + return suitablePools; } diff --git a/engine/storage/src/org/apache/cloudstack/storage/allocator/LocalStoragePoolAllocator.java b/engine/storage/src/org/apache/cloudstack/storage/allocator/LocalStoragePoolAllocator.java index 7447d988a58..632ba439cb0 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/allocator/LocalStoragePoolAllocator.java +++ b/engine/storage/src/org/apache/cloudstack/storage/allocator/LocalStoragePoolAllocator.java @@ -74,7 +74,7 @@ public class LocalStoragePoolAllocator extends AbstractStoragePoolAllocator { if (!dskCh.useLocalStorage()) { return suitablePools; } - + // data disk and host identified from deploying vm (attach volume case) if (dskCh.getType() == Volume.Type.DATADISK && plan.getHostId() != null) { List hostPools = _poolHostDao.listByHostId(plan.getHostId()); @@ -85,7 +85,9 @@ public class LocalStoragePoolAllocator extends AbstractStoragePoolAllocator { if (filter(avoid, pol, dskCh, plan)) { s_logger.debug("Found suitable local storage pool " + pool.getId() + ", adding to list"); suitablePools.add(pol); - } + } else { + avoid.addPool(pool.getId()); + } } if (suitablePools.size() == returnUpTo) { @@ -101,8 +103,19 @@ public class LocalStoragePoolAllocator extends AbstractStoragePoolAllocator { StoragePool pol = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(pool.getId()); if (filter(avoid, pol, dskCh, plan)) { suitablePools.add(pol); - } + } else { + avoid.addPool(pool.getId()); + } } + + // add remaining pools in cluster, that did not match tags, to avoid + // set + List allPools = _storagePoolDao.findLocalStoragePoolsByTags(plan.getDataCenterId(), + plan.getPodId(), plan.getClusterId(), null); + allPools.removeAll(availablePools); + for (StoragePoolVO pool : allPools) { + avoid.addPool(pool.getId()); + } } if (s_logger.isDebugEnabled()) { @@ -111,7 +124,7 @@ public class LocalStoragePoolAllocator extends AbstractStoragePoolAllocator { return suitablePools; } - + @Override public boolean configure(String name, Map params) throws ConfigurationException { super.configure(name, params); diff --git a/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java b/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java index 1d3cd819d70..e9769802a37 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java +++ b/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java @@ -39,18 +39,18 @@ import com.cloud.vm.VirtualMachineProfile; @Component public class ZoneWideStoragePoolAllocator extends AbstractStoragePoolAllocator { private static final Logger s_logger = Logger.getLogger(ZoneWideStoragePoolAllocator.class); - @Inject PrimaryDataStoreDao _storagePoolDao; - @Inject DataStoreManager dataStoreMgr; - + @Inject PrimaryDataStoreDao _storagePoolDao; + @Inject DataStoreManager dataStoreMgr; + @Override - protected boolean filter(ExcludeList avoid, StoragePool pool, DiskProfile dskCh, + protected boolean filter(ExcludeList avoid, StoragePool pool, DiskProfile dskCh, DeploymentPlan plan) { Volume volume = _volumeDao.findById(dskCh.getVolumeId()); List requestVolumes = new ArrayList(); requestVolumes.add(volume); return storageMgr.storagePoolHasEnoughSpace(requestVolumes, pool); } - + @Override protected List select(DiskProfile dskCh, VirtualMachineProfile vmProfile, @@ -64,9 +64,16 @@ public class ZoneWideStoragePoolAllocator extends AbstractStoragePoolAllocator { return suitablePools; } } - + List storagePools = _storagePoolDao.findZoneWideStoragePoolsByTags(plan.getDataCenterId(), dskCh.getTags()); - + + // add remaining pools in zone, that did not match tags, to avoid set + List allPools = _storagePoolDao.findZoneWideStoragePoolsByTags(plan.getDataCenterId(), null); + allPools.removeAll(storagePools); + for (StoragePoolVO pool : allPools) { + avoid.addPool(pool.getId()); + } + for (StoragePoolVO storage : storagePools) { if (suitablePools.size() == returnUpTo) { break; @@ -74,7 +81,9 @@ public class ZoneWideStoragePoolAllocator extends AbstractStoragePoolAllocator { StoragePool pol = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(storage.getId()); if (filter(avoid, pol, dskCh, plan)) { suitablePools.add(pol); - } + } else { + avoid.addPool(pol.getId()); + } } return suitablePools; } diff --git a/plugins/deployment-planners/user-concentrated-pod/src/com/cloud/deploy/UserConcentratedPodPlanner.java b/plugins/deployment-planners/user-concentrated-pod/src/com/cloud/deploy/UserConcentratedPodPlanner.java index 2ab98566e0a..d917893719e 100644 --- a/plugins/deployment-planners/user-concentrated-pod/src/com/cloud/deploy/UserConcentratedPodPlanner.java +++ b/plugins/deployment-planners/user-concentrated-pod/src/com/cloud/deploy/UserConcentratedPodPlanner.java @@ -11,7 +11,7 @@ // 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 +// KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package com.cloud.deploy; @@ -24,18 +24,17 @@ import javax.ejb.Local; import org.apache.log4j.Logger; -import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.utils.Pair; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; @Local(value=DeploymentPlanner.class) -public class UserConcentratedPodPlanner extends FirstFitPlanner implements DeploymentPlanner { +public class UserConcentratedPodPlanner extends FirstFitPlanner implements DeploymentClusterPlanner { private static final Logger s_logger = Logger.getLogger(UserConcentratedPodPlanner.class); - + /** - * This method should reorder the given list of Cluster Ids by applying any necessary heuristic + * This method should reorder the given list of Cluster Ids by applying any necessary heuristic * for this planner * For UserConcentratedPodPlanner we need to order the clusters in a zone across pods, by considering those pods first which have more number of VMs for this account * This reordering is not done incase the clusters within single pod are passed when the allocation is applied at pod-level. @@ -49,7 +48,7 @@ public class UserConcentratedPodPlanner extends FirstFitPlanner implements Deplo } return applyUserConcentrationPodHeuristicToClusters(id, clusterIdsByCapacity, vmProfile.getOwner().getAccountId()); } - + private List applyUserConcentrationPodHeuristicToClusters(long zoneId, List prioritizedClusterIds, long accountId){ //user has VMs in certain pods. - prioritize those pods first //UserConcentratedPod strategy @@ -61,8 +60,8 @@ public class UserConcentratedPodPlanner extends FirstFitPlanner implements Deplo clusterList = prioritizedClusterIds; } return clusterList; - } - + } + private List reorderClustersByPods(List clusterIds, List podIds) { if (s_logger.isDebugEnabled()) { @@ -111,11 +110,11 @@ public class UserConcentratedPodPlanner extends FirstFitPlanner implements Deplo return prioritizedPods; } - + /** - * This method should reorder the given list of Pod Ids by applying any necessary heuristic + * This method should reorder the given list of Pod Ids by applying any necessary heuristic * for this planner - * For UserConcentratedPodPlanner we need to order the pods by considering those pods first which have more number of VMs for this account + * For UserConcentratedPodPlanner we need to order the pods by considering those pods first which have more number of VMs for this account * @return List ordered list of Pod Ids */ @Override @@ -124,7 +123,7 @@ public class UserConcentratedPodPlanner extends FirstFitPlanner implements Deplo if(vmProfile.getOwner() == null){ return podIdsByCapacity; } - long accountId = vmProfile.getOwner().getAccountId(); + long accountId = vmProfile.getOwner().getAccountId(); //user has VMs in certain pods. - prioritize those pods first //UserConcentratedPod strategy @@ -138,18 +137,7 @@ public class UserConcentratedPodPlanner extends FirstFitPlanner implements Deplo }else{ return podIdsByCapacity; } - - } - @Override - public boolean canHandle(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid) { - if(vm.getHypervisorType() != HypervisorType.BareMetal){ - //check the allocation strategy - if (_allocationAlgorithm != null && (_allocationAlgorithm.equals(AllocationAlgorithm.userconcentratedpod_random.toString()) || _allocationAlgorithm.equals(AllocationAlgorithm.userconcentratedpod_firstfit.toString()))){ - return true; - } - } - return false; } } diff --git a/plugins/deployment-planners/user-dispersing/src/com/cloud/deploy/UserDispersingPlanner.java b/plugins/deployment-planners/user-dispersing/src/com/cloud/deploy/UserDispersingPlanner.java index 2db2051389d..2b0b1588802 100755 --- a/plugins/deployment-planners/user-dispersing/src/com/cloud/deploy/UserDispersingPlanner.java +++ b/plugins/deployment-planners/user-dispersing/src/com/cloud/deploy/UserDispersingPlanner.java @@ -29,14 +29,13 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; import com.cloud.configuration.Config; -import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; @Local(value=DeploymentPlanner.class) -public class UserDispersingPlanner extends FirstFitPlanner implements DeploymentPlanner { +public class UserDispersingPlanner extends FirstFitPlanner implements DeploymentClusterPlanner { private static final Logger s_logger = Logger.getLogger(UserDispersingPlanner.class); @@ -191,17 +190,6 @@ public class UserDispersingPlanner extends FirstFitPlanner implements Deployment } - @Override - public boolean canHandle(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid) { - if(vm.getHypervisorType() != HypervisorType.BareMetal){ - //check the allocation strategy - if (_allocationAlgorithm != null && _allocationAlgorithm.equals(AllocationAlgorithm.userdispersing.toString())) { - return true; - } - } - return false; - } - float _userDispersionWeight; diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalPlannerSelector.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalPlannerSelector.java deleted file mode 100755 index 45fbeb782ab..00000000000 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalPlannerSelector.java +++ /dev/null @@ -1,39 +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.baremetal.manager; - -import java.util.Map; - -import javax.ejb.Local; -import javax.naming.ConfigurationException; - -import com.cloud.deploy.AbstractDeployPlannerSelector; -import com.cloud.deploy.DeployPlannerSelector; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.vm.UserVmVO; -@Local(value = {DeployPlannerSelector.class}) -public class BaremetalPlannerSelector extends AbstractDeployPlannerSelector{ - - @Override - public String selectPlanner(UserVmVO vm) { - if (vm.getHypervisorType() == HypervisorType.BareMetal) { - return "BareMetalPlanner"; - } - return null; - } - -} diff --git a/server/pom.xml b/server/pom.xml index 004d9c8e068..6385bf2f233 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -90,6 +90,11 @@ cloud-api ${project.version} + + org.apache.cloudstack + cloud-framework-ipc + ${project.version} + org.apache.cloudstack cloud-framework-events diff --git a/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java b/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java index b54b1c1f527..b6286aab8da 100755 --- a/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java +++ b/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java @@ -78,7 +78,7 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { @Inject ConsoleProxyDao _consoleProxyDao = null; @Inject SecondaryStorageVmDao _secStorgaeVmDao = null; @Inject ConfigurationDao _configDao = null; - @Inject GuestOSDao _guestOSDao = null; + @Inject GuestOSDao _guestOSDao = null; @Inject GuestOSCategoryDao _guestOSCategoryDao = null; @Inject VMInstanceDao _vmInstanceDao = null; @Inject ResourceManager _resourceMgr; @@ -88,17 +88,17 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { boolean _checkHvm = true; protected String _allocationAlgorithm = "random"; @Inject CapacityManager _capacityMgr; - - + + @Override public List allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, ExcludeList avoid, int returnUpTo) { return allocateTo(vmProfile, plan, type, avoid, returnUpTo, true); } - + @Override public List allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, ExcludeList avoid, int returnUpTo, boolean considerReservedCapacity) { - + long dcId = plan.getDataCenterId(); Long podId = plan.getPodId(); Long clusterId = plan.getClusterId(); @@ -110,19 +110,19 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { // FirstFitAllocator should be used for user VMs only since it won't care whether the host is capable of routing or not return new ArrayList(); } - + if(s_logger.isDebugEnabled()){ s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId ); } - + String hostTagOnOffering = offering.getHostTag(); String hostTagOnTemplate = template.getTemplateTag(); - + boolean hasSvcOfferingTag = hostTagOnOffering != null ? true : false; boolean hasTemplateTag = hostTagOnTemplate != null ? true : false; - + List clusterHosts = new ArrayList(); - + String haVmTag = (String)vmProfile.getParameter(VirtualMachineProfile.Param.HaTag); if (haVmTag != null) { clusterHosts = _hostDao.listByHostTag(type, clusterId, podId, dcId, haVmTag); @@ -133,31 +133,31 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { List hostsMatchingOfferingTag = new ArrayList(); List hostsMatchingTemplateTag = new ArrayList(); if (hasSvcOfferingTag){ - if (s_logger.isDebugEnabled()){ + if (s_logger.isDebugEnabled()){ s_logger.debug("Looking for hosts having tag specified on SvcOffering:" + hostTagOnOffering); } hostsMatchingOfferingTag = _hostDao.listByHostTag(type, clusterId, podId, dcId, hostTagOnOffering); - if (s_logger.isDebugEnabled()){ + if (s_logger.isDebugEnabled()){ s_logger.debug("Hosts with tag '" + hostTagOnOffering + "' are:" + hostsMatchingOfferingTag); - } + } } if (hasTemplateTag){ - if (s_logger.isDebugEnabled()){ + if (s_logger.isDebugEnabled()){ s_logger.debug("Looking for hosts having tag specified on Template:" + hostTagOnTemplate); } - hostsMatchingTemplateTag = _hostDao.listByHostTag(type, clusterId, podId, dcId, hostTagOnTemplate); - if (s_logger.isDebugEnabled()){ + hostsMatchingTemplateTag = _hostDao.listByHostTag(type, clusterId, podId, dcId, hostTagOnTemplate); + if (s_logger.isDebugEnabled()){ s_logger.debug("Hosts with tag '" + hostTagOnTemplate+"' are:" + hostsMatchingTemplateTag); - } + } } - + if (hasSvcOfferingTag && hasTemplateTag){ hostsMatchingOfferingTag.retainAll(hostsMatchingTemplateTag); - clusterHosts = _hostDao.listByHostTag(type, clusterId, podId, dcId, hostTagOnTemplate); - if (s_logger.isDebugEnabled()){ + clusterHosts = _hostDao.listByHostTag(type, clusterId, podId, dcId, hostTagOnTemplate); + if (s_logger.isDebugEnabled()){ s_logger.debug("Found "+ hostsMatchingOfferingTag.size() +" Hosts satisfying both tags, host ids are:" + hostsMatchingOfferingTag); } - + clusterHosts = hostsMatchingOfferingTag; } else { if (hasSvcOfferingTag){ @@ -168,7 +168,14 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { } } } - + + // add all hosts that we are not considering to the avoid list + List allhostsInCluster = _hostDao.listAllUpAndEnabledNonHAHosts(type, clusterId, podId, dcId, null); + allhostsInCluster.removeAll(clusterHosts); + for (HostVO host : allhostsInCluster) { + avoid.addHost(host.getId()); + } + return allocateTo(plan, offering, template, avoid, clusterHosts, returnUpTo, considerReservedCapacity, account); } @@ -226,11 +233,11 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { }else if(_allocationAlgorithm.equals("userdispersing")){ hosts = reorderHostsByNumberOfVms(plan, hosts, account); } - + if (s_logger.isDebugEnabled()) { s_logger.debug("FirstFitAllocator has " + hosts.size() + " hosts to check for allocation: "+hosts); } - + // We will try to reorder the host lists such that we give priority to hosts that have // the minimums to support a VM's requirements hosts = prioritizeHosts(template, hosts); @@ -242,7 +249,7 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { if (s_logger.isDebugEnabled()) { s_logger.debug("Looking for speed=" + (offering.getCpu() * offering.getSpeed()) + "Mhz, Ram=" + offering.getRamSize()); } - + List suitableHosts = new ArrayList(); for (HostVO host : hosts) { @@ -255,7 +262,7 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { } continue; } - + //find number of guest VMs occupying capacity on this host. if (_capacityMgr.checkIfHostReachMaxGuestLimit(host)){ if (s_logger.isDebugEnabled()) { @@ -285,13 +292,14 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { if (s_logger.isDebugEnabled()) { s_logger.debug("Not using host " + host.getId() + "; numCpusGood: " + numCpusGood + "; cpuFreqGood: " + cpuFreqGood + ", host has capacity?" + hostHasCapacity); } + avoid.addHost(host.getId()); } } - + if (s_logger.isDebugEnabled()) { s_logger.debug("Host Allocator returning "+suitableHosts.size() +" suitable hosts"); } - + return suitableHosts; } @@ -302,26 +310,26 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { long dcId = plan.getDataCenterId(); Long podId = plan.getPodId(); Long clusterId = plan.getClusterId(); - + List hostIdsByVmCount = _vmInstanceDao.listHostIdsByVmCount(dcId, podId, clusterId, account.getAccountId()); if (s_logger.isDebugEnabled()) { s_logger.debug("List of hosts in ascending order of number of VMs: "+ hostIdsByVmCount); } - + //now filter the given list of Hosts by this ordered list - Map hostMap = new HashMap(); + Map hostMap = new HashMap(); for (HostVO host : hosts) { hostMap.put(host.getId(), host); } List matchingHostIds = new ArrayList(hostMap.keySet()); - + hostIdsByVmCount.retainAll(matchingHostIds); - + List reorderedHosts = new ArrayList(); for(Long id: hostIdsByVmCount){ reorderedHosts.add(hostMap.get(id)); } - + return reorderedHosts; } @@ -336,13 +344,13 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { if (template == null) { return hosts; } - + // Determine the guest OS category of the template String templateGuestOSCategory = getTemplateGuestOSCategory(template); - + List prioritizedHosts = new ArrayList(); List noHvmHosts = new ArrayList(); - + // If a template requires HVM and a host doesn't support HVM, remove it from consideration List hostsToCheck = new ArrayList(); if (template.isRequiresHvm()) { @@ -356,7 +364,7 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { } else { hostsToCheck.addAll(hosts); } - + if (s_logger.isDebugEnabled()) { if (noHvmHosts.size() > 0) { s_logger.debug("Not considering hosts: " + noHvmHosts + " to deploy template: " + template +" as they are not HVM enabled"); @@ -376,10 +384,10 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { lowPriorityHosts.add(host); } } - + hostsToCheck.removeAll(highPriorityHosts); hostsToCheck.removeAll(lowPriorityHosts); - + // Prioritize the remaining hosts by HVM capability for (HostVO host : hostsToCheck) { if (!template.isRequiresHvm() && !hostSupportsHVM(host)) { @@ -390,21 +398,21 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { prioritizedHosts.add(host); } } - + // Merge the lists prioritizedHosts.addAll(0, highPriorityHosts); prioritizedHosts.addAll(lowPriorityHosts); - + return prioritizedHosts; } - + protected boolean hostSupportsHVM(HostVO host) { if ( !_checkHvm ) { return true; } // Determine host capabilities String caps = host.getCapabilities(); - + if (caps != null) { String[] tokens = caps.split(","); for (String token : tokens) { @@ -413,24 +421,24 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { } } } - + return false; } - + protected String getHostGuestOSCategory(HostVO host) { DetailVO hostDetail = _hostDetailsDao.findDetail(host.getId(), "guest.os.category.id"); if (hostDetail != null) { String guestOSCategoryIdString = hostDetail.getValue(); long guestOSCategoryId; - + try { guestOSCategoryId = Long.parseLong(guestOSCategoryIdString); } catch (Exception e) { return null; } - + GuestOSCategoryVO guestOSCategory = _guestOSCategoryDao.findById(guestOSCategoryId); - + if (guestOSCategory != null) { return guestOSCategory.getName(); } else { @@ -440,7 +448,7 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { return null; } } - + protected String getTemplateGuestOSCategory(VMTemplateVO template) { long guestOSId = template.getGuestOSId(); GuestOSVO guestOS = _guestOSDao.findById(guestOSId); @@ -455,7 +463,7 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { Map configs = _configDao.getConfiguration(params); String opFactor = configs.get("cpu.overprovisioning.factor"); _factor = NumbersUtil.parseFloat(opFactor, 1); - + String allocationAlgorithm = configs.get("vm.allocation.algorithm"); if (allocationAlgorithm != null) { _allocationAlgorithm = allocationAlgorithm; diff --git a/server/src/com/cloud/api/query/dao/ServiceOfferingJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/ServiceOfferingJoinDaoImpl.java index 9795fef66fd..ce20562d5f7 100644 --- a/server/src/com/cloud/api/query/dao/ServiceOfferingJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/ServiceOfferingJoinDaoImpl.java @@ -73,6 +73,7 @@ public class ServiceOfferingJoinDaoImpl extends GenericDaoBase params) throws ConfigurationException { _vmCapacityReleaseInterval = NumbersUtil.parseInt(_configDao.getValue(Config.CapacitySkipcountingHours.key()), 3600); @@ -552,6 +564,20 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, ServiceOffering so = offeringsMap.get(vm.getServiceOfferingId()); reservedMemory += so.getRamSize() * 1024L * 1024L; reservedCpu += so.getCpu() * so.getSpeed(); + } else { + // signal if not done already, that the VM has been stopped for skip.counting.hours, + // hence capacity will not be reserved anymore. + UserVmDetailVO messageSentFlag = _userVmDetailsDao.findDetail(vm.getId(), MESSAGE_RESERVED_CAPACITY_FREED_FLAG); + if (messageSentFlag == null || !Boolean.valueOf(messageSentFlag.getValue())) { + _messageBus.publish(_name, "VM_ReservedCapacity_Free", PublishScope.LOCAL, vm); + + if (vm.getType() == VirtualMachine.Type.User) { + UserVmVO userVM = _userVMDao.findById(vm.getId()); + _userVMDao.loadDetails(userVM); + userVM.setDetail(MESSAGE_RESERVED_CAPACITY_FREED_FLAG, "true"); + _userVMDao.saveDetails(userVM); + } + } } } @@ -688,6 +714,18 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, allocateVmCapacity(vm, fromLastHost); } + if (newState == State.Stopped) { + if (vm.getType() == VirtualMachine.Type.User) { + + UserVmVO userVM = _userVMDao.findById(vm.getId()); + _userVMDao.loadDetails(userVM); + // free the message sent flag if it exists + userVM.setDetail(MESSAGE_RESERVED_CAPACITY_FREED_FLAG, "false"); + _userVMDao.saveDetails(userVM); + + } + } + return true; } diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index 77ca2de1923..e1d3751f290 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -214,6 +214,8 @@ public enum Config { SecStorageProxy("Advanced", AgentManager.class, String.class, "secstorage.proxy", null, "http proxy used by ssvm, in http://username:password@proxyserver:port format", null), AlertPurgeInterval("Advanced", ManagementServer.class, Integer.class, "alert.purge.interval", "86400", "The interval (in seconds) to wait before running the alert purge thread", null), AlertPurgeDelay("Advanced", ManagementServer.class, Integer.class, "alert.purge.delay", "0", "Alerts older than specified number days will be purged. Set this value to 0 to never delete alerts", null), + HostReservationReleasePeriod("Advanced", ManagementServer.class, Integer.class, "host.reservation.release.period", "300000", "The interval in milliseconds between host reservation release checks", null), + // LB HealthCheck Interval. LBHealthCheck("Advanced", ManagementServer.class, String.class, "healthcheck.update.interval", "600", @@ -235,6 +237,7 @@ public enum Config { ApplyAllocationAlgorithmToPods("Advanced", ManagementServer.class, Boolean.class, "apply.allocation.algorithm.to.pods", "false", "If true, deployment planner applies the allocation heuristics at pods first in the given datacenter during VM resource allocation", "true,false"), VmUserDispersionWeight("Advanced", ManagementServer.class, Float.class, "vm.user.dispersion.weight", "1", "Weight for user dispersion heuristic (as a value between 0 and 1) applied to resource allocation during vm deployment. Weight for capacity heuristic will be (1 - weight of user dispersion)", null), VmAllocationAlgorithm("Advanced", ManagementServer.class, String.class, "vm.allocation.algorithm", "random", "'random', 'firstfit', 'userdispersing', 'userconcentratedpod_random', 'userconcentratedpod_firstfit' : Order in which hosts within a cluster will be considered for VM/volume allocation.", null), + VmDeploymentPlanner("Advanced", ManagementServer.class, String.class, "vm.deployment.planner", "FirstFitPlanner", "'FirstFitPlanner', 'UserDispersingPlanner', 'UserConcentratedPodPlanner': DeploymentPlanner heuristic that will be used for VM deployment.", null), EndpointeUrl("Advanced", ManagementServer.class, String.class, "endpointe.url", "http://localhost:8080/client/api", "Endpointe Url", null), ElasticLoadBalancerEnabled("Advanced", ManagementServer.class, String.class, "network.loadbalancer.basiczone.elb.enabled", "false", "Whether the load balancing service is enabled for basic zones", "true,false"), ElasticLoadBalancerNetwork("Advanced", ManagementServer.class, String.class, "network.loadbalancer.basiczone.elb.network", "guest", "Whether the elastic load balancing service public ips are taken from the public or guest network", "guest,public"), diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java index 84ffc3e1aad..d0ae914c20f 100755 --- a/server/src/com/cloud/configuration/ConfigurationManager.java +++ b/server/src/com/cloud/configuration/ConfigurationManager.java @@ -79,10 +79,11 @@ public interface ConfigurationManager extends ConfigurationService, Manager { * TODO * @param id * @param useVirtualNetwork + * @param deploymentPlanner * @return ID */ ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, VirtualMachine.Type vm_typeType, String name, int cpu, int ramSize, int speed, String displayText, boolean localStorageRequired, - boolean offerHA, boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate); + boolean offerHA, boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate, String deploymentPlanner); /** * Creates a new disk offering diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 887878254b3..9e0c847ed57 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.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, @@ -162,6 +162,7 @@ import com.cloud.org.Grouping.AllocationState; import com.cloud.projects.Project; import com.cloud.projects.ProjectManager; import com.cloud.server.ConfigurationServer; +import com.cloud.server.ManagementService; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.DiskOfferingVO; @@ -302,7 +303,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati @Inject AlertManager _alertMgr; // @com.cloud.utils.component.Inject(adapter = SecurityChecker.class) - @Inject + @Inject List _secChecker; @Inject @@ -346,6 +347,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati @Inject NicIpAliasDao _nicIpAliasDao; + @Inject + public ManagementService _mgr; + // FIXME - why don't we have interface for DataCenterLinkLocalIpAddressDao? @Inject protected DataCenterLinkLocalIpAddressDao _LinkLocalIpAllocDao; @@ -356,11 +360,11 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati @Override public boolean configure(final String name, final Map params) throws ConfigurationException { String maxVolumeSizeInGbString = _configDao.getValue(Config.MaxVolumeSize.key()); - _maxVolumeSizeInGb = NumbersUtil.parseInt(maxVolumeSizeInGbString, + _maxVolumeSizeInGb = NumbersUtil.parseInt(maxVolumeSizeInGbString, Integer.parseInt(Config.MaxVolumeSize.getDefaultValue())); String defaultPageSizeString = _configDao.getValue(Config.DefaultPageSize.key()); - _defaultPageSize = NumbersUtil.parseLong(defaultPageSizeString, + _defaultPageSize = NumbersUtil.parseLong(defaultPageSizeString, Long.parseLong(Config.DefaultPageSize.getDefaultValue())); populateConfigValuesForValidationSet(); @@ -920,7 +924,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati checkPodCidrSubnets(zoneId, podId, cidr); /* * Commenting out due to Bug 11593 - CIDR conflicts with zone when extending pod but not when creating it - * + * * checkCidrVlanOverlap(zoneId, cidr); */ } @@ -1713,7 +1717,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if (internalDns2 == null) { internalDns2 = zone.getInternalDns2(); } - + if (guestCidr == null) { guestCidr = zone.getGuestNetworkCidr(); } @@ -2034,17 +2038,29 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati throw new InvalidParameterValueException("Network rate can be specified only for non-System offering and system offerings having \"domainrouter\" systemvmtype"); } + if (cmd.getDeploymentPlanner() != null) { + List planners = _mgr.listDeploymentPlanners(); + if (planners != null && !planners.isEmpty()) { + if (!planners.contains(cmd.getDeploymentPlanner())) { + throw new InvalidParameterValueException( + "Invalid name for Deployment Planner specified, please use listDeploymentPlanners to get the valid set"); + } + } else { + throw new InvalidParameterValueException("No deployment planners found"); + } + } + return createServiceOffering(userId, cmd.getIsSystem(), vmType, cmd.getServiceOfferingName(), cpuNumber.intValue(), memory.intValue(), cpuSpeed.intValue(), cmd.getDisplayText(), - localStorageRequired, offerHA, limitCpuUse, volatileVm, cmd.getTags(), cmd.getDomainId(), cmd.getHostTag(), cmd.getNetworkRate()); + localStorageRequired, offerHA, limitCpuUse, volatileVm, cmd.getTags(), cmd.getDomainId(), cmd.getHostTag(), cmd.getNetworkRate(), cmd.getDeploymentPlanner()); } @Override @ActionEvent(eventType = EventTypes.EVENT_SERVICE_OFFERING_CREATE, eventDescription = "creating service offering") public ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, VirtualMachine.Type vm_type, String name, int cpu, int ramSize, int speed, String displayText, - boolean localStorageRequired, boolean offerHA, boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate) { + boolean localStorageRequired, boolean offerHA, boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate, String deploymentPlanner) { tags = cleanupTags(tags); ServiceOfferingVO offering = new ServiceOfferingVO(name, cpu, ramSize, speed, networkRate, null, offerHA, limitResourceUse, volatileVm, displayText, localStorageRequired, false, tags, isSystem, vm_type, - domainId, hostTag); + domainId, hostTag, deploymentPlanner); if ((offering = _serviceOfferingDao.persist(offering)) != null) { UserContext.current().setEventDetails("Service offering id=" + offering.getId()); @@ -2328,9 +2344,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati String endIPv6 = cmd.getEndIpv6(); String ip6Gateway = cmd.getIp6Gateway(); String ip6Cidr = cmd.getIp6Cidr(); - + Account vlanOwner = null; - + boolean ipv4 = (startIP != null); boolean ipv6 = (startIPv6 != null); @@ -2387,7 +2403,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } else if (ipv6) { throw new InvalidParameterValueException("Only support IPv6 on extending existed network"); } - + // Verify that zone exists DataCenterVO zone = _zoneDao.findById(zoneId); if (zone == null) { @@ -2434,18 +2450,18 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } } } - - + + // Check if zone is enabled Account caller = UserContext.current().getCaller(); if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) { throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + zoneId); - } + } if (zone.isSecurityGroupEnabled() && zone.getNetworkType() != DataCenter.NetworkType.Basic && forVirtualNetwork) { throw new InvalidParameterValueException("Can't add virtual ip range into a zone with security group enabled"); } - + // If networkId is not specified, and vlan is Virtual or Direct Untagged, try to locate default networks if (forVirtualNetwork) { if (network == null) { @@ -2604,35 +2620,35 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati 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; - + if (startIP != null) { ipv4 = true; } - + if (startIPv6 != null) { ipv6 = true; } - + if (!ipv4 && !ipv6) { throw new InvalidParameterValueException("Please specify IPv4 or IPv6 address."); } - + //Validate the zone DataCenterVO zone = _zoneDao.findById(zoneId); if (zone == null) { throw new InvalidParameterValueException("Please specify a valid zone."); } - + // ACL check checkZoneAccess(UserContext.current().getCaller(), zone); - + //Validate the physical network if (_physicalNetworkDao.findById(physicalNetworkId) == null) { throw new InvalidParameterValueException("Please specify a valid physical network id"); } - + //Validate the pod if (podId != null) { Pod pod = _podDao.findById(podId); @@ -2644,11 +2660,11 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } //pod vlans can be created in basic zone only if (zone.getNetworkType() != NetworkType.Basic || network.getTrafficType() != TrafficType.Guest) { - throw new InvalidParameterValueException("Pod id can be specified only for the networks of type " - + TrafficType.Guest + " in zone of type " + NetworkType.Basic); + throw new InvalidParameterValueException("Pod id can be specified only for the networks of type " + + TrafficType.Guest + " in zone of type " + NetworkType.Basic); } } - + //1) if vlan is specified for the guest network range, it should be the same as network's vlan //2) if vlan is missing, default it to the guest network's vlan if (network.getTrafficType() == TrafficType.Guest) { @@ -2660,7 +2676,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati //For pvlan networkVlanId = networkVlanId.split("-")[0]; } - + if (vlanId != null) { // if vlan is specified, throw an error if it's not equal to network's vlanId if (networkVlanId != null && !networkVlanId.equalsIgnoreCase(vlanId)) { @@ -2673,14 +2689,14 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati //vlan id is required for public network throw new InvalidParameterValueException("Vlan id is required when add ip range to the public network"); } - + if (vlanId == null) { vlanId = Vlan.UNTAGGED; } VlanType vlanType = forVirtualNetwork ? VlanType.VirtualNetwork : VlanType.DirectAttached; - - + + if (vlanOwner != null && zone.getNetworkType() != NetworkType.Advanced) { throw new InvalidParameterValueException("Vlan owner can be defined only in the zone of type " + NetworkType.Advanced); } @@ -2696,7 +2712,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati throw new InvalidParameterValueException("Please specify a valid netmask"); } } - + if (ipv6) { if (!NetUtils.isValidIpv6(vlanIp6Gateway)) { throw new InvalidParameterValueException("Please specify a valid IPv6 gateway"); @@ -2751,7 +2767,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati List vlans = _vlanDao.listByZone(zone.getId()); for (VlanVO vlan : vlans) { String otherVlanGateway = vlan.getVlanGateway(); - // Continue if it's not IPv4 + // Continue if it's not IPv4 if (otherVlanGateway == null) { continue; } @@ -2787,14 +2803,14 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } } } - + String ipv6Range = null; if (ipv6) { ipv6Range = startIPv6; if (endIPv6 != null) { ipv6Range += "-" + endIPv6; } - + List vlans = _vlanDao.listByZone(zone.getId()); for (VlanVO vlan : vlans) { if (vlan.getIp6Gateway() == null) { @@ -2820,14 +2836,14 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } String ipRange = null; - + if (ipv4) { ipRange = startIP; if (endIP != null) { ipRange += "-" + endIP; } } - + // Everything was fine, so persist the VLAN Transaction txn = Transaction.currentTxn(); txn.start(); @@ -2839,7 +2855,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // IPv6 use a used ip map, is different from ipv4, no need to save public ip range if (ipv4) { if (!savePublicIPRange(startIP, endIP, zoneId, vlan.getId(), networkId, physicalNetworkId)) { - throw new CloudRuntimeException("Failed to save IPv4 range. Please contact Cloud Support."); + throw new CloudRuntimeException("Failed to save IPv4 range. Please contact Cloud Support."); } } @@ -2875,7 +2891,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if (vlanRange == null) { throw new InvalidParameterValueException("Please specify a valid IP range id."); } - + boolean isAccountSpecific = false; List acctVln = _accountVlanMapDao.listAccountVlanMapsByVlan(vlanRange.getId()); // Check for account wide pool. It will have an entry for account_vlan_map. @@ -2888,7 +2904,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati List ips = _publicIpAddressDao.listByVlanId(vlanDbId); boolean success = true; if (allocIpCount > 0) { - if (isAccountSpecific) { + if (isAccountSpecific) { try { vlanRange = _vlanDao.acquireInLockTable(vlanDbId, 30); if (vlanRange == null) { @@ -2901,7 +2917,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati for (IPAddressVO ip : ips) { if (ip.isOneToOneNat()) { - throw new InvalidParameterValueException("Can't delete account specific vlan " + vlanDbId + + throw new InvalidParameterValueException("Can't delete account specific vlan " + vlanDbId + " as ip " + ip + " belonging to the range is used for static nat purposes. Cleanup the rules first"); } @@ -2910,9 +2926,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati " as ip " + ip + " belonging to the range is a source nat ip for the network id=" + ip.getSourceNetworkId() + ". IP range with the source nat ip address can be removed either as a part of Network, or account removal"); } - + if (_firewallDao.countRulesByIpId(ip.getId()) > 0) { - throw new InvalidParameterValueException("Can't delete account specific vlan " + vlanDbId + + throw new InvalidParameterValueException("Can't delete account specific vlan " + vlanDbId + " as ip " + ip + " belonging to the range has firewall rules applied. Cleanup the rules first"); } //release public ip address here @@ -3268,7 +3284,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati return true; } - + @DB protected boolean savePublicIPRange(String startIP, String endIP, long zoneId, long vlanDbId, long sourceNetworkid, long physicalNetworkId) { @@ -3471,7 +3487,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } } - + private boolean validPod(long podId) { return (_podDao.findById(podId) != null); } @@ -3690,7 +3706,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if (provider == Provider.JuniperSRX || provider == Provider.CiscoVnmc) { firewallProvider = provider; } - + if ((service == Service.PortForwarding || service == Service.StaticNat) && provider == Provider.VirtualRouter){ firewallProvider = Provider.VirtualRouter; } @@ -3890,7 +3906,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if (!specifyVlan && type == GuestType.Shared) { throw new InvalidParameterValueException("SpecifyVlan should be true if network offering's type is " + type); } - + //specifyIpRanges should always be true for Shared networks //specifyIpRanges can only be true for Isolated networks with no Source Nat service if (specifyIpRanges) { @@ -3914,7 +3930,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if (availability == NetworkOffering.Availability.Required) { boolean canOffBeRequired = (type == GuestType.Isolated && serviceProviderMap.containsKey(Service.SourceNat)); if (!canOffBeRequired) { - throw new InvalidParameterValueException("Availability can be " + NetworkOffering.Availability.Required + throw new InvalidParameterValueException("Availability can be " + NetworkOffering.Availability.Required + " only for networkOfferings of type " + GuestType.Isolated + " and with " + Service.SourceNat.getName() + " enabled"); } @@ -3922,11 +3938,11 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // only one network offering in the system can be Required List offerings = _networkOfferingDao.listByAvailability(Availability.Required, false); if (!offerings.isEmpty()) { - throw new InvalidParameterValueException("System already has network offering id=" + offerings.get(0).getId() + throw new InvalidParameterValueException("System already has network offering id=" + offerings.get(0).getId() + " with availability " + Availability.Required); } } - + boolean dedicatedLb = false; boolean elasticLb = false; boolean sharedSourceNat = false; @@ -3938,7 +3954,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati boolean internalLb = false; if (serviceCapabilityMap != null && !serviceCapabilityMap.isEmpty()) { Map lbServiceCapabilityMap = serviceCapabilityMap.get(Service.Lb); - + if ((lbServiceCapabilityMap != null) && (!lbServiceCapabilityMap.isEmpty())) { String isolationCapability = lbServiceCapabilityMap.get(Capability.SupportedLBIsolation); if (isolationCapability != null) { @@ -3952,7 +3968,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if (param != null) { elasticLb = param.contains("true"); } - + String inlineMode = lbServiceCapabilityMap.get(Capability.InlineMode); if (inlineMode != null) { _networkModel.checkCapabilityForProvider(serviceProviderMap.get(Service.Lb), Service.Lb, Capability.InlineMode, inlineMode); @@ -3983,14 +3999,14 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if ((sourceNatServiceCapabilityMap != null) && (!sourceNatServiceCapabilityMap.isEmpty())) { String sourceNatType = sourceNatServiceCapabilityMap.get(Capability.SupportedSourceNatTypes); if (sourceNatType != null) { - _networkModel.checkCapabilityForProvider(serviceProviderMap.get(Service.SourceNat), Service.SourceNat, + _networkModel.checkCapabilityForProvider(serviceProviderMap.get(Service.SourceNat), Service.SourceNat, Capability.SupportedSourceNatTypes, sourceNatType); sharedSourceNat = sourceNatType.contains("perzone"); } String param = sourceNatServiceCapabilityMap.get(Capability.RedundantRouter); if (param != null) { - _networkModel.checkCapabilityForProvider(serviceProviderMap.get(Service.SourceNat), Service.SourceNat, + _networkModel.checkCapabilityForProvider(serviceProviderMap.get(Service.SourceNat), Service.SourceNat, Capability.RedundantRouter, param); redundantRouter = param.contains("true"); } @@ -4009,7 +4025,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } } - NetworkOfferingVO offering = new NetworkOfferingVO(name, displayText, trafficType, systemOnly, specifyVlan, + 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, publicLb, internalLb); @@ -4041,7 +4057,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati _ntwkOffServiceMapDao.persist(offService); s_logger.trace("Added service for the network offering: " + offService + " with provider " + provider.getName()); } - + if (vpcOff) { List supportedSvcs = new ArrayList(); supportedSvcs.addAll(serviceProviderMap.keySet()); @@ -4251,7 +4267,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // filter by supported services boolean listBySupportedServices = (supportedServicesStr != null && !supportedServicesStr.isEmpty() && !offerings.isEmpty()); boolean checkIfProvidersAreEnabled = (zoneId != null); - boolean parseOfferings = (listBySupportedServices || sourceNatSupported != null || checkIfProvidersAreEnabled + boolean parseOfferings = (listBySupportedServices || sourceNatSupported != null || checkIfProvidersAreEnabled || forVpc != null || network != null); if (parseOfferings) { @@ -4299,7 +4315,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if (sourceNatSupported != null) { addOffering = addOffering && (_networkModel.areServicesSupportedByNetworkOffering(offering.getId(), Network.Service.SourceNat) == sourceNatSupported); } - + if (forVpc != null) { addOffering = addOffering && (isOfferingForVpc(offering) == forVpc.booleanValue()); } else if (network != null){ @@ -4418,14 +4434,14 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } } if (availability == null) { - throw new InvalidParameterValueException("Invalid value for Availability. Supported types: " + throw new InvalidParameterValueException("Invalid value for Availability. Supported types: " + Availability.Required + ", " + Availability.Optional); } else { if (availability == NetworkOffering.Availability.Required) { - boolean canOffBeRequired = (offeringToUpdate.getGuestType() == GuestType.Isolated + boolean canOffBeRequired = (offeringToUpdate.getGuestType() == GuestType.Isolated && _networkModel.areServicesSupportedByNetworkOffering(offeringToUpdate.getId(), Service.SourceNat)); if (!canOffBeRequired) { - throw new InvalidParameterValueException("Availability can be " + + throw new InvalidParameterValueException("Availability can be " + NetworkOffering.Availability.Required + " only for networkOfferings of type " + GuestType.Isolated + " and with " + Service.SourceNat.getName() + " enabled"); } @@ -4433,7 +4449,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // only one network offering in the system can be Required List offerings = _networkOfferingDao.listByAvailability(Availability.Required, false); if (!offerings.isEmpty() && offerings.get(0).getId() != offeringToUpdate.getId()) { - throw new InvalidParameterValueException("System already has network offering id=" + + throw new InvalidParameterValueException("System already has network offering id=" + offerings.get(0).getId() + " with availability " + Availability.Required); } } @@ -4452,7 +4468,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati @ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_MARK_DEFAULT_ZONE, eventDescription = "Marking account with the " + "default zone", async=true) public AccountVO markDefaultZone(String accountName, long domainId, long defaultZoneId) { - + // Check if the account exists Account account = _accountDao.findEnabledAccount(accountName, domainId); if (account == null) { @@ -4466,9 +4482,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } AccountVO acctForUpdate = _accountDao.findById(account.getId()); - + acctForUpdate.setDefaultZoneId(defaultZoneId); - + if (_accountDao.update(account.getId(), acctForUpdate)) { UserContext.current().setEventDetails("Default zone id= " + defaultZoneId); return _accountDao.findById(account.getId()); @@ -4476,7 +4492,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati return null; } } - + // Note: This method will be used for entity name validations in the coming // releases (place holder for now) private void validateEntityName(String str) { @@ -4604,10 +4620,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati public ClusterVO getCluster(long id) { return _clusterDao.findById(id); } - + @Override public AllocationState findClusterAllocationState(ClusterVO cluster){ - + if(cluster.getAllocationState() == AllocationState.Disabled){ return AllocationState.Disabled; }else if(ApiDBUtils.findPodById(cluster.getPodId()).getAllocationState() == AllocationState.Disabled){ @@ -4615,20 +4631,20 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati }else { DataCenterVO zone = ApiDBUtils.findZoneById(cluster.getDataCenterId()); return zone.getAllocationState(); - } - } + } + } @Override public AllocationState findPodAllocationState(HostPodVO pod){ - + if(pod.getAllocationState() == AllocationState.Disabled){ return AllocationState.Disabled; }else { DataCenterVO zone = ApiDBUtils.findZoneById(pod.getDataCenterId()); return zone.getAllocationState(); - } + } } - + private boolean allowIpRangeOverlap(VlanVO vlan, boolean forVirtualNetwork, long networkId) { // FIXME - delete restriction for virtual network in the future if (vlan.getVlanType() == VlanType.DirectAttached && !forVirtualNetwork) { diff --git a/server/src/com/cloud/deploy/AbstractDeployPlannerSelector.java b/server/src/com/cloud/deploy/AbstractDeployPlannerSelector.java deleted file mode 100755 index 7665687be60..00000000000 --- a/server/src/com/cloud/deploy/AbstractDeployPlannerSelector.java +++ /dev/null @@ -1,84 +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.deploy; - -import java.util.Map; - -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import com.cloud.configuration.Config; -import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.utils.component.AdapterBase; -import com.cloud.vm.UserVmVO; - -public abstract class AbstractDeployPlannerSelector extends AdapterBase implements DeployPlannerSelector { - protected Map params; - protected String name; - protected int runLevel; - - @Inject - protected ConfigurationDao _configDao; - protected String _allocationAlgorithm = "random"; - - @Override - public String getName() { - return name; - } - - @Override - public void setName(String name) { - this.name = name; - } - - @Override - public void setConfigParams(Map params) { - this.params = params; - } - - @Override - public Map getConfigParams() { - return params; - } - - @Override - public int getRunLevel() { - return runLevel; - } - - @Override - public void setRunLevel(int level) { - this.runLevel = level; - } - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - super.configure(name, params); - _allocationAlgorithm = _configDao.getValue(Config.VmAllocationAlgorithm.key()); - return true; - } - - @Override - public boolean start() { - return true; - } - - @Override - public boolean stop() { - return true; - } -} diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java index c7162a2003f..c86d5e1a1b2 100644 --- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -16,32 +16,107 @@ // under the License. package com.cloud.deploy; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; +import java.util.TreeSet; import javax.ejb.Local; import javax.inject.Inject; +import javax.naming.ConfigurationException; import org.apache.cloudstack.affinity.AffinityGroupProcessor; -import org.apache.cloudstack.affinity.AffinityGroupVMMapVO; + import org.apache.cloudstack.affinity.dao.AffinityGroupDao; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator; +import org.apache.cloudstack.framework.messagebus.MessageBus; +import org.apache.cloudstack.framework.messagebus.MessageSubscriber; + +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; + +import com.cloud.capacity.CapacityManager; +import com.cloud.capacity.dao.CapacityDao; +import com.cloud.cluster.ManagementServerNode; +import com.cloud.configuration.Config; +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.DataCenter; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.Pod; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.HostPodDao; import com.cloud.deploy.DeploymentPlanner.ExcludeList; +import com.cloud.deploy.DeploymentPlanner.PlannerResourceUsage; +import com.cloud.deploy.dao.PlannerHostReservationDao; import com.cloud.exception.AffinityConflictException; +import com.cloud.exception.ConnectionException; import com.cloud.exception.InsufficientServerCapacityException; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.host.Status; +import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.offering.ServiceOffering; +import com.cloud.org.Cluster; +import com.cloud.org.Grouping; +import com.cloud.resource.ResourceState; +import com.cloud.storage.DiskOfferingVO; +import com.cloud.storage.StorageManager; +import com.cloud.storage.StoragePool; +import com.cloud.storage.StoragePoolHostVO; +import com.cloud.storage.Volume; +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.VolumeDao; +import com.cloud.user.AccountManager; +import com.cloud.utils.DateUtil; +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.db.DB; +import com.cloud.utils.db.Transaction; +import com.cloud.vm.DiskProfile; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; +import com.cloud.agent.AgentManager; +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.Command; +import com.cloud.agent.api.StartupCommand; +import com.cloud.agent.api.StartupRoutingCommand; +import com.cloud.agent.manager.allocator.HostAllocator; + @Local(value = { DeploymentPlanningManager.class }) -public class DeploymentPlanningManagerImpl extends ManagerBase implements DeploymentPlanningManager, Manager { +public class DeploymentPlanningManagerImpl extends ManagerBase implements DeploymentPlanningManager, Manager, Listener { private static final Logger s_logger = Logger.getLogger(DeploymentPlanningManagerImpl.class); @Inject + AgentManager _agentMgr; + @Inject protected UserVmDao _vmDao; @Inject protected VMInstanceDao _vmInstanceDao; @@ -49,6 +124,53 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy protected AffinityGroupDao _affinityGroupDao; @Inject protected AffinityGroupVMMapDao _affinityGroupVMMapDao; + @Inject + DataCenterDao _dcDao; + @Inject + PlannerHostReservationDao _plannerHostReserveDao; + private int _vmCapacityReleaseInterval; + @Inject + MessageBus _messageBus; + private Timer _timer = null; + private long _hostReservationReleasePeriod = 60L * 60L * 1000L; // one hour by default + + private static final long INITIAL_RESERVATION_RELEASE_CHECKER_DELAY = 30L * 1000L; // thirty seconds expressed in milliseconds + protected long _nodeId = -1; + + protected List _storagePoolAllocators; + public List getStoragePoolAllocators() { + return _storagePoolAllocators; + } + public void setStoragePoolAllocators( + List _storagePoolAllocators) { + this._storagePoolAllocators = _storagePoolAllocators; + } + + protected List _hostAllocators; + public List getHostAllocators() { + return _hostAllocators; + } + public void setHostAllocators(List _hostAllocators) { + this._hostAllocators = _hostAllocators; + } + + @Inject protected HostDao _hostDao; + @Inject protected HostPodDao _podDao; + @Inject protected ClusterDao _clusterDao; + @Inject protected GuestOSDao _guestOSDao = null; + @Inject protected GuestOSCategoryDao _guestOSCategoryDao = null; + @Inject protected DiskOfferingDao _diskOfferingDao; + @Inject protected StoragePoolHostDao _poolHostDao; + + @Inject protected VolumeDao _volsDao; + @Inject protected CapacityManager _capacityMgr; + @Inject protected ConfigurationDao _configDao; + @Inject protected PrimaryDataStoreDao _storagePoolDao; + @Inject protected CapacityDao _capacityDao; + @Inject protected AccountManager _accountMgr; + @Inject protected StorageManager _storageMgr; + @Inject DataStoreManager dataStoreMgr; + @Inject protected ClusterDetailsDao _clusterDetailsDao; protected List _planners; public List getPlanners() { @@ -87,20 +209,908 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy } // call planners - DeployDestination dest = null; - for (DeploymentPlanner planner : _planners) { - if (planner.canHandle(vmProfile, plan, avoids)) { - dest = planner.plan(vmProfile, plan, avoids); - } else { - continue; + DataCenter dc = _dcDao.findById(vm.getDataCenterId()); + // check if datacenter is in avoid set + if (avoids.shouldAvoid(dc)) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("DataCenter id = '" + dc.getId() + + "' provided is in avoid set, DeploymentPlanner cannot allocate the VM, returning."); } - if (dest != null) { - avoids.addHost(dest.getHost().getId()); + return null; + } + + + ServiceOffering offering = vmProfile.getServiceOffering(); + String plannerName = offering.getDeploymentPlanner(); + if (plannerName == null) { + if (vm.getHypervisorType() == HypervisorType.BareMetal) { + plannerName = "BareMetalPlanner"; + } else { + plannerName = _configDao.getValue(Config.VmDeploymentPlanner.key()); + } + } + DeploymentPlanner planner = null; + for (DeploymentPlanner plannerInList : _planners) { + if (plannerName.equals(plannerInList.getName())) { + planner = plannerInList; break; } - } + + int cpu_requested = offering.getCpu() * offering.getSpeed(); + long ram_requested = offering.getRamSize() * 1024L * 1024L; + + if (s_logger.isDebugEnabled()) { + s_logger.debug("DeploymentPlanner allocation algorithm: " + planner); + + s_logger.debug("Trying to allocate a host and storage pools from dc:" + plan.getDataCenterId() + ", pod:" + + plan.getPodId() + ",cluster:" + plan.getClusterId() + ", requested cpu: " + cpu_requested + + ", requested ram: " + ram_requested); + + s_logger.debug("Is ROOT volume READY (pool already allocated)?: " + + (plan.getPoolId() != null ? "Yes" : "No")); + } + + String haVmTag = (String) vmProfile.getParameter(VirtualMachineProfile.Param.HaTag); + + if (plan.getHostId() != null && haVmTag == null) { + Long hostIdSpecified = plan.getHostId(); + if (s_logger.isDebugEnabled()) { + s_logger.debug("DeploymentPlan has host_id specified, choosing this host and making no checks on this host: " + + hostIdSpecified); + } + HostVO host = _hostDao.findById(hostIdSpecified); + if (host == null) { + s_logger.debug("The specified host cannot be found"); + } else if (avoids.shouldAvoid(host)) { + s_logger.debug("The specified host is in avoid set"); + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Looking for suitable pools for this host under zone: " + host.getDataCenterId() + + ", pod: " + host.getPodId() + ", cluster: " + host.getClusterId()); + } + + // search for storage under the zone, pod, cluster of the host. + DataCenterDeployment lastPlan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), + host.getClusterId(), hostIdSpecified, plan.getPoolId(), null, plan.getReservationContext()); + + Pair>, List> result = findSuitablePoolsForVolumes(vmProfile, + lastPlan, avoids, HostAllocator.RETURN_UPTO_ALL); + Map> suitableVolumeStoragePools = result.first(); + List readyAndReusedVolumes = result.second(); + + // choose the potential pool for this VM for this host + if (!suitableVolumeStoragePools.isEmpty()) { + List suitableHosts = new ArrayList(); + suitableHosts.add(host); + + Pair> potentialResources = findPotentialDeploymentResources( + suitableHosts, suitableVolumeStoragePools, avoids, getPlannerUsage(planner)); + if (potentialResources != null) { + Pod pod = _podDao.findById(host.getPodId()); + Cluster cluster = _clusterDao.findById(host.getClusterId()); + Map storageVolMap = potentialResources.second(); + // remove the reused vol<->pool from destination, since + // we don't have to prepare this volume. + for (Volume vol : readyAndReusedVolumes) { + storageVolMap.remove(vol); + } + DeployDestination dest = new DeployDestination(dc, pod, cluster, host, storageVolMap); + s_logger.debug("Returning Deployment Destination: " + dest); + return dest; + } + } + } + s_logger.debug("Cannnot deploy to specified host, returning."); + return null; + } + + if (vm.getLastHostId() != null && haVmTag == null) { + s_logger.debug("This VM has last host_id specified, trying to choose the same host: " + vm.getLastHostId()); + + HostVO host = _hostDao.findById(vm.getLastHostId()); + if (host == null) { + s_logger.debug("The last host of this VM cannot be found"); + } else if (avoids.shouldAvoid(host)) { + s_logger.debug("The last host of this VM is in avoid set"); + } else if (_capacityMgr.checkIfHostReachMaxGuestLimit(host)) { + s_logger.debug("The last Host, hostId: " + + host.getId() + + " already has max Running VMs(count includes system VMs), skipping this and trying other available hosts"); + } else { + if (host.getStatus() == Status.Up && host.getResourceState() == ResourceState.Enabled) { + long cluster_id = host.getClusterId(); + ClusterDetailsVO cluster_detail_cpu = _clusterDetailsDao.findDetail(cluster_id, + "cpuOvercommitRatio"); + ClusterDetailsVO cluster_detail_ram = _clusterDetailsDao.findDetail(cluster_id, + "memoryOvercommitRatio"); + Float cpuOvercommitRatio = Float.parseFloat(cluster_detail_cpu.getValue()); + Float memoryOvercommitRatio = Float.parseFloat(cluster_detail_ram.getValue()); + if (_capacityMgr.checkIfHostHasCapacity(host.getId(), cpu_requested, ram_requested, true, + cpuOvercommitRatio, memoryOvercommitRatio, true)) { + s_logger.debug("The last host of this VM is UP and has enough capacity"); + s_logger.debug("Now checking for suitable pools under zone: " + host.getDataCenterId() + + ", pod: " + host.getPodId() + ", cluster: " + host.getClusterId()); + // search for storage under the zone, pod, cluster of + // the last host. + DataCenterDeployment lastPlan = new DataCenterDeployment(host.getDataCenterId(), + host.getPodId(), host.getClusterId(), host.getId(), plan.getPoolId(), null); + Pair>, List> result = findSuitablePoolsForVolumes( + vmProfile, lastPlan, avoids, HostAllocator.RETURN_UPTO_ALL); + Map> suitableVolumeStoragePools = result.first(); + List readyAndReusedVolumes = result.second(); + // choose the potential pool for this VM for this host + if (!suitableVolumeStoragePools.isEmpty()) { + List suitableHosts = new ArrayList(); + suitableHosts.add(host); + + Pair> potentialResources = findPotentialDeploymentResources( + suitableHosts, suitableVolumeStoragePools, avoids, getPlannerUsage(planner)); + if (potentialResources != null) { + Pod pod = _podDao.findById(host.getPodId()); + Cluster cluster = _clusterDao.findById(host.getClusterId()); + Map storageVolMap = potentialResources.second(); + // remove the reused vol<->pool from + // destination, since we don't have to prepare + // this volume. + for (Volume vol : readyAndReusedVolumes) { + storageVolMap.remove(vol); + } + DeployDestination dest = new DeployDestination(dc, pod, cluster, host, storageVolMap); + s_logger.debug("Returning Deployment Destination: " + dest); + return dest; + } + } + } else { + s_logger.debug("The last host of this VM does not have enough capacity"); + } + } else { + s_logger.debug("The last host of this VM is not UP or is not enabled, host status is: " + + host.getStatus().name() + ", host resource state is: " + host.getResourceState()); + } + } + s_logger.debug("Cannot choose the last host to deploy this VM "); + } + + DeployDestination dest = null; + List clusterList = null; + + if (planner != null && planner.canHandle(vmProfile, plan, avoids)) { + while (true) { + + if (planner instanceof DeploymentClusterPlanner) { + + ExcludeList PlannerAvoidInput = new ExcludeList(avoids.getDataCentersToAvoid(), + avoids.getPodsToAvoid(), avoids.getClustersToAvoid(), avoids.getHostsToAvoid(), + avoids.getPoolsToAvoid()); + + clusterList = ((DeploymentClusterPlanner) planner).orderClusters(vmProfile, plan, avoids); + + if (clusterList != null && !clusterList.isEmpty()) { + // planner refactoring. call allocators to list hosts + ExcludeList PlannerAvoidOutput = new ExcludeList(avoids.getDataCentersToAvoid(), + avoids.getPodsToAvoid(), avoids.getClustersToAvoid(), avoids.getHostsToAvoid(), + avoids.getPoolsToAvoid()); + + resetAvoidSet(PlannerAvoidOutput, PlannerAvoidInput); + + dest = checkClustersforDestination(clusterList, vmProfile, plan, avoids, dc, + getPlannerUsage(planner), PlannerAvoidOutput); + if (dest != null) { + return dest; + } + // reset the avoid input to the planners + resetAvoidSet(avoids, PlannerAvoidOutput); + + } else { + return null; + } + } else { + dest = planner.plan(vmProfile, plan, avoids); + if (dest != null) { + long hostId = dest.getHost().getId(); + avoids.addHost(dest.getHost().getId()); + + if (checkIfHostFitsPlannerUsage(hostId, DeploymentPlanner.PlannerResourceUsage.Shared)) { + // found destination + return dest; + } else { + // find another host - seems some concurrent + // deployment picked it up for dedicated access + continue; + } + } else { + return null; + } + } + } + } + + return dest; } + private void resetAvoidSet(ExcludeList avoidSet, ExcludeList removeSet) { + if (avoidSet.getDataCentersToAvoid() != null && removeSet.getDataCentersToAvoid() != null) { + avoidSet.getDataCentersToAvoid().removeAll(removeSet.getDataCentersToAvoid()); + } + if (avoidSet.getPodsToAvoid() != null && removeSet.getPodsToAvoid() != null) { + avoidSet.getPodsToAvoid().removeAll(removeSet.getPodsToAvoid()); + } + if (avoidSet.getClustersToAvoid() != null && removeSet.getClustersToAvoid() != null) { + avoidSet.getClustersToAvoid().removeAll(removeSet.getClustersToAvoid()); + } + if (avoidSet.getHostsToAvoid() != null && removeSet.getHostsToAvoid() != null) { + avoidSet.getHostsToAvoid().removeAll(removeSet.getHostsToAvoid()); + } + if (avoidSet.getPoolsToAvoid() != null && removeSet.getPoolsToAvoid() != null) { + avoidSet.getPoolsToAvoid().removeAll(removeSet.getPoolsToAvoid()); + } + } + + private PlannerResourceUsage getPlannerUsage(DeploymentPlanner planner) { + if (planner != null && planner instanceof DeploymentClusterPlanner) { + return ((DeploymentClusterPlanner) planner).getResourceUsage(); + } else { + return DeploymentPlanner.PlannerResourceUsage.Shared; + } + + } + + @DB + private boolean checkIfHostFitsPlannerUsage(long hostId, PlannerResourceUsage resourceUsageRequired) { + // TODO Auto-generated method stub + // check if this host has been picked up by some other planner + // exclusively + // if planner can work with shared host, check if this host has + // been marked as 'shared' + // else if planner needs dedicated host, + + PlannerHostReservationVO reservationEntry = _plannerHostReserveDao.findByHostId(hostId); + if (reservationEntry != null) { + long id = reservationEntry.getId(); + PlannerResourceUsage hostResourceType = reservationEntry.getResourceUsage(); + + if (hostResourceType != null) { + if (hostResourceType == resourceUsageRequired) { + return true; + } else { + s_logger.debug("Cannot use this host for usage: " + resourceUsageRequired + + ", since this host has been reserved for planner usage : " + hostResourceType); + return false; + } + } else { + // reserve the host for required resourceType + // let us lock the reservation entry before updating. + final Transaction txn = Transaction.currentTxn(); + + try { + txn.start(); + + final PlannerHostReservationVO lockedEntry = _plannerHostReserveDao.lockRow(id, true); + if (lockedEntry == null) { + s_logger.error("Unable to lock the host entry for reservation, host: " + hostId); + return false; + } + // check before updating + if (lockedEntry.getResourceUsage() == null) { + lockedEntry.setResourceUsage(resourceUsageRequired); + _plannerHostReserveDao.persist(lockedEntry); + return true; + } else { + // someone updated it earlier. check if we can still use it + if (lockedEntry.getResourceUsage() == resourceUsageRequired) { + return true; + } else { + s_logger.debug("Cannot use this host for usage: " + resourceUsageRequired + + ", since this host has been reserved for planner usage : " + hostResourceType); + return false; + } + } + } finally { + txn.commit(); + } + } + + } + + return false; + } + + @DB + public boolean checkHostReservationRelease(Long hostId) { + + if (hostId != null) { + PlannerHostReservationVO reservationEntry = _plannerHostReserveDao.findByHostId(hostId); + if (reservationEntry != null && reservationEntry.getResourceUsage() != null) { + + // check if any VMs are starting or running on this host + List vms = _vmInstanceDao.listUpByHostId(hostId); + if (vms.size() > 0) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Cannot release reservation, Found " + vms.size() + " VMs Running on host " + + hostId); + } + return false; + } + + List vmsByLastHostId = _vmInstanceDao.listByLastHostId(hostId); + if (vmsByLastHostId.size() > 0) { + // check if any VMs are within skip.counting.hours, if yes + // we + // cannot release the host + for (VMInstanceVO stoppedVM : vmsByLastHostId) { + long secondsSinceLastUpdate = (DateUtil.currentGMTTime().getTime() - stoppedVM.getUpdateTime() + .getTime()) / 1000; + if (secondsSinceLastUpdate < _vmCapacityReleaseInterval) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Cannot release reservation, Found VM: " + stoppedVM + + " Stopped but reserved on host " + hostId); + } + return false; + } + } + } + + // check if any VMs are stopping on or migrating to this host + List vmsStoppingMigratingByHostId = _vmInstanceDao.findByHostInStates(hostId, + State.Stopping, State.Migrating, State.Starting); + if (vmsStoppingMigratingByHostId.size() > 0) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Cannot release reservation, Found " + vms.size() + + " VMs stopping/migrating on host " + hostId); + } + return false; + } + + // check if any VMs are in starting state with no hostId set yet + // - + // just ignore host release to avoid race condition + List vmsStartingNoHost = _vmInstanceDao.listStartingWithNoHostId(); + + if (vmsStartingNoHost.size() > 0) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Cannot release reservation, Found " + vms.size() + + " VMs starting as of now and no hostId yet stored"); + } + return false; + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Host has no VMs associated, releasing the planner reservation for host " + hostId); + } + + long id = reservationEntry.getId(); + final Transaction txn = Transaction.currentTxn(); + + try { + txn.start(); + + final PlannerHostReservationVO lockedEntry = _plannerHostReserveDao.lockRow(id, true); + if (lockedEntry == null) { + s_logger.error("Unable to lock the host entry for reservation, host: " + hostId); + return false; + } + // check before updating + if (lockedEntry.getResourceUsage() != null) { + lockedEntry.setResourceUsage(null); + _plannerHostReserveDao.persist(lockedEntry); + return true; + } + } finally { + txn.commit(); + } + } + + } + return false; + } + + class HostReservationReleaseChecker extends TimerTask { + @Override + public void run() { + try { + s_logger.debug("Checking if any host reservation can be released ... "); + checkHostReservations(); + s_logger.debug("Done running HostReservationReleaseChecker ... "); + } catch (Throwable t) { + s_logger.error("Exception in HostReservationReleaseChecker", t); + } + } + } + + private void checkHostReservations() { + List reservedHosts = _plannerHostReserveDao.listAllReservedHosts(); + + for (PlannerHostReservationVO hostReservation : reservedHosts) { + HostVO host = _hostDao.findById(hostReservation.getHostId()); + if (host != null && host.getManagementServerId() != null && host.getManagementServerId() == _nodeId) { + checkHostReservationRelease(hostReservation.getHostId()); + } + } + + } + + @Override + public boolean processAnswers(long agentId, long seq, Answer[] answers) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean processCommands(long agentId, long seq, Command[] commands) { + // TODO Auto-generated method stub + return false; + } + + @Override + public AgentControlAnswer processControlCommand(long agentId, AgentControlCommand cmd) { + // TODO Auto-generated method stub + return null; + } + + @Override + public void processConnect(HostVO host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { + if (!(cmd instanceof StartupRoutingCommand)) { + return; + } + + PlannerHostReservationVO reservationEntry = _plannerHostReserveDao.findByHostId(host.getId()); + if (reservationEntry == null) { + // record the host in this table + PlannerHostReservationVO newHost = new PlannerHostReservationVO(host.getId(), host.getDataCenterId(), + host.getPodId(), host.getClusterId()); + _plannerHostReserveDao.persist(newHost); + } + + } + + @Override + public boolean processDisconnect(long agentId, Status state) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isRecurring() { + // TODO Auto-generated method stub + return false; + } + + @Override + public int getTimeout() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public boolean processTimeout(long agentId, long seq) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean configure(final String name, final Map params) throws ConfigurationException { + _agentMgr.registerForHostEvents(this, true, false, true); + _messageBus.subscribe("VM_ReservedCapacity_Free", new MessageSubscriber() { + @Override + public void onPublishMessage(String senderAddress, String subject, Object obj) { + VMInstanceVO vm = ((VMInstanceVO) obj); + s_logger.debug("MessageBus message: host reserved capacity released for VM: " + vm.getLastHostId() + + ", checking if host reservation can be released for host:" + vm.getLastHostId()); + Long hostId = vm.getLastHostId(); + checkHostReservationRelease(hostId); + } + }); + + _vmCapacityReleaseInterval = NumbersUtil.parseInt(_configDao.getValue(Config.CapacitySkipcountingHours.key()), + 3600); + + String hostReservationReleasePeriod = _configDao.getValue(Config.HostReservationReleasePeriod.key()); + if (hostReservationReleasePeriod != null) { + _hostReservationReleasePeriod = Long.parseLong(hostReservationReleasePeriod); + if (_hostReservationReleasePeriod <= 0) + _hostReservationReleasePeriod = Long.parseLong(Config.HostReservationReleasePeriod.getDefaultValue()); + } + + _timer = new Timer("HostReservationReleaseChecker"); + + _nodeId = ManagementServerNode.getManagementServerId(); + + return super.configure(name, params); + } + + @Override + public boolean start() { + _timer.schedule(new HostReservationReleaseChecker(), INITIAL_RESERVATION_RELEASE_CHECKER_DELAY, + _hostReservationReleasePeriod); + return true; + } + + @Override + public boolean stop() { + _timer.cancel(); + return true; + } + + // /refactoring planner methods + private DeployDestination checkClustersforDestination(List clusterList, + VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid, + DataCenter dc, DeploymentPlanner.PlannerResourceUsage resourceUsageRequired, ExcludeList PlannerAvoidOutput) { + + if (s_logger.isTraceEnabled()) { + s_logger.trace("ClusterId List to consider: " + clusterList); + } + + for (Long clusterId : clusterList) { + ClusterVO clusterVO = _clusterDao.findById(clusterId); + + if (clusterVO.getHypervisorType() != vmProfile.getHypervisorType()) { + s_logger.debug("Cluster: " + clusterId + + " has HyperVisorType that does not match the VM, skipping this cluster"); + avoid.addCluster(clusterVO.getId()); + continue; + } + + s_logger.debug("Checking resources in Cluster: " + clusterId + " under Pod: " + clusterVO.getPodId()); + // search for resources(hosts and storage) under this zone, pod, + // cluster. + DataCenterDeployment potentialPlan = new DataCenterDeployment(plan.getDataCenterId(), clusterVO.getPodId(), + clusterVO.getId(), null, plan.getPoolId(), null, plan.getReservationContext()); + + // find suitable hosts under this cluster, need as many hosts as we + // get. + List suitableHosts = findSuitableHosts(vmProfile, potentialPlan, avoid, HostAllocator.RETURN_UPTO_ALL); + // if found suitable hosts in this cluster, find suitable storage + // pools for each volume of the VM + if (suitableHosts != null && !suitableHosts.isEmpty()) { + if (vmProfile.getHypervisorType() == HypervisorType.BareMetal) { + Pod pod = _podDao.findById(clusterVO.getPodId()); + DeployDestination dest = new DeployDestination(dc, pod, clusterVO, suitableHosts.get(0)); + return dest; + } + + Pair>, List> result = findSuitablePoolsForVolumes(vmProfile, + potentialPlan, avoid, StoragePoolAllocator.RETURN_UPTO_ALL); + Map> suitableVolumeStoragePools = result.first(); + List readyAndReusedVolumes = result.second(); + + // choose the potential host and pool for the VM + if (!suitableVolumeStoragePools.isEmpty()) { + Pair> potentialResources = findPotentialDeploymentResources( + suitableHosts, suitableVolumeStoragePools, avoid, resourceUsageRequired); + + if (potentialResources != null) { + Pod pod = _podDao.findById(clusterVO.getPodId()); + Host host = _hostDao.findById(potentialResources.first().getId()); + Map storageVolMap = potentialResources.second(); + // remove the reused vol<->pool from destination, since + // we don't have to prepare this volume. + for (Volume vol : readyAndReusedVolumes) { + storageVolMap.remove(vol); + } + DeployDestination dest = new DeployDestination(dc, pod, clusterVO, host, storageVolMap); + s_logger.debug("Returning Deployment Destination: " + dest); + return dest; + } + } else { + s_logger.debug("No suitable storagePools found under this Cluster: " + clusterId); + } + } else { + s_logger.debug("No suitable hosts found under this Cluster: " + clusterId); + } + + if (canAvoidCluster(clusterVO, avoid, PlannerAvoidOutput)) { + avoid.addCluster(clusterVO.getId()); + } + } + s_logger.debug("Could not find suitable Deployment Destination for this VM under any clusters, returning. "); + return null; + } + + private boolean canAvoidCluster(Cluster clusterVO, ExcludeList avoids, ExcludeList plannerAvoidOutput) { + + ExcludeList allocatorAvoidOutput = new ExcludeList(avoids.getDataCentersToAvoid(), avoids.getPodsToAvoid(), + avoids.getClustersToAvoid(), avoids.getHostsToAvoid(), avoids.getPoolsToAvoid()); + + // remove any hosts/pools that the planners might have added + // to get the list of hosts/pools that Allocators flagged as 'avoid' + if (allocatorAvoidOutput.getHostsToAvoid() != null && plannerAvoidOutput.getHostsToAvoid() != null) { + allocatorAvoidOutput.getHostsToAvoid().removeAll(plannerAvoidOutput.getHostsToAvoid()); + } + if (allocatorAvoidOutput.getPoolsToAvoid() != null && plannerAvoidOutput.getPoolsToAvoid() != null) { + allocatorAvoidOutput.getPoolsToAvoid().removeAll(plannerAvoidOutput.getPoolsToAvoid()); + } + + // if all hosts or all pools in the cluster are in avoid set after this + // pass, then put the cluster in avoid set. + boolean avoidAllHosts = true, avoidAllPools = true; + + List allhostsInCluster = _hostDao.listAllUpAndEnabledNonHAHosts(Host.Type.Routing, clusterVO.getId(), + clusterVO.getPodId(), clusterVO.getDataCenterId(), null); + for (HostVO host : allhostsInCluster) { + if (allocatorAvoidOutput.getHostsToAvoid() == null + || !allocatorAvoidOutput.getHostsToAvoid().contains(host.getId())) { + // there's some host in the cluster that is not yet in avoid set + avoidAllHosts = false; + } + } + + List allPoolsInCluster = _storagePoolDao.findPoolsByTags(clusterVO.getDataCenterId(), + clusterVO.getPodId(), clusterVO.getId(), null); + for (StoragePoolVO pool : allPoolsInCluster) { + if (allocatorAvoidOutput.getPoolsToAvoid() == null + || !allocatorAvoidOutput.getPoolsToAvoid().contains(pool.getId())) { + // there's some pool in the cluster that is not yet in avoid set + avoidAllPools = false; + } + } + + if (avoidAllHosts || avoidAllPools) { + return true; + } + return false; + } + + protected Pair> findPotentialDeploymentResources(List suitableHosts, + Map> suitableVolumeStoragePools, ExcludeList avoid, + DeploymentPlanner.PlannerResourceUsage resourceUsageRequired) { + s_logger.debug("Trying to find a potenial host and associated storage pools from the suitable host/pool lists for this VM"); + + boolean hostCanAccessPool = false; + boolean haveEnoughSpace = false; + Map storage = new HashMap(); + TreeSet volumesOrderBySizeDesc = new TreeSet(new Comparator() { + @Override + public int compare(Volume v1, Volume v2) { + if (v1.getSize() < v2.getSize()) + return 1; + else + return -1; + } + }); + volumesOrderBySizeDesc.addAll(suitableVolumeStoragePools.keySet()); + boolean multipleVolume = volumesOrderBySizeDesc.size() > 1; + for (Host potentialHost : suitableHosts) { + Map> volumeAllocationMap = new HashMap>(); + for (Volume vol : volumesOrderBySizeDesc) { + haveEnoughSpace = false; + s_logger.debug("Checking if host: " + potentialHost.getId() + + " can access any suitable storage pool for volume: " + vol.getVolumeType()); + List volumePoolList = suitableVolumeStoragePools.get(vol); + hostCanAccessPool = false; + for (StoragePool potentialSPool : volumePoolList) { + if (hostCanAccessSPool(potentialHost, potentialSPool)) { + hostCanAccessPool = true; + if (multipleVolume) { + List requestVolumes = null; + if (volumeAllocationMap.containsKey(potentialSPool)) + requestVolumes = volumeAllocationMap.get(potentialSPool); + else + requestVolumes = new ArrayList(); + requestVolumes.add(vol); + + if (!_storageMgr.storagePoolHasEnoughSpace(requestVolumes, potentialSPool)) + continue; + volumeAllocationMap.put(potentialSPool, requestVolumes); + } + storage.put(vol, potentialSPool); + haveEnoughSpace = true; + break; + } + } + if (!hostCanAccessPool) { + break; + } + if (!haveEnoughSpace) { + s_logger.warn("insufficient capacity to allocate all volumes"); + break; + } + } + if (hostCanAccessPool && haveEnoughSpace + && checkIfHostFitsPlannerUsage(potentialHost.getId(), resourceUsageRequired)) { + s_logger.debug("Found a potential host " + "id: " + potentialHost.getId() + " name: " + + potentialHost.getName() + " and associated storage pools for this VM"); + return new Pair>(potentialHost, storage); + } else { + avoid.addHost(potentialHost.getId()); + } + } + s_logger.debug("Could not find a potential host that has associated storage pools from the suitable host/pool lists for this VM"); + return null; + } + + protected boolean hostCanAccessSPool(Host host, StoragePool pool) { + boolean hostCanAccessSPool = false; + + StoragePoolHostVO hostPoolLinkage = _poolHostDao.findByPoolHost(pool.getId(), host.getId()); + if (hostPoolLinkage != null) { + hostCanAccessSPool = true; + } + + s_logger.debug("Host: " + host.getId() + (hostCanAccessSPool ? " can" : " cannot") + " access pool: " + + pool.getId()); + return hostCanAccessSPool; + } + + protected List findSuitableHosts(VirtualMachineProfile vmProfile, + DeploymentPlan plan, ExcludeList avoid, int returnUpTo) { + List suitableHosts = new ArrayList(); + for (HostAllocator allocator : _hostAllocators) { + suitableHosts = allocator.allocateTo(vmProfile, plan, Host.Type.Routing, avoid, returnUpTo); + if (suitableHosts != null && !suitableHosts.isEmpty()) { + break; + } + } + + if (suitableHosts.isEmpty()) { + s_logger.debug("No suitable hosts found"); + } + return suitableHosts; + } + + protected Pair>, List> findSuitablePoolsForVolumes( + VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid, + int returnUpTo) { + List volumesTobeCreated = _volsDao.findUsableVolumesForInstance(vmProfile.getId()); + Map> suitableVolumeStoragePools = new HashMap>(); + List readyAndReusedVolumes = new ArrayList(); + + // for each volume find list of suitable storage pools by calling the + // allocators + for (VolumeVO toBeCreated : volumesTobeCreated) { + s_logger.debug("Checking suitable pools for volume (Id, Type): (" + toBeCreated.getId() + "," + + toBeCreated.getVolumeType().name() + ")"); + + // 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()); + List suitablePools = new ArrayList(); + StoragePool pool = null; + if (toBeCreated.getPoolId() != null) { + pool = (StoragePool) this.dataStoreMgr.getPrimaryDataStore(toBeCreated.getPoolId()); + } else { + pool = (StoragePool) this.dataStoreMgr.getPrimaryDataStore(plan.getPoolId()); + } + + 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); + } + continue; + } else { + s_logger.debug("Pool of the volume does not fit the specified plan, 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"); + } + } else { + s_logger.debug("Pool of the volume is in maintenance, need to reallocate a pool for this volume"); + } + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("We need to allocate new storagepool for this volume"); + } + if (!isRootAdmin(plan.getReservationContext())) { + if (!isEnabledForAllocation(plan.getDataCenterId(), plan.getPodId(), plan.getClusterId())) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Cannot allocate new storagepool for this volume in this cluster, allocation state is disabled"); + s_logger.debug("Cannot deploy to this specified plan, allocation state is disabled, returning."); + } + // Cannot find suitable storage pools under this cluster for + // this volume since allocation_state is disabled. + // - remove any suitable pools found for other volumes. + // All volumes should get suitable pools under this cluster; + // else we cant use this cluster. + suitableVolumeStoragePools.clear(); + break; + } + } + + s_logger.debug("Calling StoragePoolAllocators to find suitable pools"); + + DiskOfferingVO diskOffering = _diskOfferingDao.findById(toBeCreated.getDiskOfferingId()); + DiskProfile diskProfile = new DiskProfile(toBeCreated, diskOffering, vmProfile.getHypervisorType()); + + boolean useLocalStorage = false; + if (vmProfile.getType() != VirtualMachine.Type.User) { + String ssvmUseLocalStorage = _configDao.getValue(Config.SystemVMUseLocalStorage.key()); + if (ssvmUseLocalStorage.equalsIgnoreCase("true")) { + useLocalStorage = true; + } + } else { + useLocalStorage = diskOffering.getUseLocalStorage(); + + // TODO: this is a hacking fix for the problem of deploy + // ISO-based VM on local storage + // when deploying VM based on ISO, we have a service offering + // and an additional disk offering, use-local storage flag is + // actually + // saved in service offering, overrde the flag from service + // offering when it is a ROOT disk + if (!useLocalStorage && vmProfile.getServiceOffering().getUseLocalStorage()) { + if (toBeCreated.getVolumeType() == Volume.Type.ROOT) + useLocalStorage = true; + } + } + diskProfile.setUseLocalStorage(useLocalStorage); + + boolean foundPotentialPools = false; + for (StoragePoolAllocator allocator : _storagePoolAllocators) { + final List suitablePools = allocator.allocateToPool(diskProfile, vmProfile, plan, avoid, + returnUpTo); + if (suitablePools != null && !suitablePools.isEmpty()) { + suitableVolumeStoragePools.put(toBeCreated, suitablePools); + foundPotentialPools = true; + break; + } + } + + if (!foundPotentialPools) { + s_logger.debug("No suitable pools found for volume: " + toBeCreated + " under cluster: " + + plan.getClusterId()); + // No suitable storage pools found under this cluster for this + // volume. - remove any suitable pools found for other volumes. + // All volumes should get suitable pools under this cluster; + // else we cant use this cluster. + suitableVolumeStoragePools.clear(); + break; + } + } + + if (suitableVolumeStoragePools.isEmpty()) { + s_logger.debug("No suitable pools found"); + } + + return new Pair>, List>(suitableVolumeStoragePools, readyAndReusedVolumes); + } + + private boolean isEnabledForAllocation(long zoneId, Long podId, Long clusterId) { + // Check if the zone exists in the system + DataCenterVO zone = _dcDao.findById(zoneId); + if (zone != null && Grouping.AllocationState.Disabled == zone.getAllocationState()) { + s_logger.info("Zone is currently disabled, cannot allocate to this zone: " + zoneId); + return false; + } + + Pod pod = _podDao.findById(podId); + if (pod != null && Grouping.AllocationState.Disabled == pod.getAllocationState()) { + s_logger.info("Pod is currently disabled, cannot allocate to this pod: " + podId); + return false; + } + + Cluster cluster = _clusterDao.findById(clusterId); + if (cluster != null && Grouping.AllocationState.Disabled == cluster.getAllocationState()) { + s_logger.info("Cluster is currently disabled, cannot allocate to this cluster: " + clusterId); + return false; + } + + return true; + } + + private boolean isRootAdmin(ReservationContext reservationContext) { + if (reservationContext != null) { + if (reservationContext.getAccount() != null) { + return _accountMgr.isRootAdmin(reservationContext.getAccount().getType()); + } else { + return false; + } + } + return false; + } } diff --git a/server/src/com/cloud/deploy/FirstFitPlanner.java b/server/src/com/cloud/deploy/FirstFitPlanner.java index e8504a991c1..caf8c6e92db 100755 --- a/server/src/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/com/cloud/deploy/FirstFitPlanner.java @@ -49,6 +49,7 @@ import com.cloud.dc.Pod; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; +import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.exception.InsufficientServerCapacityException; import com.cloud.host.Host; import com.cloud.host.HostVO; @@ -81,7 +82,7 @@ import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; @Local(value=DeploymentPlanner.class) -public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { +public class FirstFitPlanner extends PlannerBase implements DeploymentClusterPlanner { private static final Logger s_logger = Logger.getLogger(FirstFitPlanner.class); @Inject protected HostDao _hostDao; @Inject protected DataCenterDao _dcDao; @@ -103,28 +104,13 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { @Inject DataStoreManager dataStoreMgr; @Inject protected ClusterDetailsDao _clusterDetailsDao; - protected List _storagePoolAllocators; - public List getStoragePoolAllocators() { - return _storagePoolAllocators; - } - public void setStoragePoolAllocators( - List _storagePoolAllocators) { - this._storagePoolAllocators = _storagePoolAllocators; - } - - protected List _hostAllocators; - public List getHostAllocators() { - return _hostAllocators; - } - public void setHostAllocators(List _hostAllocators) { - this._hostAllocators = _hostAllocators; - } protected String _allocationAlgorithm = "random"; + protected String _globalDeploymentPlanner = "FirstFitPlanner"; @Override - public DeployDestination plan(VirtualMachineProfile vmProfile, + public List orderClusters(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid) throws InsufficientServerCapacityException { VirtualMachine vm = vmProfile.getVirtualMachine(); @@ -138,136 +124,19 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { return null; } - ServiceOffering offering = vmProfile.getServiceOffering(); - int cpu_requested = offering.getCpu() * offering.getSpeed(); - long ram_requested = offering.getRamSize() * 1024L * 1024L; - - - if (s_logger.isDebugEnabled()) { - s_logger.debug("DeploymentPlanner allocation algorithm: "+_allocationAlgorithm); - - s_logger.debug("Trying to allocate a host and storage pools from dc:" + plan.getDataCenterId() + ", pod:" + plan.getPodId() + ",cluster:" + plan.getClusterId() + - ", requested cpu: " + cpu_requested + ", requested ram: " + ram_requested); - - s_logger.debug("Is ROOT volume READY (pool already allocated)?: " + (plan.getPoolId()!=null ? "Yes": "No")); - } - - String haVmTag = (String)vmProfile.getParameter(VirtualMachineProfile.Param.HaTag); - - if(plan.getHostId() != null && haVmTag == null){ - Long hostIdSpecified = plan.getHostId(); - if (s_logger.isDebugEnabled()){ - s_logger.debug("DeploymentPlan has host_id specified, choosing this host and making no checks on this host: " - + hostIdSpecified); - } - HostVO host = _hostDao.findById(hostIdSpecified); - if (host == null) { - s_logger.debug("The specified host cannot be found"); - } else if (avoid.shouldAvoid(host)) { - s_logger.debug("The specified host is in avoid set"); - } else { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Looking for suitable pools for this host under zone: "+host.getDataCenterId() +", pod: "+ host.getPodId()+", cluster: "+ host.getClusterId()); - } - - // search for storage under the zone, pod, cluster of the host. - DataCenterDeployment lastPlan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), - host.getClusterId(), hostIdSpecified, plan.getPoolId(), null, plan.getReservationContext()); - - Pair>, List> result = findSuitablePoolsForVolumes(vmProfile, - lastPlan, avoid, HostAllocator.RETURN_UPTO_ALL); - Map> suitableVolumeStoragePools = result.first(); - List readyAndReusedVolumes = result.second(); - - // choose the potential pool for this VM for this host - if (!suitableVolumeStoragePools.isEmpty()) { - List suitableHosts = new ArrayList(); - suitableHosts.add(host); - - Pair> potentialResources = findPotentialDeploymentResources( - suitableHosts, suitableVolumeStoragePools); - if (potentialResources != null) { - Pod pod = _podDao.findById(host.getPodId()); - Cluster cluster = _clusterDao.findById(host.getClusterId()); - Map storageVolMap = potentialResources.second(); - // remove the reused vol<->pool from destination, since - // we don't have to prepare this volume. - for (Volume vol : readyAndReusedVolumes) { - storageVolMap.remove(vol); - } - DeployDestination dest = new DeployDestination(dc, pod, cluster, host, storageVolMap); - s_logger.debug("Returning Deployment Destination: " + dest); - return dest; - } - } - } - s_logger.debug("Cannnot deploy to specified host, returning."); - return null; - } - - if (vm.getLastHostId() != null && haVmTag == null) { - s_logger.debug("This VM has last host_id specified, trying to choose the same host: " +vm.getLastHostId()); - - HostVO host = _hostDao.findById(vm.getLastHostId()); - if(host == null){ - s_logger.debug("The last host of this VM cannot be found"); - }else if(avoid.shouldAvoid(host)){ - s_logger.debug("The last host of this VM is in avoid set"); - }else if(_capacityMgr.checkIfHostReachMaxGuestLimit(host)){ - s_logger.debug("The last Host, hostId: "+ host.getId() +" already has max Running VMs(count includes system VMs), skipping this and trying other available hosts"); - }else{ - if (host.getStatus() == Status.Up && host.getResourceState() == ResourceState.Enabled) { - long cluster_id = host.getClusterId(); - ClusterDetailsVO cluster_detail_cpu = _clusterDetailsDao.findDetail(cluster_id,"cpuOvercommitRatio"); - ClusterDetailsVO cluster_detail_ram = _clusterDetailsDao.findDetail(cluster_id,"memoryOvercommitRatio"); - Float cpuOvercommitRatio = Float.parseFloat(cluster_detail_cpu.getValue()); - Float memoryOvercommitRatio = Float.parseFloat(cluster_detail_ram.getValue()); - if(_capacityMgr.checkIfHostHasCapacity(host.getId(), cpu_requested, ram_requested, true, cpuOvercommitRatio, memoryOvercommitRatio, true)){ - s_logger.debug("The last host of this VM is UP and has enough capacity"); - s_logger.debug("Now checking for suitable pools under zone: "+host.getDataCenterId() +", pod: "+ host.getPodId()+", cluster: "+ host.getClusterId()); - //search for storage under the zone, pod, cluster of the last host. - DataCenterDeployment lastPlan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), host.getClusterId(), host.getId(), plan.getPoolId(), null); - Pair>, List> result = findSuitablePoolsForVolumes(vmProfile, lastPlan, avoid, HostAllocator.RETURN_UPTO_ALL); - Map> suitableVolumeStoragePools = result.first(); - List readyAndReusedVolumes = result.second(); - //choose the potential pool for this VM for this host - if(!suitableVolumeStoragePools.isEmpty()){ - List suitableHosts = new ArrayList(); - suitableHosts.add(host); - - Pair> potentialResources = findPotentialDeploymentResources(suitableHosts, suitableVolumeStoragePools); - if(potentialResources != null){ - Pod pod = _podDao.findById(host.getPodId()); - Cluster cluster = _clusterDao.findById(host.getClusterId()); - Map storageVolMap = potentialResources.second(); - // remove the reused vol<->pool from destination, since we don't have to prepare this volume. - for(Volume vol : readyAndReusedVolumes){ - storageVolMap.remove(vol); - } - DeployDestination dest = new DeployDestination(dc, pod, cluster, host, storageVolMap); - s_logger.debug("Returning Deployment Destination: "+ dest); - return dest; - } - } - }else{ - s_logger.debug("The last host of this VM does not have enough capacity"); - } - }else{ - s_logger.debug("The last host of this VM is not UP or is not enabled, host status is: "+host.getStatus().name() + ", host resource state is: "+host.getResourceState()); - } - } - s_logger.debug("Cannot choose the last host to deploy this VM "); - } - - List clusterList = new ArrayList(); if (plan.getClusterId() != null) { Long clusterIdSpecified = plan.getClusterId(); s_logger.debug("Searching resources only under specified Cluster: "+ clusterIdSpecified); ClusterVO cluster = _clusterDao.findById(plan.getClusterId()); if (cluster != null ){ - clusterList.add(clusterIdSpecified); - return checkClustersforDestination(clusterList, vmProfile, plan, avoid, dc); + if (avoid.shouldAvoid(cluster)) { + s_logger.debug("The specified cluster is in avoid set, returning."); + } else { + clusterList.add(clusterIdSpecified); + removeClustersCrossingThreshold(clusterList, avoid, vmProfile, plan); + } + return clusterList; }else{ s_logger.debug("The specified cluster cannot be found, returning."); avoid.addCluster(plan.getClusterId()); @@ -280,11 +149,15 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { HostPodVO pod = _podDao.findById(podIdSpecified); if (pod != null) { - DeployDestination dest = scanClustersForDestinationInZoneOrPod(podIdSpecified, false, vmProfile, plan, avoid); - if(dest == null){ - avoid.addPod(plan.getPodId()); + if (avoid.shouldAvoid(pod)) { + s_logger.debug("The specified pod is in avoid set, returning."); + } else { + clusterList = scanClustersForDestinationInZoneOrPod(podIdSpecified, false, vmProfile, plan, avoid); + if (clusterList == null) { + avoid.addPod(plan.getPodId()); + } } - return dest; + return clusterList; } else { s_logger.debug("The specified Pod cannot be found, returning."); avoid.addPod(plan.getPodId()); @@ -305,7 +178,7 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { } - private DeployDestination scanPodsForDestination(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid){ + private List scanPodsForDestination(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid){ ServiceOffering offering = vmProfile.getServiceOffering(); int requiredCpu = offering.getCpu() * offering.getSpeed(); @@ -341,20 +214,24 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { if(!podsWithCapacity.isEmpty()){ prioritizedPodIds = reorderPods(podCapacityInfo, vmProfile, plan); + if (prioritizedPodIds == null || prioritizedPodIds.isEmpty()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("No Pods found for destination, returning."); + } + return null; + } + List clusterList = new ArrayList(); //loop over pods for(Long podId : prioritizedPodIds){ s_logger.debug("Checking resources under Pod: "+podId); - DeployDestination dest = scanClustersForDestinationInZoneOrPod(podId, false, vmProfile, plan, avoid); - if(dest != null){ - return dest; + List clustersUnderPod = scanClustersForDestinationInZoneOrPod(podId, false, vmProfile, plan, + avoid); + if (clustersUnderPod != null) { + clusterList.addAll(clustersUnderPod); } - avoid.addPod(podId); } - if (s_logger.isDebugEnabled()) { - s_logger.debug("No Pods found for destination, returning."); - } - return null; + return clusterList; }else{ if (s_logger.isDebugEnabled()) { s_logger.debug("No Pods found after removing disabled pods and pods in avoid list, returning."); @@ -363,7 +240,69 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { } } - private DeployDestination scanClustersForDestinationInZoneOrPod(long id, boolean isZone, VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid){ + 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); + capacityList.add(Capacity.CAPACITY_TYPE_MEMORY); + return capacityList; + } + + private void removeClustersCrossingThreshold(List clusterListForVmAllocation, ExcludeList avoid, + VirtualMachineProfile vmProfile, DeploymentPlan plan) { + + List capacityList = getCapacitiesForCheckingThreshold(); + List clustersCrossingThreshold = new ArrayList(); + + ServiceOffering offering = vmProfile.getServiceOffering(); + int cpu_requested = offering.getCpu() * offering.getSpeed(); + long ram_requested = offering.getRamSize() * 1024L * 1024L; + + // For each capacity get the cluster list crossing the threshold and + // remove it from the clusterList that will be used for vm allocation. + for (short capacity : capacityList) { + + if (clusterListForVmAllocation == null || clusterListForVmAllocation.size() == 0) { + return; + } + if (capacity == Capacity.CAPACITY_TYPE_CPU) { + clustersCrossingThreshold = _capacityDao.listClustersCrossingThreshold(capacity, + plan.getDataCenterId(), Config.CPUCapacityDisableThreshold.key(), cpu_requested); + } else if (capacity == Capacity.CAPACITY_TYPE_MEMORY) { + clustersCrossingThreshold = _capacityDao.listClustersCrossingThreshold(capacity, + plan.getDataCenterId(), Config.MemoryCapacityDisableThreshold.key(), ram_requested); + } + + if (clustersCrossingThreshold != null && clustersCrossingThreshold.size() != 0) { + // addToAvoid Set + avoid.addClusterList(clustersCrossingThreshold); + // 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 defined at each cluster/ at global value for capacity Type : " + capacity + ", skipping these clusters"); + } + + } + } + + private List scanClustersForDestinationInZoneOrPod(long id, boolean isZone, + VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid) { VirtualMachine vm = vmProfile.getVirtualMachine(); ServiceOffering offering = vmProfile.getServiceOffering(); @@ -396,6 +335,9 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { prioritizedClusterIds.removeAll(disabledClusters); } } + + removeClustersCrossingThreshold(prioritizedClusterIds, avoid, vmProfile, plan); + }else{ if (s_logger.isDebugEnabled()) { s_logger.debug("No clusters found having a host with enough capacity, returning."); @@ -404,7 +346,7 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { } if(!prioritizedClusterIds.isEmpty()){ List clusterList = reorderClusters(id, isZone, clusterCapacityInfo, vmProfile, plan); - return checkClustersforDestination(clusterList, vmProfile, plan, avoid, dc); + return clusterList; //return checkClustersforDestination(clusterList, vmProfile, plan, avoid, dc); }else{ if (s_logger.isDebugEnabled()) { s_logger.debug("No clusters found after removing disabled clusters and clusters in avoid list, returning."); @@ -452,114 +394,6 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { return disabledPods; } - private List getCapacitiesForCheckingThreshold(){ - List capacityList = new ArrayList(); - capacityList.add(Capacity.CAPACITY_TYPE_CPU); - capacityList.add(Capacity.CAPACITY_TYPE_MEMORY); - return capacityList; - } - - private void removeClustersCrossingThreshold(List clusterListForVmAllocation, ExcludeList avoid, VirtualMachineProfile vmProfile, DeploymentPlan plan){ - - List capacityList = getCapacitiesForCheckingThreshold(); - List clustersCrossingThreshold = new ArrayList(); - - ServiceOffering offering = vmProfile.getServiceOffering(); - int cpu_requested = offering.getCpu() * offering.getSpeed(); - long ram_requested = offering.getRamSize() * 1024L * 1024L; - - // For each capacity get the cluster list crossing the threshold and remove it from the clusterList that will be used for vm allocation. - for(short capacity : capacityList){ - - if (clusterListForVmAllocation == null || clusterListForVmAllocation.size() == 0){ - return; - } - if (capacity == Capacity.CAPACITY_TYPE_CPU) { - clustersCrossingThreshold = _capacityDao.listClustersCrossingThreshold(capacity, plan.getDataCenterId(), Config.CPUCapacityDisableThreshold.key(), cpu_requested); - } - else if (capacity == Capacity.CAPACITY_TYPE_MEMORY ) { - clustersCrossingThreshold = _capacityDao.listClustersCrossingThreshold(capacity, plan.getDataCenterId(), - Config.MemoryCapacityDisableThreshold.key(), ram_requested ); - } - - - if (clustersCrossingThreshold != null && clustersCrossingThreshold.size() != 0){ - // addToAvoid Set - avoid.addClusterList(clustersCrossingThreshold); - // 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 defined at each cluster/ at global value for capacity Type : " + capacity + ", skipping these clusters"); - } - - } - } - - private DeployDestination checkClustersforDestination(List clusterList, VirtualMachineProfile vmProfile, - DeploymentPlan plan, ExcludeList avoid, DataCenter dc){ - - if (s_logger.isTraceEnabled()) { - s_logger.trace("ClusterId List to consider: " + clusterList); - } - - removeClustersCrossingThreshold(clusterList, avoid, vmProfile, plan); - - for(Long clusterId : clusterList){ - Cluster clusterVO = _clusterDao.findById(clusterId); - - if (clusterVO.getHypervisorType() != vmProfile.getHypervisorType()) { - s_logger.debug("Cluster: "+clusterId + " has HyperVisorType that does not match the VM, skipping this cluster"); - avoid.addCluster(clusterVO.getId()); - continue; - } - - s_logger.debug("Checking resources in Cluster: "+clusterId + " under Pod: "+clusterVO.getPodId()); - //search for resources(hosts and storage) under this zone, pod, cluster. - DataCenterDeployment potentialPlan = new DataCenterDeployment(plan.getDataCenterId(), clusterVO.getPodId(), clusterVO.getId(), null, plan.getPoolId(), null, plan.getReservationContext()); - - //find suitable hosts under this cluster, need as many hosts as we get. - List suitableHosts = findSuitableHosts(vmProfile, potentialPlan, avoid, HostAllocator.RETURN_UPTO_ALL); - //if found suitable hosts in this cluster, find suitable storage pools for each volume of the VM - if(suitableHosts != null && !suitableHosts.isEmpty()){ - if (vmProfile.getHypervisorType() == HypervisorType.BareMetal) { - Pod pod = _podDao.findById(clusterVO.getPodId()); - DeployDestination dest = new DeployDestination(dc, pod, clusterVO, suitableHosts.get(0)); - return dest; - } - - Pair>, List> result = findSuitablePoolsForVolumes(vmProfile, potentialPlan, avoid, StoragePoolAllocator.RETURN_UPTO_ALL); - Map> suitableVolumeStoragePools = result.first(); - List readyAndReusedVolumes = result.second(); - - //choose the potential host and pool for the VM - if(!suitableVolumeStoragePools.isEmpty()){ - Pair> potentialResources = findPotentialDeploymentResources(suitableHosts, suitableVolumeStoragePools); - - if(potentialResources != null){ - Pod pod = _podDao.findById(clusterVO.getPodId()); - Host host = _hostDao.findById(potentialResources.first().getId()); - Map storageVolMap = potentialResources.second(); - // remove the reused vol<->pool from destination, since we don't have to prepare this volume. - for(Volume vol : readyAndReusedVolumes){ - storageVolMap.remove(vol); - } - DeployDestination dest = new DeployDestination(dc, pod, clusterVO, host, storageVolMap ); - s_logger.debug("Returning Deployment Destination: "+ dest); - return dest; - } - }else{ - s_logger.debug("No suitable storagePools found under this Cluster: "+clusterId); - } - }else{ - s_logger.debug("No suitable hosts found under this Cluster: "+clusterId); - } - avoid.addCluster(clusterVO.getId()); - } - s_logger.debug("Could not find suitable Deployment Destination for this VM under any clusters, returning. "); - return null; - } - protected Pair, Map> listClustersByCapacity(long id, int requiredCpu, long requiredRam, ExcludeList avoid, boolean isZone){ //look at the aggregate available cpu and ram per cluster @@ -630,215 +464,6 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { } - - protected Pair> findPotentialDeploymentResources(List suitableHosts, Map> suitableVolumeStoragePools){ - s_logger.debug("Trying to find a potenial host and associated storage pools from the suitable host/pool lists for this VM"); - - boolean hostCanAccessPool = false; - boolean haveEnoughSpace = false; - Map storage = new HashMap(); - TreeSet volumesOrderBySizeDesc = new TreeSet(new Comparator() { - @Override - public int compare(Volume v1, Volume v2) { - if(v1.getSize() < v2.getSize()) - return 1; - else - return -1; - } - }); - volumesOrderBySizeDesc.addAll(suitableVolumeStoragePools.keySet()); - boolean multipleVolume = volumesOrderBySizeDesc.size() > 1; - for(Host potentialHost : suitableHosts){ - Map> volumeAllocationMap = new HashMap>(); - for(Volume vol : volumesOrderBySizeDesc){ - haveEnoughSpace = false; - s_logger.debug("Checking if host: "+potentialHost.getId() +" can access any suitable storage pool for volume: "+ vol.getVolumeType()); - List volumePoolList = suitableVolumeStoragePools.get(vol); - hostCanAccessPool = false; - for(StoragePool potentialSPool : volumePoolList){ - if(hostCanAccessSPool(potentialHost, potentialSPool)){ - hostCanAccessPool = true; - if(multipleVolume){ - List requestVolumes = null; - if(volumeAllocationMap.containsKey(potentialSPool)) - requestVolumes = volumeAllocationMap.get(potentialSPool); - else - requestVolumes = new ArrayList(); - requestVolumes.add(vol); - - if(!_storageMgr.storagePoolHasEnoughSpace(requestVolumes, potentialSPool)) - continue; - volumeAllocationMap.put(potentialSPool,requestVolumes); - } - storage.put(vol, potentialSPool); - haveEnoughSpace = true; - break; - } - } - if(!hostCanAccessPool){ - break; - } - if(!haveEnoughSpace) { - s_logger.warn("insufficient capacity to allocate all volumes"); - break; - } - } - if(hostCanAccessPool && haveEnoughSpace){ - s_logger.debug("Found a potential host " + "id: "+potentialHost.getId() + " name: " +potentialHost.getName() + " and associated storage pools for this VM"); - return new Pair>(potentialHost, storage); - } - } - s_logger.debug("Could not find a potential host that has associated storage pools from the suitable host/pool lists for this VM"); - return null; - } - - protected boolean hostCanAccessSPool(Host host, StoragePool pool){ - boolean hostCanAccessSPool = false; - - StoragePoolHostVO hostPoolLinkage = _poolHostDao.findByPoolHost(pool.getId(), host.getId()); - if(hostPoolLinkage != null){ - hostCanAccessSPool = true; - } - - s_logger.debug("Host: "+ host.getId() + (hostCanAccessSPool ?" can" : " cannot") + " access pool: "+ pool.getId()); - return hostCanAccessSPool; - } - - protected List findSuitableHosts(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid, int returnUpTo){ - List suitableHosts = new ArrayList(); - for(HostAllocator allocator : _hostAllocators) { - suitableHosts = allocator.allocateTo(vmProfile, plan, Host.Type.Routing, avoid, returnUpTo); - if (suitableHosts != null && !suitableHosts.isEmpty()) { - break; - } - } - - if(suitableHosts.isEmpty()){ - s_logger.debug("No suitable hosts found"); - } - return suitableHosts; - } - - protected Pair>, List> findSuitablePoolsForVolumes(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid, int returnUpTo){ - List volumesTobeCreated = _volsDao.findUsableVolumesForInstance(vmProfile.getId()); - Map> suitableVolumeStoragePools = new HashMap>(); - List readyAndReusedVolumes = new ArrayList(); - - //for each volume find list of suitable storage pools by calling the allocators - for (VolumeVO toBeCreated : volumesTobeCreated) { - s_logger.debug("Checking suitable pools for volume (Id, Type): ("+toBeCreated.getId() +"," +toBeCreated.getVolumeType().name() + ")"); - - //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(" + 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 != 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); - } - continue; - }else{ - s_logger.debug("Pool of the volume does not fit the specified plan, 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"); - } - }else{ - s_logger.debug("Pool of the volume is in maintenance, need to reallocate a pool for this volume"); - } - }else{ - s_logger.debug("Unable to find pool by provided id"); - } - } - - if(s_logger.isDebugEnabled()){ - s_logger.debug("We need to allocate new storagepool for this volume"); - } - if(!isRootAdmin(plan.getReservationContext())){ - if(!isEnabledForAllocation(plan.getDataCenterId(), plan.getPodId(), plan.getClusterId())){ - if(s_logger.isDebugEnabled()){ - s_logger.debug("Cannot allocate new storagepool for this volume in this cluster, allocation state is disabled"); - s_logger.debug("Cannot deploy to this specified plan, allocation state is disabled, returning."); - } - //Cannot find suitable storage pools under this cluster for this volume since allocation_state is disabled. - //- remove any suitable pools found for other volumes. - //All volumes should get suitable pools under this cluster; else we cant use this cluster. - suitableVolumeStoragePools.clear(); - break; - } - } - - s_logger.debug("Calling StoragePoolAllocators to find suitable pools"); - - DiskOfferingVO diskOffering = _diskOfferingDao.findById(toBeCreated.getDiskOfferingId()); - DiskProfile diskProfile = new DiskProfile(toBeCreated, diskOffering, vmProfile.getHypervisorType()); - - boolean useLocalStorage = false; - if (vmProfile.getType() != VirtualMachine.Type.User) { - String ssvmUseLocalStorage = _configDao.getValue(Config.SystemVMUseLocalStorage.key()); - if (ssvmUseLocalStorage.equalsIgnoreCase("true")) { - useLocalStorage = true; - } - } else { - useLocalStorage = diskOffering.getUseLocalStorage(); - - // TODO: this is a hacking fix for the problem of deploy ISO-based VM on local storage - // when deploying VM based on ISO, we have a service offering and an additional disk offering, use-local storage flag is actually - // saved in service offering, overrde the flag from service offering when it is a ROOT disk - if(!useLocalStorage && vmProfile.getServiceOffering().getUseLocalStorage()) { - if(toBeCreated.getVolumeType() == Volume.Type.ROOT) - useLocalStorage = true; - } - } - diskProfile.setUseLocalStorage(useLocalStorage); - - boolean foundPotentialPools = false; - for(StoragePoolAllocator allocator : _storagePoolAllocators) { - final List suitablePools = allocator.allocateToPool(diskProfile, vmProfile, plan, avoid, returnUpTo); - if (suitablePools != null && !suitablePools.isEmpty()) { - suitableVolumeStoragePools.put(toBeCreated, suitablePools); - foundPotentialPools = true; - break; - } - } - - if(!foundPotentialPools){ - s_logger.debug("No suitable pools found for volume: "+toBeCreated +" under cluster: "+plan.getClusterId()); - //No suitable storage pools found under this cluster for this volume. - remove any suitable pools found for other volumes. - //All volumes should get suitable pools under this cluster; else we cant use this cluster. - suitableVolumeStoragePools.clear(); - break; - } - } - - if(suitableVolumeStoragePools.isEmpty()){ - s_logger.debug("No suitable pools found"); - } - - return new Pair>, List>(suitableVolumeStoragePools, readyAndReusedVolumes); - } - - private boolean isRootAdmin(ReservationContext reservationContext) { if(reservationContext != null){ if(reservationContext.getAccount() != null){ @@ -859,10 +484,17 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { @Override public boolean canHandle(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid) { - if(vm.getHypervisorType() != HypervisorType.BareMetal){ - //check the allocation strategy - if (_allocationAlgorithm != null && (_allocationAlgorithm.equals(AllocationAlgorithm.random.toString()) || _allocationAlgorithm.equals(AllocationAlgorithm.firstfit.toString()))) { - return true; + // check what the ServiceOffering says. If null, check the global config + ServiceOffering offering = vm.getServiceOffering(); + if (vm.getHypervisorType() != HypervisorType.BareMetal) { + if (offering != null && offering.getDeploymentPlanner() != null) { + if (offering.getDeploymentPlanner().equals(this.getName())) { + return true; + } + } else { + if (_globalDeploymentPlanner != null && _globalDeploymentPlanner.equals(this._name)) { + return true; + } } } return false; @@ -872,29 +504,20 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { public boolean configure(String name, Map params) throws ConfigurationException { super.configure(name, params); _allocationAlgorithm = _configDao.getValue(Config.VmAllocationAlgorithm.key()); + _globalDeploymentPlanner = _configDao.getValue(Config.VmDeploymentPlanner.key()); return true; } - private boolean isEnabledForAllocation(long zoneId, Long podId, Long clusterId){ - // Check if the zone exists in the system - DataCenterVO zone = _dcDao.findById(zoneId); - if(zone != null && Grouping.AllocationState.Disabled == zone.getAllocationState()){ - s_logger.info("Zone is currently disabled, cannot allocate to this zone: "+ zoneId); - return false; - } - Pod pod = _podDao.findById(podId); - if(pod != null && Grouping.AllocationState.Disabled == pod.getAllocationState()){ - s_logger.info("Pod is currently disabled, cannot allocate to this pod: "+ podId); - return false; - } + @Override + public DeployDestination plan(VirtualMachineProfile vm, DeploymentPlan plan, + ExcludeList avoid) throws InsufficientServerCapacityException { + // TODO Auto-generated method stub + return null; + } - Cluster cluster = _clusterDao.findById(clusterId); - if(cluster != null && Grouping.AllocationState.Disabled == cluster.getAllocationState()){ - s_logger.info("Cluster is currently disabled, cannot allocate to this cluster: "+ clusterId); - return false; - } - - return true; + @Override + public PlannerResourceUsage getResourceUsage() { + return PlannerResourceUsage.Shared; } } diff --git a/server/src/com/cloud/deploy/HypervisorVmPlannerSelector.java b/server/src/com/cloud/deploy/HypervisorVmPlannerSelector.java deleted file mode 100755 index ce494051376..00000000000 --- a/server/src/com/cloud/deploy/HypervisorVmPlannerSelector.java +++ /dev/null @@ -1,54 +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.deploy; - -import javax.ejb.Local; - -import org.apache.log4j.Logger; - -import com.cloud.deploy.DeploymentPlanner.AllocationAlgorithm; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.vm.UserVmVO; - -@Local(value = {DeployPlannerSelector.class}) -public class HypervisorVmPlannerSelector extends AbstractDeployPlannerSelector { - private static final Logger s_logger = Logger.getLogger(HypervisorVmPlannerSelector.class); - - @Override - public String selectPlanner(UserVmVO vm) { - if (vm.getHypervisorType() != HypervisorType.BareMetal) { - //check the allocation strategy - if (_allocationAlgorithm != null) { - if (_allocationAlgorithm.equals(AllocationAlgorithm.random.toString()) - || _allocationAlgorithm.equals(AllocationAlgorithm.firstfit.toString())) { - return "FirstFitPlanner"; - } else if (_allocationAlgorithm.equals(AllocationAlgorithm.userdispersing.toString())) { - return "UserDispersingPlanner"; - } else if (_allocationAlgorithm.equals(AllocationAlgorithm.userconcentratedpod_random.toString()) - || _allocationAlgorithm.equals(AllocationAlgorithm.userconcentratedpod_firstfit.toString())) { - return "UserConcentratedPodPlanner"; - } - } else { - if (s_logger.isDebugEnabled()) { - s_logger.debug("The allocation algorithm is null, cannot select the planner"); - } - } - } - - return null; - } -} diff --git a/server/src/com/cloud/deploy/PlannerHostReservationVO.java b/server/src/com/cloud/deploy/PlannerHostReservationVO.java new file mode 100644 index 00000000000..cf5f03177f7 --- /dev/null +++ b/server/src/com/cloud/deploy/PlannerHostReservationVO.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.deploy; + + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import org.apache.cloudstack.api.InternalIdentity; + +import com.cloud.deploy.DeploymentPlanner.PlannerResourceUsage; + +@Entity +@Table(name = "op_host_planner_reservation") +public class PlannerHostReservationVO implements InternalIdentity { + @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) + @Column(name="id") + private long id; + + @Column(name="host_id") + private Long hostId; + + @Column(name="data_center_id") + private Long dataCenterId; + + @Column(name="pod_id") + private Long podId; + + @Column(name="cluster_id") + private Long clusterId; + + @Column(name = "resource_usage") + @Enumerated(EnumType.STRING) + private PlannerResourceUsage resourceUsage; + + public PlannerHostReservationVO() { + } + + public PlannerHostReservationVO(Long hostId, Long dataCenterId, Long podId, Long clusterId) { + this.hostId = hostId; + this.dataCenterId = dataCenterId; + this.podId = podId; + this.clusterId = clusterId; + } + + public PlannerHostReservationVO(Long hostId, Long dataCenterId, Long podId, Long clusterId, + PlannerResourceUsage resourceUsage) { + this.hostId = hostId; + this.dataCenterId = dataCenterId; + this.podId = podId; + this.clusterId = clusterId; + this.resourceUsage = resourceUsage; + } + + @Override + public long getId() { + return id; + } + + public Long getHostId() { + return hostId; + } + + public void setHostId(Long hostId) { + this.hostId = hostId; + } + + public Long getDataCenterId() { + return dataCenterId; + } + public void setDataCenterId(Long dataCenterId) { + this.dataCenterId = dataCenterId; + } + + public Long getPodId() { + return podId; + } + public void setPodId(long podId) { + this.podId = new Long(podId); + } + + public Long getClusterId() { + return clusterId; + } + public void setClusterId(long clusterId) { + this.clusterId = new Long(clusterId); + } + + public PlannerResourceUsage getResourceUsage() { + return resourceUsage; + } + + public void setResourceUsage(PlannerResourceUsage resourceType) { + this.resourceUsage = resourceType; + } + +} diff --git a/server/src/com/cloud/deploy/DeployPlannerSelector.java b/server/src/com/cloud/deploy/dao/PlannerHostReservationDao.java old mode 100755 new mode 100644 similarity index 67% rename from server/src/com/cloud/deploy/DeployPlannerSelector.java rename to server/src/com/cloud/deploy/dao/PlannerHostReservationDao.java index 062b492d8fc..69118f13896 --- a/server/src/com/cloud/deploy/DeployPlannerSelector.java +++ b/server/src/com/cloud/deploy/dao/PlannerHostReservationDao.java @@ -1,24 +1,30 @@ -// 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.deploy; - -import com.cloud.utils.component.Adapter; -import com.cloud.vm.UserVmVO; - -public interface DeployPlannerSelector extends Adapter { - String selectPlanner(UserVmVO vm); -} +// 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.deploy.dao; + +import java.util.List; + +import com.cloud.deploy.PlannerHostReservationVO; +import com.cloud.utils.db.GenericDao; + +public interface PlannerHostReservationDao extends GenericDao { + + PlannerHostReservationVO findByHostId(long hostId); + + List listAllReservedHosts(); + +} diff --git a/server/src/com/cloud/deploy/dao/PlannerHostReservationDaoImpl.java b/server/src/com/cloud/deploy/dao/PlannerHostReservationDaoImpl.java new file mode 100644 index 00000000000..41e09647d7e --- /dev/null +++ b/server/src/com/cloud/deploy/dao/PlannerHostReservationDaoImpl.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 com.cloud.deploy.dao; + +import java.util.List; + +import javax.annotation.PostConstruct; +import javax.ejb.Local; +import com.cloud.deploy.PlannerHostReservationVO; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +@Local(value = { PlannerHostReservationDao.class }) +public class PlannerHostReservationDaoImpl extends GenericDaoBase implements + PlannerHostReservationDao { + + private SearchBuilder _hostIdSearch; + private SearchBuilder _reservedHostSearch; + + public PlannerHostReservationDaoImpl() { + + } + + @PostConstruct + protected void init() { + _hostIdSearch = createSearchBuilder(); + _hostIdSearch.and("hostId", _hostIdSearch.entity().getHostId(), SearchCriteria.Op.EQ); + _hostIdSearch.done(); + + _reservedHostSearch = createSearchBuilder(); + _reservedHostSearch.and("usage", _reservedHostSearch.entity().getResourceUsage(), SearchCriteria.Op.NNULL); + _reservedHostSearch.done(); + } + + @Override + public PlannerHostReservationVO findByHostId(long hostId) { + SearchCriteria sc = _hostIdSearch.create(); + sc.setParameters("hostId", hostId); + return findOneBy(sc); + } + + @Override + public List listAllReservedHosts() { + SearchCriteria sc = _reservedHostSearch.create(); + return listBy(sc); + } + +} diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index 0ab35dd00a2..c60f0953a78 100755 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -85,6 +85,10 @@ import com.cloud.dc.dao.ClusterVSMMapDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.DataCenterIpAddressDao; import com.cloud.dc.dao.HostPodDao; +import com.cloud.deploy.PlannerHostReservationVO; +import com.cloud.deploy.dao.PlannerHostReservationDao; +import com.cloud.event.ActionEvent; +import com.cloud.event.EventTypes; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.DiscoveryException; import com.cloud.exception.InvalidParameterValueException; @@ -212,6 +216,8 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, protected HighAvailabilityManager _haMgr; @Inject protected StorageService _storageSvr; + @Inject + PlannerHostReservationDao _plannerHostReserveDao; protected List _discoverers; public List getDiscoverers() { @@ -2851,4 +2857,41 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, ResourceState.Enabled); return sc.list(); } + + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_HOST_RESERVATION_RELEASE, eventDescription = "releasing host reservation", async = true) + public boolean releaseHostReservation(Long hostId) { + Transaction txn = Transaction.currentTxn(); + try { + txn.start(); + PlannerHostReservationVO reservationEntry = _plannerHostReserveDao.findByHostId(hostId); + if (reservationEntry != null) { + long id = reservationEntry.getId(); + PlannerHostReservationVO hostReservation = _plannerHostReserveDao.lockRow(id, true); + if (hostReservation == null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Host reservation for host: " + hostId + " does not even exist. Release reservartion call is ignored."); + } + txn.rollback(); + return false; + } + hostReservation.setResourceUsage(null); + _plannerHostReserveDao.persist(hostReservation); + txn.commit(); + return true; + } + if (s_logger.isDebugEnabled()) { + s_logger.debug("Host reservation for host: " + hostId + + " does not even exist. Release reservartion call is ignored."); + } + return false; + } catch (CloudRuntimeException e) { + throw e; + } catch (Throwable t) { + s_logger.error("Unable to release host reservation for host: " + hostId, t); + txn.rollback(); + return false; + } + } } diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index bc3728203bc..f74b7ad964c 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -78,6 +78,7 @@ 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.ReleaseHostReservationCmd; 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; @@ -462,6 +463,7 @@ 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; @@ -589,6 +591,7 @@ 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.api.command.admin.config.ListDeploymentPlannersCmd; public class ManagementServerImpl extends ManagerBase implements ManagementServer { @@ -726,11 +729,21 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe private List _userAuthenticators; private List _userPasswordEncoders; + protected List _planners; + + public List getPlanners() { + return _planners; + } + + public void setPlanners(List _planners) { + this._planners = _planners; + } + @Inject ClusterManager _clusterMgr; private String _hashKey = null; private String _encryptionKey = null; private String _encryptionIV = null; - + @Inject protected AffinityGroupVMMapDao _affinityGroupVMMapDao; @@ -976,29 +989,29 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe 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); + + 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); + 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(); + + + SearchCriteria sc = sb.create(); if (id != null) { - sc.setParameters("id", id); + sc.setParameters("id", id); } if (name != null) { @@ -1026,9 +1039,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe } if(zoneType != null) { - sc.setJoinParameters("zoneSb", "zoneNetworkType", zoneType); + sc.setJoinParameters("zoneSb", "zoneNetworkType", zoneType); } - + if (keyword != null) { SearchCriteria ssc = _clusterDao.createSearchCriteria(); ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%"); @@ -1441,26 +1454,26 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe public Pair, Integer> searchForPods(ListPodsByCmd cmd) { 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(); + 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("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); + 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(); @@ -1473,23 +1486,23 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe if (id != null) { sc.setParameters("id", id); } - + if (podName != null) { sc.setParameters("name", "%" + podName + "%"); } - + if (zoneId != null) { sc.setParameters("dataCenterId", zoneId); } - + if (allocationState != null) { sc.setParameters("allocationState", allocationState); - } - - if(zoneType != null) { - sc.setJoinParameters("zoneSb", "zoneNetworkType", zoneType); } - + + if(zoneType != null) { + sc.setJoinParameters("zoneSb", "zoneNetworkType", zoneType); + } + Pair, Integer> result = _hostPodDao.searchAndCount(sc, searchFilter); return new Pair, Integer>(result.first(), result.second()); } @@ -2903,7 +2916,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(ListAffinityGroupsCmd.class); cmdList.add(UpdateVMAffinityGroupCmd.class); cmdList.add(ListAffinityGroupTypesCmd.class); - + cmdList.add(ListDeploymentPlannersCmd.class); + cmdList.add(ReleaseHostReservationCmd.class); cmdList.add(AddResourceDetailCmd.class); cmdList.add(RemoveResourceDetailCmd.class); cmdList.add(ListResourceDetailsCmd.class); @@ -3105,10 +3119,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe if(zoneType != null) { SearchBuilder zoneSb = _dcDao.createSearchBuilder(); - zoneSb.and("zoneNetworkType", zoneSb.entity().getNetworkType(), SearchCriteria.Op.EQ); + 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) { @@ -3150,9 +3164,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe } if(zoneType != null) { - sc.setJoinParameters("zoneSb", "zoneNetworkType", zoneType); + sc.setJoinParameters("zoneSb", "zoneNetworkType", zoneType); } - + Pair, Integer> result = _vmInstanceDao.searchAndCount(sc, searchFilter); return new Pair, Integer>(result.first(), result.second()); } @@ -3677,7 +3691,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe // although we may have race conditioning here, database transaction serialization should // give us the same key if (_hashKey == null) { - _hashKey = _configDao.getValueAndInitIfNotExist(Config.HashKey.key(), Config.HashKey.getCategory(), + _hashKey = _configDao.getValueAndInitIfNotExist(Config.HashKey.key(), Config.HashKey.getCategory(), getBase64EncodedRandomKey(128)); } return _hashKey; @@ -3686,41 +3700,41 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe @Override public String getEncryptionKey() { if (_encryptionKey == null) { - _encryptionKey = _configDao.getValueAndInitIfNotExist(Config.EncryptionKey.key(), - Config.EncryptionKey.getCategory(), + _encryptionKey = _configDao.getValueAndInitIfNotExist(Config.EncryptionKey.key(), + Config.EncryptionKey.getCategory(), getBase64EncodedRandomKey(128)); } return _encryptionKey; } - + @Override public String getEncryptionIV() { if (_encryptionIV == null) { - _encryptionIV = _configDao.getValueAndInitIfNotExist(Config.EncryptionIV.key(), - Config.EncryptionIV.getCategory(), + _encryptionIV = _configDao.getValueAndInitIfNotExist(Config.EncryptionIV.key(), + Config.EncryptionIV.getCategory(), getBase64EncodedRandomKey(128)); } return _encryptionIV; } - + @Override @DB public void resetEncryptionKeyIV() { - + SearchBuilder sb = _configDao.createSearchBuilder(); sb.and("name1", sb.entity().getName(), SearchCriteria.Op.EQ); sb.or("name2", sb.entity().getName(), SearchCriteria.Op.EQ); sb.done(); - + SearchCriteria sc = sb.create(); sc.setParameters("name1", Config.EncryptionKey.key()); sc.setParameters("name2", Config.EncryptionIV.key()); - + _configDao.expunge(sc); _encryptionKey = null; _encryptionIV = null; } - + private static String getBase64EncodedRandomKey(int nBits) { SecureRandom random; try { @@ -4056,4 +4070,15 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe } } + + @Override + public List listDeploymentPlanners() { + List plannersAvailable = new ArrayList(); + for (DeploymentPlanner planner : _planners) { + plannersAvailable.add(planner.getName()); + } + + return plannersAvailable; + } + } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index aa065294f8c..a3b731ab2a5 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -98,7 +98,6 @@ import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; -import com.cloud.deploy.DeployPlannerSelector; import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; @@ -402,9 +401,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use @Inject AffinityGroupDao _affinityGroupDao; - @Inject - List plannerSelectors; - protected ScheduledExecutorService _executor = null; protected int _expungeInterval; protected int _expungeDelay; @@ -2836,7 +2832,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } return result; } - + @Override public boolean finalizeDeployment(Commands cmds, VirtualMachineProfile profile, DeployDestination dest, @@ -3036,7 +3032,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use + " stop due to exception ", ex); } } - + VMInstanceVO vm = profile.getVirtualMachine(); List nics = _nicDao.listByVmId(vm.getId()); for (NicVO nic : nics) { @@ -3174,15 +3170,15 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid()); - String plannerName = null; - for (DeployPlannerSelector dps : plannerSelectors) { - plannerName = dps.selectPlanner(vm); - if (plannerName != null) { - break; - } - } + // Get serviceOffering for Virtual Machine + ServiceOfferingVO offering = _serviceOfferingDao.findByIdIncludingRemoved(vm.getServiceOfferingId()); + String plannerName = offering.getDeploymentPlanner(); if (plannerName == null) { - throw new CloudRuntimeException(String.format("cannot find DeployPlannerSelector for vm[uuid:%s, hypervisorType:%s]", vm.getUuid(), vm.getHypervisorType())); + if (vm.getHypervisorType() == HypervisorType.BareMetal) { + plannerName = "BareMetalPlanner"; + } else { + plannerName = _configDao.getValue(Config.VmDeploymentPlanner.key()); + } } String reservationId = vmEntity.reserve(plannerName, plan, new ExcludeList(), new Long(callerUser.getId()).toString()); @@ -3826,7 +3822,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use + cmd.getAccountName() + " is disabled."); } - //check caller has access to both the old and new account + //check caller has access to both the old and new account _accountMgr.checkAccess(caller, null, true, oldAccount); _accountMgr.checkAccess(caller, null, true, newAccount); diff --git a/server/test/com/cloud/resource/MockResourceManagerImpl.java b/server/test/com/cloud/resource/MockResourceManagerImpl.java index 5202c317e56..1fff3a63b1d 100644 --- a/server/test/com/cloud/resource/MockResourceManagerImpl.java +++ b/server/test/com/cloud/resource/MockResourceManagerImpl.java @@ -608,4 +608,10 @@ public class MockResourceManagerImpl extends ManagerBase implements ResourceMana return null; } + @Override + public boolean releaseHostReservation(Long hostId) { + // TODO Auto-generated method stub + return false; + } + } diff --git a/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java b/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java new file mode 100644 index 00000000000..e3b7d311ba7 --- /dev/null +++ b/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java @@ -0,0 +1,359 @@ +// 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 static org.junit.Assert.*; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import com.cloud.service.ServiceOfferingVO; +import com.cloud.storage.StorageManager; +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.VolumeDao; +import com.cloud.capacity.CapacityManager; +import com.cloud.capacity.dao.CapacityDao; +import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.deploy.DeploymentPlanner.ExcludeList; +import com.cloud.agent.AgentManager; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.ClusterVO; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.HostPodDao; +import com.cloud.deploy.DataCenterDeployment; +import com.cloud.deploy.DeployDestination; +import com.cloud.deploy.DeploymentClusterPlanner; +import com.cloud.deploy.DeploymentPlanner; +import com.cloud.deploy.DeploymentPlanner.PlannerResourceUsage; +import com.cloud.deploy.DeploymentPlanningManagerImpl; +import com.cloud.deploy.FirstFitPlanner; +import com.cloud.deploy.PlannerHostReservationVO; +import com.cloud.deploy.dao.PlannerHostReservationDao; +import org.apache.cloudstack.affinity.AffinityGroupProcessor; +import org.apache.cloudstack.affinity.dao.AffinityGroupDao; +import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.framework.messagebus.MessageBus; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +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.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 org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; + +import com.cloud.exception.AffinityConflictException; +import com.cloud.exception.InsufficientServerCapacityException; +import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.user.AccountManager; +import com.cloud.utils.component.ComponentContext; +import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.VMInstanceDao; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(loader = AnnotationConfigContextLoader.class) +public class DeploymentPlanningManagerImplTest { + + @Inject + DeploymentPlanningManagerImpl _dpm; + + @Inject + PlannerHostReservationDao _plannerHostReserveDao; + + @Inject VirtualMachineProfileImpl vmProfile; + + @Inject + AffinityGroupVMMapDao _affinityGroupVMMapDao; + + @Inject + ExcludeList avoids; + + @Inject + DataCenterVO dc; + + @Inject + DataCenterDao _dcDao; + + @Inject + FirstFitPlanner _planner; + + @Inject + ClusterDao _clusterDao; + + private static long domainId = 5L; + + private static long dataCenterId = 1L; + + + @BeforeClass + public static void setUp() throws ConfigurationException { + } + + @Before + public void testSetUp() { + ComponentContext.initComponentsLifeCycle(); + + PlannerHostReservationVO reservationVO = new PlannerHostReservationVO(200L, 1L, 2L, 3L, PlannerResourceUsage.Shared); + Mockito.when(_plannerHostReserveDao.persist(Mockito.any(PlannerHostReservationVO.class))).thenReturn(reservationVO); + Mockito.when(_plannerHostReserveDao.findById(Mockito.anyLong())).thenReturn(reservationVO); + Mockito.when(_affinityGroupVMMapDao.countAffinityGroupsForVm(Mockito.anyLong())).thenReturn(0L); + + VMInstanceVO vm = new VMInstanceVO(); + Mockito.when(vmProfile.getVirtualMachine()).thenReturn(vm); + + Mockito.when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + Mockito.when(dc.getId()).thenReturn(dataCenterId); + + ClusterVO clusterVO = new ClusterVO(); + clusterVO.setHypervisorType(HypervisorType.XenServer.toString()); + Mockito.when(_clusterDao.findById(Mockito.anyLong())).thenReturn(clusterVO); + + Mockito.when(_planner.getName()).thenReturn("FirstFitPlanner"); + List planners = new ArrayList(); + planners.add(_planner); + _dpm.setPlanners(planners); + + } + + @Test + public void dataCenterAvoidTest() throws InsufficientServerCapacityException, AffinityConflictException { + ServiceOfferingVO svcOffering = new ServiceOfferingVO("testOffering", 1, 512, 500, 1, 1, false, false, false, + "test dpm", false, false, null, false, VirtualMachine.Type.User, domainId, null, "FirstFitPlanner"); + Mockito.when(vmProfile.getServiceOffering()).thenReturn(svcOffering); + + DataCenterDeployment plan = new DataCenterDeployment(dataCenterId); + + Mockito.when(avoids.shouldAvoid((DataCenterVO) Mockito.anyObject())).thenReturn(true); + DeployDestination dest = _dpm.planDeployment(vmProfile, plan, avoids); + assertNull("DataCenter is in avoid set, destination should be null! ", dest); + } + + @Test + public void plannerCannotHandleTest() throws InsufficientServerCapacityException, AffinityConflictException { + ServiceOfferingVO svcOffering = new ServiceOfferingVO("testOffering", 1, 512, 500, 1, 1, false, false, false, + "test dpm", false, false, null, false, VirtualMachine.Type.User, domainId, null, + "UserDispersingPlanner"); + Mockito.when(vmProfile.getServiceOffering()).thenReturn(svcOffering); + + DataCenterDeployment plan = new DataCenterDeployment(dataCenterId); + Mockito.when(avoids.shouldAvoid((DataCenterVO) Mockito.anyObject())).thenReturn(false); + + Mockito.when(_planner.canHandle(vmProfile, plan, avoids)).thenReturn(false); + DeployDestination dest = _dpm.planDeployment(vmProfile, plan, avoids); + assertNull("Planner cannot handle, destination should be null! ", dest); + } + + @Test + public void emptyClusterListTest() throws InsufficientServerCapacityException, AffinityConflictException { + ServiceOfferingVO svcOffering = new ServiceOfferingVO("testOffering", 1, 512, 500, 1, 1, false, false, false, + "test dpm", false, false, null, false, VirtualMachine.Type.User, domainId, null, "FirstFitPlanner"); + Mockito.when(vmProfile.getServiceOffering()).thenReturn(svcOffering); + + DataCenterDeployment plan = new DataCenterDeployment(dataCenterId); + Mockito.when(avoids.shouldAvoid((DataCenterVO) Mockito.anyObject())).thenReturn(false); + Mockito.when(_planner.canHandle(vmProfile, plan, avoids)).thenReturn(true); + + Mockito.when(((DeploymentClusterPlanner) _planner).orderClusters(vmProfile, plan, avoids)).thenReturn(null); + DeployDestination dest = _dpm.planDeployment(vmProfile, plan, avoids); + assertNull("Planner cannot handle, destination should be null! ", dest); + } + + + @Configuration + @ComponentScan(basePackageClasses = { DeploymentPlanningManagerImpl.class }, includeFilters = { @Filter(value = TestConfiguration.Library.class, type = FilterType.CUSTOM) }, useDefaultFilters = false) + public static class TestConfiguration extends SpringUtils.CloudStackTestConfiguration { + + @Bean + public FirstFitPlanner firstFitPlanner() { + return Mockito.mock(FirstFitPlanner.class); + } + + @Bean + public DeploymentPlanner deploymentPlanner() { + return Mockito.mock(DeploymentPlanner.class); + } + + @Bean + public DataCenterVO dataCenter() { + return Mockito.mock(DataCenterVO.class); + } + + @Bean + public ExcludeList excludeList() { + return Mockito.mock(ExcludeList.class); + } + + @Bean + public VirtualMachineProfileImpl virtualMachineProfileImpl() { + return Mockito.mock(VirtualMachineProfileImpl.class); + } + + @Bean + public ClusterDetailsDao clusterDetailsDao() { + return Mockito.mock(ClusterDetailsDao.class); + } + + @Bean + public DataStoreManager cataStoreManager() { + return Mockito.mock(DataStoreManager.class); + } + + @Bean + public StorageManager storageManager() { + return Mockito.mock(StorageManager.class); + } + + @Bean + public HostDao hostDao() { + return Mockito.mock(HostDao.class); + } + + @Bean + public HostPodDao hostPodDao() { + return Mockito.mock(HostPodDao.class); + } + + @Bean + public ClusterDao clusterDao() { + return Mockito.mock(ClusterDao.class); + } + + @Bean + public GuestOSDao guestOSDao() { + return Mockito.mock(GuestOSDao.class); + } + + @Bean + public GuestOSCategoryDao guestOSCategoryDao() { + return Mockito.mock(GuestOSCategoryDao.class); + } + + @Bean + public CapacityManager capacityManager() { + return Mockito.mock(CapacityManager.class); + } + + @Bean + public StoragePoolHostDao storagePoolHostDao() { + return Mockito.mock(StoragePoolHostDao.class); + } + + @Bean + public VolumeDao volumeDao() { + return Mockito.mock(VolumeDao.class); + } + + @Bean + public ConfigurationDao configurationDao() { + return Mockito.mock(ConfigurationDao.class); + } + + @Bean + public DiskOfferingDao diskOfferingDao() { + return Mockito.mock(DiskOfferingDao.class); + } + + @Bean + public PrimaryDataStoreDao primaryDataStoreDao() { + return Mockito.mock(PrimaryDataStoreDao.class); + } + + @Bean + public CapacityDao capacityDao() { + return Mockito.mock(CapacityDao.class); + } + + @Bean + public PlannerHostReservationDao plannerHostReservationDao() { + return Mockito.mock(PlannerHostReservationDao.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 AgentManager agentManager() { + return Mockito.mock(AgentManager.class); + } + + @Bean + public MessageBus messageBus() { + return Mockito.mock(MessageBus.class); + } + + + @Bean + public UserVmDao userVMDao() { + return Mockito.mock(UserVmDao.class); + } + + @Bean + public VMInstanceDao vmInstanceDao() { + return Mockito.mock(VMInstanceDao.class); + } + + @Bean + public DataCenterDao dataCenterDao() { + return Mockito.mock(DataCenterDao.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/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java index b64278c9709..ba18fa1c11d 100755 --- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -431,7 +431,7 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu */ @Override public ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, Type vm_typeType, String name, int cpu, int ramSize, int speed, String displayText, boolean localStorageRequired, boolean offerHA, - boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate) { + boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate, String deploymentPlanner) { // TODO Auto-generated method stub return null; } diff --git a/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java b/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java index 6f52397251b..7ffbe32d8bd 100644 --- a/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java +++ b/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java @@ -82,6 +82,7 @@ import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.offerings.dao.NetworkOfferingServiceMapDaoImpl; import com.cloud.projects.ProjectManager; +import com.cloud.server.ManagementService; import com.cloud.service.dao.ServiceOfferingDaoImpl; import com.cloud.storage.dao.DiskOfferingDaoImpl; import com.cloud.storage.dao.S3DaoImpl; @@ -155,162 +156,167 @@ useDefaultFilters=false ) public class ChildTestConfiguration { - + + @Bean + public ManagementService managementService() { + return Mockito.mock(ManagementService.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 UserContext userContext() { return Mockito.mock(UserContext.class); } - + @Bean public UserContextInitializer userContextInitializer() { return Mockito.mock(UserContextInitializer.class); } - + @Bean public NetworkManager networkManager() { return Mockito.mock(NetworkManager.class); } - + @Bean public NetworkOfferingDao networkOfferingDao() { return Mockito.mock(NetworkOfferingDao.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); @@ -342,5 +348,5 @@ public class ChildTestConfiguration { } } - + } diff --git a/server/test/resources/affinityContext.xml b/server/test/resources/affinityContext.xml new file mode 100644 index 00000000000..ed880dd5648 --- /dev/null +++ b/server/test/resources/affinityContext.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index 334aae76f33..442a5446be5 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -973,9 +973,61 @@ 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; +CREATE TABLE `cloud`.`op_host_planner_reservation` ( + `id` bigint unsigned NOT NULL auto_increment, + `data_center_id` bigint unsigned NOT NULL, + `pod_id` bigint unsigned, + `cluster_id` bigint unsigned, + `host_id` bigint unsigned, + `resource_usage` varchar(255) COMMENT 'Shared(between planners) Vs Dedicated (exclusive usage to a planner)', + PRIMARY KEY (`id`), + INDEX `i_op_host_planner_reservation__host_resource_usage`(`host_id`, `resource_usage`), + CONSTRAINT `fk_planner_reservation__host_id` FOREIGN KEY (`host_id`) REFERENCES `host`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_planner_reservation__data_center_id` FOREIGN KEY (`data_center_id`) REFERENCES `cloud`.`data_center`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_planner_reservation__pod_id` FOREIGN KEY (`pod_id`) REFERENCES `cloud`.`host_pod_ref`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_planner_reservation__cluster_id` FOREIGN KEY (`cluster_id`) REFERENCES `cloud`.`cluster`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +ALTER TABLE `cloud`.`service_offering` ADD COLUMN `deployment_planner` varchar(255) COMMENT 'Planner heuristics used to deploy a VM of this offering; if null global config vm.deployment.planner is used'; + +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'vm.deployment.planner', 'FirstFitPlanner', '[''FirstFitPlanner'', ''UserDispersingPlanner'', ''UserConcentratedPodPlanner'']: DeploymentPlanner heuristic that will be used for VM deployment.'); +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'host.reservation.release.period', '300000', 'The interval in milliseconds between host reservation release checks'); + +DROP VIEW IF EXISTS `cloud`.`service_offering_view`; +CREATE VIEW `cloud`.`service_offering_view` AS + select + service_offering.id, + disk_offering.uuid, + disk_offering.name, + disk_offering.display_text, + disk_offering.created, + disk_offering.tags, + disk_offering.removed, + disk_offering.use_local_storage, + disk_offering.system_use, + service_offering.cpu, + service_offering.speed, + service_offering.ram_size, + service_offering.nw_rate, + service_offering.mc_rate, + service_offering.ha_enabled, + service_offering.limit_cpu_use, + service_offering.host_tag, + service_offering.default_use, + service_offering.vm_type, + service_offering.sort_key, + service_offering.deployment_planner, + domain.id domain_id, + domain.uuid domain_uuid, + domain.name domain_name, + domain.path domain_path + from + `cloud`.`service_offering` + inner join + `cloud`.`disk_offering` ON service_offering.id = disk_offering.id + left join + `cloud`.`domain` ON disk_offering.domain_id = domain.id; -- Add "default" field to account/user tables ALTER TABLE `cloud`.`account` ADD COLUMN `default` int(1) unsigned NOT NULL DEFAULT '0' COMMENT '1 if account is default'; @@ -1605,3 +1657,8 @@ CREATE TABLE `cloud`.`nic_ip_alias` ( alter table `cloud`.`vpc_gateways` add column network_acl_id bigint unsigned default 1 NOT NULL; update `cloud`.`vpc_gateways` set network_acl_id = 2; + +-- Re-enable foreign key checking, at the end of the upgrade path +SET foreign_key_checks = 1; + + diff --git a/test/integration/smoke/test_deploy_vms_with_varied_deploymentplanners.py b/test/integration/smoke/test_deploy_vms_with_varied_deploymentplanners.py new file mode 100644 index 00000000000..d904a4cb7d8 --- /dev/null +++ b/test/integration/smoke/test_deploy_vms_with_varied_deploymentplanners.py @@ -0,0 +1,164 @@ +# 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. + +#!/usr/bin/env python + +import marvin +from marvin import cloudstackTestCase +from marvin.cloudstackTestCase import * + +import unittest +import hashlib +import random + +class TestDeployVmWithVariedPlanners(cloudstackTestCase): + """ + This test tests that we can create serviceOfferings with different deployment Planners and deploy virtual machines into a user account + using these service offerings and builtin template + """ + def setUp(self): + """ + CloudStack internally saves its passwords in md5 form and that is how we + specify it in the API. Python's hashlib library helps us to quickly hash + strings as follows + """ + mdf = hashlib.md5() + mdf.update('password') + mdf_pass = mdf.hexdigest() + + self.apiClient = self.testClient.getApiClient() #Get ourselves an API client + + self.acct = createAccount.createAccountCmd() #The createAccount command + self.acct.accounttype = 0 #We need a regular user. admins have accounttype=1 + self.acct.firstname = 'test' + self.acct.lastname = 'user' #What's up doc? + self.acct.username = 'testuser' + self.acct.password = mdf_pass #The md5 hashed password string + self.acct.email = 'test@domain.com' + self.acct.account = 'testacct' + self.acct.domainid = 1 #The default ROOT domain + self.acctResponse = self.apiClient.createAccount(self.acct) + # And upon successful creation we'll log a helpful message in our logs + # using the default debug logger of the test framework + self.debug("successfully created account: %s, id: \ + %s"%(self.acctResponse.name, \ + self.acctResponse.id)) + + #Create service offerings with varied planners + self.svcOfferingFirstFit = createServiceOffering.createServiceOfferingCmd() + self.svcOfferingFirstFit.name = 'Tiny Instance FirstFit' + self.svcOfferingFirstFit.displaytext = 'Tiny Instance with FirstFitPlanner' + self.svcOfferingFirstFit.cpuspeed = 100 + self.svcOfferingFirstFit.cpunumber = 1 + self.svcOfferingFirstFit.memory = 256 + self.svcOfferingFirstFit.deploymentplanner = 'FirstFitPlanner' + self.svcOfferingFirstFitResponse = self.apiClient.createServiceOffering(self.svcOfferingFirstFit) + + self.debug("successfully created serviceofferring name: %s, id: \ + %s, deploymentPlanner: %s"%(self.svcOfferingFirstFitResponse.name, \ + self.svcOfferingFirstFitResponse.id,self.svcOfferingFirstFitResponse.deploymentplanner)) + + #Create service offerings with varied planners + self.svcOfferingUserDispersing = createServiceOffering.createServiceOfferingCmd() + self.svcOfferingUserDispersing.name = 'Tiny Instance UserDispersing' + self.svcOfferingUserDispersing.displaytext = 'Tiny Instance with UserDispersingPlanner' + self.svcOfferingUserDispersing.cpuspeed = 100 + self.svcOfferingUserDispersing.cpunumber = 1 + self.svcOfferingUserDispersing.memory = 256 + self.svcOfferingUserDispersing.deploymentplanner = 'FirstFitPlanner' + self.svcOfferingUserDispersingResponse = self.apiClient.createServiceOffering(self.svcOfferingUserDispersing) + + self.debug("successfully created serviceofferring name: %s, id: \ + %s, deploymentPlanner: %s"%(self.svcOfferingUserDispersingResponse.name, \ + self.svcOfferingUserDispersingResponse.id,self.svcOfferingUserDispersingResponse.deploymentplanner)) + + def test_DeployVm(self): + """ + Let's start by defining the attributes of our VM that we will be + deploying on CloudStack. We will be assuming a single zone is available + and is configured and all templates are Ready + + The hardcoded values are used only for brevity. + """ + deployVmCmd = deployVirtualMachine.deployVirtualMachineCmd() + deployVmCmd.zoneid = 1 + deployVmCmd.account = self.acct.account + deployVmCmd.domainid = self.acct.domainid + deployVmCmd.templateid = 5 #For default template- CentOS 5.6(64 bit) + deployVmCmd.serviceofferingid = self.svcOfferingFirstFitResponse.id + + deployVmResponse = self.apiClient.deployVirtualMachine(deployVmCmd) + self.debug("VM %s was deployed in the job %s"%(deployVmResponse.id, deployVmResponse.jobid)) + + # At this point our VM is expected to be Running. Let's find out what + # listVirtualMachines tells us about VMs in this account + + listVmCmd = listVirtualMachines.listVirtualMachinesCmd() + listVmCmd.id = deployVmResponse.id + listVmResponse = self.apiClient.listVirtualMachines(listVmCmd) + + self.assertNotEqual(len(listVmResponse), 0, "Check if the list API \ + returns a non-empty response") + + vm1 = listVmResponse[0] + + self.assertEqual(vm1.id, deployVmResponse.id, "Check if the VM returned \ + is the same as the one we deployed") + self.assertEqual(vm1.state, "Running", "Check if VM has reached \ + a state of running") + + + deployVm2Cmd = deployVirtualMachine.deployVirtualMachineCmd() + deployVm2Cmd.zoneid = 1 + deployVm2Cmd.account = self.acct.account + deployVm2Cmd.domainid = self.acct.domainid + deployVm2Cmd.templateid = 5 #For default template- CentOS 5.6(64 bit) + deployVm2Cmd.serviceofferingid = self.svcOfferingFirstFitResponse.id + + deployVm2Response = self.apiClient.deployVirtualMachine(deployVm2Cmd) + self.debug("VM %s was deployed in the job %s"%(deployVm2Response.id, deployVm2Response.jobid)) + + # At this point our VM is expected to be Running. Let's find out what + # listVirtualMachines tells us about VMs in this account + + listVm2Cmd = listVirtualMachines.listVirtualMachinesCmd() + listVm2Cmd.id = deployVm2Response.id + listVm2Response = self.apiClient.listVirtualMachines(listVm2Cmd) + self.assertNotEqual(len(listVm2Response), 0, "Check if the list API \ + returns a non-empty response") + vm2 = listVm2Response[0] + self.assertEqual(vm2.id, deployVm2Response.id, "Check if the VM returned \ + is the same as the one we deployed") + self.assertEqual(vm2.state, "Running", "Check if VM has reached \ + a state of running") + + + def tearDown(self): # Teardown will delete the Account as well as the VM once the VM reaches "Running" state + """ + And finally let us cleanup the resources we created by deleting the + account. All good unittests are atomic and rerunnable this way + """ + deleteAcct = deleteAccount.deleteAccountCmd() + deleteAcct.id = self.acctResponse.id + self.apiClient.deleteAccount(deleteAcct) + deleteSvcOfferingFirstFit = deleteServiceOffering.deleteServiceOfferingCmd() + deleteSvcOfferingFirstFit.id = self.svcOfferingFirstFitResponse.id + self.apiClient.deleteServiceOffering(deleteSvcOfferingFirstFit); + deleteSvcOfferingUserDispersing = deleteServiceOffering.deleteServiceOfferingCmd() + deleteSvcOfferingUserDispersing.id = self.svcOfferingUserDispersingResponse.id + self.apiClient.deleteServiceOffering(deleteSvcOfferingUserDispersing); + \ No newline at end of file diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index 8b6460e5507..375850304b7 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -142,6 +142,7 @@ known_categories = { 'listNics':'Nic', 'AffinityGroup': 'Affinity Group', 'InternalLoadBalancer': 'Internal LB', + 'DeploymentPlanners': 'Configuration', } From 890603be37949308c127701765b31438605ab033 Mon Sep 17 00:00:00 2001 From: Prachi Damle Date: Thu, 16 May 2013 15:28:02 -0700 Subject: [PATCH 55/59] Unit test does not use this file anymore. --- server/test/resources/affinityContext.xml | 42 ----------------------- 1 file changed, 42 deletions(-) delete mode 100644 server/test/resources/affinityContext.xml diff --git a/server/test/resources/affinityContext.xml b/server/test/resources/affinityContext.xml deleted file mode 100644 index ed880dd5648..00000000000 --- a/server/test/resources/affinityContext.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 35de50debfadf82dfbec2aab473abeea74fc6248 Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Thu, 16 May 2013 14:26:46 -0700 Subject: [PATCH 56/59] cloud-sysvmadm: 1) added -z paramters. If specified, restrict system vm restarts to specific zone. If not specified, the intances will be restarted in all zones. 2) Fixed the help for restartNetwork option. It gets triggered by -n, not -e parameter --- setup/bindir/cloud-sysvmadm.in | 50 +++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/setup/bindir/cloud-sysvmadm.in b/setup/bindir/cloud-sysvmadm.in index 0a7b454ef95..3cb7858150b 100755 --- a/setup/bindir/cloud-sysvmadm.in +++ b/setup/bindir/cloud-sysvmadm.in @@ -23,7 +23,7 @@ #set -x usage() { - printf "\nThe tool stopping/starting running system vms and domain routers \n\nUsage: %s: [-d] [-u] [-p] [-m] [-s] [-r] [-a] [-t] [-e]\n\n -d - cloud DB server ip address, defaulted to localhost if not specified \n -u - user name to access cloud DB, defaulted to "root" if not specified \n -p - cloud DB user password, defaulted to no password if not specified \n\n -m - the ip address of management server, defaulted to localhost if not specified\n\n -s - stop then start all running SSVMs and Console Proxies \n -r - stop then start all running Virtual Routers\n -a - stop then start all running SSVMs, Console Proxies, and Virtual Routers \n -e - restart all Guest networks \n -t - number of parallel threads used for stopping Domain Routers. Default is 10.\n -l - log file location. Default is cloud.log under current directory.\n\n" $(basename $0) >&2 + printf "\nThe tool stopping/starting running system vms and domain routers \n\nUsage: %s: [-d] [-u] [-p] [-m] [-s] [-r] [-a] [-t] [-n] [-z]\n\n -d - cloud DB server ip address, defaulted to localhost if not specified \n -u - user name to access cloud DB, defaulted to "root" if not specified \n -p - cloud DB user password, defaulted to no password if not specified \n\n -m - the ip address of management server, defaulted to localhost if not specified\n\n -s - stop then start all running SSVMs and Console Proxies \n -r - stop then start all running Virtual Routers\n -a - stop then start all running SSVMs, Console Proxies, and Virtual Routers \n -n - restart all Guest networks \n -t - number of parallel threads used for stopping Domain Routers. Default is 10.\n -l - log file location. Default is cloud.log under current directory.\n -z - do restart only for the instances in the specific zone. If not specified, restart will apply to instances in all zones\n\n" $(basename $0) >&2 } @@ -37,9 +37,12 @@ password= help= maxthreads=10 LOGFILE=cloud.log +zone="" +inzone="" -while getopts 'sarhnd:m:u:p:t:l:' OPTION + +while getopts 'sarhnd:m:u:p:t:l:z:' OPTION do case $OPTION in s) system=1 @@ -63,6 +66,9 @@ do t) maxthreads="$OPTARG" ;; l) LOGFILE="$OPTARG" + ;; + z) zone=" AND data_center_id=""$OPTARG" + inzone=" in zone id=""$OPTARG" esac done @@ -70,14 +76,14 @@ done stop_start_system() { -secondary=(`mysql -h $db --user=$user --password=$password --skip-column-names -U cloud -e "select id from vm_instance where state=\"Running\" and type=\"SecondaryStorageVm\""`) -console=(`mysql -h $db --user=$user --password=$password --skip-column-names -U cloud -e "select id from vm_instance where state=\"Running\" and type=\"ConsoleProxy\""`) +secondary=(`mysql -h $db --user=$user --password=$password --skip-column-names -U cloud -e "select id from vm_instance where state=\"Running\" and type=\"SecondaryStorageVm\"$zone"`) +console=(`mysql -h $db --user=$user --password=$password --skip-column-names -U cloud -e "select id from vm_instance where state=\"Running\" and type=\"ConsoleProxy\"$zone"`) length_secondary=(${#secondary[@]}) length_console=(${#console[@]}) -echo -e "\nStopping and starting $length_secondary secondary storage vm(s)..." -echo -e "Stopping and starting $length_secondary secondary storage vm(s)..." >>$LOGFILE +echo -e "\nStopping and starting $length_secondary secondary storage vm(s)$inzone..." +echo -e "Stopping and starting $length_secondary secondary storage vm(s)$inzone..." >>$LOGFILE for d in "${secondary[@]}"; do echo "INFO: Stopping secondary storage vm with id $d" >>$LOGFILE @@ -98,12 +104,12 @@ done if [ "$length_secondary" == "0" ];then echo -e "No running secondary storage vms found \n" else - echo -e "Done stopping and starting secondary storage vm(s)" - echo -e "Done stopping and starting secondary storage vm(s)." >>$LOGFILE + echo -e "Done stopping and starting secondary storage vm(s)$inzone" + echo -e "Done stopping and starting secondary storage vm(s)$inzone." >>$LOGFILE fi -echo -e "\nStopping and starting $length_console console proxy vm(s)..." -echo -e "Stopping and starting $length_console console proxy vm(s)..." >>$LOGFILE +echo -e "\nStopping and starting $length_console console proxy vm(s)$inzone..." +echo -e "Stopping and starting $length_console console proxy vm(s)$inzone..." >>$LOGFILE for d in "${console[@]}"; do echo "INFO: Stopping console proxy with id $d" >>$LOGFILE @@ -124,17 +130,17 @@ done if [ "$length_console" == "0" ];then echo -e "No running console proxy vms found \n" else - echo "Done stopping and starting console proxy vm(s)." - echo "Done stopping and starting console proxy vm(s)." >>$LOGFILE + echo "Done stopping and starting console proxy vm(s) $inzone." + echo "Done stopping and starting console proxy vm(s) $inzone." >>$LOGFILE fi } stop_start_router() { - router=(`mysql -h $db --user=$user --password=$password --skip-column-names -U cloud -e "select id from vm_instance where state=\"Running\" and type=\"DomainRouter\""`) + router=(`mysql -h $db --user=$user --password=$password --skip-column-names -U cloud -e "select id from vm_instance where state=\"Running\" and type=\"DomainRouter\"$zone"`) length_router=(${#router[@]}) - echo -e "\nStopping and starting $length_router running routing vm(s)... " - echo -e "Stopping and starting $length_router running routing vm(s)... " >>$LOGFILE + echo -e "\nStopping and starting $length_router running routing vm(s)$inzone... " + echo -e "Stopping and starting $length_router running routing vm(s)$inzone... " >>$LOGFILE #Spawn reboot router in parallel - run commands in chunks - number of threads is configurable @@ -185,8 +191,8 @@ stop_start_router() { sleep 10 done - echo -e "Done restarting router(s). \n" - echo -e "Done restarting router(s). \n" >>$LOGFILE + echo -e "Done restarting router(s)$inzone. \n" + echo -e "Done restarting router(s)$inzone. \n" >>$LOGFILE fi } @@ -231,11 +237,11 @@ reboot_router(){ restart_networks(){ networks=(`mysql -h $db --user=$user --password=$password --skip-column-names -U cloud -e "select n.id - from networks n, network_offerings no where n.network_offering_id = no.id and no.system_only = 0 and n.removed is null"`) + from networks n, network_offerings no where n.network_offering_id = no.id and no.system_only = 0 and n.removed is null$zone"`) length_networks=(${#networks[@]}) - echo -e "\nRestarting networks... " - echo -e "Restarting networks... " >>$LOGFILE + echo -e "\nRestarting $length_networks networks$inzone... " + echo -e "Restarting $length_networks networks$inzone... " >>$LOGFILE #Spawn restart network in parallel - run commands in chunks - number of threads is configurable @@ -287,8 +293,8 @@ restart_networks(){ sleep 10 done - echo -e "Done restarting networks. \n" - echo -e "Done restarting networks. \n" >>$LOGFILE + echo -e "Done restarting networks$inzone. \n" + echo -e "Done restarting networks$inzone. \n" >>$LOGFILE fi } From 3ed9e42dd2b000299aeab51681d96eb7c9d74249 Mon Sep 17 00:00:00 2001 From: Mice Xia Date: Thu, 16 May 2013 16:50:29 +0800 Subject: [PATCH 57/59] fix null pointer dereference in cloud-server --- server/src/com/cloud/network/StorageNetworkManagerImpl.java | 5 +++-- .../region/gslb/GlobalLoadBalancingRulesServiceImpl.java | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/server/src/com/cloud/network/StorageNetworkManagerImpl.java b/server/src/com/cloud/network/StorageNetworkManagerImpl.java index 9a173826576..901e2041490 100755 --- a/server/src/com/cloud/network/StorageNetworkManagerImpl.java +++ b/server/src/com/cloud/network/StorageNetworkManagerImpl.java @@ -315,9 +315,10 @@ public class StorageNetworkManagerImpl extends ManagerBase implements StorageNet List ranges = _sNwIpRangeDao.listByPodId(podId); for (StorageNetworkIpRangeVO r : ranges) { try { - r = _sNwIpRangeDao.acquireInLockTable(r.getId()); + Long rangeId = r.getId(); + r = _sNwIpRangeDao.acquireInLockTable(rangeId); if (r == null) { - String msg = "Unable to acquire lock on storage network ip range id=" + r.getId() + ", delete failed"; + String msg = "Unable to acquire lock on storage network ip range id=" + rangeId + ", delete failed"; s_logger.warn(msg); throw new CloudRuntimeException(msg); } diff --git a/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancingRulesServiceImpl.java b/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancingRulesServiceImpl.java index 0622f77f750..a1865c64af7 100644 --- a/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancingRulesServiceImpl.java +++ b/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancingRulesServiceImpl.java @@ -155,7 +155,7 @@ public class GlobalLoadBalancingRulesServiceImpl implements GlobalLoadBalancingR long gslbRuleId = assignToGslbCmd.getGlobalLoadBalancerRuleId(); GlobalLoadBalancerRuleVO gslbRule = _gslbRuleDao.findById(gslbRuleId); if (gslbRule == null) { - throw new InvalidParameterValueException("Invalid global load balancer rule id: " + gslbRule.getUuid()); + throw new InvalidParameterValueException("Invalid global load balancer rule id: " + gslbRuleId); } _accountMgr.checkAccess(caller, SecurityChecker.AccessType.ModifyEntry, true, gslbRule); @@ -282,7 +282,7 @@ public class GlobalLoadBalancingRulesServiceImpl implements GlobalLoadBalancingR long gslbRuleId = removeFromGslbCmd.getGlobalLoadBalancerRuleId(); GlobalLoadBalancerRuleVO gslbRule = _gslbRuleDao.findById(gslbRuleId); if (gslbRule == null) { - throw new InvalidParameterValueException("Invalid global load balancer rule id: " + gslbRule.getUuid()); + throw new InvalidParameterValueException("Invalid global load balancer rule id: " + gslbRuleId); } _accountMgr.checkAccess(caller, SecurityChecker.AccessType.ModifyEntry, true, gslbRule); From 973c43a152d39b85f53428b00f451fba9cb82003 Mon Sep 17 00:00:00 2001 From: Dave Brosius Date: Thu, 16 May 2013 07:16:12 -0500 Subject: [PATCH 58/59] CLOUDSTACK-2530: fix npe if no network isolation methods Signed-off-by: Mice Xia --- .../command/admin/network/ListNetworkIsolationMethodsCmd.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 7eef22a78b4..0d23fd67557 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/network/ListNetworkIsolationMethodsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/network/ListNetworkIsolationMethodsCmd.java @@ -44,7 +44,7 @@ public class ListNetworkIsolationMethodsCmd extends BaseListCmd{ isolationResponses.add(isolationMethod); } } - response.setResponses(isolationResponses, methods.length); + response.setResponses(isolationResponses, isolationResponses.size()); response.setResponseName(getCommandName()); this.setResponseObject(response); From caf0dd22b7de584f87427d0f3039ce391f2d406b Mon Sep 17 00:00:00 2001 From: Likitha Shetty Date: Thu, 16 May 2013 14:04:20 +0530 Subject: [PATCH 59/59] Dedicate Public IP range - If every public ip range in the system is dedicated when an account with no dedicate ranges acquires a new public ip the request should fail --- .../com/cloud/network/NetworkManagerImpl.java | 114 +++++++++--------- 1 file changed, 58 insertions(+), 56 deletions(-) diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index c58ef220ea1..40fc3d30154 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -284,6 +284,10 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L Long guestNetworkId, boolean sourceNat, boolean assign, String requestedIp, boolean isSystem, Long vpcId) throws InsufficientAddressCapacityException { StringBuilder errorMessage = new StringBuilder("Unable to get ip adress in "); + boolean fetchFromDedicatedRange = false; + List dedicatedVlanDbIds = new ArrayList(); + List nonDedicatedVlanDbIds = new ArrayList(); + Transaction txn = Transaction.currentTxn(); txn.start(); SearchCriteria sc = null; @@ -296,9 +300,37 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L errorMessage.append(" zone id=" + dcId); } - if ( vlanDbIds != null && !vlanDbIds.isEmpty() ) { - sc.setParameters("vlanId", vlanDbIds.toArray()); - errorMessage.append(", vlanId id=" + vlanDbIds.toArray()); + // If owner has dedicated Public IP ranges, fetch IP from the dedicated range + // Otherwise fetch IP from the system pool + List maps = _accountVlanMapDao.listAccountVlanMapsByAccount(owner.getId()); + for (AccountVlanMapVO map : maps) { + if (vlanDbIds == null || vlanDbIds.contains(map.getVlanDbId())) + dedicatedVlanDbIds.add(map.getVlanDbId()); + } + List nonDedicatedVlans = _vlanDao.listZoneWideNonDedicatedVlans(dcId); + for (VlanVO nonDedicatedVlan : nonDedicatedVlans) { + if (vlanDbIds == null || vlanDbIds.contains(nonDedicatedVlan.getId())) + nonDedicatedVlanDbIds.add(nonDedicatedVlan.getId()); + } + if (dedicatedVlanDbIds != null && !dedicatedVlanDbIds.isEmpty()) { + fetchFromDedicatedRange = true; + sc.setParameters("vlanId", dedicatedVlanDbIds.toArray()); + errorMessage.append(", vlanId id=" + dedicatedVlanDbIds.toArray()); + } else if (nonDedicatedVlanDbIds != null && !nonDedicatedVlanDbIds.isEmpty()) { + sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray()); + errorMessage.append(", vlanId id=" + nonDedicatedVlanDbIds.toArray()); + } else { + if (podId != null) { + InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException + ("Insufficient address capacity", Pod.class, podId); + ex.addProxyObject(ApiDBUtils.findPodById(podId).getUuid()); + throw ex; + } + s_logger.warn(errorMessage.toString()); + InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException + ("Insufficient address capacity", DataCenter.class, dcId); + ex.addProxyObject(ApiDBUtils.findZoneById(dcId).getUuid()); + throw ex; } sc.setParameters("dc", dcId); @@ -321,6 +353,16 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L List addrs = _ipAddressDao.lockRows(sc, filter, true); + // If all the dedicated IPs of the owner are in use fetch an IP from the system pool + if (addrs.size() == 0 && fetchFromDedicatedRange) { + if (nonDedicatedVlanDbIds != null && !nonDedicatedVlanDbIds.isEmpty()) { + fetchFromDedicatedRange = false; + sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray()); + errorMessage.append(", vlanId id=" + nonDedicatedVlanDbIds.toArray()); + addrs = _ipAddressDao.lockRows(sc, filter, true); + } + } + if (addrs.size() == 0) { if (podId != null) { InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException @@ -338,6 +380,16 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L assert (addrs.size() == 1) : "Return size is incorrect: " + addrs.size(); + if (!fetchFromDedicatedRange) { + // Check that the maximum number of public IPs for the given accountId will not be exceeded + try { + _resourceLimitMgr.checkResourceLimit(owner, ResourceType.public_ip); + } catch (ResourceAllocationException ex) { + s_logger.warn("Failed to allocate resource of type " + ex.getResourceType() + " for account " + owner); + throw new AccountLimitException("Maximum number of public IP addresses for account: " + owner.getAccountName() + " has been exceeded."); + } + } + IPAddressVO addr = addrs.get(0); addr.setSourceNat(sourceNat); addr.setAllocatedTime(new Date()); @@ -442,14 +494,6 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L long ownerId = owner.getId(); - // Check that the maximum number of public IPs for the given accountId will not be exceeded - try { - _resourceLimitMgr.checkResourceLimit(owner, ResourceType.public_ip); - } catch (ResourceAllocationException ex) { - s_logger.warn("Failed to allocate resource of type " + ex.getResourceType() + " for account " + owner); - throw new AccountLimitException("Maximum number of public IP addresses for account: " + owner.getAccountName() + " has been exceeded."); - } - PublicIp ip = null; Transaction txn = Transaction.currentTxn(); try { @@ -466,15 +510,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L s_logger.debug("lock account " + ownerId + " is acquired"); } - // If account has Account specific ip ranges, try to allocate ip from there - List vlanIds = new ArrayList(); - List maps = _accountVlanMapDao.listAccountVlanMapsByAccount(ownerId); - if (maps != null && !maps.isEmpty()) { - vlanIds.add(maps.get(0).getVlanDbId()); - } - - - ip = fetchNewPublicIp(dcId, null, vlanIds, owner, VlanType.VirtualNetwork, guestNtwkId, + ip = fetchNewPublicIp(dcId, null, null, owner, VlanType.VirtualNetwork, guestNtwkId, isSourceNat, false, null, false, vpcId); IPAddressVO publicIp = ip.ip(); @@ -610,9 +646,6 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L VlanType vlanType = VlanType.VirtualNetwork; boolean assign = false; - boolean allocateFromDedicatedRange = false; - List dedicatedVlanDbIds = new ArrayList(); - List nonDedicatedVlanDbIds = new ArrayList(); if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) { // zone is of type DataCenter. See DataCenterVO.java. @@ -642,39 +675,8 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L txn.start(); - // If account has dedicated Public IP ranges, allocate IP from the dedicated range - List maps = _accountVlanMapDao.listAccountVlanMapsByAccount(ipOwner.getId()); - for (AccountVlanMapVO map : maps) { - dedicatedVlanDbIds.add(map.getVlanDbId()); - } - if (dedicatedVlanDbIds != null && !dedicatedVlanDbIds.isEmpty()) { - allocateFromDedicatedRange = true; - } - - try { - if (allocateFromDedicatedRange) { - ip = fetchNewPublicIp(zone.getId(), null, dedicatedVlanDbIds, ipOwner, vlanType, null, - false, assign, null, isSystem, null); - } - } catch(InsufficientAddressCapacityException e) { - s_logger.warn("All IPs dedicated to account " + ipOwner.getId() + " has been acquired." + - " Now acquiring from the system pool"); - txn.close(); - allocateFromDedicatedRange = false; - } - - if (!allocateFromDedicatedRange) { - // Check that the maximum number of public IPs for the given - // accountId will not be exceeded - _resourceLimitMgr.checkResourceLimit(accountToLock, ResourceType.public_ip); - - List nonDedicatedVlans = _vlanDao.listZoneWideNonDedicatedVlans(zone.getId()); - for (VlanVO nonDedicatedVlan : nonDedicatedVlans) { - nonDedicatedVlanDbIds.add(nonDedicatedVlan.getId()); - } - ip = fetchNewPublicIp(zone.getId(), null, nonDedicatedVlanDbIds, ipOwner, vlanType, null, false, assign, null, - isSystem, null); - } + ip = fetchNewPublicIp(zone.getId(), null, null, ipOwner, vlanType, null, false, assign, null, + isSystem, null); if (ip == null) { InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException