From d49765619dae5551e41192c4e00c324e74fa33db Mon Sep 17 00:00:00 2001 From: Sigert Goeminne Date: Wed, 26 Apr 2017 15:32:31 +0200 Subject: [PATCH] CLOUDSTACK-10024: Network migration support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Frank Maximus frank.maximus@nuagenetworks.net Co-Authored-By: Raf Smeets raf.smeets@nuagenetworks.net New API’s: * migrateNetwork * migrateVpc --- api/src/com/cloud/event/EventTypes.java | 1 + api/src/com/cloud/network/NetworkService.java | 19 + api/src/com/cloud/network/Networks.java | 1 + .../com/cloud/offering/NetworkOffering.java | 2 +- api/src/com/cloud/server/ResourceTag.java | 4 +- api/src/com/cloud/vm/NicSecondaryIp.java | 2 + .../apache/cloudstack/api/ApiConstants.java | 2 + .../admin/network/MigrateNetworkCmd.java | 155 ++ .../command/admin/network/MigrateVPCCmd.java | 144 ++ .../network/UpdateNetworkOfferingCmd.java | 7 + .../com/cloud/agent/api/ReplugNicAnswer.java | 29 + .../com/cloud/agent/api/ReplugNicCommand.java | 70 + .../com/cloud/vm/VirtualMachineManager.java | 3 + .../service/NetworkOrchestrationService.java | 7 + .../cloud/vm/VirtualMachineManagerImpl.java | 43 +- .../orchestration/NetworkOrchestrator.java | 8 +- .../src/com/cloud/network/dao/NetworkVO.java | 4 + .../cloud/network/dao/RouterNetworkVO.java | 4 + .../com/cloud/network/vpc/NetworkACLVO.java | 4 + .../com/cloud/network/vpc/VpcGatewayVO.java | 4 + .../cloud/network/vpc/dao/NetworkACLDao.java | 6 + .../network/vpc/dao/NetworkACLDaoImpl.java | 14 + .../cloud/network/vpc/dao/VpcGatewayDao.java | 2 + .../network/vpc/dao/VpcGatewayDaoImpl.java | 7 + .../vpc/dao/VpcOfferingServiceMapDaoImpl.java | 1 - .../offerings/NetworkOfferingDetailsVO.java | 35 +- .../cloud/offerings/NetworkOfferingVO.java | 4 + .../dao/NetworkOfferingDetailsDao.java | 4 +- .../dao/NetworkOfferingDetailsDaoImpl.java | 19 +- .../com/cloud/tags/dao/ResourceTagDao.java | 26 +- .../cloud/tags/dao/ResourceTagsDaoImpl.java | 27 + .../src/com/cloud/vm/dao/NicIpAliasDao.java | 1 + .../com/cloud/vm/dao/NicIpAliasDaoImpl.java | 10 + .../com/cloud/vm/dao/NicSecondaryIpDao.java | 2 + .../cloud/vm/dao/NicSecondaryIpDaoImpl.java | 11 + .../com/cloud/vm/dao/NicSecondaryIpVO.java | 5 + .../kvm/resource/BridgeVifDriver.java | 164 +- .../kvm/resource/DirectVifDriver.java | 14 + .../hypervisor/kvm/resource/IvsVifDriver.java | 16 +- .../resource/LibvirtComputingResource.java | 78 +- .../kvm/resource/LibvirtDomainXMLParser.java | 12 +- .../hypervisor/kvm/resource/LibvirtVMDef.java | 39 +- .../hypervisor/kvm/resource/OvsVifDriver.java | 44 +- .../hypervisor/kvm/resource/VifDriver.java | 8 + .../kvm/resource/VifDriverBase.java | 4 + .../LibvirtCheckNetworkCommandWrapper.java | 7 +- .../wrapper/LibvirtPlugNicCommandWrapper.java | 15 +- ...virtPrepareForMigrationCommandWrapper.java | 13 +- .../LibvirtReplugNicCommandWrapper.java | 133 ++ .../LibvirtComputingResourceTest.java | 82 +- .../resource/LibvirtDomainXMLParserTest.java | 9 +- .../kvm/resource/LibvirtVMDefTest.java | 55 +- .../LibvirtReplugNicCommandWrapperTest.java | 274 +++ .../agent/manager/MockNetworkManager.java | 4 + .../agent/manager/MockNetworkManagerImpl.java | 17 +- .../agent/manager/SimulatorManagerImpl.java | 13 +- .../vmware/resource/VmwareResource.java | 87 +- plugins/network-elements/nuage-vsp/pom.xml | 2 +- .../network/element/NuageVspElement.java | 106 +- .../guru/NuageVspGuestNetworkGuru.java | 39 +- .../com/cloud/util/NuageVspEntityBuilder.java | 63 +- .../nuage-vsp/test/com/cloud/NuageTest.java | 11 +- .../network/element/NuageVspElementTest.java | 2 + .../spring-server-core-managers-context.xml | 2 + .../ConfigurationManagerImpl.java | 20 + .../metadata/ResourceMetaDataManagerImpl.java | 14 +- .../network/NetworkMigrationManager.java | 85 + .../network/NetworkMigrationManagerImpl.java | 693 ++++++ .../com/cloud/network/NetworkModelImpl.java | 13 +- .../com/cloud/network/NetworkServiceImpl.java | 572 +++-- .../com/cloud/network/vpc/VpcManagerImpl.java | 1 + .../cloud/server/ManagementServerImpl.java | 4 + .../cloud/tags/TaggedResourceManagerImpl.java | 5 +- .../com/cloud/vpc/MockNetworkManagerImpl.java | 23 +- .../plugins/nuagevsp/nuageTestCase.py | 50 +- .../plugins/nuagevsp/nuage_test_data.py | 2 +- .../plugins/nuagevsp/test_nuage_extra_dhcp.py | 3 +- .../nuagevsp/test_nuage_internal_dns.py | 2 + .../nuagevsp/test_nuage_network_migration.py | 2002 +++++++++++++++++ .../nuagevsp/test_nuage_vpc_internal_lb.py | 3 + tools/apidoc/gen_toc.py | 1 + tools/marvin/marvin/config/test_data.py | 122 +- tools/marvin/marvin/deployDataCenter.py | 3 + tools/marvin/marvin/lib/base.py | 49 + .../hypervisor/vmware/util/VmwareHelper.java | 141 +- 85 files changed, 5297 insertions(+), 511 deletions(-) create mode 100644 api/src/org/apache/cloudstack/api/command/admin/network/MigrateNetworkCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/network/MigrateVPCCmd.java create mode 100644 core/src/com/cloud/agent/api/ReplugNicAnswer.java create mode 100644 core/src/com/cloud/agent/api/ReplugNicCommand.java create mode 100644 plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapper.java create mode 100644 plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapperTest.java create mode 100644 server/src/com/cloud/network/NetworkMigrationManager.java create mode 100644 server/src/com/cloud/network/NetworkMigrationManagerImpl.java create mode 100644 test/integration/plugins/nuagevsp/test_nuage_network_migration.py diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index d5d11e87702..ce410a6795d 100644 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -130,6 +130,7 @@ public class EventTypes { public static final String EVENT_NETWORK_CREATE = "NETWORK.CREATE"; public static final String EVENT_NETWORK_DELETE = "NETWORK.DELETE"; public static final String EVENT_NETWORK_UPDATE = "NETWORK.UPDATE"; + public static final String EVENT_NETWORK_MIGRATE = "NETWORK.MIGRATE"; public static final String EVENT_FIREWALL_OPEN = "FIREWALL.OPEN"; public static final String EVENT_FIREWALL_CLOSE = "FIREWALL.CLOSE"; public static final String EVENT_FIREWALL_UPDATE = "FIREWALL.UPDATE"; diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java index 0ad42b5acdd..2559cfa97fb 100644 --- a/api/src/com/cloud/network/NetworkService.java +++ b/api/src/com/cloud/network/NetworkService.java @@ -36,6 +36,7 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network.Service; import com.cloud.network.Networks.TrafficType; +import com.cloud.network.vpc.Vpc; import com.cloud.offering.NetworkOffering; import com.cloud.user.Account; import com.cloud.user.User; @@ -82,6 +83,24 @@ public interface NetworkService { Network updateGuestNetwork(long networkId, String name, String displayText, Account callerAccount, User callerUser, String domainSuffix, Long networkOfferingId, Boolean changeCidr, String guestVmCidr, Boolean displayNetwork, String newUUID, boolean updateInSequence, boolean forced); + /** + * Migrate a network from one physical network to another physical network + * @param networkId of the network that needs to be migrated + * @param networkOfferingId new network offering id for the network + * @param resume if previous migration failed try to resume of just fail directly because anomaly is detected + * @return the migrated network + */ + Network migrateGuestNetwork(long networkId, long networkOfferingId, Account callerAccount, User callerUser, boolean resume); + + /** + * Migrate a vpc from on physical network to another physical network + * @param vpcId the id of the vpc that needs to be migrated + * @param vpcNetworkofferingId the new vpc offering id + * @param resume if previous migration failed try to resume of just fail directly because anomaly is detected + * @return the migrated vpc + */ + Vpc migrateVpcNetwork(long vpcId, long vpcNetworkofferingId, Map networkToOffering, Account account, User callerUser, boolean resume); + PhysicalNetwork createPhysicalNetwork(Long zoneId, String vnetRange, String networkSpeed, List isolationMethods, String broadcastDomainRange, Long domainId, List tags, String name); diff --git a/api/src/com/cloud/network/Networks.java b/api/src/com/cloud/network/Networks.java index 37746f0d0f7..06f4236eb7a 100644 --- a/api/src/com/cloud/network/Networks.java +++ b/api/src/com/cloud/network/Networks.java @@ -246,6 +246,7 @@ public class Networks { * encode a string into a BroadcastUri * @param candidate the input string * @return an URI containing an appropriate (possibly given) scheme and the value + * */ public static URI fromString(String candidate) { try { diff --git a/api/src/com/cloud/offering/NetworkOffering.java b/api/src/com/cloud/offering/NetworkOffering.java index 3532010f1fa..0c8378908e6 100644 --- a/api/src/com/cloud/offering/NetworkOffering.java +++ b/api/src/com/cloud/offering/NetworkOffering.java @@ -38,7 +38,7 @@ public interface NetworkOffering extends InfrastructureEntity, InternalIdentity, } public enum Detail { - InternalLbProvider, PublicLbProvider, servicepackageuuid, servicepackagedescription, PromiscuousMode, MacAddressChanges, ForgedTransmits + InternalLbProvider, PublicLbProvider, servicepackageuuid, servicepackagedescription, PromiscuousMode, MacAddressChanges, ForgedTransmits, RelatedNetworkOffering } public final static String SystemPublicNetwork = "System-Public-Network"; diff --git a/api/src/com/cloud/server/ResourceTag.java b/api/src/com/cloud/server/ResourceTag.java index 3bed77d6d02..067cb973e2f 100644 --- a/api/src/com/cloud/server/ResourceTag.java +++ b/api/src/com/cloud/server/ResourceTag.java @@ -58,7 +58,9 @@ public interface ResourceTag extends ControlledEntity, Identity, InternalIdentit LBStickinessPolicy(false, true), LBHealthCheckPolicy(false, true), SnapshotPolicy(false, true), - GuestOs(false, true); + GuestOs(false, true), + NetworkOffering(false, true), + VpcOffering(true, false); ResourceObjectType(boolean resourceTagsSupport, boolean resourceMetadataSupport) { diff --git a/api/src/com/cloud/vm/NicSecondaryIp.java b/api/src/com/cloud/vm/NicSecondaryIp.java index b7d3668c3e2..2856e0aea75 100644 --- a/api/src/com/cloud/vm/NicSecondaryIp.java +++ b/api/src/com/cloud/vm/NicSecondaryIp.java @@ -32,6 +32,8 @@ public interface NicSecondaryIp extends ControlledEntity, Identity, InternalIden long getNicId(); + void setNicId(long nicId); + String getIp4Address(); String getIp6Address(); diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index a5bd95f83c5..64cdb23674e 100644 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -332,6 +332,7 @@ public class ApiConstants { public static final String COUNT = "count"; public static final String TRAFFIC_TYPE = "traffictype"; public static final String NETWORK_OFFERING_ID = "networkofferingid"; + public static final String TIER_NETWORK_OFFERINGS = "tiernetworkofferings"; public static final String NETWORK_IDS = "networkids"; public static final String NETWORK_ID = "networkid"; public static final String NIC_ID = "nicid"; @@ -375,6 +376,7 @@ public class ApiConstants { public static final String ZONE_TOKEN = "zonetoken"; public static final String DHCP_PROVIDER = "dhcpprovider"; public static final String RESULT = "success"; + public static final String RESUME = "resume"; public static final String LUN_ID = "lunId"; public static final String IQN = "iqn"; public static final String AGGREGATE_NAME = "aggregatename"; diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/MigrateNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/MigrateNetworkCmd.java new file mode 100644 index 00000000000..651fce87fd3 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/network/MigrateNetworkCmd.java @@ -0,0 +1,155 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.admin.network; + +import org.apache.log4j.Logger; + +import org.apache.cloudstack.acl.SecurityChecker.AccessType; +import org.apache.cloudstack.api.ACL; +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.ResponseObject.ResponseView; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.NetworkOfferingResponse; +import org.apache.cloudstack.api.response.NetworkResponse; +import org.apache.cloudstack.context.CallContext; + +import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.Network; +import com.cloud.offering.NetworkOffering; +import com.cloud.user.Account; +import com.cloud.user.User; + +@APICommand(name = "migrateNetwork", description = "moves a network to another physical network", responseObject = NetworkResponse.class, responseView = ResponseView.Restricted, entityType = {Network.class}, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) +public class MigrateNetworkCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(MigrateNetworkCmd.class.getName()); + + private static final String s_name = "migratenetworkresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + @ACL(accessType = AccessType.OperateEntry) + @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.UUID, entityType = NetworkResponse.class, + required=true, description="the ID of the network") + protected Long id; + + @Parameter(name = ApiConstants.NETWORK_OFFERING_ID, type = CommandType.UUID, entityType = NetworkOfferingResponse.class, description = "network offering ID") + private Long networkOfferingId; + + @Parameter(name = ApiConstants.RESUME, type = CommandType.BOOLEAN, description = "true if previous network migration cmd failed") + private Boolean resume; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + public Long getNetworkOfferingId() { + return networkOfferingId; + } + + public Boolean getResume() { + return resume != null ? resume : false; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + Network network = _networkService.getNetwork(id); + if (network == null) { + throw new InvalidParameterValueException("Networkd id=" + id + " doesn't exist"); + } else { + return _networkService.getNetwork(id).getAccountId(); + } + } + + @Override + public void execute() { + User callerUser = _accountService.getActiveUser(CallContext.current().getCallingUserId()); + Account callerAccount = _accountService.getActiveAccountById(callerUser.getAccountId()); + Network network = _networkService.getNetwork(id); + if (network == null) { + throw new InvalidParameterValueException("Couldn't find network by id"); + } + + Network result = + _networkService.migrateGuestNetwork(getId(), getNetworkOfferingId(), callerAccount, callerUser, getResume()); + + if (result != null) { + NetworkResponse response = _responseGenerator.createNetworkResponse(ResponseView.Restricted, result); + response.setResponseName(getCommandName()); + setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update network"); + } + } + + @Override + public String getEventDescription() { + StringBuilder eventMsg = new StringBuilder("Migrating network: " + getId()); + if (getNetworkOfferingId() != null) { + Network network = _networkService.getNetwork(getId()); + if (network == null) { + throw new InvalidParameterValueException("Network id=" + id + " doesn't exist"); + } + if (network.getNetworkOfferingId() != getNetworkOfferingId()) { + NetworkOffering oldOff = _entityMgr.findById(NetworkOffering.class, network.getNetworkOfferingId()); + NetworkOffering newOff = _entityMgr.findById(NetworkOffering.class, getNetworkOfferingId()); + if (newOff == null) { + throw new InvalidParameterValueException("Network offering id supplied is invalid"); + } + + eventMsg.append(". Original network offering id: " + oldOff.getUuid() + ", new network offering id: " + newOff.getUuid()); + } + } + + return eventMsg.toString(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_NETWORK_MIGRATE; + } + + @Override + public String getSyncObjType() { + return BaseAsyncCmd.networkSyncObject; + } + + @Override + public Long getSyncObjId() { + return id; + } + +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/MigrateVPCCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/MigrateVPCCmd.java new file mode 100644 index 00000000000..6cf115742a8 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/network/MigrateVPCCmd.java @@ -0,0 +1,144 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.admin.network; + +import org.apache.cloudstack.acl.SecurityChecker; +import org.apache.cloudstack.api.ACL; +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.ResponseObject; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.VpcOfferingResponse; +import org.apache.cloudstack.api.response.VpcResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.log4j.Logger; + +import java.util.HashMap; +import java.util.Map; + +import com.cloud.event.EventTypes; +import com.cloud.network.vpc.Vpc; +import com.cloud.user.Account; +import com.cloud.user.User; + +@APICommand(name = "migrateVPC", description = "moves a vpc to another physical network", responseObject = VpcResponse.class, responseView = ResponseObject.ResponseView.Restricted, entityType = {Vpc.class}, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) +public class MigrateVPCCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(MigrateVPCCmd.class.getName()); + + private static final String s_name = "migratevpcresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + @ACL(accessType = SecurityChecker.AccessType.OperateEntry) + @Parameter(name= ApiConstants.VPC_ID, type=CommandType.UUID, entityType = VpcResponse.class, + required=true, description = "the ID of the vpc") + protected Long id; + + @Parameter(name = ApiConstants.VPC_OFF_ID, type = CommandType.UUID, entityType = VpcOfferingResponse.class, required=true, description = "vpc offering ID") + private Long vpcOfferingId; + + @Parameter(name = ApiConstants.TIER_NETWORK_OFFERINGS, type = CommandType.MAP, description = "network offering ids for each network in the vpc. Example: tierNetworkOfferings[0].networkId=networkId1&tierNetworkOfferings[0].networkOfferingId=newNetworkofferingId1&tierNetworkOfferings[1].networkId=networkId2&tierNetworkOfferings[1].networkOfferingId=newNetworkofferingId2") + private Map> tierNetworkOfferings; + + @Parameter(name = ApiConstants.RESUME, type = CommandType.BOOLEAN, description = "true if previous network migration cmd failed") + private Boolean resume; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + public Long getVpcOfferingId() { + return vpcOfferingId; + } + + public Boolean getResume() { + return resume == null ? false : resume; + } + + public Map getTierNetworkOfferings() { + HashMap flatMap = new HashMap<>(); + + if (tierNetworkOfferings == null) { + return flatMap; + } + + for (HashMap map : tierNetworkOfferings.values()) { + flatMap.put(map.get("networkid"), map.get("networkofferingid")); + } + + return flatMap; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public void execute() { + User callerUser = _accountService.getActiveUser(CallContext.current().getCallingUserId()); + Account callerAccount = _accountService.getActiveAccountById(callerUser.getAccountId()); + + Vpc result = + _networkService.migrateVpcNetwork(getId(), getVpcOfferingId(), getTierNetworkOfferings(), callerAccount, callerUser, getResume()); + + if (result != null) { + VpcResponse response = _responseGenerator.createVpcResponse(ResponseObject.ResponseView.Restricted, result); + response.setResponseName(getCommandName()); + setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to migrate vpc"); + } + } + + @Override + public String getEventDescription() { return "Migrating vpc: " + getId() + " to new vpc offering (" + vpcOfferingId + ")"; } + + @Override + public String getEventType() { + return EventTypes.EVENT_NETWORK_MIGRATE; + } + + @Override + public String getSyncObjType() { + return BaseAsyncCmd.networkSyncObject; + } + + @Override + public Long getSyncObjId() { + return id; + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccount().getId(); + } + +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/UpdateNetworkOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/UpdateNetworkOfferingCmd.java index 411da4fd36b..5c58530fe1f 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/network/UpdateNetworkOfferingCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/network/UpdateNetworkOfferingCmd.java @@ -69,6 +69,9 @@ public class UpdateNetworkOfferingCmd extends BaseCmd { description = "maximum number of concurrent connections supported by the network offering") private Integer maxConnections; + @Parameter(name = ApiConstants.TAGS, type = CommandType.STRING, description = "the tags for the network offering.", length = 4096) + private String tags; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -105,6 +108,10 @@ public class UpdateNetworkOfferingCmd extends BaseCmd { return keepAliveEnabled; } + public String getTags() { + return tags; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/core/src/com/cloud/agent/api/ReplugNicAnswer.java b/core/src/com/cloud/agent/api/ReplugNicAnswer.java new file mode 100644 index 00000000000..7de39c3fa33 --- /dev/null +++ b/core/src/com/cloud/agent/api/ReplugNicAnswer.java @@ -0,0 +1,29 @@ +// +// 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; + +public class ReplugNicAnswer extends Answer { + public ReplugNicAnswer() { + } + + public ReplugNicAnswer(ReplugNicCommand cmd, boolean success, String result) { + super(cmd, success, result); + } +} diff --git a/core/src/com/cloud/agent/api/ReplugNicCommand.java b/core/src/com/cloud/agent/api/ReplugNicCommand.java new file mode 100644 index 00000000000..1c61f0a649e --- /dev/null +++ b/core/src/com/cloud/agent/api/ReplugNicCommand.java @@ -0,0 +1,70 @@ +// +// 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.util.Map; + +import com.cloud.agent.api.to.NicTO; +import com.cloud.vm.VirtualMachine; + +public class ReplugNicCommand extends Command { + + NicTO nic; + String instanceName; + VirtualMachine.Type vmType; + Map details; + + public NicTO getNic() { + return nic; + } + + @Override + public boolean executeInSequence() { + return true; + } + + protected ReplugNicCommand() { + } + + public ReplugNicCommand(NicTO nic, String instanceName, VirtualMachine.Type vmtype) { + this.nic = nic; + this.instanceName = instanceName; + this.vmType = vmtype; + } + + public ReplugNicCommand(NicTO nic, String instanceName, VirtualMachine.Type vmtype, Map details) { + this.nic = nic; + this.instanceName = instanceName; + this.vmType = vmtype; + this.details = details; + } + + public String getVmName() { + return instanceName; + } + + public VirtualMachine.Type getVMType() { + return vmType; + } + + public Map getDetails() { + return this.details; + } +} diff --git a/engine/api/src/com/cloud/vm/VirtualMachineManager.java b/engine/api/src/com/cloud/vm/VirtualMachineManager.java index 14fead7a057..a20fc7b88d7 100644 --- a/engine/api/src/com/cloud/vm/VirtualMachineManager.java +++ b/engine/api/src/com/cloud/vm/VirtualMachineManager.java @@ -193,6 +193,9 @@ public interface VirtualMachineManager extends Manager { */ VirtualMachineTO toVmTO(VirtualMachineProfile profile); + boolean replugNic(Network network, NicTO nic, VirtualMachineTO vm, ReservationContext context, DeployDestination dest) throws ConcurrentOperationException, + ResourceUnavailableException, InsufficientCapacityException; + VirtualMachine reConfigureVm(String vmUuid, ServiceOffering newServiceOffering, boolean sameHost) throws ResourceUnavailableException, ConcurrentOperationException, InsufficientServerCapacityException; diff --git a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java index e2a471fef6a..86a8fe91a36 100644 --- a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java +++ b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java @@ -129,6 +129,11 @@ public interface NetworkOrchestrationService { Map getExtraDhcpOptions(long nicId); + /** + * Returns all extra dhcp options which are set on the provided nic + * @param nicId + * @return map which maps the dhcp value on it's option code + */ /** * prepares vm nic change for migration * @@ -275,4 +280,6 @@ public interface NetworkOrchestrationService { int getResourceCount(Network network); void finalizeUpdateInSequence(Network network, boolean success); + + List getNetworkGurus(); } diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java index 74927b9d465..da13b7ac20a 100755 --- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -38,8 +38,8 @@ import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.cloudstack.framework.jobs.impl.JobSerializerHelper; -import com.cloud.agent.api.AttachOrDettachConfigDriveCommand; +import org.apache.log4j.Logger; + import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; import org.apache.cloudstack.ca.CAManager; import org.apache.cloudstack.context.CallContext; @@ -59,6 +59,7 @@ import org.apache.cloudstack.framework.jobs.AsyncJobManager; import org.apache.cloudstack.framework.jobs.Outcome; import org.apache.cloudstack.framework.jobs.dao.VmWorkJobDao; import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO; +import org.apache.cloudstack.framework.jobs.impl.JobSerializerHelper; import org.apache.cloudstack.framework.jobs.impl.OutcomeImpl; import org.apache.cloudstack.framework.jobs.impl.VmWorkJobVO; import org.apache.cloudstack.framework.messagebus.MessageBus; @@ -70,13 +71,13 @@ import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.to.VolumeObjectTO; import org.apache.cloudstack.utils.identity.ManagementServerNode; -import org.apache.log4j.Logger; 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.AttachOrDettachConfigDriveCommand; import com.cloud.agent.api.CheckVirtualMachineAnswer; import com.cloud.agent.api.CheckVirtualMachineCommand; import com.cloud.agent.api.ClusterVMMetaDataSyncAnswer; @@ -89,6 +90,8 @@ import com.cloud.agent.api.PlugNicCommand; import com.cloud.agent.api.PrepareForMigrationCommand; import com.cloud.agent.api.RebootAnswer; import com.cloud.agent.api.RebootCommand; +import com.cloud.agent.api.ReplugNicAnswer; +import com.cloud.agent.api.ReplugNicCommand; import com.cloud.agent.api.RestoreVMSnapshotAnswer; import com.cloud.agent.api.RestoreVMSnapshotCommand; import com.cloud.agent.api.ScaleVmCommand; @@ -3635,6 +3638,36 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } } + @Override + public boolean replugNic(final Network network, final NicTO nic, final VirtualMachineTO vm, final ReservationContext context, final DeployDestination dest) throws ConcurrentOperationException, + ResourceUnavailableException, InsufficientCapacityException { + boolean result = true; + + final VMInstanceVO router = _vmDao.findById(vm.getId()); + if (router.getState() == State.Running) { + try { + final ReplugNicCommand replugNicCmd = new ReplugNicCommand(nic, vm.getName(), vm.getType(), vm.getDetails()); + final Commands cmds = new Commands(Command.OnError.Stop); + cmds.addCommand("replugnic", replugNicCmd); + _agentMgr.send(dest.getHost().getId(), cmds); + final ReplugNicAnswer replugNicAnswer = cmds.getAnswer(ReplugNicAnswer.class); + if (replugNicAnswer == null || !replugNicAnswer.getResult()) { + s_logger.warn("Unable to replug nic for vm " + vm.getName()); + result = false; + } + } catch (final OperationTimedoutException e) { + throw new AgentUnavailableException("Unable to plug nic for router " + vm.getName() + " in network " + network, dest.getHost().getId(), e); + } + } else { + s_logger.warn("Unable to apply ReplugNic, vm " + router + " is not in the right state " + router.getState()); + + throw new ResourceUnavailableException("Unable to apply ReplugNic on the backend," + " vm " + vm + " is not in the right state", DataCenter.class, + router.getDataCenterId()); + } + + return result; + } + public boolean plugNic(final Network network, final NicTO nic, final VirtualMachineTO vm, final ReservationContext context, final DeployDestination dest) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { boolean result = true; @@ -3647,7 +3680,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac cmds.addCommand("plugnic", plugNicCmd); _agentMgr.send(dest.getHost().getId(), cmds); final PlugNicAnswer plugNicAnswer = cmds.getAnswer(PlugNicAnswer.class); - if (!(plugNicAnswer != null && plugNicAnswer.getResult())) { + if (plugNicAnswer == null || !plugNicAnswer.getResult()) { s_logger.warn("Unable to plug nic for vm " + vm.getName()); result = false; } @@ -3683,7 +3716,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac _agentMgr.send(dest.getHost().getId(), cmds); final UnPlugNicAnswer unplugNicAnswer = cmds.getAnswer(UnPlugNicAnswer.class); - if (!(unplugNicAnswer != null && unplugNicAnswer.getResult())) { + if (unplugNicAnswer == null || !unplugNicAnswer.getResult()) { s_logger.warn("Unable to unplug nic from router " + router); result = false; } diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 2d30cedcb8d..d5b02440bb7 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -292,7 +292,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra List networkGurus; - + @Override public List getNetworkGurus() { return networkGurus; } @@ -1156,7 +1156,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra } if (s_logger.isDebugEnabled()) { - s_logger.debug("Asking " + element.getName() + " to implemenet " + network); + s_logger.debug("Asking " + element.getName() + " to implement " + network); } if (!element.implement(network, offering, dest, context)) { @@ -2644,7 +2644,9 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra public void doInTransactionWithoutResult(final TransactionStatus status) { final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, networkFinal.getGuruName()); - guru.trash(networkFinal, _networkOfferingDao.findById(networkFinal.getNetworkOfferingId())); + if (!guru.trash(networkFinal, _networkOfferingDao.findById(networkFinal.getNetworkOfferingId()))) { + throw new CloudRuntimeException("Failed to trash network."); + } if (!deleteVlansInNetwork(networkFinal.getId(), context.getCaller().getId(), callerAccount)) { s_logger.warn("Failed to delete network " + networkFinal + "; was unable to cleanup corresponding ip ranges"); diff --git a/engine/schema/src/com/cloud/network/dao/NetworkVO.java b/engine/schema/src/com/cloud/network/dao/NetworkVO.java index 08a326a0e1e..f8717880773 100644 --- a/engine/schema/src/com/cloud/network/dao/NetworkVO.java +++ b/engine/schema/src/com/cloud/network/dao/NetworkVO.java @@ -318,6 +318,10 @@ public class NetworkVO implements Network { return related; } + public void setRelated(long related) { + this.related = related; + } + @Override public long getId() { return id; diff --git a/engine/schema/src/com/cloud/network/dao/RouterNetworkVO.java b/engine/schema/src/com/cloud/network/dao/RouterNetworkVO.java index db86cfa26b0..5808af3a3e8 100644 --- a/engine/schema/src/com/cloud/network/dao/RouterNetworkVO.java +++ b/engine/schema/src/com/cloud/network/dao/RouterNetworkVO.java @@ -68,6 +68,10 @@ public class RouterNetworkVO implements InternalIdentity { return guestType; } + public void setNetworkId(long networkId) { + this.networkId = networkId; + } + @Override public long getId() { return id; diff --git a/engine/schema/src/com/cloud/network/vpc/NetworkACLVO.java b/engine/schema/src/com/cloud/network/vpc/NetworkACLVO.java index b6ed5cbd2cb..fb6a239c58d 100644 --- a/engine/schema/src/com/cloud/network/vpc/NetworkACLVO.java +++ b/engine/schema/src/com/cloud/network/vpc/NetworkACLVO.java @@ -93,6 +93,10 @@ public class NetworkACLVO implements NetworkACL { this.display = display; } + public void setVpcId(long vpcId) { + this.vpcId = vpcId; + } + @Override public boolean isDisplay() { return display; diff --git a/engine/schema/src/com/cloud/network/vpc/VpcGatewayVO.java b/engine/schema/src/com/cloud/network/vpc/VpcGatewayVO.java index 23568b49230..9919ba3bf7f 100644 --- a/engine/schema/src/com/cloud/network/vpc/VpcGatewayVO.java +++ b/engine/schema/src/com/cloud/network/vpc/VpcGatewayVO.java @@ -220,4 +220,8 @@ public class VpcGatewayVO implements VpcGateway { public Class getEntityType() { return VpcGateway.class; } + + public void setVpcId(Long vpcId) { + this.vpcId = vpcId; + } } diff --git a/engine/schema/src/com/cloud/network/vpc/dao/NetworkACLDao.java b/engine/schema/src/com/cloud/network/vpc/dao/NetworkACLDao.java index 5e2a6f50c9c..37ba3471ce8 100644 --- a/engine/schema/src/com/cloud/network/vpc/dao/NetworkACLDao.java +++ b/engine/schema/src/com/cloud/network/vpc/dao/NetworkACLDao.java @@ -16,8 +16,14 @@ // under the License. package com.cloud.network.vpc.dao; +import java.util.List; + import com.cloud.network.vpc.NetworkACLVO; +import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDao; public interface NetworkACLDao extends GenericDao { + + @DB + List listByVpcId(long vpcId); } diff --git a/engine/schema/src/com/cloud/network/vpc/dao/NetworkACLDaoImpl.java b/engine/schema/src/com/cloud/network/vpc/dao/NetworkACLDaoImpl.java index 00bb1d87c02..d21df1244f6 100644 --- a/engine/schema/src/com/cloud/network/vpc/dao/NetworkACLDaoImpl.java +++ b/engine/schema/src/com/cloud/network/vpc/dao/NetworkACLDaoImpl.java @@ -19,15 +19,29 @@ package com.cloud.network.vpc.dao; import org.springframework.stereotype.Component; +import java.util.List; + import com.cloud.network.vpc.NetworkACLVO; import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; @Component @DB() public class NetworkACLDaoImpl extends GenericDaoBase implements NetworkACLDao { + protected final SearchBuilder AllFieldsSearch; protected NetworkACLDaoImpl() { + AllFieldsSearch = createSearchBuilder(); + AllFieldsSearch.and("vpcId", AllFieldsSearch.entity().getVpcId(), SearchCriteria.Op.EQ); + AllFieldsSearch.and("id", AllFieldsSearch.entity().getId(), SearchCriteria.Op.EQ); + AllFieldsSearch.done(); } + @Override public List listByVpcId(long vpcId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("vpcId", vpcId); + return listBy(sc); + } } diff --git a/engine/schema/src/com/cloud/network/vpc/dao/VpcGatewayDao.java b/engine/schema/src/com/cloud/network/vpc/dao/VpcGatewayDao.java index a2a449b9930..e6a72c870b0 100644 --- a/engine/schema/src/com/cloud/network/vpc/dao/VpcGatewayDao.java +++ b/engine/schema/src/com/cloud/network/vpc/dao/VpcGatewayDao.java @@ -30,4 +30,6 @@ public interface VpcGatewayDao extends GenericDao { List listByVpcIdAndType(long vpcId, VpcGateway.Type type); List listByAclIdAndType(long aclId, VpcGateway.Type type); + + List listByVpcId(long vpcId); } diff --git a/engine/schema/src/com/cloud/network/vpc/dao/VpcGatewayDaoImpl.java b/engine/schema/src/com/cloud/network/vpc/dao/VpcGatewayDaoImpl.java index 284fd8884c1..39d33192a09 100644 --- a/engine/schema/src/com/cloud/network/vpc/dao/VpcGatewayDaoImpl.java +++ b/engine/schema/src/com/cloud/network/vpc/dao/VpcGatewayDaoImpl.java @@ -82,4 +82,11 @@ public class VpcGatewayDaoImpl extends GenericDaoBase implem sc.setParameters("type", type); return listBy(sc); } + + @Override + public List listByVpcId(long vpcId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("vpcId", vpcId); + return listBy(sc); + } } diff --git a/engine/schema/src/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java b/engine/schema/src/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java index 9679c3af7d8..9e14bb5348f 100644 --- a/engine/schema/src/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java +++ b/engine/schema/src/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java @@ -97,7 +97,6 @@ public class VpcOfferingServiceMapDaoImpl extends GenericDaoBase listServicesForVpcOffering(long offId) { SearchCriteria sc = ServicesSearch.create(); - ; sc.setParameters("offeringId", offId); return customSearch(sc, null); } diff --git a/engine/schema/src/com/cloud/offerings/NetworkOfferingDetailsVO.java b/engine/schema/src/com/cloud/offerings/NetworkOfferingDetailsVO.java index c16c5ac4bf1..d28e150da7c 100644 --- a/engine/schema/src/com/cloud/offerings/NetworkOfferingDetailsVO.java +++ b/engine/schema/src/com/cloud/offerings/NetworkOfferingDetailsVO.java @@ -25,21 +25,20 @@ import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; -import org.apache.cloudstack.api.InternalIdentity; - import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.Detail; +import org.apache.cloudstack.api.ResourceDetail; @Entity @Table(name = "network_offering_details") -public class NetworkOfferingDetailsVO implements InternalIdentity { +public class NetworkOfferingDetailsVO implements ResourceDetail { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private long id; @Column(name = "network_offering_id") - private long offeringId; + private long resourceId; @Enumerated(value = EnumType.STRING) @Column(name = "name") @@ -51,8 +50,8 @@ public class NetworkOfferingDetailsVO implements InternalIdentity { public NetworkOfferingDetailsVO() { } - public NetworkOfferingDetailsVO(long offeringId, Detail detailName, String value) { - this.offeringId = offeringId; + public NetworkOfferingDetailsVO(long resourceId, Detail detailName, String value) { + this.resourceId = resourceId; this.name = detailName; this.value = value; } @@ -62,11 +61,20 @@ public class NetworkOfferingDetailsVO implements InternalIdentity { return id; } - public long getOfferingId() { - return offeringId; + @Override + public long getResourceId() { + return resourceId; } - public NetworkOffering.Detail getName() { + public void setResourceId(long resourceId) { + this.resourceId = resourceId; + } + + public String getName() { + return name.name(); + } + + public NetworkOffering.Detail getDetailName() { return name; } @@ -74,12 +82,13 @@ public class NetworkOfferingDetailsVO implements InternalIdentity { return value; } - public void setId(long id) { - this.id = id; + @Override + public boolean isDisplay() { + return false; } - public void setOfferingId(long offeringId) { - this.offeringId = offeringId; + public void setId(long id) { + this.id = id; } public void setName(NetworkOffering.Detail name) { diff --git a/engine/schema/src/com/cloud/offerings/NetworkOfferingVO.java b/engine/schema/src/com/cloud/offerings/NetworkOfferingVO.java index f6451fb72c9..e31714356e6 100644 --- a/engine/schema/src/com/cloud/offerings/NetworkOfferingVO.java +++ b/engine/schema/src/com/cloud/offerings/NetworkOfferingVO.java @@ -223,6 +223,10 @@ public class NetworkOfferingVO implements NetworkOffering { return tags; } + public void setTags(String tags) { + this.tags = tags; + } + public void setName(String name) { this.name = name; } diff --git a/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDao.java b/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDao.java index 6af9c91c122..94e5006a708 100644 --- a/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDao.java +++ b/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDao.java @@ -21,9 +21,9 @@ import java.util.Map; import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.Detail; import com.cloud.offerings.NetworkOfferingDetailsVO; -import com.cloud.utils.db.GenericDao; +import org.apache.cloudstack.resourcedetail.ResourceDetailsDao; -public interface NetworkOfferingDetailsDao extends GenericDao { +public interface NetworkOfferingDetailsDao extends ResourceDetailsDao { Map getNtwkOffDetails(long offeringId); diff --git a/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDaoImpl.java b/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDaoImpl.java index ea476709c2e..786b71c17c4 100644 --- a/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDaoImpl.java +++ b/engine/schema/src/com/cloud/offerings/dao/NetworkOfferingDetailsDaoImpl.java @@ -16,6 +16,8 @@ // under the License. package com.cloud.offerings.dao; +import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase; + import java.util.HashMap; import java.util.List; import java.util.Map; @@ -23,27 +25,27 @@ import java.util.Map; import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.Detail; import com.cloud.offerings.NetworkOfferingDetailsVO; -import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericSearchBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Func; import com.cloud.utils.db.SearchCriteria.Op; -public class NetworkOfferingDetailsDaoImpl extends GenericDaoBase implements NetworkOfferingDetailsDao { +public class NetworkOfferingDetailsDaoImpl extends ResourceDetailsDaoBase implements NetworkOfferingDetailsDao { protected final SearchBuilder DetailSearch; private final GenericSearchBuilder ValueSearch; public NetworkOfferingDetailsDaoImpl() { DetailSearch = createSearchBuilder(); - DetailSearch.and("offeringId", DetailSearch.entity().getOfferingId(), SearchCriteria.Op.EQ); + DetailSearch.and("resourceId", DetailSearch.entity().getResourceId(), SearchCriteria.Op.EQ); DetailSearch.and("name", DetailSearch.entity().getName(), SearchCriteria.Op.EQ); + DetailSearch.and("value", DetailSearch.entity().getValue(), SearchCriteria.Op.EQ); DetailSearch.done(); ValueSearch = createSearchBuilder(String.class); ValueSearch.select(null, Func.DISTINCT, ValueSearch.entity().getValue()); - ValueSearch.and("offeringId", ValueSearch.entity().getOfferingId(), SearchCriteria.Op.EQ); + ValueSearch.and("resourceId", ValueSearch.entity().getResourceId(), SearchCriteria.Op.EQ); ValueSearch.and("name", ValueSearch.entity().getName(), Op.EQ); ValueSearch.done(); } @@ -51,12 +53,12 @@ public class NetworkOfferingDetailsDaoImpl extends GenericDaoBase getNtwkOffDetails(long offeringId) { SearchCriteria sc = DetailSearch.create(); - sc.setParameters("offeringId", offeringId); + sc.setParameters("resourceId", offeringId); List results = search(sc, null); Map details = new HashMap(results.size()); for (NetworkOfferingDetailsVO result : results) { - details.put(result.getName(), result.getValue()); + details.put(result.getDetailName(), result.getValue()); } return details; @@ -66,7 +68,7 @@ public class NetworkOfferingDetailsDaoImpl extends GenericDaoBase sc = ValueSearch.create(); sc.setParameters("name", detailName); - sc.setParameters("offeringId", offeringId); + sc.setParameters("resourceId", offeringId); List results = customSearch(sc, null); if (results.isEmpty()) { return null; @@ -75,4 +77,7 @@ public class NetworkOfferingDetailsDaoImpl extends GenericDaoBase { /** - * @param resourceId - * @param resourceType - * @return + * Remove a resourceTag based on the resourceId and type + * @param resourceId the id of the resource you want to remove + * @param resourceType the resource type + * @return true if successful */ boolean removeByIdAndType(long resourceId, ResourceObjectType resourceType); List listBy(long resourceId, ResourceObjectType resourceType); + /** + * Find a resource tag based on the resource id, resource type and key + * @param resourceId the id of the resource you want to find + * @param resourceType the resource type (e.g. VPC) + * @param key the key value + * @return the ResourceTag matching the search criteria + */ + ResourceTag findByKey(long resourceId, ResourceObjectType resourceType, String key); + void updateResourceId(long srcId, long destId, ResourceObjectType resourceType); Map> listTags(); + + /** + * remove a resource tag based on the resource id, resource type and key + * @param resourceId the id of the resource you want to remove + * @param resourceType the resource type (e.g. VPC) + * @param key the key value + */ + void removeByResourceIdAndKey(long resourceId, ResourceObjectType resourceType, String key); + + List listByResourceUuid(String resourceUuid); } diff --git a/engine/schema/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java b/engine/schema/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java index d5578a8fded..cc9d99e6ab1 100644 --- a/engine/schema/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java +++ b/engine/schema/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java @@ -42,6 +42,8 @@ public class ResourceTagsDaoImpl extends GenericDaoBase imp AllFieldsSearch.and("resourceId", AllFieldsSearch.entity().getResourceId(), Op.EQ); AllFieldsSearch.and("uuid", AllFieldsSearch.entity().getResourceUuid(), Op.EQ); AllFieldsSearch.and("resourceType", AllFieldsSearch.entity().getResourceType(), Op.EQ); + AllFieldsSearch.and("key", AllFieldsSearch.entity().getKey(), Op.EQ); + AllFieldsSearch.and("resourceUuid", AllFieldsSearch.entity().getResourceUuid(), Op.EQ); AllFieldsSearch.done(); } @@ -62,6 +64,15 @@ public class ResourceTagsDaoImpl extends GenericDaoBase imp return listBy(sc); } + @Override + public ResourceTag findByKey(long resourceId, ResourceObjectType resourceType, String key) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("resourceId", resourceId); + sc.setParameters("resourceType", resourceType); + sc.setParameters("key", key); + return findOneBy(sc); + } + @Override public void updateResourceId(long srcId, long destId, ResourceObjectType resourceType) { SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("resourceId", srcId); @@ -93,4 +104,20 @@ public class ResourceTagsDaoImpl extends GenericDaoBase imp } return resourceTagMap; } + + @Override + public void removeByResourceIdAndKey(long resourceId, ResourceObjectType resourceType, String key) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("resourceId", resourceId); + sc.setParameters("resourceType", resourceType); + sc.setParameters("key", key); + remove(sc); + } + + @Override + public List listByResourceUuid(String resourceUuid) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("resourceUuid", resourceUuid); + return listBy(sc); + } } diff --git a/engine/schema/src/com/cloud/vm/dao/NicIpAliasDao.java b/engine/schema/src/com/cloud/vm/dao/NicIpAliasDao.java index b79c101b828..40e7e407241 100644 --- a/engine/schema/src/com/cloud/vm/dao/NicIpAliasDao.java +++ b/engine/schema/src/com/cloud/vm/dao/NicIpAliasDao.java @@ -58,4 +58,5 @@ public interface NicIpAliasDao extends GenericDao { List listByNetworkIdAndState(long networkId, NicIpAlias.State state); + int moveIpAliases(long fromNicId, long toNicId); } \ No newline at end of file diff --git a/engine/schema/src/com/cloud/vm/dao/NicIpAliasDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/NicIpAliasDaoImpl.java index 48cc6621b44..d1453aa4630 100644 --- a/engine/schema/src/com/cloud/vm/dao/NicIpAliasDaoImpl.java +++ b/engine/schema/src/com/cloud/vm/dao/NicIpAliasDaoImpl.java @@ -172,4 +172,14 @@ public class NicIpAliasDaoImpl extends GenericDaoBase implem List list = listBy(sc); return list.size(); } + + @Override + public int moveIpAliases(long fromNicId, long toNicId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("nicId", fromNicId); + + NicIpAliasVO update = createForUpdate(); + update.setNicId(toNicId); + return update(update, sc); + } } diff --git a/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpDao.java b/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpDao.java index ef8df516e9f..96b80b84dd7 100644 --- a/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpDao.java +++ b/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpDao.java @@ -57,4 +57,6 @@ public interface NicSecondaryIpDao extends GenericDao { Long countByNicId(long nicId); List listSecondaryIpUsingKeyword(long nicId, String keyword); + + int moveSecondaryIps(long fromNicId, long toNicId); } diff --git a/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java index 50733de002d..01f53bc99fb 100644 --- a/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java +++ b/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java @@ -172,4 +172,15 @@ public class NicSecondaryIpDaoImpl extends GenericDaoBase sc = AllFieldsSearch.create(); + sc.setParameters("nicId", fromNicId); + + return update(update, sc); + } } diff --git a/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpVO.java b/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpVO.java index 23e45e8a235..d60ac9298fc 100644 --- a/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpVO.java +++ b/engine/schema/src/com/cloud/vm/dao/NicSecondaryIpVO.java @@ -97,6 +97,11 @@ public class NicSecondaryIpVO implements NicSecondaryIp { return nicId; } + @Override + public void setNicId(long nicId) { + this.nicId = nicId; + } + @Override public long getDomainId() { return domainId; diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/BridgeVifDriver.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/BridgeVifDriver.java index 2fab9a83cf7..11b22c494f4 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/BridgeVifDriver.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/BridgeVifDriver.java @@ -20,16 +20,19 @@ package com.cloud.hypervisor.kvm.resource; import java.io.File; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.naming.ConfigurationException; -import com.google.common.base.Strings; import org.apache.log4j.Logger; import org.libvirt.LibvirtException; +import com.google.common.base.Strings; + import com.cloud.agent.api.to.NicTO; import com.cloud.exception.InternalErrorException; import com.cloud.network.Networks; @@ -54,6 +57,8 @@ public class BridgeVifDriver extends VifDriverBase { super.configure(params); + getPifs(); + // Set the domr scripts directory params.put("domr.scripts.dir", "scripts/network/domr/kvm"); @@ -80,12 +85,125 @@ public class BridgeVifDriver extends VifDriverBase { if (libvirtVersion == null) { libvirtVersion = 0L; } + } - try { - createControlNetwork(); - } catch (LibvirtException e) { - throw new ConfigurationException(e.getMessage()); + public void getPifs() { + final File dir = new File("/sys/devices/virtual/net"); + final File[] netdevs = dir.listFiles(); + final List bridges = new ArrayList(); + for (File netdev : netdevs) { + final File isbridge = new File(netdev.getAbsolutePath() + "/bridge"); + final String netdevName = netdev.getName(); + s_logger.debug("looking in file " + netdev.getAbsolutePath() + "/bridge"); + if (isbridge.exists()) { + s_logger.debug("Found bridge " + netdevName); + bridges.add(netdevName); + } } + + String guestBridgeName = _libvirtComputingResource.getGuestBridgeName(); + String publicBridgeName = _libvirtComputingResource.getPublicBridgeName(); + + for (final String bridge : bridges) { + s_logger.debug("looking for pif for bridge " + bridge); + final String pif = getPif(bridge); + if (_libvirtComputingResource.isPublicBridge(bridge)) { + _pifs.put("public", pif); + } + if (guestBridgeName != null && bridge.equals(guestBridgeName)) { + _pifs.put("private", pif); + } + _pifs.put(bridge, pif); + } + + // guest(private) creates bridges on a pif, if private bridge not found try pif direct + // This addresses the unnecessary requirement of someone to create an unused bridge just for traffic label + if (_pifs.get("private") == null) { + s_logger.debug("guest(private) traffic label '" + guestBridgeName + "' not found as bridge, looking for physical interface"); + final File dev = new File("/sys/class/net/" + guestBridgeName); + if (dev.exists()) { + s_logger.debug("guest(private) traffic label '" + guestBridgeName + "' found as a physical device"); + _pifs.put("private", guestBridgeName); + } + } + + // public creates bridges on a pif, if private bridge not found try pif direct + // This addresses the unnecessary requirement of someone to create an unused bridge just for traffic label + if (_pifs.get("public") == null) { + s_logger.debug("public traffic label '" + publicBridgeName+ "' not found as bridge, looking for physical interface"); + final File dev = new File("/sys/class/net/" + publicBridgeName); + if (dev.exists()) { + s_logger.debug("public traffic label '" + publicBridgeName + "' found as a physical device"); + _pifs.put("public", publicBridgeName); + } + } + + s_logger.debug("done looking for pifs, no more bridges"); + } + + private String getPif(final String bridge) { + String pif = matchPifFileInDirectory(bridge); + final File vlanfile = new File("/proc/net/vlan/" + pif); + + if (vlanfile.isFile()) { + pif = Script.runSimpleBashScript("grep ^Device\\: /proc/net/vlan/" + pif + " | awk {'print $2'}"); + } + + return pif; + } + + private String matchPifFileInDirectory(final String bridgeName) { + final File brif = new File("/sys/devices/virtual/net/" + bridgeName + "/brif"); + + if (!brif.isDirectory()) { + final File pif = new File("/sys/class/net/" + bridgeName); + if (pif.isDirectory()) { + // if bridgeName already refers to a pif, return it as-is + return bridgeName; + } + s_logger.debug("failing to get physical interface from bridge " + bridgeName + ", does " + brif.getAbsolutePath() + "exist?"); + return ""; + } + + final File[] interfaces = brif.listFiles(); + + for (File anInterface : interfaces) { + final String fname = anInterface.getName(); + s_logger.debug("matchPifFileInDirectory: file name '" + fname + "'"); + if (isInterface(fname)) { + return fname; + } + } + + s_logger.debug("failing to get physical interface from bridge " + bridgeName + ", did not find an eth*, bond*, team*, vlan*, em*, p*p*, ens*, eno*, enp*, or enx* in " + brif.getAbsolutePath()); + return ""; + } + + private static final String [] IF_NAME_PATTERNS = { + "^eth", + "^bond", + "^vlan", + "^vx", + "^em", + "^ens", + "^eno", + "^enp", + "^team", + "^enx", + "^p\\d+p\\d+" + }; + + /** + * @param fname + * @return + */ + private static boolean isInterface(final String fname) { + StringBuilder commonPattern = new StringBuilder(); + for (final String ifNamePattern : IF_NAME_PATTERNS) { + commonPattern.append("|(").append(ifNamePattern).append(".*)"); + } + + return fname.matches(commonPattern.toString()); } @Override @@ -161,6 +279,7 @@ public class BridgeVifDriver extends VifDriverBase { if (nic.getPxeDisable() == true) { intf.setPxeDisable(true); } + return intf; } @@ -169,6 +288,16 @@ public class BridgeVifDriver extends VifDriverBase { deleteVnetBr(iface.getBrName()); } + @Override + public void attach(LibvirtVMDef.InterfaceDef iface) { + Script.runSimpleBashScript("brctl addif " + iface.getBrName() + " " + iface.getDevName()); + } + + @Override + public void detach(LibvirtVMDef.InterfaceDef iface) { + Script.runSimpleBashScript("test -d /sys/class/net/" + iface.getBrName() + "/brif/" + iface.getDevName() + " && brctl delif " + iface.getBrName() + " " + iface.getDevName()); + } + private String setVnetBrName(String pifName, String vnetId) { return "br" + pifName + "-" + vnetId; } @@ -272,10 +401,6 @@ public class BridgeVifDriver extends VifDriverBase { } } - private void createControlNetwork() throws LibvirtException { - createControlNetwork(_bridges.get("linklocal")); - } - private void deleteExistingLinkLocalRouteTable(String linkLocalBr) { Script command = new Script("/bin/bash", _timeout); command.add("-c"); @@ -304,16 +429,21 @@ public class BridgeVifDriver extends VifDriverBase { } } - private void createControlNetwork(String privBrName) { - deleteExistingLinkLocalRouteTable(privBrName); - if (!isBridgeExists(privBrName)) { - Script.runSimpleBashScript("brctl addbr " + privBrName + "; ip link set " + privBrName + " up; ip address add 169.254.0.1/16 dev " + privBrName, _timeout); - } - + private void createControlNetwork() { + createControlNetwork(_bridges.get("linklocal")); } - private boolean isBridgeExists(String bridgeName) { - File f = new File("/sys/devices/virtual/net/" + bridgeName); + @Override + public void createControlNetwork(String privBrName) { + deleteExistingLinkLocalRouteTable(privBrName); + if (!isExistingBridge(privBrName)) { + Script.runSimpleBashScript("brctl addbr " + privBrName + "; ip link set " + privBrName + " up; ip address add 169.254.0.1/16 dev " + privBrName, _timeout); + } + } + + @Override + public boolean isExistingBridge(String bridgeName) { + File f = new File("/sys/devices/virtual/net/" + bridgeName + "/bridge"); if (f.exists()) { return true; } else { diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/DirectVifDriver.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/DirectVifDriver.java index 3cc8839176c..b8763fa8da7 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/DirectVifDriver.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/DirectVifDriver.java @@ -63,4 +63,18 @@ public class DirectVifDriver extends VifDriverBase { // not needed, libvirt will cleanup } + @Override + public void attach(LibvirtVMDef.InterfaceDef iface) { + + } + + @Override + public void detach(LibvirtVMDef.InterfaceDef iface) { + + } + + @Override + public void createControlNetwork(String privBrName) { + } + } diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/IvsVifDriver.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/IvsVifDriver.java index 1aae2b58933..8e73d859039 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/IvsVifDriver.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/IvsVifDriver.java @@ -74,8 +74,6 @@ public class IvsVifDriver extends VifDriverBase { if (libvirtVersion == null) { libvirtVersion = 0L; } - - createControlNetwork(_bridges.get("linklocal")); } @Override @@ -145,6 +143,17 @@ public class IvsVifDriver extends VifDriverBase { public void unplug(InterfaceDef iface) { } + @Override + public void attach(LibvirtVMDef.InterfaceDef iface) { + Script.runSimpleBashScript("/usr/sbin/ivs-ctl add-port " + iface.getDevName()); + } + + @Override + public void detach(LibvirtVMDef.InterfaceDef iface) { + Script.runSimpleBashScript("/usr/sbin/ivs-ctl del-port " + iface.getDevName()); + } + + private void createControlNetwork() throws LibvirtException { createControlNetwork(_bridges.get("linklocal")); } @@ -268,7 +277,8 @@ public class IvsVifDriver extends VifDriverBase { } } - private void createControlNetwork(String privBrName) { + @Override + public void createControlNetwork(String privBrName) { deleteExitingLinkLocalRouteTable(privBrName); if (!isBridgeExists(privBrName)) { Script.runSimpleBashScript("brctl addbr " + privBrName + "; ip link set " + privBrName + " up; ip address add 169.254.0.1/16 dev " + privBrName, _timeout); 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 51b9737312e..9c97b3ed23f 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -47,12 +47,6 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; -import org.apache.cloudstack.storage.to.VolumeObjectTO; -import org.apache.cloudstack.utils.hypervisor.HypervisorUtils; -import org.apache.cloudstack.utils.linux.CPUStat; -import org.apache.cloudstack.utils.linux.MemStat; -import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.ArrayUtils; @@ -76,6 +70,15 @@ import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; +import com.google.common.base.Strings; + +import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; +import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.cloudstack.utils.hypervisor.HypervisorUtils; +import org.apache.cloudstack.utils.linux.CPUStat; +import org.apache.cloudstack.utils.linux.MemStat; +import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat; + import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; import com.cloud.agent.api.HostVmStateReportEntry; @@ -167,7 +170,6 @@ import com.cloud.utils.ssh.SshHelper; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.PowerState; import com.cloud.vm.VmDetailConstants; -import com.google.common.base.Strings; /** * LibvirtComputingResource execute requests on the computing/routing host using @@ -968,6 +970,18 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv } } + final Map bridges = new HashMap(); + + params.put("libvirt.host.bridges", bridges); + params.put("libvirt.host.pifs", _pifs); + + params.put("libvirt.computing.resource", this); + params.put("libvirtVersion", _hypervisorLibvirtVersion); + + + configureVifDrivers(params); + + /* switch (_bridgeType) { case OPENVSWITCH: getOvsPifs(); @@ -977,6 +991,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv getPifs(); break; } + */ if (_pifs.get("private") == null) { s_logger.debug("Failed to get private nic name"); @@ -1027,19 +1042,13 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv params.put("vm.migrate.speed", String.valueOf(_migrateSpeed)); } - final Map bridges = new HashMap(); bridges.put("linklocal", _linkLocalBridgeName); bridges.put("public", _publicBridgeName); bridges.put("private", _privBridgeName); bridges.put("guest", _guestBridgeName); - params.put("libvirt.host.bridges", bridges); - params.put("libvirt.host.pifs", _pifs); + getVifDriver(TrafficType.Control).createControlNetwork(_linkLocalBridgeName); - params.put("libvirt.computing.resource", this); - params.put("libvirtVersion", _hypervisorLibvirtVersion); - - configureVifDrivers(params); configureDiskActivityChecks(params); final KVMStorageProcessor storageProcessor = new KVMStorageProcessor(_storagePoolMgr, this); @@ -1132,6 +1141,23 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv return vifDriver; } + public VifDriver getVifDriver(final TrafficType trafficType, final String bridgeName) { + VifDriver vifDriver = null; + + for (VifDriver driver : getAllVifDrivers()) { + if (driver.isExistingBridge(bridgeName)) { + vifDriver = driver; + break; + } + } + + if (vifDriver == null) { + vifDriver = getVifDriver(trafficType); + } + + return vifDriver; + } + public List getAllVifDrivers() { final Set vifDrivers = new HashSet(); @@ -1160,10 +1186,10 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv for (final String bridge : bridges) { s_logger.debug("looking for pif for bridge " + bridge); final String pif = getPif(bridge); - if (_publicBridgeName != null && bridge.equals(_publicBridgeName)) { + if (isPublicBridge(bridge)) { _pifs.put("public", pif); } - if (_guestBridgeName != null && bridge.equals(_guestBridgeName)) { + if (isGuestBridge(bridge)) { _pifs.put("private", pif); } _pifs.put(bridge, pif); @@ -1194,6 +1220,10 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv s_logger.debug("done looking for pifs, no more bridges"); } + boolean isGuestBridge(String bridge) { + return _guestBridgeName != null && bridge.equals(_guestBridgeName); + } + private void getOvsPifs() { final String cmdout = Script.runSimpleBashScript("ovs-vsctl list-br | sed '{:q;N;s/\\n/%/g;t q}'"); s_logger.debug("cmdout was " + cmdout); @@ -1204,10 +1234,10 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv // Not really interested in the pif name at this point for ovs // bridges final String pif = bridge; - if (_publicBridgeName != null && bridge.equals(_publicBridgeName)) { + if (isPublicBridge(bridge)) { _pifs.put("public", pif); } - if (_guestBridgeName != null && bridge.equals(_guestBridgeName)) { + if (isGuestBridge(bridge)) { _pifs.put("private", pif); } _pifs.put(bridge, pif); @@ -1215,6 +1245,10 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv s_logger.debug("done looking for pifs, no more bridges"); } + public boolean isPublicBridge(String bridge) { + return _publicBridgeName != null && bridge.equals(_publicBridgeName); + } + private String getPif(final String bridge) { String pif = matchPifFileInDirectory(bridge); final File vlanfile = new File("/proc/net/vlan/" + pif); @@ -1281,12 +1315,12 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv return false; } - public boolean checkNetwork(final String networkName) { + public boolean checkNetwork(final TrafficType trafficType, final String networkName) { if (networkName == null) { return true; } - if (_bridgeType == BridgeType.OPENVSWITCH) { + if (getVifDriver(trafficType, networkName) instanceof OvsVifDriver) { return checkOvsNetwork(networkName); } else { return checkBridgeNetwork(networkName); @@ -1421,7 +1455,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv public synchronized boolean findOrCreateTunnelNetwork(final String nwName) { try { - if (checkNetwork(nwName)) { + if (checkNetwork(TrafficType.Guest, nwName)) { return true; } // if not found, create a new one @@ -2324,7 +2358,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv } } - vm.getDevices().addDevice(getVifDriver(nic.getType()).plug(nic, vm.getPlatformEmulator().toString(), nicAdapter).toString()); + vm.getDevices().addDevice(getVifDriver(nic.getType(), nic.getName()).plug(nic, vm.getPlatformEmulator(), nicAdapter)); } public boolean cleanupDisk(final DiskDef disk) { diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java index 847d77553f4..d979d553f48 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java @@ -27,7 +27,7 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import com.google.common.base.Strings; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -36,7 +36,8 @@ import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; -import com.cloud.utils.StringUtils; +import com.google.common.base.Strings; + import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef; @@ -161,6 +162,8 @@ public class LibvirtDomainXMLParser { String mac = getAttrValue("mac", "address", nic); String dev = getAttrValue("target", "dev", nic); String model = getAttrValue("model", "type", nic); + String slot = StringUtils.removeStart(getAttrValue("address", "slot", nic), "0x"); + InterfaceDef def = new InterfaceDef(); NodeList bandwidth = nic.getElementsByTagName("bandwidth"); Integer networkRateKBps = 0; @@ -181,6 +184,11 @@ public class LibvirtDomainXMLParser { String scriptPath = getAttrValue("script", "path", nic); def.defEthernet(dev, mac, NicModel.valueOf(model.toUpperCase()), scriptPath, networkRateKBps); } + + if (StringUtils.isNotBlank(slot)) { + def.setSlot(Integer.parseInt(slot, 16)); + } + interfaces.add(def); } diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java index 0f34a92d6d6..0196c85bb58 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java @@ -16,16 +16,17 @@ // under the License. package com.cloud.hypervisor.kvm.resource; -import com.google.common.collect.Maps; -import org.apache.commons.lang.StringEscapeUtils; -import org.apache.log4j.Logger; - import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.log4j.Logger; + +import com.google.common.collect.Maps; + public class LibvirtVMDef { private static final Logger s_logger = Logger.getLogger(LibvirtVMDef.class); @@ -890,7 +891,7 @@ public class LibvirtVMDef { } } - enum NicModel { + public enum NicModel { E1000("e1000"), VIRTIO("virtio"), RTL8139("rtl8139"), NE2KPCI("ne2k_pci"), VMXNET3("vmxnet3"); String _model; @@ -925,6 +926,8 @@ public class LibvirtVMDef { private String _virtualPortInterfaceId; private int _vlanTag = -1; private boolean _pxeDisable = false; + private boolean _linkStateUp = true; + private Integer _slot; public void defBridgeNet(String brName, String targetBrName, String macAddr, NicModel model) { defBridgeNet(brName, targetBrName, macAddr, model, 0); @@ -1012,6 +1015,10 @@ public class LibvirtVMDef { return _networkName; } + public void setDevName(String networkName) { + _networkName = networkName; + } + public String getMacAddress() { return _macAddr; } @@ -1044,6 +1051,22 @@ public class LibvirtVMDef { return _vlanTag; } + public void setSlot(Integer slot) { + _slot = slot; + } + + public Integer getSlot() { + return _slot; + } + + public void setLinkStateUp(boolean linkStateUp) { + _linkStateUp = linkStateUp; + } + + public boolean isLinkStateUp() { + return _linkStateUp; + } + @Override public String toString() { StringBuilder netBuilder = new StringBuilder(); @@ -1086,6 +1109,12 @@ public class LibvirtVMDef { if (_vlanTag > 0 && _vlanTag < 4095) { netBuilder.append("\n\n"); } + + netBuilder.append("\n"); + + if (_slot != null) { + netBuilder.append(String.format("
\n", _slot)); + } netBuilder.append("\n"); return netBuilder.toString(); } 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 6462df7cf30..06cd1617b78 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 @@ -18,6 +18,8 @@ */ package com.cloud.hypervisor.kvm.resource; +import java.util.Arrays; +import java.util.List; import java.util.Map; import javax.naming.ConfigurationException; @@ -42,6 +44,8 @@ public class OvsVifDriver extends VifDriverBase { public void configure(Map params) throws ConfigurationException { super.configure(params); + getPifs(); + String networkScriptsDir = (String)params.get("network.scripts.dir"); if (networkScriptsDir == null) { networkScriptsDir = "scripts/vm/network/vnet"; @@ -49,8 +53,27 @@ public class OvsVifDriver extends VifDriverBase { String value = (String)params.get("scripts.timeout"); _timeout = NumbersUtil.parseInt(value, 30 * 60) * 1000; + } - createControlNetwork(_bridges.get("linklocal")); + public void getPifs() { + final String cmdout = Script.runSimpleBashScript("ovs-vsctl list-br | sed '{:q;N;s/\\n/%/g;t q}'"); + s_logger.debug("cmdout was " + cmdout); + final List bridges = Arrays.asList(cmdout.split("%")); + for (final String bridge : bridges) { + s_logger.debug("looking for pif for bridge " + bridge); + // String pif = getOvsPif(bridge); + // Not really interested in the pif name at this point for ovs + // bridges + final String pif = bridge; + if (_libvirtComputingResource.isPublicBridge(bridge)) { + _pifs.put("public", pif); + } + if (_libvirtComputingResource.isGuestBridge(bridge)) { + _pifs.put("private", pif); + } + _pifs.put(bridge, pif); + } + s_logger.debug("done looking for pifs, no more bridges"); } @Override @@ -132,6 +155,17 @@ public class OvsVifDriver extends VifDriverBase { // Libvirt apparently takes care of this, see BridgeVifDriver unplug } + + @Override + public void attach(LibvirtVMDef.InterfaceDef iface) { + Script.runSimpleBashScript("ovs-vsctl add-port " + iface.getBrName() + " " + iface.getDevName()); + } + + @Override + public void detach(LibvirtVMDef.InterfaceDef iface) { + Script.runSimpleBashScript("ovs-vsctl port-to-br " + iface.getDevName() + " && ovs-vsctl del-port " + iface.getBrName() + " " + iface.getDevName()); + } + private void deleteExitingLinkLocalRouteTable(String linkLocalBr) { Script command = new Script("/bin/bash", _timeout); command.add("-c"); @@ -156,14 +190,16 @@ public class OvsVifDriver extends VifDriverBase { } } - private void createControlNetwork(String privBrName) { + @Override + public void createControlNetwork(String privBrName) { deleteExitingLinkLocalRouteTable(privBrName); - if (!isBridgeExists(privBrName)) { + if (!isExistingBridge(privBrName)) { Script.runSimpleBashScript("ovs-vsctl add-br " + privBrName + "; ip link set " + privBrName + " up; ip address add 169.254.0.1/16 dev " + privBrName, _timeout); } } - private boolean isBridgeExists(String bridgeName) { + @Override + public boolean isExistingBridge(String bridgeName) { Script command = new Script("/bin/sh", _timeout); command.add("-c"); command.add("ovs-vsctl br-exists " + bridgeName); diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/VifDriver.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/VifDriver.java index 5cd2d6151a4..387a552b55e 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/VifDriver.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/VifDriver.java @@ -36,4 +36,12 @@ public interface VifDriver { public void unplug(LibvirtVMDef.InterfaceDef iface); + void attach(LibvirtVMDef.InterfaceDef iface); + + void detach(LibvirtVMDef.InterfaceDef iface); + + void createControlNetwork(String privBrName); + + boolean isExistingBridge(String bridgeName); + } diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/VifDriverBase.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/VifDriverBase.java index 2baec276a0f..dad73f28c16 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/VifDriverBase.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/VifDriverBase.java @@ -63,4 +63,8 @@ public abstract class VifDriverBase implements VifDriver { return LibvirtVMDef.InterfaceDef.NicModel.E1000; } } + + public boolean isExistingBridge(String bridgeName) { + return false; + } } diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckNetworkCommandWrapper.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckNetworkCommandWrapper.java index 0d3df1f274c..1ce491cd16c 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckNetworkCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckNetworkCommandWrapper.java @@ -25,6 +25,7 @@ import com.cloud.agent.api.Answer; import com.cloud.agent.api.CheckNetworkAnswer; import com.cloud.agent.api.CheckNetworkCommand; import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource; +import com.cloud.network.Networks; import com.cloud.network.PhysicalNetworkSetupInfo; import com.cloud.resource.CommandWrapper; import com.cloud.resource.ResourceWrapper; @@ -38,13 +39,13 @@ public final class LibvirtCheckNetworkCommandWrapper extends CommandWrapper { @@ -61,7 +60,7 @@ public final class LibvirtPlugNicCommandWrapper extends CommandWrapper { @@ -60,7 +59,7 @@ public final class LibvirtPrepareForMigrationCommandWrapper extends CommandWrapp final Connect conn = libvirtUtilitiesHelper.getConnectionByVmName(vm.getName()); for (final NicTO nic : nics) { - libvirtComputingResource.getVifDriver(nic.getType()).plug(nic, null, ""); + libvirtComputingResource.getVifDriver(nic.getType(), nic.getName()).plug(nic, null, ""); } /* setup disks, e.g for iso */ diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapper.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapper.java new file mode 100644 index 00000000000..8c20a33e608 --- /dev/null +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapper.java @@ -0,0 +1,133 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.hypervisor.kvm.resource.wrapper; + +import java.util.List; + +import org.apache.log4j.Logger; +import org.libvirt.Connect; +import org.libvirt.Domain; +import org.libvirt.LibvirtException; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.ReplugNicAnswer; +import com.cloud.agent.api.ReplugNicCommand; +import com.cloud.agent.api.to.NicTO; +import com.cloud.exception.InternalErrorException; +import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource; +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef; +import com.cloud.hypervisor.kvm.resource.VifDriver; +import com.cloud.resource.CommandWrapper; +import com.cloud.resource.ResourceWrapper; + +@ResourceWrapper(handles = ReplugNicCommand.class) +public final class LibvirtReplugNicCommandWrapper extends CommandWrapper { + + private static final Logger s_logger = Logger.getLogger(LibvirtReplugNicCommandWrapper.class); + public enum DomainAffect { + CURRENT(0), LIVE(1), CONFIG(2), BOTH(3); + + private int value; + DomainAffect(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + + @Override + public Answer execute(final ReplugNicCommand command, final LibvirtComputingResource libvirtComputingResource) { + final NicTO nic = command.getNic(); + final String vmName = command.getVmName(); + Domain vm = null; + try { + final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper(); + final Connect conn = libvirtUtilitiesHelper.getConnectionByVmName(vmName); + vm = libvirtComputingResource.getDomain(conn, vmName); + + InterfaceDef oldPluggedNic = findPluggedNic(libvirtComputingResource, nic, vmName, conn); + + final VifDriver newVifDriver = libvirtComputingResource.getVifDriver(nic.getType(), nic.getName()); + final InterfaceDef interfaceDef = newVifDriver.plug(nic, "Other PV", oldPluggedNic.getModel().toString()); + + interfaceDef.setSlot(oldPluggedNic.getSlot()); + interfaceDef.setDevName(oldPluggedNic.getDevName()); + interfaceDef.setLinkStateUp(false); + + oldPluggedNic.setSlot(null); + + int i = 0; + do { + i++; + s_logger.debug("ReplugNic: Detaching interface" + oldPluggedNic + " (Attempt: " + i + ")"); + vm.detachDevice(oldPluggedNic.toString()); + } while (findPluggedNic(libvirtComputingResource, nic, vmName, conn) != null && i <= 10); + + s_logger.debug("ReplugNic: Attaching interface" + interfaceDef); + vm.attachDevice(interfaceDef.toString()); + + interfaceDef.setLinkStateUp(true); + s_logger.debug("ReplugNic: Updating interface" + interfaceDef); + vm.updateDeviceFlags(interfaceDef.toString(), DomainAffect.LIVE.getValue()); + + /* + // Manual replug + for (final VifDriver vifDriver : libvirtComputingResource.getAllVifDrivers()) { + vifDriver.detach(oldPluggedNic); + } + newVifDriver.attach(interfaceDef); + */ + + // We don't know which "traffic type" is associated with + // each interface at this point, so inform all vif drivers + for (final VifDriver vifDriver : libvirtComputingResource.getAllVifDrivers()) { + vifDriver.unplug(oldPluggedNic); + } + + return new ReplugNicAnswer(command, true, "success"); + } catch (final LibvirtException | InternalErrorException e) { + final String msg = " Plug Nic failed due to " + e.toString(); + s_logger.warn(msg, e); + return new ReplugNicAnswer(command, false, msg); + } finally { + if (vm != null) { + try { + vm.free(); + } catch (final LibvirtException l) { + s_logger.trace("Ignoring libvirt error.", l); + } + } + } + } + + private InterfaceDef findPluggedNic(LibvirtComputingResource libvirtComputingResource, NicTO nic, String vmName, Connect conn) { + InterfaceDef oldPluggedNic = null; + + final List pluggedNics = libvirtComputingResource.getInterfaces(conn, vmName); + + for (final InterfaceDef pluggedNic : pluggedNics) { + if (pluggedNic.getMacAddress().equalsIgnoreCase(nic.getMac())) { + oldPluggedNic = pluggedNic; + } + } + + return oldPluggedNic; + } +} \ No newline at end of file diff --git a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java index b3f85300321..2fd7692df58 100644 --- a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java +++ b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java @@ -19,16 +19,6 @@ package com.cloud.hypervisor.kvm.resource; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; @@ -48,11 +38,6 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; -import org.apache.cloudstack.storage.command.AttachAnswer; -import org.apache.cloudstack.storage.command.AttachCommand; -import org.apache.cloudstack.utils.linux.CPUStat; -import org.apache.cloudstack.utils.linux.MemStat; -import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat; import org.apache.commons.lang.SystemUtils; import org.joda.time.Duration; import org.junit.Assert; @@ -78,6 +63,12 @@ import org.mockito.runners.MockitoJUnitRunner; import org.w3c.dom.Document; import org.xml.sax.SAXException; +import org.apache.cloudstack.storage.command.AttachAnswer; +import org.apache.cloudstack.storage.command.AttachCommand; +import org.apache.cloudstack.utils.linux.CPUStat; +import org.apache.cloudstack.utils.linux.MemStat; +import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat; + import com.cloud.agent.api.Answer; import com.cloud.agent.api.AttachIsoCommand; import com.cloud.agent.api.BackupSnapshotCommand; @@ -178,6 +169,16 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.PowerState; import com.cloud.vm.VirtualMachine.Type; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + @RunWith(MockitoJUnitRunner.class) public class LibvirtComputingResourceTest { @@ -1021,7 +1022,7 @@ public class LibvirtComputingResourceTest { when(nicTO.getType()).thenReturn(TrafficType.Guest); when(diskTO.getType()).thenReturn(Volume.Type.ISO); - when(libvirtComputingResource.getVifDriver(nicTO.getType())).thenReturn(vifDriver); + when(libvirtComputingResource.getVifDriver(nicTO.getType(), nicTO.getName())).thenReturn(vifDriver); when(libvirtComputingResource.getStoragePoolMgr()).thenReturn(storagePoolManager); final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance(); @@ -1069,7 +1070,7 @@ public class LibvirtComputingResourceTest { when(nicTO.getType()).thenReturn(TrafficType.Guest); when(diskTO.getType()).thenReturn(Volume.Type.ISO); - when(libvirtComputingResource.getVifDriver(nicTO.getType())).thenReturn(vifDriver); + when(libvirtComputingResource.getVifDriver(nicTO.getType(), nicTO.getName())).thenReturn(vifDriver); when(libvirtComputingResource.getStoragePoolMgr()).thenReturn(storagePoolManager); when(storagePoolManager.connectPhysicalDisksViaVmSpec(vm)).thenReturn(true); @@ -1161,7 +1162,7 @@ public class LibvirtComputingResourceTest { when(nicTO.getType()).thenReturn(TrafficType.Guest); when(volume.getType()).thenReturn(Volume.Type.ISO); - when(libvirtComputingResource.getVifDriver(nicTO.getType())).thenReturn(vifDriver); + when(libvirtComputingResource.getVifDriver(nicTO.getType(), nicTO.getName())).thenReturn(vifDriver); when(libvirtComputingResource.getStoragePoolMgr()).thenReturn(storagePoolManager); try { when(libvirtComputingResource.getVolumePath(conn, volume)).thenThrow(URISyntaxException.class); @@ -1213,7 +1214,7 @@ public class LibvirtComputingResourceTest { when(vm.getNics()).thenReturn(new NicTO[]{nicTO}); when(nicTO.getType()).thenReturn(TrafficType.Guest); - when(libvirtComputingResource.getVifDriver(nicTO.getType())).thenThrow(InternalErrorException.class); + when(libvirtComputingResource.getVifDriver(nicTO.getType(), nicTO.getName())).thenThrow(InternalErrorException.class); when(libvirtComputingResource.getStoragePoolMgr()).thenReturn(storagePoolManager); try { when(libvirtComputingResource.getVolumePath(conn, volume)).thenReturn("/path"); @@ -2550,9 +2551,9 @@ public class LibvirtComputingResourceTest { final CheckNetworkCommand command = new CheckNetworkCommand(networkInfoList); - when(libvirtComputingResource.checkNetwork(nic.getGuestNetworkName())).thenReturn(true); - when(libvirtComputingResource.checkNetwork(nic.getPrivateNetworkName())).thenReturn(true); - when(libvirtComputingResource.checkNetwork(nic.getPublicNetworkName())).thenReturn(true); + when(libvirtComputingResource.checkNetwork(TrafficType.Guest, nic.getGuestNetworkName())).thenReturn(true); + when(libvirtComputingResource.checkNetwork(TrafficType.Management, nic.getPrivateNetworkName())).thenReturn(true); + when(libvirtComputingResource.checkNetwork(TrafficType.Public, nic.getPublicNetworkName())).thenReturn(true); final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance(); assertNotNull(wrapper); @@ -2560,9 +2561,9 @@ public class LibvirtComputingResourceTest { final Answer answer = wrapper.execute(command, libvirtComputingResource); assertTrue(answer.getResult()); - verify(libvirtComputingResource, times(3)).checkNetwork(nic.getGuestNetworkName()); - verify(libvirtComputingResource, times(3)).checkNetwork(nic.getPrivateNetworkName()); - verify(libvirtComputingResource, times(3)).checkNetwork(nic.getPublicNetworkName()); + verify(libvirtComputingResource, times(1)).checkNetwork(TrafficType.Guest, nic.getGuestNetworkName()); + verify(libvirtComputingResource, times(1)).checkNetwork(TrafficType.Management, nic.getPrivateNetworkName()); + verify(libvirtComputingResource, times(1)).checkNetwork(TrafficType.Public, nic.getPublicNetworkName()); } @Test @@ -2574,7 +2575,7 @@ public class LibvirtComputingResourceTest { final CheckNetworkCommand command = new CheckNetworkCommand(networkInfoList); - when(libvirtComputingResource.checkNetwork(networkSetupInfo.getGuestNetworkName())).thenReturn(false); + when(libvirtComputingResource.checkNetwork(TrafficType.Guest, networkSetupInfo.getGuestNetworkName())).thenReturn(false); final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance(); assertNotNull(wrapper); @@ -2582,7 +2583,7 @@ public class LibvirtComputingResourceTest { final Answer answer = wrapper.execute(command, libvirtComputingResource); assertFalse(answer.getResult()); - verify(libvirtComputingResource, times(1)).checkNetwork(networkSetupInfo.getGuestNetworkName()); + verify(libvirtComputingResource, times(1)).checkNetwork(TrafficType.Guest, networkSetupInfo.getGuestNetworkName()); } @Test @@ -2594,8 +2595,8 @@ public class LibvirtComputingResourceTest { final CheckNetworkCommand command = new CheckNetworkCommand(networkInfoList); - when(libvirtComputingResource.checkNetwork(networkSetupInfo.getGuestNetworkName())).thenReturn(true); - when(libvirtComputingResource.checkNetwork(networkSetupInfo.getPrivateNetworkName())).thenReturn(false); + when(libvirtComputingResource.checkNetwork(TrafficType.Guest, networkSetupInfo.getGuestNetworkName())).thenReturn(true); + when(libvirtComputingResource.checkNetwork(TrafficType.Management, networkSetupInfo.getPrivateNetworkName())).thenReturn(false); final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance(); assertNotNull(wrapper); @@ -2603,8 +2604,8 @@ public class LibvirtComputingResourceTest { final Answer answer = wrapper.execute(command, libvirtComputingResource); assertFalse(answer.getResult()); - verify(libvirtComputingResource, times(1)).checkNetwork(networkSetupInfo.getGuestNetworkName()); - verify(libvirtComputingResource, times(1)).checkNetwork(networkSetupInfo.getPrivateNetworkName()); + verify(libvirtComputingResource, times(1)).checkNetwork(TrafficType.Guest, networkSetupInfo.getGuestNetworkName()); + verify(libvirtComputingResource, times(1)).checkNetwork(TrafficType.Management, networkSetupInfo.getPrivateNetworkName()); } @Test @@ -2616,9 +2617,9 @@ public class LibvirtComputingResourceTest { final CheckNetworkCommand command = new CheckNetworkCommand(networkInfoList); - when(libvirtComputingResource.checkNetwork(networkSetupInfo.getGuestNetworkName())).thenReturn(true); - when(libvirtComputingResource.checkNetwork(networkSetupInfo.getPrivateNetworkName())).thenReturn(true); - when(libvirtComputingResource.checkNetwork(networkSetupInfo.getPublicNetworkName())).thenReturn(false); + when(libvirtComputingResource.checkNetwork(TrafficType.Guest, networkSetupInfo.getGuestNetworkName())).thenReturn(true); + when(libvirtComputingResource.checkNetwork(TrafficType.Management, networkSetupInfo.getPrivateNetworkName())).thenReturn(true); + when(libvirtComputingResource.checkNetwork(TrafficType.Public, networkSetupInfo.getPublicNetworkName())).thenReturn(false); final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance(); assertNotNull(wrapper); @@ -2626,8 +2627,8 @@ public class LibvirtComputingResourceTest { final Answer answer = wrapper.execute(command, libvirtComputingResource); assertFalse(answer.getResult()); - verify(libvirtComputingResource, times(1)).checkNetwork(networkSetupInfo.getGuestNetworkName()); - verify(libvirtComputingResource, times(1)).checkNetwork(networkSetupInfo.getPrivateNetworkName()); + verify(libvirtComputingResource, times(1)).checkNetwork(TrafficType.Guest, networkSetupInfo.getGuestNetworkName()); + verify(libvirtComputingResource, times(1)).checkNetwork(TrafficType.Management, networkSetupInfo.getPrivateNetworkName()); } @Test @@ -3151,12 +3152,13 @@ public class LibvirtComputingResourceTest { when(intDef.getMacAddress()).thenReturn("00:00:00:00"); when(nic.getMac()).thenReturn("00:00:00:01"); + when(nic.getName()).thenReturn("br0"); try { when(libvirtUtilitiesHelper.getConnectionByVmName(command.getVmName())).thenReturn(conn); when(libvirtComputingResource.getDomain(conn, instanceName)).thenReturn(vm); - when(libvirtComputingResource.getVifDriver(nic.getType())).thenReturn(vifDriver); + when(libvirtComputingResource.getVifDriver(nic.getType(), nic.getName())).thenReturn(vifDriver); when(vifDriver.plug(nic, "Other PV", "")).thenReturn(interfaceDef); when(interfaceDef.toString()).thenReturn("Interface"); @@ -3180,7 +3182,7 @@ public class LibvirtComputingResourceTest { try { verify(libvirtUtilitiesHelper, times(1)).getConnectionByVmName(command.getVmName()); verify(libvirtComputingResource, times(1)).getDomain(conn, instanceName); - verify(libvirtComputingResource, times(1)).getVifDriver(nic.getType()); + verify(libvirtComputingResource, times(1)).getVifDriver(nic.getType(), nic.getName()); verify(vifDriver, times(1)).plug(nic, "Other PV", ""); } catch (final LibvirtException e) { fail(e.getMessage()); @@ -3253,7 +3255,7 @@ public class LibvirtComputingResourceTest { when(libvirtUtilitiesHelper.getConnectionByVmName(command.getVmName())).thenReturn(conn); when(libvirtComputingResource.getDomain(conn, instanceName)).thenReturn(vm); - when(libvirtComputingResource.getVifDriver(nic.getType())).thenReturn(vifDriver); + when(libvirtComputingResource.getVifDriver(nic.getType(), nic.getName())).thenReturn(vifDriver); when(vifDriver.plug(nic, "Other PV", "")).thenThrow(InternalErrorException.class); @@ -3273,7 +3275,7 @@ public class LibvirtComputingResourceTest { try { verify(libvirtUtilitiesHelper, times(1)).getConnectionByVmName(command.getVmName()); verify(libvirtComputingResource, times(1)).getDomain(conn, instanceName); - verify(libvirtComputingResource, times(1)).getVifDriver(nic.getType()); + verify(libvirtComputingResource, times(1)).getVifDriver(nic.getType(), nic.getName()); verify(vifDriver, times(1)).plug(nic, "Other PV", ""); } catch (final LibvirtException e) { fail(e.getMessage()); diff --git a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java index 78c4e868f2c..9197013af20 100644 --- a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java +++ b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java @@ -19,14 +19,15 @@ package com.cloud.hypervisor.kvm.resource; -import junit.framework.TestCase; - import java.io.File; import java.util.List; + +import junit.framework.TestCase; + +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.RngDef; -import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef; public class LibvirtDomainXMLParserTest extends TestCase { @@ -227,6 +228,8 @@ public class LibvirtDomainXMLParserTest extends TestCase { for (int i = 0; i < ifs.size(); i++) { assertEquals(ifModel, ifs.get(i).getModel()); assertEquals(ifType, ifs.get(i).getNetType()); + assertEquals(Integer.valueOf(i + 3), ifs.get(i).getSlot()); + assertEquals("vnet" + i, ifs.get(i).getDevName()); } List rngs = parser.getRngs(); diff --git a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java index e758dece166..006562c213e 100644 --- a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java +++ b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java @@ -19,14 +19,15 @@ package com.cloud.hypervisor.kvm.resource; +import java.io.File; + import junit.framework.TestCase; -import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef; + import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef; +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.SCSIDef; import com.cloud.utils.Pair; -import java.io.File; - public class LibvirtVMDefTest extends TestCase { public void testInterfaceEtehrnet() { @@ -34,8 +35,12 @@ public class LibvirtVMDefTest extends TestCase { ifDef.defEthernet("targetDeviceName", "00:11:22:aa:bb:dd", LibvirtVMDef.InterfaceDef.NicModel.VIRTIO); String expected = - "\n" + "\n" + "\n" + "\n" - + "\n"; + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n"; assertEquals(expected, ifDef.toString()); } @@ -45,8 +50,44 @@ public class LibvirtVMDefTest extends TestCase { ifDef.defDirectNet("targetDeviceName", null, "00:11:22:aa:bb:dd", LibvirtVMDef.InterfaceDef.NicModel.VIRTIO, "private"); String expected = - "\n" + "\n" + - "\n" + "\n" + "\n"; + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n"; + + assertEquals(expected, ifDef.toString()); + } + + public void testInterfaceBridgeSlot() { + LibvirtVMDef.InterfaceDef ifDef = new LibvirtVMDef.InterfaceDef(); + ifDef.defBridgeNet("targetDeviceName", null, "00:11:22:aa:bb:dd", LibvirtVMDef.InterfaceDef.NicModel.VIRTIO); + ifDef.setSlot(16); + + String expected = + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "
\n" + + "\n"; + + assertEquals(expected, ifDef.toString()); + + ifDef.setLinkStateUp(false); + ifDef.setDevName("vnet11"); + + expected = + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "
\n" + + "\n"; assertEquals(expected, ifDef.toString()); } diff --git a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapperTest.java b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapperTest.java new file mode 100644 index 00000000000..86e455be271 --- /dev/null +++ b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapperTest.java @@ -0,0 +1,274 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.hypervisor.kvm.resource.wrapper; + +import static org.mockito.AdditionalMatchers.not; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import javax.naming.ConfigurationException; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.libvirt.Connect; +import org.libvirt.Domain; +import org.libvirt.LibvirtException; +import org.mockito.BDDMockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.ReplugNicCommand; +import com.cloud.agent.api.to.NicTO; +import com.cloud.hypervisor.kvm.resource.BridgeVifDriver; +import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource; +import com.cloud.hypervisor.kvm.resource.OvsVifDriver; +import com.cloud.network.Networks; +import com.cloud.utils.script.Script; +import com.cloud.vm.VirtualMachine; +@RunWith(PowerMockRunner.class) +@PrepareForTest(Script.class) +public class LibvirtReplugNicCommandWrapperTest { + private static final String part_1 = + "\n" + + " i-85-285-VM\n" + + " 8825b180-468f-4227-beb7-6b06fd342116\n" + + " CentOS 5.5 (64-bit)\n" + + " 262144\n" + + " 262144\n" + + " 1\n" + + " \n" + + " 256\n" + + " \n" + + " \n" + + " \n" + + " Apache Software Foundation\n" + + " CloudStack KVM Hypervisor\n" + + " 8825b180-468f-4227-beb7-6b06fd342116\n" + + " \n" + + " \n" + + " \n" + + " hvm\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " destroy\n" + + " restart\n" + + " destroy\n" + + " \n" + + " /usr/libexec/qemu-kvm\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 0c4aae6926524a04b460\n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n"; + private static final String part_2 = + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n"; + private static final String part_3 = + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "