From 26759d1d139b52b8adfd8adba7809e32091423b5 Mon Sep 17 00:00:00 2001 From: Sigert Goeminne Date: Thu, 28 Dec 2017 10:25:15 +0100 Subject: [PATCH] CLOUDSTACK-10189: Adding nuage VSD managed network support to CloudStack (#2360) Exposing externalId en domainId field in the UI to CS users. Co-Authored-By: Sigert Goeminne sigert.goeminne@nuagenetworks.net Co-Authored-By: Raf Smeets raf.smeets@nuagenetworks.net --- api/src/com/cloud/network/Network.java | 2 + api/src/com/cloud/network/NetworkProfile.java | 7 + .../apache/cloudstack/api/ApiConstants.java | 2 + .../user/network/CreateNetworkCmd.java | 9 +- .../api/response/NetworkResponse.java | 8 + .../service/NetworkOrchestrationService.java | 2 +- .../src/com/cloud/network/vpc/VpcManager.java | 2 +- .../orchestration/NetworkOrchestrator.java | 17 +- .../META-INF/db/schema-41000to41100.sql | 3 + .../src/com/cloud/network/dao/NetworkVO.java | 14 +- plugins/network-elements/nuage-vsp/pom.xml | 2 +- .../api/element/ShutDownVpcVspCommand.java | 16 +- .../api/guru/ImplementNetworkVspCommand.java | 8 +- .../manager/ImplementNetworkVspAnswer.java | 10 +- .../network/element/NuageVspElement.java | 5 +- .../guru/NuageVspGuestNetworkGuru.java | 156 +++++- .../network/manager/NuageVspManager.java | 11 +- .../network/resource/NuageVspResource.java | 10 + .../NuageVspCheckHealthCommandWrapper.java | 43 ++ .../wrapper/NuageVspCommandWrapper.java | 2 +- ...VspGuruImplementNetworkCommandWrapper.java | 15 +- .../NuageVspShutdownVpcCommandWrapper.java | 2 +- .../com/cloud/util/NuageVspEntityBuilder.java | 71 ++- .../nuage-vsp/test/com/cloud/NuageTest.java | 1 - .../guru/NuageVspGuestNetworkGuruTest.java | 14 +- .../resource/NuageVspResourceTest.java | 18 +- .../src/com/cloud/api/ApiResponseHelper.java | 1 + .../cloud/network/IpAddressManagerImpl.java | 2 +- .../com/cloud/network/NetworkServiceImpl.java | 13 +- .../com/cloud/network/vpc/VpcManagerImpl.java | 9 +- .../src/com/cloud/vm/UserVmManagerImpl.java | 8 +- .../network/CreatePrivateNetworkTest.java | 4 +- .../com/cloud/vpc/MockNetworkManagerImpl.java | 2 +- .../plugins/nuagevsp/nuageTestCase.py | 3 +- .../nuagevsp/test_nuage_vsp_mngd_subnets.py | 512 ++++++++++++++++++ tools/marvin/marvin/config/test_data.py | 64 +++ tools/marvin/marvin/lib/base.py | 5 +- ui/l10n/en.js | 1 + ui/scripts/docs.js | 4 + ui/scripts/domains.js | 15 +- ui/scripts/network.js | 13 +- ui/scripts/vpc.js | 12 +- 42 files changed, 1005 insertions(+), 113 deletions(-) create mode 100644 plugins/network-elements/nuage-vsp/src/com/cloud/network/vsp/resource/wrapper/NuageVspCheckHealthCommandWrapper.java create mode 100644 test/integration/plugins/nuagevsp/test_nuage_vsp_mngd_subnets.py diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index 95833d86b63..8b402bcefd1 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -390,4 +390,6 @@ public interface Network extends ControlledEntity, StateObject, I void setNetworkACLId(Long networkACLId); boolean isStrechedL2Network(); + + String getExternalId(); } diff --git a/api/src/com/cloud/network/NetworkProfile.java b/api/src/com/cloud/network/NetworkProfile.java index ab033edaa53..127750aa2ef 100644 --- a/api/src/com/cloud/network/NetworkProfile.java +++ b/api/src/com/cloud/network/NetworkProfile.java @@ -57,6 +57,7 @@ public class NetworkProfile implements Network { private Long networkAclId; private final String guruName; private boolean strechedL2Subnet; + private String externalId; public NetworkProfile(Network network) { id = network.getId(); @@ -91,6 +92,7 @@ public class NetworkProfile implements Network { guruName = network.getGuruName(); strechedL2Subnet = network.isStrechedL2Network(); isRedundant = network.isRedundant(); + externalId = network.getExternalId(); } public String getDns1() { @@ -300,4 +302,9 @@ public class NetworkProfile implements Network { return false; } + @Override + public String getExternalId() { + return externalId; + } + } diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 55e8c285e6b..24099c418d5 100644 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -654,6 +654,7 @@ public class ApiConstants { public static final String IAM_ALLOW_DENY = "permission"; public static final String ENTITY_TYPE = "entitytype"; public static final String ENTITY_ID = "entityid"; + public static final String EXTERNAL_ID = "externalid"; public static final String ACCESS_TYPE = "accesstype"; public static final String RESOURCE_DETAILS = "resourcedetails"; @@ -706,6 +707,7 @@ public class ApiConstants { public static final String HAS_ANNOTATION = "hasannotation"; public static final String LAST_ANNOTATED = "lastannotated"; + public enum HostDetails { all, capacity, events, stats, min; } diff --git a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java index 17312614808..befef999bfd 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java @@ -16,7 +16,6 @@ // under the License. package org.apache.cloudstack.api.command.user.network; -import com.cloud.utils.net.NetUtils; import org.apache.log4j.Logger; import org.apache.cloudstack.acl.RoleType; @@ -44,6 +43,7 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.network.Network; import com.cloud.network.Network.GuestType; import com.cloud.offering.NetworkOffering; +import com.cloud.utils.net.NetUtils; @APICommand(name = "createNetwork", description = "Creates a network", responseObject = NetworkResponse.class, responseView = ResponseView.Restricted, entityType = {Network.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) @@ -134,6 +134,9 @@ public class CreateNetworkCmd extends BaseCmd { @Parameter(name = ApiConstants.IP6_CIDR, type = CommandType.STRING, description = "the CIDR of IPv6 network, must be at least /64") private String ip6Cidr; + @Parameter(name = ApiConstants.EXTERNAL_ID, type = CommandType.STRING, description = "ID of the network in an external system.") + private String externalId; + @Parameter(name = ApiConstants.DISPLAY_NETWORK, type = CommandType.BOOLEAN, description = "an optional field, whether to the display the network to the end user or not.", authorized = {RoleType.Admin}) @@ -209,6 +212,10 @@ public class CreateNetworkCmd extends BaseCmd { return displayNetwork; } + public String getExternalId() { + return externalId; + } + @Override public boolean isDisplay() { if(displayNetwork == null) diff --git a/api/src/org/apache/cloudstack/api/response/NetworkResponse.java b/api/src/org/apache/cloudstack/api/response/NetworkResponse.java index 40c90729cd6..f54b063ad41 100644 --- a/api/src/org/apache/cloudstack/api/response/NetworkResponse.java +++ b/api/src/org/apache/cloudstack/api/response/NetworkResponse.java @@ -225,6 +225,10 @@ public class NetworkResponse extends BaseResponse implements ControlledEntityRes @Param(description = "If a network is enabled for 'streched l2 subnet' then represents zones on which network currently spans", since = "4.4") private Set networkSpannedZones; + @SerializedName(ApiConstants.EXTERNAL_ID) + @Param(description = "The external id of the network", since = "4.11") + private String externalId; + public Boolean getDisplayNetwork() { return displayNetwork; } @@ -429,4 +433,8 @@ public class NetworkResponse extends BaseResponse implements ControlledEntityRes public void setNetworkSpannedZones(Set networkSpannedZones) { this.networkSpannedZones = networkSpannedZones; } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } } 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 86a8fe91a36..67471d0d3e4 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 @@ -169,7 +169,7 @@ public interface NetworkOrchestrationService { Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, boolean bypassVlanOverlapCheck, String networkDomain, Account owner, Long domainId, PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr, - Boolean displayNetworkEnabled, String isolatedPvlan) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException; + Boolean displayNetworkEnabled, String isolatedPvlan, String externalId) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException; UserDataServiceProvider getPasswordResetProvider(Network network); diff --git a/engine/components-api/src/com/cloud/network/vpc/VpcManager.java b/engine/components-api/src/com/cloud/network/vpc/VpcManager.java index 28ad0524a2a..db4221f9e3e 100644 --- a/engine/components-api/src/com/cloud/network/vpc/VpcManager.java +++ b/engine/components-api/src/com/cloud/network/vpc/VpcManager.java @@ -109,7 +109,7 @@ public interface VpcManager { Network createVpcGuestNetwork(long ntwkOffId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner, Long domainId, PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess, long vpcId, Long aclId, Account caller, - Boolean displayNetworkEnabled) + Boolean displayNetworkEnabled, String externalId) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException; 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 d5b02440bb7..9afd642f7ae 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -38,7 +38,8 @@ import java.util.stream.Collectors; import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.vm.NicExtraDhcpOptionVO; +import org.apache.log4j.Logger; + import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.cloud.entity.api.db.VMNetworkMapVO; @@ -53,7 +54,7 @@ import org.apache.cloudstack.framework.messagebus.MessageBus; import org.apache.cloudstack.framework.messagebus.PublishScope; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.region.PortableIpDao; -import org.apache.log4j.Logger; + import com.cloud.agent.AgentManager; import com.cloud.agent.Listener; @@ -204,6 +205,7 @@ import com.cloud.vm.DomainRouterVO; import com.cloud.utils.net.Dhcp; import com.cloud.vm.Nic; import com.cloud.vm.Nic.ReservationStrategy; +import com.cloud.vm.NicExtraDhcpOptionVO; import com.cloud.vm.NicIpAlias; import com.cloud.vm.NicProfile; import com.cloud.vm.NicVO; @@ -700,7 +702,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra public void doInTransactionWithoutResult(final TransactionStatus status) { final NetworkVO vo = new NetworkVO(id, network, offering.getId(), guru.getName(), owner.getDomainId(), owner.getId(), relatedFile, name, displayText, predefined .getNetworkDomain(), offering.getGuestType(), plan.getDataCenterId(), plan.getPhysicalNetworkId(), aclType, offering.getSpecifyIpRanges(), - vpcId, offering.getRedundantRouter()); + vpcId, offering.getRedundantRouter(), predefined.getExternalId()); vo.setDisplayNetwork(isDisplayNetworkEnabled == null ? true : isDisplayNetworkEnabled); vo.setStrechedL2Network(offering.getSupportsStrechedL2()); final NetworkVO networkPersisted = _networksDao.persist(vo, vo.getGuestType() == Network.GuestType.Isolated, @@ -2083,7 +2085,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra public Network createGuestNetwork(final long networkOfferingId, final String name, final String displayText, final String gateway, final String cidr, String vlanId, boolean bypassVlanOverlapCheck, String networkDomain, final Account owner, final Long domainId, final PhysicalNetwork pNtwk, final long zoneId, final ACLType aclType, Boolean subdomainAccess, final Long vpcId, final String ip6Gateway, final String ip6Cidr, - final Boolean isDisplayNetworkEnabled, final String isolatedPvlan) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { + final Boolean isDisplayNetworkEnabled, final String isolatedPvlan, String externalId) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { final NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId); // this method supports only guest network creation @@ -2333,14 +2335,17 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra userNetwork.setIp6Gateway(ip6Gateway); } + if (externalId != null) { + userNetwork.setExternalId(externalId); + } + if (vlanIdFinal != null) { if (isolatedPvlan == null) { URI uri = null; if (UuidUtils.validateUUID(vlanIdFinal)){ //Logical router's UUID provided as VLAN_ID userNetwork.setVlanIdAsUUID(vlanIdFinal); //Set transient field - } - else { + } else { uri = BroadcastDomainType.fromString(vlanIdFinal); } userNetwork.setBroadcastUri(uri); diff --git a/engine/schema/resources/META-INF/db/schema-41000to41100.sql b/engine/schema/resources/META-INF/db/schema-41000to41100.sql index 3dbe5c3e564..19c903927ca 100644 --- a/engine/schema/resources/META-INF/db/schema-41000to41100.sql +++ b/engine/schema/resources/META-INF/db/schema-41000to41100.sql @@ -496,3 +496,6 @@ UPDATE `cloud`.`monitoring_services` SET pidfile="/var/run/apache2/apache2.pid" -- Use 'Other Linux 64-bit' as guest os for the default systemvmtemplate for VMware -- This fixes a memory allocation issue to systemvms on VMware/ESXi UPDATE `cloud`.`vm_template` SET guest_os_id=99 WHERE id=8; + +-- Network External Ids +ALTER TABLE `cloud`.`networks` ADD `external_id` varchar(255); diff --git a/engine/schema/src/com/cloud/network/dao/NetworkVO.java b/engine/schema/src/com/cloud/network/dao/NetworkVO.java index f8717880773..320256b90c0 100644 --- a/engine/schema/src/com/cloud/network/dao/NetworkVO.java +++ b/engine/schema/src/com/cloud/network/dao/NetworkVO.java @@ -172,6 +172,9 @@ public class NetworkVO implements Network { @Column(name = "streched_l2") boolean strechedL2Network = false; + @Column(name = "external_id") + String externalId; + @Transient transient String vlanIdAsUUID; @@ -216,7 +219,7 @@ public class NetworkVO implements Network { } public NetworkVO(long id, Network that, long offeringId, String guruName, long domainId, long accountId, long related, String name, String displayText, - String networkDomain, GuestType guestType, long dcId, Long physicalNetworkId, ACLType aclType, boolean specifyIpRanges, Long vpcId, final boolean isRedundant) { + String networkDomain, GuestType guestType, long dcId, Long physicalNetworkId, ACLType aclType, boolean specifyIpRanges, Long vpcId, final boolean isRedundant, String externalId) { this(id, that.getTrafficType(), that.getMode(), @@ -248,6 +251,7 @@ public class NetworkVO implements Network { uuid = UUID.randomUUID().toString(); ip6Gateway = that.getIp6Gateway(); ip6Cidr = that.getIp6Cidr(); + this.externalId = externalId; } /** @@ -638,4 +642,12 @@ public class NetworkVO implements Network { public void setVpcId(Long vpcId) { this.vpcId = vpcId; } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } } diff --git a/plugins/network-elements/nuage-vsp/pom.xml b/plugins/network-elements/nuage-vsp/pom.xml index bea8cb924a0..7e0b1ef89cd 100644 --- a/plugins/network-elements/nuage-vsp/pom.xml +++ b/plugins/network-elements/nuage-vsp/pom.xml @@ -35,7 +35,7 @@ - 1.0.6 + 1.0.7 diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ShutDownVpcVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ShutDownVpcVspCommand.java index 77b22bc2af3..6c98238c944 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ShutDownVpcVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ShutDownVpcVspCommand.java @@ -20,11 +20,15 @@ package com.cloud.agent.api.element; import java.util.List; +import java.util.Map; import java.util.Objects; import org.apache.commons.lang.builder.HashCodeBuilder; import com.cloud.agent.api.Command; +import com.cloud.network.manager.NuageVspManager; + +import net.nuage.vsp.acs.client.api.model.NetworkRelatedVsdIds; public class ShutDownVpcVspCommand extends Command { @@ -32,13 +36,19 @@ public class ShutDownVpcVspCommand extends Command { private final String _vpcUuid; private final String _domainTemplateName; private final List _domainRouterUuids; + private final NetworkRelatedVsdIds _relatedVsdIds; - public ShutDownVpcVspCommand(String domainUuid, String vpcUuid, String domainTemplateName, List domainRouterUuids) { + public ShutDownVpcVspCommand(String domainUuid, String vpcUuid, String domainTemplateName, List domainRouterUuids, Map details) { super(); this._domainUuid = domainUuid; this._vpcUuid = vpcUuid; this._domainTemplateName = domainTemplateName; this._domainRouterUuids = domainRouterUuids; + this._relatedVsdIds = new NetworkRelatedVsdIds.Builder() + .vsdDomainId(details.get(NuageVspManager.NETWORK_METADATA_VSD_DOMAIN_ID)) + .vsdZoneId(details.get(NuageVspManager.NETWORK_METADATA_VSD_ZONE_ID)) + .withVsdManaged(details.get(NuageVspManager.NETWORK_METADATA_VSD_MANAGED) != null && details.get(NuageVspManager.NETWORK_METADATA_VSD_MANAGED).equals("true")) + .build(); } public String getDomainUuid() { @@ -57,6 +67,10 @@ public class ShutDownVpcVspCommand extends Command { return _domainRouterUuids; } + public NetworkRelatedVsdIds getRelatedVsdIds() { + return _relatedVsdIds; + } + @Override public boolean executeInSequence() { return false; diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/ImplementNetworkVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/ImplementNetworkVspCommand.java index 5dc4ba7a5da..2f2d5fd98a2 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/ImplementNetworkVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/ImplementNetworkVspCommand.java @@ -33,11 +33,13 @@ public class ImplementNetworkVspCommand extends Command { private final VspNetwork _network; private final VspDhcpDomainOption _dhcpOption; + private final boolean _isVsdManaged; - public ImplementNetworkVspCommand(VspNetwork network, VspDhcpDomainOption dhcpOption) { + public ImplementNetworkVspCommand(VspNetwork network, VspDhcpDomainOption dhcpOption, boolean isVsdManaged) { super(); this._network = network; this._dhcpOption = dhcpOption; + this._isVsdManaged = isVsdManaged; } public VspNetwork getNetwork() { @@ -85,4 +87,8 @@ public class ImplementNetworkVspCommand extends Command { .append("dhcpOption", _dhcpOption) .toString(); } + + public boolean isVsdManaged() { + return _isVsdManaged; + } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/ImplementNetworkVspAnswer.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/ImplementNetworkVspAnswer.java index 03ab183d7b5..8cfb715743c 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/ImplementNetworkVspAnswer.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/ImplementNetworkVspAnswer.java @@ -20,6 +20,7 @@ package com.cloud.agent.api.manager; import net.nuage.vsp.acs.client.api.model.NetworkRelatedVsdIds; +import net.nuage.vsp.acs.client.api.model.VspNetwork; import com.cloud.agent.api.Answer; import com.cloud.agent.api.guru.ImplementNetworkVspCommand; @@ -30,8 +31,11 @@ import com.cloud.agent.api.guru.ImplementNetworkVspCommand; public class ImplementNetworkVspAnswer extends Answer { private NetworkRelatedVsdIds networkRelatedVsdIds; - public ImplementNetworkVspAnswer(ImplementNetworkVspCommand command, NetworkRelatedVsdIds networkRelatedVsdIds) { + private VspNetwork vspNetwork; + + public ImplementNetworkVspAnswer(ImplementNetworkVspCommand command, VspNetwork vspNetwork, NetworkRelatedVsdIds networkRelatedVsdIds) { super(command); + this.vspNetwork = vspNetwork; this.networkRelatedVsdIds = networkRelatedVsdIds; } @@ -42,4 +46,8 @@ public class ImplementNetworkVspAnswer extends Answer { public NetworkRelatedVsdIds getNetworkRelatedVsdIds() { return networkRelatedVsdIds; } + + public VspNetwork getVspNetwork() { + return vspNetwork; + } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java index e91901a2c8e..26fdaac5e14 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java @@ -507,7 +507,6 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider return true; } - @Override public boolean applyStaticNats(Network config, List rules) throws ResourceUnavailableException { List vspStaticNatDetails = new ArrayList(); @@ -687,6 +686,8 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider preConfiguredDomainTemplateName = _configDao.getValue(NuageVspManager.NuageVspVpcDomainTemplateName.key()); } + Map vpcDetails = _vpcDetailsDao.listDetailsKeyPairs(vpc.getId(), false); + cleanUpVpcCaching(vpc.getId()); //related to migration caching List vpcResourceDetails = _resourceTagDao.listByResourceUuid(vpc.getUuid()); @@ -698,7 +699,7 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider .ifPresent(this::cleanUpVpcCaching); } - ShutDownVpcVspCommand cmd = new ShutDownVpcVspCommand(vpcDomain.getUuid(), vpc.getUuid(), preConfiguredDomainTemplateName, domainRouterUuids); + ShutDownVpcVspCommand cmd = new ShutDownVpcVspCommand(vpcDomain.getUuid(), vpc.getUuid(), preConfiguredDomainTemplateName, domainRouterUuids, vpcDetails); Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); if (answer == null || !answer.getResult()) { s_logger.error("ShutDownVpcVspCommand for VPC " + vpc.getUuid() + " failed on Nuage VSD " + nuageVspHost.getDetail("hostname")); diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/guru/NuageVspGuestNetworkGuru.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/guru/NuageVspGuestNetworkGuru.java index f43e350d4dc..a36bc0a07d0 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/guru/NuageVspGuestNetworkGuru.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/guru/NuageVspGuestNetworkGuru.java @@ -58,7 +58,9 @@ import com.cloud.agent.api.manager.ImplementNetworkVspAnswer; import com.cloud.configuration.ConfigurationManager; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.dc.DataCenterDetailVO; import com.cloud.dc.VlanVO; +import com.cloud.dc.dao.DataCenterDetailsDao; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; import com.cloud.domain.dao.DomainDao; @@ -67,7 +69,6 @@ import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientVirtualNetworkCapacityException; import com.cloud.exception.UnsupportedServiceException; import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; import com.cloud.network.Network; import com.cloud.network.Network.GuestType; import com.cloud.network.Network.State; @@ -76,13 +77,10 @@ import com.cloud.network.Networks; import com.cloud.network.PhysicalNetwork; import com.cloud.network.PhysicalNetwork.IsolationMethod; import com.cloud.network.dao.IPAddressVO; -import com.cloud.network.dao.NetworkDetailVO; import com.cloud.network.dao.NetworkDetailsDao; import com.cloud.network.dao.NetworkVO; -import com.cloud.network.dao.NuageVspDao; import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.manager.NuageVspManager; -import com.cloud.network.vpc.dao.VpcDao; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; @@ -92,6 +90,7 @@ import com.cloud.user.dao.AccountDao; import com.cloud.util.NuageVspEntityBuilder; import com.cloud.utils.StringUtils; import com.cloud.utils.db.DB; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.Ip; import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; @@ -102,7 +101,7 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.dao.VMInstanceDao; -public class NuageVspGuestNetworkGuru extends GuestNetworkGuru { +public class NuageVspGuestNetworkGuru extends GuestNetworkGuru implements NetworkGuruAdditionalFunctions { public static final Logger s_logger = Logger.getLogger(NuageVspGuestNetworkGuru.class); @Inject @@ -114,12 +113,6 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru { @Inject AccountDao _accountDao; @Inject - NuageVspDao _nuageVspDao; - @Inject - HostDao _hostDao; - @Inject - VpcDao _vpcDao; - @Inject VMInstanceDao _vmInstanceDao; @Inject AgentManager _agentMgr; @@ -135,6 +128,8 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru { VpcDetailsDao _vpcDetailsDao; @Inject NetworkOrchestrationService _networkOrchestrationService; + @Inject + DataCenterDetailsDao _dcDetailsDao; public NuageVspGuestNetworkGuru() { super(); @@ -158,10 +153,90 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru { } networkObject.setBroadcastDomainType(Networks.BroadcastDomainType.Vsp); + + if (userSpecified instanceof NetworkVO && userSpecified.getExternalId() != null) { + if (owner.getType() < Account.ACCOUNT_TYPE_ADMIN) { + throw new IllegalArgumentException("vsdManaged networks are only useable by admins."); + } + + if (!isUniqueReference(plan.getDataCenterId(), userSpecified.getExternalId())) { + s_logger.debug("Refusing to design network. VsdManaged network object already present in zone."); + return null; + } + } + return networkObject; } + private boolean isUniqueReference(long dataCenterId, String vsdSubnetId) { + DataCenterDetailVO detail = _dcDetailsDao.findDetail(dataCenterId, vsdSubnetId); + return detail == null; + } + + private boolean isVsdManagedVpc(long vpcId) { + //Check if it's a vpc and if the vpc is already vsdManaged OR if it has 0 tiers + Map vpcDetails = _vpcDetailsDao.listDetailsKeyPairs(vpcId, false); + return vpcDetails.get(NuageVspManager.NETWORK_METADATA_VSD_MANAGED) != null && vpcDetails.get(NuageVspManager.NETWORK_METADATA_VSD_MANAGED).equals("true"); + } + /** In case an externalId is specified, we get called here, and store the id the same way as cached data */ + @Override + public void finalizeNetworkDesign(long networkId, String vlanIdAsUUID) { + NetworkVO designedNetwork = _networkDao.findById(networkId); + String externalId = designedNetwork.getExternalId(); + boolean isVpc = designedNetwork.getVpcId() != null; + + if (isVpc && _networkDao.listByVpc(designedNetwork.getVpcId()).size() > 1) { + boolean isVsdManagedVpc = isVsdManagedVpc(designedNetwork.getVpcId()); + if (isVsdManagedVpc && externalId == null) { + throw new CloudRuntimeException("Refusing to design network. Network is vsdManaged but is part of a non vsd managed vpc."); + } else if (!isVsdManagedVpc && externalId != null) { + throw new CloudRuntimeException("Refusing to design network. Network is not vsdManaged but is part of a vsd managed vpc."); + } + } + + if (externalId == null) { + return; + } + + VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(designedNetwork, externalId); + HostVO nuageVspHost = _nuageVspManager.getNuageVspHost(designedNetwork.getPhysicalNetworkId()); + + ImplementNetworkVspCommand cmd = new ImplementNetworkVspCommand(vspNetwork, null, true); + Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); + if (answer == null || !answer.getResult()) { + s_logger.error("ImplementNetworkVspCommand for network " + vspNetwork.getUuid() + " failed on Nuage VSD " + nuageVspHost.getDetail("hostname")); + if ((null != answer) && (null != answer.getDetails())) { + s_logger.error(answer.getDetails()); + } + throw new CloudRuntimeException("ImplementNetworkVspCommand for network " + vspNetwork.getUuid() + " failed on Nuage VSD " + nuageVspHost.getDetail("hostname")); + } + + //check if the network does not violate the uuid cidr + ImplementNetworkVspAnswer implementAnswer = (ImplementNetworkVspAnswer) answer; + VspNetwork updatedVspNetwork = implementAnswer.getVspNetwork(); + NetworkVO forUpdate = _networkDao.createForUpdate(networkId); + + if (isVpc && (!designedNetwork.getCidr().equals(updatedVspNetwork.getCidr()) || !designedNetwork.getGateway().equals(updatedVspNetwork.getGateway()))) { + throw new CloudRuntimeException("Tier network does not match the VsdManaged subnet cidr or gateway."); + } else { + forUpdate.setCidr(updatedVspNetwork.getCidr()); + forUpdate.setGateway(updatedVspNetwork.getGateway()); + } + + saveNetworkAndVpcDetails(vspNetwork, implementAnswer.getNetworkRelatedVsdIds(), designedNetwork.getVpcId()); + saveNetworkDetail(networkId, NuageVspManager.NETWORK_METADATA_VSD_SUBNET_ID, externalId); + saveNetworkDetail(networkId, NuageVspManager.NETWORK_METADATA_VSD_MANAGED, "true"); + + forUpdate.setState(State.Allocated); + _networkDao.update(networkId, forUpdate); + } + + @Override + public Map listAdditionalNicParams(String nicUuid) { + return null; + } + @Override public Network implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws InsufficientVirtualNetworkCapacityException { long networkId = network.getId(); @@ -213,7 +288,7 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru { implemented = new NetworkVO(network.getId(), network, network.getNetworkOfferingId(), network.getGuruName(), network.getDomainId(), network.getAccountId(), network.getRelated(), network.getName(), network.getDisplayText(), network.getNetworkDomain(), network.getGuestType(), network.getDataCenterId(), - physicalNetworkId, network.getAclType(), network.getSpecifyIpRanges(), network.getVpcId(), offering.getRedundantRouter()); + physicalNetworkId, network.getAclType(), network.getSpecifyIpRanges(), network.getVpcId(), offering.getRedundantRouter(), network.getExternalId()); implemented.setUuid(network.getUuid()); implemented.setState(State.Allocated); if (network.getGateway() != null) { @@ -229,7 +304,7 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru { implemented.setBroadcastUri(Networks.BroadcastDomainType.Vsp.toUri(broadcastUriStr)); implemented.setBroadcastDomainType(Networks.BroadcastDomainType.Vsp); - boolean implementSucceeded = implement(network.getVpcId(), physicalNetworkId, vspNetwork, _nuageVspEntityBuilder.buildNetworkDhcpOption(network, offering)); + boolean implementSucceeded = implement(network.getVpcId(), physicalNetworkId, vspNetwork, implemented, _nuageVspEntityBuilder.buildNetworkDhcpOption(network, offering)); if (!implementSucceeded) { return null; @@ -237,11 +312,9 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru { if (StringUtils.isNotBlank(vspNetwork.getDomainTemplateName())) { if (network.getVpcId() != null) { - VpcDetailVO vpcDetail = new VpcDetailVO(network.getVpcId(), NuageVspManager.nuageDomainTemplateDetailName, vspNetwork.getDomainTemplateName(), false); - _vpcDetailsDao.persist(vpcDetail); + saveVpcDetail(network.getVpcId(), NuageVspManager.nuageDomainTemplateDetailName, vspNetwork.getDomainTemplateName()); } else { - NetworkDetailVO networkDetail = new NetworkDetailVO(implemented.getId(), NuageVspManager.nuageDomainTemplateDetailName, vspNetwork.getDomainTemplateName(), false); - _networkDetailsDao.persist(networkDetail); + saveNetworkDetail(implemented.getId(), NuageVspManager.nuageDomainTemplateDetailName, vspNetwork.getDomainTemplateName()); } } @@ -252,10 +325,19 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru { return implemented; } - private boolean implement(Long vpcId, long physicalNetworkId, VspNetwork vspNetwork, VspDhcpDomainOption vspDhcpDomainOption) { + private boolean implement(Long vpcId, long physicalNetworkId, VspNetwork vspNetwork, NetworkVO implemented, VspDhcpDomainOption vspDhcpDomainOption) { HostVO nuageVspHost = _nuageVspManager.getNuageVspHost(physicalNetworkId); - ImplementNetworkVspCommand cmd = new ImplementNetworkVspCommand(vspNetwork, vspDhcpDomainOption); - ImplementNetworkVspAnswer answer = (ImplementNetworkVspAnswer) _agentMgr.easySend(nuageVspHost.getId(), cmd); + final boolean isVsdManaged = vspNetwork.getNetworkRelatedVsdIds() + .getVsdSubnetId() + .isPresent(); + if (isVsdManaged) { + //Implement cmd was already send in design step. + _dcDetailsDao.persist(implemented.getDataCenterId(), vspNetwork.getNetworkRelatedVsdIds().getVsdSubnetId().orElseThrow(() -> new CloudRuntimeException("Managed but no subnetId. How can this happen?")), implemented.getUuid()); + return true; + } + + ImplementNetworkVspCommand cmd = new ImplementNetworkVspCommand(vspNetwork, vspDhcpDomainOption, false); + Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); if (answer == null || !answer.getResult()) { s_logger.error("ImplementNetworkVspCommand for network " + vspNetwork.getUuid() + " failed on Nuage VSD " + nuageVspHost.getDetail("hostname")); if ((null != answer) && (null != answer.getDetails())) { @@ -263,7 +345,9 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru { } return false; } - saveNetworkAndVpcDetails(vspNetwork, answer.getNetworkRelatedVsdIds(), vpcId); + + ImplementNetworkVspAnswer implementAnswer = (ImplementNetworkVspAnswer) answer; + saveNetworkAndVpcDetails(vspNetwork, implementAnswer.getNetworkRelatedVsdIds(), vpcId); return true; } @@ -274,23 +358,31 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru { long networkId = vspNetwork.getId(); for (Map.Entry networkDetail : networkDetails.entrySet()) { - _networkDetailsDao.addDetail(networkId, networkDetail.getKey(), networkDetail.getValue(), false); + saveNetworkDetail(vspNetwork.getId(), networkDetail.getKey(), networkDetail.getValue()); } if(vspNetwork.isVpc()) { Map vpcDetails = constructVpcDetails(networkRelatedVsdIds); for (Map.Entry vpcDetail : vpcDetails.entrySet()) { - _vpcDetailsDao.addDetail(vpcId, vpcDetail.getKey(), vpcDetail.getValue(), false); + saveVpcDetail(vpcId, vpcDetail.getKey(), vpcDetail.getValue()); } } } } + private void saveVpcDetail(Long vpcId, String key, String value) { + _vpcDetailsDao.addDetail(vpcId, key, value, false); + } + + private void saveNetworkDetail(long networkId, String key, String value) { + _networkDetailsDao.addDetail(networkId, key, value, false); + } + private static Map constructNetworkDetails(NetworkRelatedVsdIds networkRelatedVsdIds, boolean isVpc) { Map networkDetails = Maps.newHashMap(); - if(!isVpc) { + if (!isVpc) { networkRelatedVsdIds.getVsdDomainId().ifPresent(v -> networkDetails.put(NuageVspManager.NETWORK_METADATA_VSD_DOMAIN_ID, v)); networkRelatedVsdIds.getVsdZoneId().ifPresent(v -> networkDetails.put(NuageVspManager.NETWORK_METADATA_VSD_ZONE_ID, v)); } @@ -304,6 +396,9 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru { networkRelatedVsdIds.getVsdDomainId().ifPresent(v -> vpcDetails.put(NuageVspManager.NETWORK_METADATA_VSD_DOMAIN_ID, v)); networkRelatedVsdIds.getVsdZoneId().ifPresent(v -> vpcDetails.put(NuageVspManager.NETWORK_METADATA_VSD_ZONE_ID, v)); + if (networkRelatedVsdIds.isVsdManaged()) { + vpcDetails.put(NuageVspManager.NETWORK_METADATA_VSD_MANAGED, "true"); + } return vpcDetails; } @@ -355,7 +450,7 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru { if (vm.getType() == VirtualMachine.Type.DomainRouter && vspNetwork.getVirtualRouterIp().equals("null")) { //In case of upgrade network offering - vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(vm.getVirtualMachine().getDomainId(), network, true); + vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(vm.getVirtualMachine().getDomainId(), network, null, true); String broadcastUriStr = network.getUuid() + "/" + vspNetwork.getVirtualRouterIp(); NetworkVO updatedNetwork = _networkDao.createForUpdate(network.getId()); updatedNetwork.setBroadcastUri(Networks.BroadcastDomainType.Vsp.toUri(broadcastUriStr)); @@ -381,7 +476,7 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru { // Make sure the shared network is present NetworkOffering offering = _ntwkOfferingDao.findById(network.getNetworkOfferingId()); - if (!implement(network.getVpcId(), network.getPhysicalNetworkId(), vspNetwork, _nuageVspEntityBuilder.buildNetworkDhcpOption(network, offering))) { + if (!implement(network.getVpcId(), network.getPhysicalNetworkId(), vspNetwork, null, _nuageVspEntityBuilder.buildNetworkDhcpOption(network, offering))) { s_logger.error("Failed to implement shared network " + network.getUuid() + " under domain " + context.getDomain().getUuid()); throw new InsufficientVirtualNetworkCapacityException("Failed to implement shared network " + network.getUuid() + " under domain " + context.getDomain().getUuid(), Network.class, network.getId()); @@ -643,6 +738,15 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru { } VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(network); + + //Clean up VSD managed subnet caching + if (vspNetwork.getNetworkRelatedVsdIds().isVsdManaged()) { + final long dataCenterId = network.getDataCenterId(); + vspNetwork.getNetworkRelatedVsdIds().getVsdSubnetId().ifPresent(subnetId -> { + _dcDetailsDao.removeDetail(dataCenterId, subnetId); + }); + } + HostVO nuageVspHost = _nuageVspManager.getNuageVspHost(network.getPhysicalNetworkId()); TrashNetworkVspCommand cmd = new TrashNetworkVspCommand(vspNetwork); Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManager.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManager.java index 056b22eab41..6f91dc34276 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManager.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManager.java @@ -19,6 +19,11 @@ package com.cloud.network.manager; +import java.util.List; + +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.ConfigKey.Scope; + import com.cloud.agent.api.manager.EntityExistsCommand; import com.cloud.api.commands.AddNuageVspDeviceCmd; import com.cloud.api.commands.AssociateNuageVspDomainTemplateCmd; @@ -35,12 +40,8 @@ import com.cloud.network.Network; import com.cloud.network.NuageVspDeviceVO; import com.cloud.utils.component.PluggableService; -import org.apache.cloudstack.framework.config.ConfigKey; -import org.apache.cloudstack.framework.config.ConfigKey.Scope; -import java.util.List; - public interface NuageVspManager extends PluggableService { String nuageVspSharedNetworkOfferingWithSGServiceName = "DefaultNuageVspSharedNetworkOfferingWithSGService"; @@ -86,6 +87,8 @@ public interface NuageVspManager extends PluggableService { String NETWORK_METADATA_VSD_SUBNET_ID = "vsdSubnetId"; + String NETWORK_METADATA_VSD_MANAGED = "isVsdManaged"; + String CMSID_CONFIG_KEY = "nuagevsp.cms.id"; String NUAGE_VSP_ISOLATION = "VSP"; diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/resource/NuageVspResource.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/resource/NuageVspResource.java index 502b4bda7f2..a96b67097e8 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/resource/NuageVspResource.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/resource/NuageVspResource.java @@ -241,6 +241,16 @@ public class NuageVspResource extends ManagerBase implements ServerResource, Vsp return pingNuageVspCommand; } + public boolean getStatus() { + try { + login(); + return true; + } catch (NuageVspException | ConfigurationException e) { + s_logger.error("Failed to ping to Nuage VSD on " + _name + " as user " +_vspHost.getCmsUserLogin(), e); + return false; + } + } + @Override public Answer executeRequest(final Command cmd) { final NuageVspRequestWrapper wrapper = NuageVspRequestWrapper.getInstance(); diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/vsp/resource/wrapper/NuageVspCheckHealthCommandWrapper.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/vsp/resource/wrapper/NuageVspCheckHealthCommandWrapper.java new file mode 100644 index 00000000000..d66fc1b5441 --- /dev/null +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/vsp/resource/wrapper/NuageVspCheckHealthCommandWrapper.java @@ -0,0 +1,43 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.network.vsp.resource.wrapper; + +import javax.naming.ConfigurationException; + +import net.nuage.vsp.acs.client.exception.NuageVspException; + +import com.cloud.agent.api.CheckHealthCommand; +import com.cloud.network.resource.NuageVspResource; +import com.cloud.resource.ResourceWrapper; + +@ResourceWrapper(handles = CheckHealthCommand.class) +public class NuageVspCheckHealthCommandWrapper extends NuageVspCommandWrapper { + + @Override + public boolean executeNuageVspCommand(CheckHealthCommand cmd, NuageVspResource nuageVspResource) throws ConfigurationException, NuageVspException { + return nuageVspResource.getStatus(); + } + + @Override + public StringBuilder fillDetail(StringBuilder stringBuilder, CheckHealthCommand cmd) { + return stringBuilder.append("Check Health"); + } + +} diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/vsp/resource/wrapper/NuageVspCommandWrapper.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/vsp/resource/wrapper/NuageVspCommandWrapper.java index 879ba812a1b..3e3c4a12c44 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/vsp/resource/wrapper/NuageVspCommandWrapper.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/vsp/resource/wrapper/NuageVspCommandWrapper.java @@ -45,7 +45,7 @@ public abstract class NuageVspCommandWrapper extends CommandW } catch (NuageVspUnsupportedRequestException e) { s_logger.error("Failure during " + command + " on " + nuageVspResource.getName(), e); return new UnsupportedAnswer(command, e.getMessage()); //New Exception so there is no stacktrace showed in the UI when changing ACL lists. - } catch (NuageVspException | ConfigurationException e) { + } catch (Exception e) { s_logger.error("Failure during " + command + " on " + nuageVspResource.getName(), e); return new Answer(command, e); } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/vsp/resource/wrapper/NuageVspGuruImplementNetworkCommandWrapper.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/vsp/resource/wrapper/NuageVspGuruImplementNetworkCommandWrapper.java index 1e57e244e65..4d2ef637386 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/vsp/resource/wrapper/NuageVspGuruImplementNetworkCommandWrapper.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/vsp/resource/wrapper/NuageVspGuruImplementNetworkCommandWrapper.java @@ -19,11 +19,9 @@ package com.cloud.network.vsp.resource.wrapper; -import javax.naming.ConfigurationException; - import net.nuage.vsp.acs.client.api.NuageVspGuruClient; import net.nuage.vsp.acs.client.api.model.NetworkRelatedVsdIds; -import net.nuage.vsp.acs.client.exception.NuageVspException; +import net.nuage.vsp.acs.client.api.model.VspNetwork; import com.cloud.agent.api.guru.ImplementNetworkVspCommand; import com.cloud.agent.api.manager.ImplementNetworkVspAnswer; @@ -38,9 +36,14 @@ public final class NuageVspGuruImplementNetworkCommandWrapper extends CommandWra public ImplementNetworkVspAnswer execute(ImplementNetworkVspCommand command, NuageVspResource serverResource) { try { NuageVspGuruClient client = serverResource.getNuageVspGuruClient(); - NetworkRelatedVsdIds networkRelatedVsdIds = client.implement(command.getNetwork(), command.getDhcpOption()); - return new ImplementNetworkVspAnswer(command, networkRelatedVsdIds); - } catch (ConfigurationException | NuageVspException e) { + if (command.isVsdManaged()) { + VspNetwork vspNetwork = client.addPermissionL3Network(command.getNetwork()); + return new ImplementNetworkVspAnswer(command, vspNetwork, vspNetwork.getNetworkRelatedVsdIds()); + } else { + NetworkRelatedVsdIds networkRelatedVsdIds = client.implement(command.getNetwork(), command.getDhcpOption()); + return new ImplementNetworkVspAnswer(command, command.getNetwork(), networkRelatedVsdIds); + } + } catch (Exception e) { return new ImplementNetworkVspAnswer(command, e); } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/vsp/resource/wrapper/NuageVspShutdownVpcCommandWrapper.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/vsp/resource/wrapper/NuageVspShutdownVpcCommandWrapper.java index d2d9ea705b2..a3910cfa5a0 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/vsp/resource/wrapper/NuageVspShutdownVpcCommandWrapper.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/vsp/resource/wrapper/NuageVspShutdownVpcCommandWrapper.java @@ -31,7 +31,7 @@ import com.cloud.resource.ResourceWrapper; public final class NuageVspShutdownVpcCommandWrapper extends NuageVspCommandWrapper { @Override public boolean executeNuageVspCommand(ShutDownVpcVspCommand cmd, NuageVspResource nuageVspResource) throws ConfigurationException, NuageVspException { - nuageVspResource.getNuageVspElementClient().shutdownVpc(cmd.getDomainUuid(), cmd.getVpcUuid(), cmd.getDomainTemplateName(), cmd.getDomainRouterUuids()); + nuageVspResource.getNuageVspElementClient().shutdownVpc(cmd.getDomainUuid(), cmd.getVpcUuid(), cmd.getDomainTemplateName(), cmd.getDomainRouterUuids(), cmd.getRelatedVsdIds()); return true; } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspEntityBuilder.java b/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspEntityBuilder.java index c024a7b6adb..b34337fe2aa 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspEntityBuilder.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspEntityBuilder.java @@ -43,6 +43,7 @@ import net.nuage.vsp.acs.client.api.model.VspStaticNat; import net.nuage.vsp.acs.client.api.model.VspVm; import net.nuage.vsp.acs.client.common.model.Pair; +import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; @@ -50,7 +51,7 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.resourcedetail.dao.VpcDetailsDao; import com.cloud.dc.Vlan; import com.cloud.dc.VlanVO; @@ -88,8 +89,6 @@ import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.NicSecondaryIpDao; import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.dao.VMInstanceDao; -import org.apache.cloudstack.resourcedetail.dao.VpcDetailsDao; -import org.apache.commons.collections.MapUtils; public class NuageVspEntityBuilder { private static final Logger s_logger = Logger.getLogger(NuageVspEntityBuilder.class); @@ -113,8 +112,6 @@ public class NuageVspEntityBuilder { @Inject VlanDetailsDao _vlanDetailsDao; @Inject - ConfigurationDao _configurationDao; - @Inject IPAddressDao _ipAddressDao; @Inject NetworkDetailsDao _networkDetailsDao; @@ -160,18 +157,30 @@ public class NuageVspEntityBuilder { } public VspNetwork buildVspNetwork(Network network) { - return buildVspNetwork(network.getDomainId(), network, false); - } - - public VspNetwork buildVspNetwork(long domainId, Network network) { - return buildVspNetwork(domainId, network, false); + return buildVspNetwork(network.getDomainId(), network, null, false); } public VspNetwork buildVspNetwork(Network network, boolean recalculateBroadcastUri) { - return buildVspNetwork(network.getDomainId(), network, recalculateBroadcastUri); + return buildVspNetwork(network.getDomainId(), network, null, recalculateBroadcastUri); + } + + public VspNetwork buildVspNetwork(Network network, String vsdSubnetId) { + return buildVspNetwork(network.getDomainId(), network, vsdSubnetId, false); + } + + public VspNetwork buildVspNetwork(long domainId, Network network) { + return buildVspNetwork(domainId, network, null, false); } public VspNetwork buildVspNetwork(long domainId, Network network, boolean recalculateBroadcastUri) { + return buildVspNetwork(domainId, network, null, recalculateBroadcastUri); + } + + public VspNetwork buildVspNetwork(long domainId, Network network, String vsdSubnetId) { + return buildVspNetwork(domainId, network, vsdSubnetId, false); + } + + public VspNetwork buildVspNetwork(long domainId, Network network, String vsdSubnetId, boolean recalculateBroadcastUri) { VspNetwork.Builder vspNetworkBuilder = new VspNetwork.Builder() .id(network.getId()) .uuid(network.getUuid()) @@ -183,21 +192,26 @@ public class NuageVspEntityBuilder { VspDomain vspDomain = buildVspDomain(domain); vspNetworkBuilder.domain(vspDomain); + AccountVO account = _accountDao.findById(network.getAccountId()); if (account != null) { vspNetworkBuilder.accountUuid(account.getUuid()).accountName(account.getAccountName()); } NetworkOfferingVO networkOffering = _networkOfferingDao.findById(network.getNetworkOfferingId()); - vspNetworkBuilder.egressDefaultPolicy(networkOffering.getEgressDefaultPolicy()).publicAccess(networkOffering.getSupportsPublicAccess()); + vspNetworkBuilder.egressDefaultPolicy(networkOffering.getEgressDefaultPolicy()) + .publicAccess(networkOffering.getSupportsPublicAccess()); Map networkDetails = _networkDetailsDao.listDetailsKeyPairs(network.getId(), false); - String vsdSubnetId = null; - String vsdZoneId = null; - String vsdDomainId = null; + + final NetworkRelatedVsdIds.Builder relatedVsdIdsBuilder = new NetworkRelatedVsdIds.Builder(); if (MapUtils.isNotEmpty(networkDetails)) { - vsdSubnetId = networkDetails.get(NuageVspManager.NETWORK_METADATA_VSD_SUBNET_ID); + relatedVsdIdsBuilder.vsdSubnetId(networkDetails.get(NuageVspManager.NETWORK_METADATA_VSD_SUBNET_ID)) + .withVsdManaged("true".equals(networkDetails.get(NuageVspManager.NETWORK_METADATA_VSD_MANAGED))); + } else if (vsdSubnetId != null) { + relatedVsdIdsBuilder.vsdSubnetId(vsdSubnetId) + .withVsdManaged("true".equals(networkDetails.get(NuageVspManager.NETWORK_METADATA_VSD_MANAGED))); } if (network.getVpcId() != null) { @@ -207,16 +221,9 @@ public class NuageVspEntityBuilder { .vpcName(vpc.getName()) .networkType(VspNetwork.NetworkType.Vpc); Map vpcDetails = _vpcDetailsDao.listDetailsKeyPairs(vpcId, false); - if (MapUtils.isNotEmpty(vpcDetails)) { - vsdDomainId = vpcDetails.get(NuageVspManager.NETWORK_METADATA_VSD_DOMAIN_ID); - vsdZoneId = vpcDetails.get(NuageVspManager.NETWORK_METADATA_VSD_ZONE_ID); - } - + applyDomainAndZoneId(relatedVsdIdsBuilder, vpcDetails); } else { - if (MapUtils.isNotEmpty(networkDetails)) { - vsdDomainId = networkDetails.get(NuageVspManager.NETWORK_METADATA_VSD_DOMAIN_ID); - vsdZoneId = networkDetails.get(NuageVspManager.NETWORK_METADATA_VSD_ZONE_ID); - } + applyDomainAndZoneId(relatedVsdIdsBuilder, networkDetails); if (networkOffering.getGuestType() == Network.GuestType.Shared) { List vlans = _vlanDao.listVlansByNetworkIdIncludingRemoved(network.getId()); @@ -238,11 +245,7 @@ public class NuageVspEntityBuilder { } - NetworkRelatedVsdIds networkRelatedVsdIds = new NetworkRelatedVsdIds.Builder() - .vsdDomainId(vsdDomainId) - .vsdSubnetId(vsdSubnetId) - .vsdZoneId(vsdZoneId) - .build(); + NetworkRelatedVsdIds networkRelatedVsdIds = relatedVsdIdsBuilder.build(); vspNetworkBuilder.networkRelatedVsdIds(networkRelatedVsdIds); boolean firewallServiceSupported = _networkModel.areServicesSupportedByNetworkOffering(network.getNetworkOfferingId(), Network.Service.Firewall); @@ -266,6 +269,14 @@ public class NuageVspEntityBuilder { return vspNetworkBuilder.build(); } + private void applyDomainAndZoneId(NetworkRelatedVsdIds.Builder relatedVsdIdsBuilder, Map details) { + if (MapUtils.isNotEmpty(details)) { + relatedVsdIdsBuilder + .vsdDomainId(details.get(NuageVspManager.NETWORK_METADATA_VSD_DOMAIN_ID)) + .vsdZoneId(details.get(NuageVspManager.NETWORK_METADATA_VSD_ZONE_ID)); + } + } + public boolean usesVirtualRouter(long networkOfferingId) { return _networkOfferingServiceMapDao.isProviderForNetworkOffering(networkOfferingId, Network.Provider.VirtualRouter) || _networkOfferingServiceMapDao.isProviderForNetworkOffering(networkOfferingId, Network.Provider.VPCVirtualRouter); diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/NuageTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/NuageTest.java index fea759dccdf..ae383bfea0b 100644 --- a/plugins/network-elements/nuage-vsp/test/com/cloud/NuageTest.java +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/NuageTest.java @@ -146,7 +146,6 @@ public class NuageTest { return new NetworkRelatedVsdIds.Builder() .vsdZoneId("vsdZoneId") .vsdDomainId("vsdDomainId") - .vsdEnterpriseId("vsdEnterpriseId") .vsdSubnetId("vsdSubnetId") .build(); } diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/network/guru/NuageVspGuestNetworkGuruTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/network/guru/NuageVspGuestNetworkGuruTest.java index d8bdd4bda18..957408d06dc 100644 --- a/plugins/network-elements/nuage-vsp/test/com/cloud/network/guru/NuageVspGuestNetworkGuruTest.java +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/network/guru/NuageVspGuestNetworkGuruTest.java @@ -31,6 +31,7 @@ import org.junit.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.internal.util.collections.Sets; +import org.mockito.invocation.InvocationOnMock; import com.google.common.collect.ImmutableMap; @@ -45,6 +46,7 @@ import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.DataCenterVO; import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.DataCenterDetailsDao; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; import com.cloud.domain.Domain; @@ -110,6 +112,7 @@ public class NuageVspGuestNetworkGuruTest extends NuageTest { @Mock private IPAddressDao _ipAddressDao; @Mock private NuageVspManager _nuageVspManager; @Mock private ConfigurationManager _configurationManager; + @Mock private DataCenterDetailsDao _dcDetailsDao; @Mock private NetworkDetailsDao _networkDetailsDao; @Mock private PhysicalNetworkVO physnet; @@ -138,7 +141,7 @@ public class NuageVspGuestNetworkGuruTest extends NuageTest { when(_hostDao.findById(NETWORK_ID)).thenReturn(host); when(host.getId()).thenReturn(NETWORK_ID); when(_agentManager.easySend(eq(NETWORK_ID), any(Command.class))).thenReturn(new Answer(null)); - when(_agentManager.easySend(eq(NETWORK_ID), any(ImplementNetworkVspCommand.class))).thenReturn(new ImplementNetworkVspAnswer(null, new NetworkRelatedVsdIds.Builder().build())); + when(_agentManager.easySend(eq(NETWORK_ID), any(ImplementNetworkVspCommand.class))).thenAnswer(this::mockImplement); when(_nuageVspManager.getNuageVspHost(NETWORK_ID)).thenReturn(host); final NuageVspDeviceVO device = mock(NuageVspDeviceVO.class); @@ -147,6 +150,15 @@ public class NuageVspGuestNetworkGuruTest extends NuageTest { when(device.getHostId()).thenReturn(NETWORK_ID); } + Answer mockImplement(InvocationOnMock invocation) { + if (invocation.getArguments()[1] instanceof ImplementNetworkVspCommand) { + ImplementNetworkVspCommand command = (ImplementNetworkVspCommand)(invocation.getArguments()[1]); + return new ImplementNetworkVspAnswer(command, command.getNetwork(), new NetworkRelatedVsdIds.Builder().build()); + } else { + return new Answer(null); + } + } + @Test public void testCanHandle() { final NetworkOffering offering = mock(NetworkOffering.class); diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/network/resource/NuageVspResourceTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/network/resource/NuageVspResourceTest.java index fb67e6ff9d7..560f53dbda2 100644 --- a/plugins/network-elements/nuage-vsp/test/com/cloud/network/resource/NuageVspResourceTest.java +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/network/resource/NuageVspResourceTest.java @@ -20,6 +20,7 @@ package com.cloud.network.resource; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -152,12 +153,25 @@ public class NuageVspResourceTest extends NuageTest { VspNetwork vspNetwork = buildVspNetwork(); VspDhcpDomainOption vspDhcpOptions = buildspDhcpDomainOption(); - ImplementNetworkVspCommand cmd = new ImplementNetworkVspCommand(vspNetwork, vspDhcpOptions); + ImplementNetworkVspCommand cmd = new ImplementNetworkVspCommand(vspNetwork, vspDhcpOptions, false); ImplementNetworkVspAnswer implNtwkAns = (ImplementNetworkVspAnswer)_resource.executeRequest(cmd); assertTrue(implNtwkAns.getResult()); verify(_mockNuageVspGuruClient).implement(vspNetwork, vspDhcpOptions); } + @Test + public void testImplementVsdManagedNetworkVspCommand() throws Exception { + _resource.configure("NuageVspResource", _hostDetails); + + VspNetwork vspNetwork = buildVspNetwork(); + VspDhcpDomainOption vspDhcpOptions = buildspDhcpDomainOption(); + when(_mockNuageVspGuruClient.addPermissionL3Network(vspNetwork)).thenReturn(vspNetwork); + ImplementNetworkVspCommand cmd = new ImplementNetworkVspCommand(vspNetwork, vspDhcpOptions, true); + ImplementNetworkVspAnswer implNtwkAns = (ImplementNetworkVspAnswer)_resource.executeRequest(cmd); + assertTrue(implNtwkAns.getResult()); + verify(_mockNuageVspGuruClient).addPermissionL3Network(vspNetwork); + } + @Test public void testReserveVmInterfaceVspCommand() throws Exception { _resource.configure("NuageVspResource", _hostDetails); @@ -220,7 +234,7 @@ public class NuageVspResourceTest extends NuageTest { public void testShutDownVpcVspCommand() throws Exception { _resource.configure("NuageVspResource", _hostDetails); - ShutDownVpcVspCommand cmd = new ShutDownVpcVspCommand("domainUuid", "vpcUuid", "domainTemplateName", Lists.newArrayList()); + ShutDownVpcVspCommand cmd = new ShutDownVpcVspCommand("domainUuid", "vpcUuid", "domainTemplateName", Lists.newArrayList(), new HashMap<>()); Answer shutVpcAns = _resource.executeRequest(cmd); assertTrue(shutVpcAns.getResult()); } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 19730d0fc9c..c4e337ed96c 100644 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -2206,6 +2206,7 @@ public class ApiResponseHelper implements ResponseGenerator { } response.setNetworkSpannedZones(networkSpannedZones); } + response.setExternalId(network.getExternalId()); response.setObjectName("network"); return response; } diff --git a/server/src/com/cloud/network/IpAddressManagerImpl.java b/server/src/com/cloud/network/IpAddressManagerImpl.java index 55e842b7741..51809589e16 100644 --- a/server/src/com/cloud/network/IpAddressManagerImpl.java +++ b/server/src/com/cloud/network/IpAddressManagerImpl.java @@ -1662,7 +1662,7 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage s_logger.debug("Creating network for account " + owner + " from the network offering id=" + requiredOfferings.get(0).getId() + " as a part of createVlanIpRange process"); guestNetwork = _networkMgr.createGuestNetwork(requiredOfferings.get(0).getId(), owner.getAccountName() + "-network", owner.getAccountName() - + "-network", null, null, null, false, null, owner, null, physicalNetwork, zoneId, ACLType.Account, null, null, null, null, true, null); + + "-network", null, null, null, false, null, owner, null, physicalNetwork, zoneId, ACLType.Account, null, null, null, null, true, null, null); if (guestNetwork == null) { s_logger.warn("Failed to create default Virtual network for the account " + accountId + "in zone " + zoneId); throw new CloudRuntimeException("Failed to create a Guest Isolated Networks with SourceNAT " diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index a2b5dc1b3f5..81ab2b141e1 100644 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -103,6 +103,7 @@ import com.cloud.network.dao.AccountGuestVlanMapVO; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.LoadBalancerDao; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkDetailVO; import com.cloud.network.dao.NetworkDetailsDao; @@ -192,7 +193,6 @@ import com.cloud.vm.dao.NicSecondaryIpDao; import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; -import com.cloud.network.dao.LoadBalancerDao; /** * NetworkServiceImpl implements NetworkService. @@ -1031,6 +1031,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { Boolean displayNetwork = cmd.getDisplayNetwork(); Long aclId = cmd.getAclId(); String isolatedPvlan = cmd.getIsolatedPvlan(); + String externalId = cmd.getExternalId(); // Validate network offering NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId); @@ -1292,7 +1293,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { Network network = commitNetwork(networkOfferingId, gateway, startIP, endIP, netmask, networkDomain, vlanId, bypassVlanOverlapCheck, name, displayText, caller, physicalNetworkId, zoneId, domainId, isDomainSpecific, subdomainAccess, vpcId, startIPv6, endIPv6, ip6Gateway, ip6Cidr, displayNetwork, aclId, isolatedPvlan, ntwkOff, pNtwk, aclType, owner, cidr, - createVlan); + createVlan, externalId); // if the network offering has persistent set to true, implement the network if (ntwkOff.getIsPersistent()) { @@ -1325,7 +1326,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { final String vlanId, final Boolean bypassVlanOverlapCheck, final String name, final String displayText, final Account caller, final Long physicalNetworkId, final Long zoneId, final Long domainId, final boolean isDomainSpecific, final Boolean subdomainAccessFinal, final Long vpcId, final String startIPv6, final String endIPv6, final String ip6Gateway, final String ip6Cidr, final Boolean displayNetwork, final Long aclId, final String isolatedPvlan, final NetworkOfferingVO ntwkOff, final PhysicalNetwork pNtwk, - final ACLType aclType, final Account ownerFinal, final String cidr, final boolean createVlan) throws InsufficientCapacityException, ResourceAllocationException { + final ACLType aclType, final Account ownerFinal, final String cidr, final boolean createVlan, final String externalId) throws InsufficientCapacityException, ResourceAllocationException { try { Network network = Transaction.execute(new TransactionCallbackWithException() { @Override @@ -1370,7 +1371,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } } network = _vpcMgr.createVpcGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId, networkDomain, owner, sharedDomainId, pNtwk, zoneId, - aclType, subdomainAccess, vpcId, aclId, caller, displayNetwork); + aclType, subdomainAccess, vpcId, aclId, caller, displayNetwork, externalId); } else { if (_configMgr.isOfferingForVpc(ntwkOff)) { throw new InvalidParameterValueException("Network offering can be used for VPC networks only"); @@ -1380,7 +1381,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } network = _networkMgr.createGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId, bypassVlanOverlapCheck, networkDomain, owner, sharedDomainId, pNtwk, zoneId, - aclType, subdomainAccess, vpcId, ip6Gateway, ip6Cidr, displayNetwork, isolatedPvlan); + aclType, subdomainAccess, vpcId, ip6Gateway, ip6Cidr, displayNetwork, isolatedPvlan, externalId); } if (_accountMgr.isRootAdmin(caller.getId()) && createVlan && network != null) { @@ -4335,7 +4336,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { if (privateNetwork == null) { //create Guest network privateNetwork = _networkMgr.createGuestNetwork(ntwkOffFinal.getId(), networkName, displayText, gateway, cidr, uriString, false, null, owner, null, pNtwk, - pNtwk.getDataCenterId(), ACLType.Account, null, vpcId, null, null, true, null); + pNtwk.getDataCenterId(), ACLType.Account, null, vpcId, null, null, true, null, null); if (privateNetwork != null) { s_logger.debug("Successfully created guest network " + privateNetwork); } else { diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index d1a6fb55909..1f0753a9509 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -38,6 +38,9 @@ import javax.annotation.PostConstruct; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.commons.collections.CollectionUtils; +import org.apache.log4j.Logger; + import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.api.command.user.vpc.ListPrivateGatewaysCmd; import org.apache.cloudstack.api.command.user.vpc.ListStaticRoutesCmd; @@ -45,8 +48,6 @@ import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.managed.context.ManagedContextRunnable; -import org.apache.commons.collections.CollectionUtils; -import org.apache.log4j.Logger; import com.cloud.configuration.Config; import com.cloud.configuration.Resource.ResourceType; @@ -2316,7 +2317,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis @Override public Network createVpcGuestNetwork(final long ntwkOffId, final String name, final String displayText, final String gateway, final String cidr, final String vlanId, String networkDomain, final Account owner, final Long domainId, final PhysicalNetwork pNtwk, final long zoneId, final ACLType aclType, final Boolean subdomainAccess, - final long vpcId, final Long aclId, final Account caller, final Boolean isDisplayNetworkEnabled) throws ConcurrentOperationException, InsufficientCapacityException, + final long vpcId, final Long aclId, final Account caller, final Boolean isDisplayNetworkEnabled, String externalId) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { final Vpc vpc = getActiveVpc(vpcId); @@ -2341,7 +2342,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis // 2) Create network final Network guestNetwork = _ntwkMgr.createGuestNetwork(ntwkOffId, name, displayText, gateway, cidr, vlanId, false, networkDomain, owner, domainId, pNtwk, zoneId, aclType, - subdomainAccess, vpcId, null, null, isDisplayNetworkEnabled, null); + subdomainAccess, vpcId, null, null, isDisplayNetworkEnabled, null, externalId); if (guestNetwork != null) { guestNetwork.setNetworkACLId(aclId); diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 3591e603b0a..c4edf4fa112 100644 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -3156,7 +3156,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir } s_logger.debug("Creating network for account " + owner + " from the network offering id=" + requiredOfferings.get(0).getId() + " as a part of deployVM process"); Network newNetwork = _networkMgr.createGuestNetwork(requiredOfferings.get(0).getId(), owner.getAccountName() + "-network", owner.getAccountName() + "-network", - null, null, null, false, null, owner, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, null, null, true, null); + null, null, null, false, null, owner, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, null, null, true, null, + null); if (newNetwork != null) { defaultNetwork = _networkDao.findById(newNetwork.getId()); } @@ -5795,8 +5796,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir s_logger.debug("Creating network for account " + newAccount + " from the network offering id=" + requiredOfferings.get(0).getId() + " as a part of deployVM process"); Network newNetwork = _networkMgr.createGuestNetwork(requiredOfferings.get(0).getId(), newAccount.getAccountName() + "-network", - newAccount.getAccountName() + "-network", null, null, null, false, null, newAccount, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, - null, null, true, null); + newAccount.getAccountName() + "-network", null, null, null, false, null, newAccount, + null, physicalNetwork, zone.getId(), ACLType.Account, null, null, + null, null, true, null, null); // if the network offering has persistent set to true, implement the network if (requiredOfferings.get(0).getIsPersistent()) { DeployDestination dest = new DeployDestination(zone, null, null, null); diff --git a/server/test/com/cloud/network/CreatePrivateNetworkTest.java b/server/test/com/cloud/network/CreatePrivateNetworkTest.java index 5b6ead02559..2e06039ccd5 100644 --- a/server/test/com/cloud/network/CreatePrivateNetworkTest.java +++ b/server/test/com/cloud/network/CreatePrivateNetworkTest.java @@ -122,8 +122,8 @@ public class CreatePrivateNetworkTest { ACLType.Account, false, 1L, false); when( networkService._networkMgr.createGuestNetwork(eq(ntwkOff.getId()), eq("bla"), eq("fake"), eq("10.1.1.1"), eq("10.1.1.0/24"), anyString(), anyBoolean(), anyString(), - eq(account), anyLong(), eq(physicalNetwork), eq(physicalNetwork.getDataCenterId()), eq(ACLType.Account), anyBoolean(), eq(1L), anyString(), anyString(), - anyBoolean(), anyString())).thenReturn(net); + eq(account), anyLong(), eq(physicalNetwork), eq(physicalNetwork.getDataCenterId()), eq(ACLType.Account), anyBoolean(), eq(1L), anyString(), anyString(), + anyBoolean(), anyString(), anyString())).thenReturn(net); when(networkService._privateIpDao.findByIpAndSourceNetworkId(net.getId(), "10.1.1.2")).thenReturn(null); when(networkService._privateIpDao.findByIpAndSourceNetworkIdAndVpcId(eq(1L), anyString(), eq(1L))).thenReturn(null); diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index cdf7180febe..d68b7c9e96d 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -638,7 +638,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches @Override public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, boolean bypassVlanOverlapCheck, String networkDomain, Account owner, Long domainId, PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String gatewayv6, - String cidrv6, Boolean displayNetworkEnabled, String isolatedPvlan) throws ConcurrentOperationException, InsufficientCapacityException, + String cidrv6, Boolean displayNetworkEnabled, String isolatedPvlan, String externalId) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { // TODO Auto-generated method stub return null; diff --git a/test/integration/plugins/nuagevsp/nuageTestCase.py b/test/integration/plugins/nuagevsp/nuageTestCase.py index aaeb97ad8d3..45db7913ceb 100644 --- a/test/integration/plugins/nuagevsp/nuageTestCase.py +++ b/test/integration/plugins/nuagevsp/nuageTestCase.py @@ -387,7 +387,7 @@ class nuageTestCase(cloudstackTestCase): @needscleanup def create_Network(cls, nw_off, gateway="10.1.1.1", netmask="255.255.255.0", vpc=None, acl_list=None, - testdata=None, account=None, vlan=None): + testdata=None, account=None, vlan=None, externalid=None): if not account: account = cls.account cls.debug("Creating a network in the account - %s" % account.name) @@ -404,6 +404,7 @@ class nuageTestCase(cloudstackTestCase): zoneid=cls.zone.id, gateway=gateway, vlan=vlan, + externalid=externalid, vpcid=vpc.id if vpc else cls.vpc.id if hasattr(cls, "vpc") else None, aclid=acl_list.id if acl_list else None diff --git a/test/integration/plugins/nuagevsp/test_nuage_vsp_mngd_subnets.py b/test/integration/plugins/nuagevsp/test_nuage_vsp_mngd_subnets.py new file mode 100644 index 00000000000..ebbcccb7fc0 --- /dev/null +++ b/test/integration/plugins/nuagevsp/test_nuage_vsp_mngd_subnets.py @@ -0,0 +1,512 @@ +# 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. + +""" Component tests for VSP Managed Subnets functionality + with Nuage VSP SDN plugin +""" +# Import Local Modules +from nuageTestCase import nuageTestCase +from marvin.lib.base import (Account, + VirtualMachine) +from marvin.cloudstackAPI import updateZone + +# Import System Modules +from nose.plugins.attrib import attr +import time + + +class TestNuageManagedSubnets(nuageTestCase): + """Test Managed Subnets functionality with Nuage VSP SDN plugin + """ + + @classmethod + def setUpClass(cls): + super(TestNuageManagedSubnets, cls).setUpClass() + + # create a nuage vpc offering + cls.nuage_vpc_offering = \ + cls.create_VpcOffering(cls.test_data["nuagevsp"]["vpc_offering"]) + + # tier network offerings + cls.nuage_vpc_network_offering = \ + cls.create_NetworkOffering(cls.test_data["nuagevsp"] + ["vpc_network_offering"]) + + # create a Nuage isolated network offering with vr + cls.nuage_isolated_network_offering = cls.create_NetworkOffering( + cls.test_data["nuagevsp"]["isolated_network_offering"], True) + + # create a Nuage isolated network offering with vr and persistent + cls.nuage_isolated_network_offering_persistent = \ + cls.create_NetworkOffering( + cls.test_data["nuagevsp"] + ["isolated_network_offering_persistent"], + True) + + # create a Nuage isolated network offering without vr + cls.nuage_isolated_network_offering_without_vr = \ + cls.create_NetworkOffering( + cls.test_data["nuagevsp"] + ["isolated_network_offering_without_vr"], + True) + + # create a Nuage isolated network offering without vr but persistent + cls.nuage_isolated_network_offering_without_vr_persistent = \ + cls.create_NetworkOffering( + cls.test_data["nuagevsp"] + ["isolated_network_offering_without_vr_persistent"], + True) + + # create a Nuage shared network offering + cls.nuage_shared_network_offering = cls.create_NetworkOffering( + cls.test_data["nuagevsp"]["shared_nuage_network_offering"], + False) + + cls._cleanup = [ + cls.nuage_isolated_network_offering, + cls.nuage_isolated_network_offering_persistent, + cls.nuage_isolated_network_offering_without_vr, + cls.nuage_isolated_network_offering_without_vr_persistent, + cls.nuage_vpc_offering, + cls.nuage_vpc_network_offering, + cls.nuage_shared_network_offering + ] + return + + def setUp(self): + # Create an account + self.account = Account.create(self.api_client, + self.test_data["account"], + admin=True, + domainid=self.domain.id + ) + self.cleanup = [self.account] + return + + def verify_pingtovmipaddress(self, ssh, pingtovmipaddress): + """verify ping to ipaddress of the vm and retry 3 times""" + + if self.isSimulator: + return + + successfull_ping = False + nbr_retries = 0 + max_retries = 5 + cmd = 'ping -c 2 ' + pingtovmipaddress + + while not successfull_ping and nbr_retries < max_retries: + self.debug("ping vm by ipaddress with command: " + cmd) + outputlist = ssh.execute(cmd) + self.debug("command is executed properly " + cmd) + completeoutput = str(outputlist).strip('[]') + self.debug("complete output is " + completeoutput) + if '2 received' in completeoutput: + self.debug("PASS as vm is pingeable: " + completeoutput) + successfull_ping = True + else: + self.debug("FAIL as vm is not pingeable: " + completeoutput) + time.sleep(3) + nbr_retries = nbr_retries + 1 + + if not successfull_ping: + self.fail("FAILED TEST as excepted value not found in vm") + + def tearDown(self): + super(TestNuageManagedSubnets, self).tearDown() + # Cleanup resources used + self.debug("Cleaning up the resources") + for obj in reversed(self.cleanup): + try: + if isinstance(obj, VirtualMachine): + obj.delete(self.api_client, expunge=True) + else: + obj.delete(self.api_client) + except Exception as e: + self.error("Failed to cleanup %s, got %s" % (obj, e)) + # cleanup_resources(self.api_client, self.cleanup) + self.cleanup = [] + self.debug("Cloudstack Cleanup complete!") + enterprise = self.fetch_by_externalID(self._session.user.enterprises, + self.domain) + domain_template = enterprise.domain_templates.get_first() + domain_template.delete() + self.debug("VSD Cleanup complete!") + return + + @attr(tags=["advanced", "nuagevsp", "isonw"], required_hardware="false") + def test_01_nuage_mngd_subnets_isonw(self): + """Test Nuage VSP Managed Subnets for isolated networks + """ + + # 1. Create multiple L3DomainTemplate with Zone and Subnet on VSP + # Create Ingress & Egress ACL Top & Bottom Templates + # Add ACL rules to allow intra-subnet traffic + # Instiantiate these L3Domains and store its Subnet VSD ID + # 2. Create a persistent and non persistent isolated network offering + # create offerings with and without VirtualRouter + # 3. Create isolated networks specifying above offerings and + # specifying the stored Subnet ID's of VSP + # 4. Verify ACL rules and connectivity via deploying VM's , + # Enabling staticNAT, applying firewall and egress rules + + # Create all items on vsd required for this test + enterprise = self.fetch_by_externalID(self._session.user.enterprises, + self.domain) + domain_template = self.create_vsd_domain_template(enterprise) + + self.create_vsd_default_acls(domain_template) + + domain1 = self.create_vsd_domain(domain_template, enterprise, + "L3DomainToBeConsumedByACS") + zone1 = self.create_vsd_zone(domain1, "ZoneToBeConsumedByACS") + subnet1 = self.create_vsd_subnet(zone1, "SubnetToBeConsumedByACS", + "10.0.0.1/24") + + domain2 = self.create_vsd_domain(domain_template, enterprise, + "2ndL3DomainToBeConsumedByACS") + zone2 = self.create_vsd_zone(domain2, "2ndZoneToBeConsumedByACS") + subnet2 = self.create_vsd_subnet(zone2, "2ndSubnetToBeConsumedByACS", + "10.1.0.1/24") + + domain3 = self.create_vsd_domain(domain_template, enterprise, + "3rdL3DomainToBeConsumedByACS") + zone3 = self.create_vsd_zone(domain3, "3rdZoneToBeConsumedByACS") + subnet3 = self.create_vsd_subnet(zone3, "3rdSubnetToBeConsumedByACS", + "10.2.0.1/24") + + # On ACS create network using non-persistent nw offering allow + isolated_network = self.create_Network( + self.nuage_isolated_network_offering, + gateway="10.0.0.1", netmask="255.255.255.0", + externalid=subnet1.id) + + # On ACS create network using persistent nw offering allow + isolated_network2 = self.create_Network( + self.nuage_isolated_network_offering_persistent, + gateway="10.1.0.1", netmask="255.255.255.0", + externalid=subnet2.id) + + try: + self.create_Network( + self.nuage_shared_network_offering, gateway="10.2.0.1", + netmask="255.255.255.0", vlan=1201, externalid=subnet3.id) + except Exception as e: + self.debug("Shared Network Creation fails with %s" % e) + + # verify floating ip and intra subnet connectivity + vm_1 = self.create_VM(isolated_network) + vm_2 = self.create_VM(isolated_network) + self.debug("Creating Static NAT rule for the deployed VM in the " + "non persistently created Isolated network...") + public_ip = self.acquire_PublicIPAddress(isolated_network) + self.validate_PublicIPAddress(public_ip, isolated_network) + self.create_StaticNatRule_For_VM(vm_1, public_ip, isolated_network) + self.validate_PublicIPAddress( + public_ip, isolated_network, static_nat=True, vm=vm_1) + self.create_FirewallRule(public_ip, self.test_data["ingress_rule"]) + + if not self.isSimulator: + vm_public_ip = public_ip.ipaddress.ipaddress + try: + vm_1.ssh_ip = vm_public_ip + vm_1.ssh_port = self.test_data["virtual_machine"]["ssh_port"] + vm_1.username = self.test_data["virtual_machine"]["username"] + vm_1.password = self.test_data["virtual_machine"]["password"] + self.debug("SSHing into VM: %s with %s" % + (vm_1.ssh_ip, vm_1.password)) + + ssh = vm_1.get_ssh_client(ipaddress=vm_public_ip) + + except Exception as e: + self.fail("SSH into VM failed with exception %s" % e) + + self.verify_pingtovmipaddress(ssh, vm_2.ipaddress) + + vm_3 = self.create_VM(isolated_network2) + vm_4 = self.create_VM(isolated_network2) + self.debug("Creating Static NAT rule for the deployed VM in the " + "persistently created Isolated network...") + public_ip2 = self.acquire_PublicIPAddress(isolated_network2) + self.validate_PublicIPAddress(public_ip2, isolated_network2) + self.create_StaticNatRule_For_VM(vm_3, public_ip2, isolated_network2) + self.validate_PublicIPAddress( + public_ip2, isolated_network2, static_nat=True, vm=vm_3) + self.create_FirewallRule(public_ip2, self.test_data["ingress_rule"]) + + if not self.isSimulator: + vm_public_ip2 = public_ip2.ipaddress.ipaddress + try: + vm_3.ssh_ip = vm_public_ip2 + vm_3.ssh_port = self.test_data["virtual_machine"]["ssh_port"] + vm_3.username = self.test_data["virtual_machine"]["username"] + vm_3.password = self.test_data["virtual_machine"]["password"] + self.debug("SSHing into VM: %s with %s" % + (vm_3.ssh_ip, vm_3.password)) + + ssh2 = vm_3.get_ssh_client(ipaddress=vm_public_ip2) + + except Exception as e: + self.fail("SSH into VM failed with exception %s" % e) + + self.verify_pingtovmipaddress(ssh2, vm_4.ipaddress) + + @attr(tags=["advanced", "nuagevsp", "vpc"], required_hardware="false") + def test_02_nuage_mngd_subnets_vpc(self): + """Test Nuage VSP Managed Subnets for vpc and tier networks + """ + + # 1. Create multiple L3DomainTemplate with Zone and Subnet on VSP + # Create Ingress & Egress ACL Top & Bottom Templates + # Add ACL rules to allow intra-subnet traffic + # Instiantiate these L3Domains and store its Subnet VSD ID + # 2. Create a vpc network offering and create a VPC + # create vpc tier network offerings with and without VirtualRouter + # 3. Create vpc tier networks specifying above offerings and + # specifying the stored Subnet ID's of VSP + # 4. Verify ACL rules and connectivity via deploying VM's , + # Enabling staticNAT, applying firewall and egress rules + + # Create all items on vsd required for this test + enterprise = self.fetch_by_externalID(self._session.user.enterprises, + self.domain) + domain_template = self.create_vsd_domain_template(enterprise) + + self.create_vsd_default_acls(domain_template) + + domain1 = self.create_vsd_domain(domain_template, enterprise, + "L3DomainToBeConsumedByACS") + zone1 = self.create_vsd_zone(domain1, "ZoneToBeConsumedByACS") + subnet1 = self.create_vsd_subnet(zone1, "SubnetToBeConsumedByACS", + "10.1.0.1/24") + subnet2 = self.create_vsd_subnet(zone1, "2ndSubnetToBeConsumedByACS", + "10.1.128.1/24") + + cmd = updateZone.updateZoneCmd() + cmd.id = self.zone.id + cmd.domain = "vpc.com" + self.api_client.updateZone(cmd) + self.debug("Creating a VPC with Static NAT service provider as " + "VpcVirtualRouter") + vpc = self.create_Vpc(self.nuage_vpc_offering, cidr='10.1.0.0/16') + self.validate_Vpc(vpc, state="Enabled") + acl_list = self.create_NetworkAclList( + name="acl", description="acl", vpc=vpc) + self.create_NetworkAclRule( + self.test_data["ingress_rule"], acl_list=acl_list) + self.create_NetworkAclRule( + self.test_data["icmprule"], acl_list=acl_list) + self.debug("Creating a VPC tier network with Static NAT service") + vpc_tier = self.create_Network(self.nuage_vpc_network_offering, + gateway='10.1.0.1', + vpc=vpc, + acl_list=acl_list, + externalid=subnet1.id) + self.validate_Network(vpc_tier, state="Implemented") + self.debug("Creating 2nd VPC tier network with Static NAT service") + vpc_2ndtier = self.create_Network(self.nuage_vpc_network_offering, + gateway='10.1.128.1', + vpc=vpc, + acl_list=acl_list, + externalid=subnet2.id) + self.validate_Network(vpc_2ndtier, state="Implemented") + vpc_vr = self.get_Router(vpc_tier) + self.check_Router_state(vpc_vr, state="Running") + + self.debug("Deploying a VM in the created VPC tier network") + self.test_data["virtual_machine"]["displayname"] = "vpcvm1" + self.test_data["virtual_machine"]["name"] = "vpcvm1" + vpc_vm_1 = self.create_VM(vpc_tier) + self.check_VM_state(vpc_vm_1, state="Running") + self.debug("Deploying another VM in the created VPC tier network") + self.test_data["virtual_machine"]["displayname"] = "vpcvm2" + self.test_data["virtual_machine"]["name"] = "vpcvm2" + vpc_vm_2 = self.create_VM(vpc_tier) + self.check_VM_state(vpc_vm_2, state="Running") + self.debug("Deploying a VM in the 2nd VPC tier network") + self.test_data["virtual_machine"]["displayname"] = "vpcvm12" + self.test_data["virtual_machine"]["name"] = "vpcvm12" + vpc_vm_12 = self.create_VM(vpc_2ndtier) + self.check_VM_state(vpc_vm_2, state="Running") + self.test_data["virtual_machine"]["displayname"] = None + self.test_data["virtual_machine"]["name"] = None + self.debug("Creating Static NAT rule for the deployed VM " + "in the created VPC network...") + public_ip_1 = self.acquire_PublicIPAddress(vpc_tier, vpc=vpc) + self.validate_PublicIPAddress(public_ip_1, vpc_tier) + self.create_StaticNatRule_For_VM(vpc_vm_1, public_ip_1, vpc_tier) + self.validate_PublicIPAddress( + public_ip_1, vpc_tier, static_nat=True, vm=vpc_vm_1) + + if not self.isSimulator: + vm_public_ip_1 = public_ip_1.ipaddress.ipaddress + try: + vpc_vm_1.ssh_ip = vm_public_ip_1 + vpc_vm_1.ssh_port = \ + self.test_data["virtual_machine"]["ssh_port"] + vpc_vm_1.username = \ + self.test_data["virtual_machine"]["username"] + vpc_vm_1.password = \ + self.test_data["virtual_machine"]["password"] + self.debug("SSHing into VM: %s with %s" % + (vpc_vm_1.ssh_ip, vpc_vm_1.password)) + + ssh = vpc_vm_1.get_ssh_client(ipaddress=vm_public_ip_1) + + except Exception as e: + self.fail("SSH into VM failed with exception %s" % e) + + self.verify_pingtovmipaddress(ssh, vpc_vm_2.ipaddress) + self.verify_pingtovmipaddress(ssh, vpc_vm_12.ipaddress) + + def create_vsd_ingress_acl_template(self, domain_template, priority_type="TOP"): + name = "Ingress ACL " + str(priority_type).capitalize() + acl_template = self.vsdk.NUIngressACLTemplate() + acl_template.name = name + acl_template.description = name + acl_template.priority_type = priority_type + acl_template.active = True + (acl_template, connection) = \ + domain_template.create_child(acl_template) + return acl_template + + def create_vsd_egress_acl_template(self, domain_template, priority_type='TOP'): + name = "Egress ACL " + str(priority_type).capitalize() + acl_template = self.vsdk.NUEgressACLTemplate() + acl_template.name = name + acl_template.description = name + acl_template.priority_type = priority_type + acl_template.active = True + (acl_template, connection) = \ + domain_template.create_child(acl_template) + return acl_template + + def create_vsd_domain_template(self, enterprise): + domain_template = self.vsdk.NUDomainTemplate() + domain_template.name = "L3DomainTemplateToBeConsumedByACS" + domain_template.description = "L3DomainTemplateToBeConsumedByACS" + domain_template.external_id = "L3DomainTemplateToBeConsumedByACS@" \ + + str(self.cms_id) + (domain_template, connection) = \ + enterprise.create_child(domain_template) + return domain_template + + def create_vsd_default_acls(self, domain_template): + ingress_vsd_acl_template1 = self.create_vsd_ingress_acl_template( + domain_template, "TOP") + ingress_vsd_acl_template2 = self.create_vsd_ingress_acl_template( + domain_template, "BOTTOM") + ingress_vsd_acl_entry1 = self.vsdk.NUIngressACLEntryTemplate() + ingress_vsd_acl_entry1.name = "Default Intra-Subnet Allow" + ingress_vsd_acl_entry1.description = "Default Intra-Subnet Allow" + ingress_vsd_acl_entry1.external_id = "ToBeConsumedByACS@" \ + + str(self.cms_id) + ingress_vsd_acl_entry1.priority = '1' + ingress_vsd_acl_entry1.protocol = 'ANY' + ingress_vsd_acl_template1.create_child(ingress_vsd_acl_entry1) + + ingress_vsd_acl_entry2 = self.vsdk.NUIngressACLEntryTemplate() + ingress_vsd_acl_entry2.name = "Default Allow TCP" + ingress_vsd_acl_entry2.description = "Default Allow TCP" + ingress_vsd_acl_entry2.external_id = "ToBeConsumedByACS@" \ + + str(self.cms_id) + ingress_vsd_acl_entry2.priority = '1' + ingress_vsd_acl_entry2.protocol = '6' + ingress_vsd_acl_entry2.source_port = '*' + ingress_vsd_acl_entry2.destination_port = '*' + ingress_vsd_acl_template2.create_child(ingress_vsd_acl_entry2) + + ingress_vsd_acl_entry3 = self.vsdk.NUIngressACLEntryTemplate() + ingress_vsd_acl_entry3.name = "Default Allow UDP" + ingress_vsd_acl_entry3.description = "Default Allow UDP" + ingress_vsd_acl_entry3.external_id = "ToBeConsumedByACS@" \ + + str(self.cms_id) + ingress_vsd_acl_entry3.priority = '2' + ingress_vsd_acl_entry3.protocol = '17' + ingress_vsd_acl_entry3.source_port = '*' + ingress_vsd_acl_entry3.destination_port = '*' + ingress_vsd_acl_template2.create_child(ingress_vsd_acl_entry3) + ingress_vsd_acl_entry4 = self.vsdk.NUIngressACLEntryTemplate() + ingress_vsd_acl_entry4.name = "Default Allow ICMP" + ingress_vsd_acl_entry4.description = "Default Allow ICMP" + ingress_vsd_acl_entry4.external_id = "ToBeConsumedByACS@" \ + + str(self.cms_id) + ingress_vsd_acl_entry4.priority = '3' + ingress_vsd_acl_entry4.protocol = '1' + ingress_vsd_acl_template2.create_child(ingress_vsd_acl_entry4) + + egress_vsd_acl_template1 = self.create_vsd_egress_acl_template( + domain_template, 'TOP') + + egress_vsd_acl_template2 = self.create_vsd_egress_acl_template( + domain_template, 'BOTTOM') + + egress_vsd_acl_entry1 = self.vsdk.NUEgressACLEntryTemplate() + egress_vsd_acl_entry1.name = "Default Intra-Subnet Allow" + egress_vsd_acl_entry1.description = "Default Intra-Subnet Allow" + egress_vsd_acl_entry1.external_id = "ToBeConsumedByACS@" \ + + str(self.cms_id) + egress_vsd_acl_entry1.priority = '1' + egress_vsd_acl_entry1.protocol = 'ANY' + egress_vsd_acl_template1.create_child(egress_vsd_acl_entry1) + egress_vsd_acl_entry2 = self.vsdk.NUEgressACLEntryTemplate() + egress_vsd_acl_entry2.name = "Default Allow ICMP" + egress_vsd_acl_entry2.description = "Default Allow ICMP" + egress_vsd_acl_entry2.external_id = "ToBeConsumedByACS@" \ + + str(self.cms_id) + egress_vsd_acl_entry2.priority = '3' + egress_vsd_acl_entry2.protocol = '1' + egress_vsd_acl_template2.create_child(egress_vsd_acl_entry2) + + def create_vsd_domain(self, domain_template, enterprise, name): + domain = self.vsdk.NUDomain() + domain.name = name + domain.description = name + domain.external_id = name + "@" + str(self.cms_id) + (domain, connection) = \ + enterprise.instantiate_child(domain, domain_template) + return domain + + def create_vsd_zone(self, domain, name): + zone = self.vsdk.NUZone() + zone.name = name + zone.description = name + zone.external_id = name + "@" + str(self.cms_id) + (zone, connection) = domain.create_child(zone) + return zone + + def create_vsd_subnet(self, zone, name, cidr): + subnet = self.vsdk.NUSubnet() + subnet.name = name + subnet.description = name + subnet.external_id = name + "@" + str(self.cms_id) + (subnet.gateway, subnet.netmask, subnet.address) = \ + self._cidr_to_netmask(cidr) + (subnet, connection) = zone.create_child(subnet) + return subnet + + def _cidr_to_netmask(self, cidr): + import socket + import struct + network, net_bits = cidr.split('/') + host_bits = 32 - int(net_bits) + netmask_bits = (1 << 32) - (1 << host_bits) + netmask = socket.inet_ntoa(struct.pack('!I', netmask_bits)) + network_bits = struct.unpack('!I', socket.inet_aton(network))[0] + network_masked = socket.inet_ntoa( + struct.pack('!I', netmask_bits & network_bits) + ) + return network, netmask, network_masked diff --git a/tools/marvin/marvin/config/test_data.py b/tools/marvin/marvin/config/test_data.py index 9f8e6a95f87..64733f7e179 100644 --- a/tools/marvin/marvin/config/test_data.py +++ b/tools/marvin/marvin/config/test_data.py @@ -2011,6 +2011,70 @@ test_data = { "SourceNat": {"SupportedSourceNatTypes": "perzone"} } }, + # Persistent services supported by the Nuage VSP plugin for Isolated networks + "isolated_network_offering_persistent": { + "name": 'nuage_marvin', + "displaytext": 'nuage_marvin', + "guestiptype": 'Isolated', + "supportedservices": 'Dhcp,SourceNat,Connectivity,StaticNat,UserData,Firewall,Dns', + "traffictype": 'GUEST', + "availability": 'Optional', + "ispersistent": 'True', + "tags": "nuage", + "serviceProviderList": { + "Dhcp": 'NuageVsp', + "StaticNat": 'NuageVsp', + "SourceNat": 'NuageVsp', + "Firewall": 'NuageVsp', + "Connectivity": 'NuageVsp', + "UserData": 'VirtualRouter', + "Dns": 'VirtualRouter' + }, + "serviceCapabilityList": { + "SourceNat": {"SupportedSourceNatTypes": "perzone"} + } + }, + # Purely nuage network offering + "isolated_network_offering_without_vr": { + "name": 'nuage_marvin', + "displaytext": 'nuage_marvin', + "guestiptype": 'Isolated', + "supportedservices": 'Dhcp,SourceNat,Connectivity,StaticNat,Firewall', + "traffictype": 'GUEST', + "availabiliy": 'Optional', + "tags": "nuage", + "serviceProviderList": { + "Dhcp": 'NuageVsp', + "StaticNat": 'NuageVsp', + "SourceNat": 'NuageVsp', + "Firewall": 'NuageVsp', + "Connectivity": 'NuageVsp' + }, + "serviceCapabilityList": { + "SourceNat": {"SupportedSourceNatTypes": "perzone"} + } + }, + # Purely persistent nuage network offering + "isolated_network_offering_without_vr_persistent": { + "name": 'nuage_marvin', + "displaytext": 'nuage_marvin', + "guestiptype": 'Isolated', + "supportedservices": 'Dhcp,SourceNat,Connectivity,StaticNat,Firewall', + "traffictype": 'GUEST', + "availability": 'Optional', + "tags": "nuage", + "ispersistent": 'True', + "serviceProviderList": { + "Dhcp": 'NuageVsp', + "StaticNat": 'NuageVsp', + "SourceNat": 'NuageVsp', + "Firewall": 'NuageVsp', + "Connectivity": 'NuageVsp' + }, + "serviceCapabilityList": { + "SourceNat": {"SupportedSourceNatTypes": "perzone"} + } + }, # Purely nuage network offering "isolated_network_offering_without_vr": { "name": 'nuage_marvin', diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py index bd00237df17..4154e91cba2 100755 --- a/tools/marvin/marvin/lib/base.py +++ b/tools/marvin/marvin/lib/base.py @@ -2910,7 +2910,8 @@ class Network: def create(cls, apiclient, services, accountid=None, domainid=None, networkofferingid=None, projectid=None, subdomainaccess=None, zoneid=None, - gateway=None, netmask=None, vpcid=None, aclid=None, vlan=None): + gateway=None, netmask=None, vpcid=None, aclid=None, vlan=None, + externalid=None): """Create Network for account""" cmd = createNetwork.createNetworkCmd() cmd.name = services["name"] @@ -2958,6 +2959,8 @@ class Network: cmd.vpcid = vpcid if aclid: cmd.aclid = aclid + if externalid: + cmd.externalid = externalid return Network(apiclient.createNetwork(cmd).__dict__) def delete(self, apiclient): diff --git a/ui/l10n/en.js b/ui/l10n/en.js index e3b0064b060..afd95006345 100644 --- a/ui/l10n/en.js +++ b/ui/l10n/en.js @@ -807,6 +807,7 @@ var dictionary = {"ICMP.code":"ICMP Code", "label.guest":"Guest", "label.guest.cidr":"Guest CIDR", "label.guest.end.ip":"Guest end IP", +"label.guest.externalId":"External Id", "label.guest.gateway":"Guest Gateway", "label.guest.ip":"Guest IP Address", "label.guest.ip.range":"Guest IP Range", diff --git a/ui/scripts/docs.js b/ui/scripts/docs.js index 2908e8b5f64..a8ab405d754 100755 --- a/ui/scripts/docs.js +++ b/ui/scripts/docs.js @@ -395,6 +395,10 @@ cloudStack.docs = { desc: 'If you want to assign a special domain name to this domain\'s guest VM network, specify the DNS suffix', externalLink: '' }, + helpDomainId: { + desc: 'A valid domain id. CloudStack will generate one for you if empty.', + externalLink: '' + }, // Add F5 helpF5IPAddress: { desc: 'The IP address of the device', diff --git a/ui/scripts/domains.js b/ui/scripts/domains.js index 04f523c2378..704195e08a9 100644 --- a/ui/scripts/domains.js +++ b/ui/scripts/domains.js @@ -269,6 +269,12 @@ }); } + if (args.data.domainid != null && args.data.domainid.length > 0) { + $.extend(data, { + domainid: args.data.domainid + }); + } + $.ajax({ url: createURL('createDomain'), data: data, @@ -308,7 +314,14 @@ validation: { required: false } - } + }, + domainid: { + label: 'label.domain.id', + docID: 'helpDomainId', + validation: { + required: false + } + } } } }, diff --git a/ui/scripts/network.js b/ui/scripts/network.js index 7dd459dc915..7b9f75e7fda 100644 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -657,7 +657,9 @@ } } }, - + externalId: { + label: 'label.guest.externalId' + }, guestGateway: { label: 'label.guest.gateway', docID: 'helpGuestNetworkGateway' @@ -744,9 +746,14 @@ gateway: args.data.guestGateway }); } - if (args.data.guestNetmask != null && args.data.guestNetmask.length > 0) { + if (args.data.guestGateway != null && args.data.guestGateway.length > 0) { $.extend(dataObj, { - netmask: args.data.guestNetmask + gateway: args.data.guestGateway + }); + } + if (args.data.externalId != null && args.data.externalId.length > 0) { + $.extend(dataObj, { + externalid: args.data.externalId }); } if (args.$form.find('.form-item[rel=vpcid]').css("display") != "none") { diff --git a/ui/scripts/vpc.js b/ui/scripts/vpc.js index 8416d38fd7d..14e41af2b23 100644 --- a/ui/scripts/vpc.js +++ b/ui/scripts/vpc.js @@ -3948,7 +3948,9 @@ required: true } }, - + externalId: { + label: 'label.guest.externalId' + }, aclid: { label: 'label.acl', select: function(args) { @@ -4040,11 +4042,17 @@ zoneId: args.context.vpc[0].zoneid }); + if (args.data.externalId != null && args.data.externalId.length > 0) { + $.extend(dataObj, { + externalid: args.data.externalId + }); + } - if (args.data.aclid != '') + if (args.data.aclid != '') { $.extend(dataObj, { aclid: args.data.aclid }); + } if (args.$form.find('.form-item[rel=vlan]').is(':visible')) { $.extend(dataObj, {