Merge remote-tracking branch 'origin/4.17'

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
Rohit Yadav 2022-07-18 19:42:44 +05:30
commit 4baaf736b9
20 changed files with 4641 additions and 603 deletions

View File

@ -253,4 +253,8 @@ public class VpcResponse extends BaseResponseWithAnnotations implements Controll
public void setIpv6Routes(Set<Ipv6RouteResponse> ipv6Routes) {
this.ipv6Routes = ipv6Routes;
}
public Set<Ipv6RouteResponse> getIpv6Routes() {
return ipv6Routes;
}
}

6
debian/changelog vendored
View File

@ -4,6 +4,12 @@ cloudstack (4.18.0.0) unstable; urgency=low
-- the Apache CloudStack project <dev@cloudstack.apache.org> Tue, 31 May 2022 14:33:47 -0300
cloudstack (4.17.0.1) unstable; urgency=low
* Update the version to 4.17.0.1
-- the Apache CloudStack project <dev@cloudstack.apache.org> Fri, 15 Jul 2022 18:18:39 +0530
cloudstack (4.17.0.0) unstable; urgency=low
* Update the version to 4.17.0.0

View File

@ -279,7 +279,7 @@ public class NetworkOfferingDaoImpl extends GenericDaoBase<NetworkOfferingVO, Lo
}
@Override
public NetUtils.InternetProtocol getNetworkOfferingInternetProtocol(long offeringId,NetUtils.InternetProtocol defaultProtocol) {
public NetUtils.InternetProtocol getNetworkOfferingInternetProtocol(long offeringId, NetUtils.InternetProtocol defaultProtocol) {
NetUtils.InternetProtocol protocol = getNetworkOfferingInternetProtocol(offeringId);
if (protocol == null) {
return defaultProtocol;

View File

@ -0,0 +1,93 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.offerings.dao;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import com.cloud.offering.NetworkOffering;
import com.cloud.utils.net.NetUtils;
public class NetworkOfferingDaoImplTest {
@Mock
NetworkOfferingDetailsDao detailsDao;
@InjectMocks
NetworkOfferingDaoImpl networkOfferingDao = new NetworkOfferingDaoImpl();
final long offeringId = 1L;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testGetNetworkOfferingInternetProtocol() {
Mockito.when(detailsDao.getDetail(offeringId, NetworkOffering.Detail.internetProtocol)).thenReturn(null);
NetUtils.InternetProtocol protocol = networkOfferingDao.getNetworkOfferingInternetProtocol(offeringId);
Assert.assertNull(protocol);
Mockito.when(detailsDao.getDetail(offeringId, NetworkOffering.Detail.internetProtocol)).thenReturn("IPv4");
protocol = networkOfferingDao.getNetworkOfferingInternetProtocol(offeringId);
Assert.assertEquals(NetUtils.InternetProtocol.IPv4, protocol);
Mockito.when(detailsDao.getDetail(offeringId, NetworkOffering.Detail.internetProtocol)).thenReturn("IPv6");
protocol = networkOfferingDao.getNetworkOfferingInternetProtocol(offeringId);
Assert.assertEquals(NetUtils.InternetProtocol.IPv6, protocol);
Mockito.when(detailsDao.getDetail(offeringId, NetworkOffering.Detail.internetProtocol)).thenReturn("DualStack");
protocol = networkOfferingDao.getNetworkOfferingInternetProtocol(offeringId);
Assert.assertEquals(NetUtils.InternetProtocol.DualStack, protocol);
}
@Test
public void testGetNetworkOfferingInternetProtocolWithDefault() {
Mockito.when(detailsDao.getDetail(offeringId, NetworkOffering.Detail.internetProtocol)).thenReturn(null);
NetUtils.InternetProtocol protocol = networkOfferingDao.getNetworkOfferingInternetProtocol(offeringId, NetUtils.InternetProtocol.IPv4);
Assert.assertEquals(NetUtils.InternetProtocol.IPv4, protocol);
Mockito.when(detailsDao.getDetail(offeringId, NetworkOffering.Detail.internetProtocol)).thenReturn("IPv6");
protocol = networkOfferingDao.getNetworkOfferingInternetProtocol(offeringId, NetUtils.InternetProtocol.IPv4);
Assert.assertEquals(NetUtils.InternetProtocol.IPv6, protocol);
}
@Test
public void testIsIpv6Supported() {
Mockito.when(detailsDao.getDetail(offeringId, NetworkOffering.Detail.internetProtocol)).thenReturn("");
boolean result = networkOfferingDao.isIpv6Supported(offeringId);
Assert.assertFalse(result);
Mockito.when(detailsDao.getDetail(offeringId, NetworkOffering.Detail.internetProtocol)).thenReturn("IPv4");
result = networkOfferingDao.isIpv6Supported(offeringId);
Assert.assertFalse(result);
Mockito.when(detailsDao.getDetail(offeringId, NetworkOffering.Detail.internetProtocol)).thenReturn("IPv6");
result = networkOfferingDao.isIpv6Supported(offeringId);
Assert.assertTrue(result);
Mockito.when(detailsDao.getDetail(offeringId, NetworkOffering.Detail.internetProtocol)).thenReturn("DualStack");
result = networkOfferingDao.isIpv6Supported(offeringId);
Assert.assertTrue(result);
}
}

View File

@ -31,6 +31,7 @@
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml</artifactId>
<version>${cs.opensaml.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>

View File

@ -30,6 +30,7 @@ import org.apache.cloudstack.api.auth.PluggableAPIAuthenticator;
import org.apache.cloudstack.api.response.SAMLMetaDataResponse;
import org.apache.cloudstack.saml.SAML2AuthManager;
import org.apache.cloudstack.saml.SAMLProviderMetadata;
import org.apache.cloudstack.utils.security.ParserUtils;
import org.apache.log4j.Logger;
import org.opensaml.Configuration;
import org.opensaml.DefaultBootstrap;
@ -239,7 +240,7 @@ public class GetServiceProviderMetaDataCmd extends BaseCmd implements APIAuthent
StringWriter stringWriter = new StringWriter();
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilderFactory factory = ParserUtils.getSaferDocumentBuilderFactory();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.newDocument();
Marshaller out = Configuration.getMarshallerFactory().getMarshaller(spEntityDescriptor);

View File

@ -78,7 +78,6 @@ import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider;
import org.opensaml.saml2.metadata.provider.MetadataProviderException;
import org.opensaml.xml.ConfigurationException;
import org.opensaml.xml.XMLObject;
import org.opensaml.xml.parse.BasicParserPool;
import org.opensaml.xml.security.credential.UsageType;
import org.opensaml.xml.security.keyinfo.KeyInfoHelper;
import org.springframework.stereotype.Component;
@ -389,7 +388,7 @@ public class SAML2AuthManagerImpl extends AdapterBase implements SAML2AuthManage
}
}
_idpMetaDataProvider.setRequireValidMetadata(true);
_idpMetaDataProvider.setParserPool(new BasicParserPool());
_idpMetaDataProvider.setParserPool(SAMLUtils.getSaferParserPool());
_idpMetaDataProvider.initialize();
_timer.scheduleAtFixedRate(new MetadataRefreshTask(), 0, _refreshInterval * 1000);

View File

@ -42,12 +42,15 @@ import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
@ -56,6 +59,7 @@ import javax.xml.stream.FactoryConfigurationError;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.response.LoginCmdResponse;
import org.apache.cloudstack.utils.security.CertUtils;
import org.apache.cloudstack.utils.security.ParserUtils;
import org.apache.log4j.Logger;
import org.bouncycastle.operator.OperatorCreationException;
import org.joda.time.DateTime;
@ -88,6 +92,7 @@ import org.opensaml.xml.io.MarshallingException;
import org.opensaml.xml.io.Unmarshaller;
import org.opensaml.xml.io.UnmarshallerFactory;
import org.opensaml.xml.io.UnmarshallingException;
import org.opensaml.xml.parse.BasicParserPool;
import org.opensaml.xml.signature.SignatureConstants;
import org.opensaml.xml.util.Base64;
import org.opensaml.xml.util.XMLHelper;
@ -231,7 +236,7 @@ public class SAMLUtils {
public static Response decodeSAMLResponse(String responseMessage)
throws ConfigurationException, ParserConfigurationException,
SAXException, IOException, UnmarshallingException {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilderFactory documentBuilderFactory = ParserUtils.getSaferDocumentBuilderFactory();
documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder docBuilder = documentBuilderFactory.newDocumentBuilder();
byte[] base64DecodedResponse = Base64.decode(responseMessage);
@ -365,4 +370,19 @@ public class SAMLUtils {
"CN=ApacheCloudStack", "CN=ApacheCloudStack",
3, "SHA256WithRSA");
}
public static BasicParserPool getSaferParserPool() {
final Map<String, Boolean> features = new HashMap<>();
features.put(XMLConstants.FEATURE_SECURE_PROCESSING, true);
features.put("http://apache.org/xml/features/disallow-doctype-decl", true);
features.put("http://xml.org/sax/features/external-general-entities", false);
features.put("http://xml.org/sax/features/external-parameter-entities", false);
features.put("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
final BasicParserPool parserPool = new BasicParserPool();
parserPool.setXincludeAware(false);
parserPool.setIgnoreComments(true);
parserPool.setExpandEntityReferences(false);
parserPool.setBuilderFeatures(features);
return parserPool;
}
}

View File

@ -39,6 +39,11 @@ import java.util.Map;
import java.util.Random;
import java.util.UUID;
import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIpv6PrefixCmd;
import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.network.DeleteGuestNetworkIpv6PrefixCmd;
import org.apache.cloudstack.api.command.admin.network.ListGuestNetworkIpv6PrefixesCmd;
import org.apache.cloudstack.api.command.admin.vlan.CreateVlanIpRangeCmd;
import org.apache.cloudstack.api.command.admin.vlan.DedicatePublicIpRangeCmd;
import org.apache.cloudstack.api.command.admin.vlan.ReleasePublicIpRangeCmd;
import org.apache.cloudstack.api.command.user.network.ListNetworkOfferingsCmd;
@ -58,6 +63,7 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.mockito.stubbing.Answer;
import com.cloud.api.query.dao.NetworkOfferingJoinDao;
import com.cloud.api.query.vo.NetworkOfferingJoinVO;
@ -65,6 +71,8 @@ import com.cloud.configuration.Resource.ResourceType;
import com.cloud.dc.AccountVlanMapVO;
import com.cloud.dc.ClusterVO;
import com.cloud.dc.DataCenter.NetworkType;
import com.cloud.dc.DataCenterGuestIpv6Prefix;
import com.cloud.dc.DataCenterGuestIpv6PrefixVO;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.dc.Vlan;
@ -72,20 +80,27 @@ import com.cloud.dc.VlanVO;
import com.cloud.dc.dao.AccountVlanMapDao;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.DataCenterGuestIpv6PrefixDao;
import com.cloud.dc.dao.DataCenterIpAddressDao;
import com.cloud.dc.dao.DomainVlanMapDao;
import com.cloud.dc.dao.HostPodDao;
import com.cloud.dc.dao.VlanDao;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.network.IpAddressManager;
import com.cloud.network.Ipv6GuestPrefixSubnetNetworkMapVO;
import com.cloud.network.Network;
import com.cloud.network.Network.Capability;
import com.cloud.network.NetworkModel;
import com.cloud.network.Networks;
import com.cloud.network.dao.FirewallRulesDao;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.IPAddressVO;
import com.cloud.network.dao.Ipv6GuestPrefixSubnetNetworkMapDao;
import com.cloud.network.dao.PhysicalNetworkDao;
import com.cloud.network.dao.PhysicalNetworkVO;
import com.cloud.projects.ProjectManager;
@ -104,6 +119,7 @@ import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.Ip;
import com.cloud.utils.net.NetUtils;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.dao.VMInstanceDao;
@ -169,6 +185,10 @@ public class ConfigurationManagerTest {
ConfigurationDao _configDao;
@Mock
DiskOfferingVO diskOfferingVOMock;
@Mock
DataCenterGuestIpv6PrefixDao dataCenterGuestIpv6PrefixDao;
@Mock
Ipv6GuestPrefixSubnetNetworkMapDao ipv6GuestPrefixSubnetNetworkMapDao;
VlanVO vlan = new VlanVO(Vlan.VlanType.VirtualNetwork, "vlantag", "vlangateway", "vlannetmask", 1L, "iprange", 1L, 1L, null, null, null);
@ -1002,4 +1022,152 @@ public class ConfigurationManagerTest {
this.configurationMgr.updateOfferingTagsIfIsNotNull(tags, diskOfferingVOMock);
Mockito.verify(configurationMgr, Mockito.times(1)).updateOfferingTagsIfIsNotNull(tags, diskOfferingVOMock);
}
@Test(expected = IllegalArgumentException.class)
public void testInvalidCreateDataCenterGuestIpv6Prefix() {
CreateGuestNetworkIpv6PrefixCmd cmd = Mockito.mock(CreateGuestNetworkIpv6PrefixCmd.class);
Mockito.when(cmd.getZoneId()).thenReturn(1L);
Mockito.when(cmd.getPrefix()).thenReturn("Invalid");
Mockito.when(_zoneDao.findById(Mockito.anyLong())).thenReturn(Mockito.mock(DataCenterVO.class));
configurationMgr.createDataCenterGuestIpv6Prefix(cmd);
}
@Test(expected = InvalidParameterValueException.class)
public void testWrongCreateDataCenterGuestIpv6Prefix() {
CreateGuestNetworkIpv6PrefixCmd cmd = Mockito.mock(CreateGuestNetworkIpv6PrefixCmd.class);
Mockito.when(cmd.getZoneId()).thenReturn(1L);
Mockito.when(cmd.getPrefix()).thenReturn("fd17:5:8a43:e2a4:c000::/66");
Mockito.when(_zoneDao.findById(Mockito.anyLong())).thenReturn(Mockito.mock(DataCenterVO.class));
configurationMgr.createDataCenterGuestIpv6Prefix(cmd);
}
@Test(expected = InvalidParameterValueException.class)
public void testConflictingCreateDataCenterGuestIpv6Prefix() {
CreateGuestNetworkIpv6PrefixCmd cmd = Mockito.mock(CreateGuestNetworkIpv6PrefixCmd.class);
Mockito.when(cmd.getZoneId()).thenReturn(1L);
Mockito.when(cmd.getPrefix()).thenReturn("fd17:5:8a43:e2a5::/64");
Mockito.when(_zoneDao.findById(Mockito.anyLong())).thenReturn(Mockito.mock(DataCenterVO.class));
DataCenterGuestIpv6PrefixVO prefix = Mockito.mock(DataCenterGuestIpv6PrefixVO.class);
Mockito.when(prefix.getPrefix()).thenReturn("fd17:5:8a43:e2a4::/62");
Mockito.when(dataCenterGuestIpv6PrefixDao.listByDataCenterId(Mockito.anyLong())).thenReturn(List.of(prefix));
configurationMgr.createDataCenterGuestIpv6Prefix(cmd);
}
@Test
public void testCreateDataCenterGuestIpv6Prefix() {
final Long zoneId = 1L;
final String prefix = "fd17:5:8a43:e2a5::/64";
CreateGuestNetworkIpv6PrefixCmd cmd = Mockito.mock(CreateGuestNetworkIpv6PrefixCmd.class);
Mockito.when(cmd.getZoneId()).thenReturn(zoneId);
Mockito.when(cmd.getPrefix()).thenReturn(prefix);
Mockito.when(_zoneDao.findById(Mockito.anyLong())).thenReturn(Mockito.mock(DataCenterVO.class));
Mockito.when(dataCenterGuestIpv6PrefixDao.listByDataCenterId(Mockito.anyLong())).thenReturn(new ArrayList<>());
final List<DataCenterGuestIpv6PrefixVO> persistedPrefix = new ArrayList<>();
Mockito.when(dataCenterGuestIpv6PrefixDao.persist(Mockito.any(DataCenterGuestIpv6PrefixVO.class))).thenAnswer((Answer<DataCenterGuestIpv6PrefixVO>) invocation -> {
DataCenterGuestIpv6PrefixVO prefixVO = (DataCenterGuestIpv6PrefixVO)invocation.getArgument(0);
persistedPrefix.add(prefixVO);
return prefixVO;
});
configurationMgr.createDataCenterGuestIpv6Prefix(cmd);
Assert.assertEquals(1, persistedPrefix.size());
DataCenterGuestIpv6PrefixVO prefixVO = persistedPrefix.get(0);
Assert.assertEquals(zoneId, prefixVO.getDataCenterId());
Assert.assertEquals(prefix, prefixVO.getPrefix());
}
@Test
public void testListDataCenterGuestIpv6Prefixes() {
ListGuestNetworkIpv6PrefixesCmd cmd = Mockito.mock(ListGuestNetworkIpv6PrefixesCmd.class);
Mockito.when(cmd.getId()).thenReturn(1L);
Mockito.when(cmd.getZoneId()).thenReturn(1L);
Mockito.when(_zoneDao.findById(Mockito.anyLong())).thenReturn(Mockito.mock(DataCenterVO.class));
Mockito.when(dataCenterGuestIpv6PrefixDao.findById(Mockito.anyLong())).thenReturn(Mockito.mock(DataCenterGuestIpv6PrefixVO.class));
Mockito.when(dataCenterGuestIpv6PrefixDao.listByDataCenterId(Mockito.anyLong()))
.thenReturn(List.of(Mockito.mock(DataCenterGuestIpv6PrefixVO.class), Mockito.mock(DataCenterGuestIpv6PrefixVO.class)));
Mockito.when(dataCenterGuestIpv6PrefixDao.listAll())
.thenReturn(List.of(Mockito.mock(DataCenterGuestIpv6PrefixVO.class),
Mockito.mock(DataCenterGuestIpv6PrefixVO.class),
Mockito.mock(DataCenterGuestIpv6PrefixVO.class)));
List<? extends DataCenterGuestIpv6Prefix> prefixes = configurationMgr.listDataCenterGuestIpv6Prefixes(cmd);
Assert.assertEquals(1, prefixes.size());
ListGuestNetworkIpv6PrefixesCmd cmd1 = Mockito.mock(ListGuestNetworkIpv6PrefixesCmd.class);
Mockito.when(cmd1.getId()).thenReturn(null);
Mockito.when(cmd1.getZoneId()).thenReturn(1L);
prefixes = configurationMgr.listDataCenterGuestIpv6Prefixes(cmd1);
Assert.assertEquals(2, prefixes.size());
ListGuestNetworkIpv6PrefixesCmd cmd2 = Mockito.mock(ListGuestNetworkIpv6PrefixesCmd.class);
Mockito.when(cmd2.getId()).thenReturn(null);
Mockito.when(cmd2.getZoneId()).thenReturn(null);
prefixes = configurationMgr.listDataCenterGuestIpv6Prefixes(cmd2);
Assert.assertEquals(3, prefixes.size());
}
@Test(expected = InvalidParameterValueException.class)
public void testInvalidDeleteDataCenterGuestIpv6Prefix() {
DeleteGuestNetworkIpv6PrefixCmd cmd = Mockito.mock(DeleteGuestNetworkIpv6PrefixCmd.class);
Mockito.when(cmd.getId()).thenReturn(1L);
Mockito.when(dataCenterGuestIpv6PrefixDao.findById(Mockito.anyLong())).thenReturn(null);
configurationMgr.deleteDataCenterGuestIpv6Prefix(cmd);
}
@Test(expected = CloudRuntimeException.class)
public void testUsedDeleteDataCenterGuestIpv6Prefix() {
final Long prefixId = 1L;
DeleteGuestNetworkIpv6PrefixCmd cmd = Mockito.mock(DeleteGuestNetworkIpv6PrefixCmd.class);
Mockito.when(cmd.getId()).thenReturn(prefixId);
DataCenterGuestIpv6PrefixVO prefixVO = Mockito.mock(DataCenterGuestIpv6PrefixVO.class);
Mockito.when(prefixVO.getId()).thenReturn(prefixId);
Mockito.when(dataCenterGuestIpv6PrefixDao.findById(Mockito.anyLong())).thenReturn(prefixVO);
Mockito.when(ipv6GuestPrefixSubnetNetworkMapDao.listUsedByPrefix(Mockito.anyLong()))
.thenReturn(List.of(Mockito.mock(Ipv6GuestPrefixSubnetNetworkMapVO.class)));
configurationMgr.deleteDataCenterGuestIpv6Prefix(cmd);
}
@Test
public void testDeleteDataCenterGuestIpv6Prefix() {
final Long prefixId = 1L;
DeleteGuestNetworkIpv6PrefixCmd cmd = Mockito.mock(DeleteGuestNetworkIpv6PrefixCmd.class);
Mockito.when(cmd.getId()).thenReturn(prefixId);
DataCenterGuestIpv6PrefixVO prefixVO = Mockito.mock(DataCenterGuestIpv6PrefixVO.class);
Mockito.when(prefixVO.getId()).thenReturn(prefixId);
Mockito.when(dataCenterGuestIpv6PrefixDao.findById(Mockito.anyLong())).thenReturn(prefixVO);
Mockito.when(ipv6GuestPrefixSubnetNetworkMapDao.listUsedByPrefix(Mockito.anyLong())).thenReturn(new ArrayList<>());
final List<Long> removedPrefix = new ArrayList<>();
Mockito.when(dataCenterGuestIpv6PrefixDao.remove(Mockito.anyLong())).thenAnswer((Answer<Boolean>) invocation -> {
removedPrefix.add(invocation.getArgument(0));
return true;
});
configurationMgr.deleteDataCenterGuestIpv6Prefix(cmd);
Assert.assertEquals(1, removedPrefix.size());
Assert.assertEquals(prefixId, removedPrefix.get(0));
}
@Test(expected = InvalidParameterValueException.class)
public void testInvalidNetworkTypeCreateIpv6NetworkOffering() {
CreateNetworkOfferingCmd cmd = Mockito.mock(CreateNetworkOfferingCmd.class);
Mockito.when(cmd.getTraffictype()).thenReturn(Networks.TrafficType.Guest.toString());
Mockito.when(cmd.getGuestIpType()).thenReturn(Network.GuestType.L2.toString());
Mockito.when(cmd.getInternetProtocol()).thenReturn(NetUtils.InternetProtocol.DualStack.toString());
configurationMgr.createNetworkOffering(cmd);
}
@Test(expected = InvalidParameterValueException.class)
public void testDisabledConfigCreateIpv6NetworkOffering() {
CreateNetworkOfferingCmd cmd = Mockito.mock(CreateNetworkOfferingCmd.class);
Mockito.when(cmd.getTraffictype()).thenReturn(Networks.TrafficType.Guest.toString());
Mockito.when(cmd.getGuestIpType()).thenReturn(Network.GuestType.Isolated.toString());
Mockito.when(cmd.getInternetProtocol()).thenReturn(NetUtils.InternetProtocol.DualStack.toString());
configurationMgr.createNetworkOffering(cmd);
}
@Test(expected = InvalidParameterValueException.class)
public void testWrongIpv6CreateVlanAndPublicIpRange() {
CreateVlanIpRangeCmd cmd = Mockito.mock(CreateVlanIpRangeCmd.class);
Mockito.when(cmd.getIp6Cidr()).thenReturn("fd17:5:8a43:e2a4:c000::/66");
try {
configurationMgr.createVlanAndPublicIpRange(cmd);
} catch (InsufficientCapacityException | ResourceUnavailableException | ResourceAllocationException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,781 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.network;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import org.apache.cloudstack.api.command.user.ipv6.CreateIpv6FirewallRuleCmd;
import org.apache.cloudstack.api.command.user.ipv6.UpdateIpv6FirewallRuleCmd;
import org.apache.cloudstack.api.response.Ipv6RouteResponse;
import org.apache.cloudstack.api.response.VpcResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
import org.apache.commons.collections.CollectionUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.cloud.api.ApiDBUtils;
import com.cloud.dc.DataCenter;
import com.cloud.dc.DataCenterGuestIpv6PrefixVO;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.Vlan;
import com.cloud.dc.VlanVO;
import com.cloud.dc.dao.DataCenterGuestIpv6PrefixDao;
import com.cloud.dc.dao.VlanDao;
import com.cloud.event.ActionEventUtils;
import com.cloud.event.UsageEventUtils;
import com.cloud.exception.InsufficientAddressCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.network.dao.FirewallRulesDao;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.IPAddressVO;
import com.cloud.network.dao.Ipv6GuestPrefixSubnetNetworkMapDao;
import com.cloud.network.dao.NetworkDetailsDao;
import com.cloud.network.dao.NetworkVO;
import com.cloud.network.firewall.FirewallService;
import com.cloud.network.guru.PublicNetworkGuru;
import com.cloud.network.rules.FirewallManager;
import com.cloud.network.rules.FirewallRule;
import com.cloud.network.rules.FirewallRuleVO;
import com.cloud.network.vpc.Vpc;
import com.cloud.offerings.dao.NetworkOfferingDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.AccountVO;
import com.cloud.user.User;
import com.cloud.user.UserVO;
import com.cloud.utils.Pair;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.DomainRouterVO;
import com.cloud.vm.Nic;
import com.cloud.vm.NicProfile;
import com.cloud.vm.NicVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.vm.dao.NicDao;
import com.googlecode.ipv6.IPv6Network;
import com.googlecode.ipv6.IPv6NetworkMask;
@PowerMockIgnore("javax.management.*")
@RunWith(PowerMockRunner.class)
@PrepareForTest({ApiDBUtils.class, ActionEventUtils.class, UsageEventUtils.class})
public class Ipv6ServiceImplTest {
@Mock
NetworkOfferingDao networkOfferingDao;
@Mock
VlanDao vlanDao;
@Mock
DataCenterGuestIpv6PrefixDao dataCenterGuestIpv6PrefixDao;
@Mock
Ipv6GuestPrefixSubnetNetworkMapDao ipv6GuestPrefixSubnetNetworkMapDao;
@Mock
FirewallRulesDao firewallDao;
@Mock
FirewallService firewallService;
@Mock
NetworkDetailsDao networkDetailsDao;
@Mock
NicDao nicDao;
@Mock
DomainRouterDao domainRouterDao;
@Mock
AccountManager accountManager;
@Mock
NetworkModel networkModel = Mockito.mock(NetworkModelImpl.class);
@Mock
IPAddressDao ipAddressDao;
@Mock
NetworkOrchestrationService networkOrchestrationService;
FirewallManager firewallManager = Mockito.mock(FirewallManager.class);
@InjectMocks
private Ipv6ServiceImpl ipv6Service = new Ipv6ServiceImpl();
List<Ipv6GuestPrefixSubnetNetworkMapVO> updatedPrefixSubnetMap;
List<Ipv6GuestPrefixSubnetNetworkMapVO> persistedPrefixSubnetMap;
final String publicReserver = PublicNetworkGuru.class.getSimpleName();
final String vlan = "vlan";
final Long networkId = 101L;
final Long nicId = 100L;
final String ipv6Prefix = "fd17:6:8a43:e2a4::/62"; // Will have 4 /64 subnets
final String cidr = "fd17:5:8a43:e2a5::/64";
final String gateway = "fd17:5:8a43:e2a5::1";
final String macAddress = "1e:00:4c:00:00:03";
final String ipv6Address = "fd17:5:8a43:e2a5:1c00:4cff:fe00:3"; // Resulting IPv6 address using SLAAC
public static final long ACCOUNT_ID = 1;
private AccountVO account;
private UserVO user;
@Before
public void setup() {
updatedPrefixSubnetMap = new ArrayList<>();
persistedPrefixSubnetMap = new ArrayList<>();
MockitoAnnotations.initMocks(this);
ipv6Service.firewallManager = firewallManager;
Mockito.when(ipv6GuestPrefixSubnetNetworkMapDao.update(Mockito.anyLong(), Mockito.any(Ipv6GuestPrefixSubnetNetworkMapVO.class))).thenAnswer((Answer<Boolean>) invocation -> {
Ipv6GuestPrefixSubnetNetworkMapVO map = (Ipv6GuestPrefixSubnetNetworkMapVO)invocation.getArguments()[1];
updatedPrefixSubnetMap.add(map);
return true;
});
Mockito.when(ipv6GuestPrefixSubnetNetworkMapDao.persist(Mockito.any(Ipv6GuestPrefixSubnetNetworkMapVO.class))).thenAnswer((Answer<Ipv6GuestPrefixSubnetNetworkMapVO>) invocation -> {
Ipv6GuestPrefixSubnetNetworkMapVO map = (Ipv6GuestPrefixSubnetNetworkMapVO)invocation.getArguments()[0];
persistedPrefixSubnetMap.add(map);
return map;
});
PowerMockito.mockStatic(ApiDBUtils.class);
Mockito.when(ApiDBUtils.findZoneById(Mockito.anyLong())).thenReturn(Mockito.mock(DataCenterVO.class));
}
private DataCenterGuestIpv6PrefixVO prepareMocksForIpv6Subnet() {
final long prefixId = 1L;
DataCenterGuestIpv6PrefixVO prefix = Mockito.mock(DataCenterGuestIpv6PrefixVO.class);
Mockito.when(prefix.getId()).thenReturn(prefixId);
Mockito.when(prefix.getPrefix()).thenReturn(ipv6Prefix);
List<Ipv6GuestPrefixSubnetNetworkMapVO> subnets = new ArrayList<>();
Ipv6GuestPrefixSubnetNetworkMapVO subnetMap = new Ipv6GuestPrefixSubnetNetworkMapVO(prefixId, "subnet", 1L, Ipv6GuestPrefixSubnetNetworkMap.State.Allocated);
subnets.add(subnetMap);
subnetMap = new Ipv6GuestPrefixSubnetNetworkMapVO(1L, "subnet", 2L, Ipv6GuestPrefixSubnetNetworkMap.State.Allocated);
subnets.add(subnetMap);
Mockito.when(ipv6GuestPrefixSubnetNetworkMapDao.listUsedByPrefix(prefixId)).thenReturn(subnets);
return prefix;
}
@Test
public void testGetUsedTotalIpv6SubnetForPrefix() {
DataCenterGuestIpv6PrefixVO prefix = prepareMocksForIpv6Subnet();
Pair<Integer, Integer> results = ipv6Service.getUsedTotalIpv6SubnetForPrefix(prefix);
Assert.assertEquals(2, results.first().intValue());
Assert.assertEquals(4, results.second().intValue());
}
@Test
public void testNoPrefixesGetUsedTotalIpv6SubnetForZone() {
final long zoneId = 1L;
final List<DataCenterGuestIpv6PrefixVO> prefixes = new ArrayList<>();
Mockito.when(dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId)).thenReturn(prefixes);
Pair<Integer, Integer> results = ipv6Service.getUsedTotalIpv6SubnetForZone(zoneId);
Assert.assertEquals(0, results.first().intValue());
Assert.assertEquals(0, results.second().intValue());
}
@Test
public void testGetUsedTotalIpv6SubnetForZone() {
final long zoneId = 1L;
final List<DataCenterGuestIpv6PrefixVO> prefixes = new ArrayList<>();
DataCenterGuestIpv6PrefixVO prefix = prepareMocksForIpv6Subnet();
prefixes.add(prefix);
prefixes.add(prefix);
Mockito.when(dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId)).thenReturn(prefixes);
Pair<Integer, Integer> results = ipv6Service.getUsedTotalIpv6SubnetForZone(zoneId);
Assert.assertEquals(4, results.first().intValue());
Assert.assertEquals(8, results.second().intValue());
}
@Test(expected = ResourceAllocationException.class)
@DB
public void testNoPrefixesPreAllocateIpv6SubnetForNetwork() throws ResourceAllocationException, MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanRegistrationException {
final long zoneId = 1L;
final List<DataCenterGuestIpv6PrefixVO> prefixes = new ArrayList<>();
Mockito.when(dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId)).thenReturn(prefixes);
TransactionLegacy txn = TransactionLegacy.open("testNoPrefixesPreAllocateIpv6SubnetForNetwork");
try {
ipv6Service.preAllocateIpv6SubnetForNetwork(zoneId);
} finally {
txn.close("testNoPrefixesPreAllocateIpv6SubnetForNetwork");
}
}
@Test
@DB
public void testExistingPreAllocateIpv6SubnetForNetwork() {
final long zoneId = 1L;
final List<DataCenterGuestIpv6PrefixVO> prefixes = new ArrayList<>();
DataCenterGuestIpv6PrefixVO prefix = prepareMocksForIpv6Subnet();
prefixes.add(prefix);
Ipv6GuestPrefixSubnetNetworkMapVO ipv6GuestPrefixSubnetNetworkMap = new Ipv6GuestPrefixSubnetNetworkMapVO(1L, "fd17:5:8a43:e2a4::/64", null, Ipv6GuestPrefixSubnetNetworkMap.State.Free);
Mockito.when(dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId)).thenReturn(prefixes);
Mockito.when(ipv6GuestPrefixSubnetNetworkMapDao.findFirstAvailable(prefix.getId())).thenReturn(ipv6GuestPrefixSubnetNetworkMap);
updatedPrefixSubnetMap.clear();
try (TransactionLegacy txn = TransactionLegacy.open("testNoPrefixesPreAllocateIpv6SubnetForNetwork")) {
try {
ipv6Service.preAllocateIpv6SubnetForNetwork(zoneId);
} catch (ResourceAllocationException e) {
Assert.fail("ResourceAllocationException");
}
}
Assert.assertEquals(1, updatedPrefixSubnetMap.size());
Ipv6GuestPrefixSubnetNetworkMapVO map = updatedPrefixSubnetMap.get(0);
Assert.assertEquals(Ipv6GuestPrefixSubnetNetworkMap.State.Allocating, map.getState());
Assert.assertEquals(ipv6GuestPrefixSubnetNetworkMap.getSubnet(), map.getSubnet());
Assert.assertEquals(ipv6GuestPrefixSubnetNetworkMap.getPrefixId(), map.getPrefixId());
Assert.assertNull(map.getNetworkId());
}
@Test
@DB
public void testNewPreAllocateIpv6SubnetForNetwork() {
final long zoneId = 1L;
final List<DataCenterGuestIpv6PrefixVO> prefixes = new ArrayList<>();
DataCenterGuestIpv6PrefixVO prefix = prepareMocksForIpv6Subnet();
final IPv6Network ip6Prefix = IPv6Network.fromString(prefix.getPrefix());
Iterator<IPv6Network> splits = ip6Prefix.split(IPv6NetworkMask.fromPrefixLength(Ipv6Service.IPV6_SLAAC_CIDR_NETMASK));
List<String> subnets = new ArrayList<>();
while(splits.hasNext()) {
subnets.add(splits.next().toString());
}
prefixes.add(prefix);
Mockito.when(dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId)).thenReturn(prefixes);
Mockito.when(ipv6GuestPrefixSubnetNetworkMapDao.findFirstAvailable(prefix.getId())).thenReturn(null);
Mockito.when(ipv6GuestPrefixSubnetNetworkMapDao.listUsedByPrefix(prefix.getId())).thenReturn(new ArrayList<>());
persistedPrefixSubnetMap.clear();
// No subnet is used from the prefix, should allocate any subnet
try (TransactionLegacy txn = TransactionLegacy.open("testNewPreAllocateIpv6SubnetForNetwork")) {
try {
ipv6Service.preAllocateIpv6SubnetForNetwork(zoneId);
} catch (ResourceAllocationException e) {
Assert.fail("ResourceAllocationException");
}
}
Assert.assertEquals(1, persistedPrefixSubnetMap.size());
Ipv6GuestPrefixSubnetNetworkMapVO map = persistedPrefixSubnetMap.get(0);
Assert.assertEquals(Ipv6GuestPrefixSubnetNetworkMap.State.Allocating, map.getState());
Assert.assertTrue(subnets.contains(map.getSubnet()));
Assert.assertEquals(prefix.getId(), map.getPrefixId());
Assert.assertNull(map.getNetworkId());
List<Ipv6GuestPrefixSubnetNetworkMapVO> usedSubnets = new ArrayList<>();
for (String subnet : subnets) {
usedSubnets.add(new Ipv6GuestPrefixSubnetNetworkMapVO(prefix.getId(), subnet, 1L, Ipv6GuestPrefixSubnetNetworkMap.State.Allocated));
}
Mockito.when(ipv6GuestPrefixSubnetNetworkMapDao.listUsedByPrefix(prefix.getId())).thenReturn(usedSubnets);
// All subnets from the prefix are already in use, should return ResourceAllocationException
try (TransactionLegacy txn = TransactionLegacy.open("testNewPreAllocateIpv6SubnetForNetwork")) {
try {
ipv6Service.preAllocateIpv6SubnetForNetwork(zoneId);
Assert.fail("ResourceAllocationException expected but not returned");
} catch (ResourceAllocationException ignored) {}
}
persistedPrefixSubnetMap.clear();
// 3 out of 4 subnet from the prefix are in use, should return the remaining one
Ipv6GuestPrefixSubnetNetworkMapVO poppedUsedSubnetMap = usedSubnets.remove(2);
try (TransactionLegacy txn = TransactionLegacy.open("testNewPreAllocateIpv6SubnetForNetwork")) {
try {
ipv6Service.preAllocateIpv6SubnetForNetwork(zoneId);
} catch (ResourceAllocationException e) {
Assert.fail("ResourceAllocationException");
}
}
Assert.assertEquals(1, persistedPrefixSubnetMap.size());
map = persistedPrefixSubnetMap.get(0);
Assert.assertEquals(Ipv6GuestPrefixSubnetNetworkMap.State.Allocating, map.getState());
Assert.assertEquals(poppedUsedSubnetMap.getSubnet(), map.getSubnet());
Assert.assertEquals(prefix.getId(), map.getPrefixId());
Assert.assertNull(map.getNetworkId());
}
@Test
@DB
public void testAssignIpv6SubnetToNetwork() {
final long prefixId = 1L;
final String subnet = "fd17:5:8a43:e2a5::/64";
final Long networkId = 100L;
Ipv6GuestPrefixSubnetNetworkMapVO allocatingMap = new Ipv6GuestPrefixSubnetNetworkMapVO(prefixId, subnet, null, Ipv6GuestPrefixSubnetNetworkMap.State.Allocating);
Mockito.when(ipv6GuestPrefixSubnetNetworkMapDao.findBySubnet(subnet)).thenReturn(allocatingMap);
Mockito.when(ipv6GuestPrefixSubnetNetworkMapDao.createForUpdate(Mockito.anyLong())).thenReturn(allocatingMap);
updatedPrefixSubnetMap.clear();
try (TransactionLegacy txn = TransactionLegacy.open("testNewPreAllocateIpv6SubnetForNetwork")) {
ipv6Service.assignIpv6SubnetToNetwork(subnet, networkId);
}
Assert.assertEquals(1, updatedPrefixSubnetMap.size());
Ipv6GuestPrefixSubnetNetworkMapVO map = updatedPrefixSubnetMap.get(0);
Assert.assertEquals(Ipv6GuestPrefixSubnetNetworkMap.State.Allocated, map.getState());
Assert.assertEquals(subnet, map.getSubnet());
Assert.assertEquals(prefixId, map.getPrefixId());
Assert.assertEquals(networkId, map.getNetworkId());
}
@Test
@DB
public void testReleaseIpv6SubnetForNetwork() {
final long prefixId = 1L;
final String subnet = "fd17:5:8a43:e2a5::/64";
Ipv6GuestPrefixSubnetNetworkMapVO allocatingMap = new Ipv6GuestPrefixSubnetNetworkMapVO(prefixId, subnet, networkId, Ipv6GuestPrefixSubnetNetworkMap.State.Allocated);
Mockito.when(ipv6GuestPrefixSubnetNetworkMapDao.findByNetworkId(networkId)).thenReturn(allocatingMap);
Mockito.when(ipv6GuestPrefixSubnetNetworkMapDao.createForUpdate(Mockito.anyLong())).thenReturn(allocatingMap);
updatedPrefixSubnetMap.clear();
try (TransactionLegacy txn = TransactionLegacy.open("testNewPreAllocateIpv6SubnetForNetwork")) {
ipv6Service.releaseIpv6SubnetForNetwork(networkId);
}
Assert.assertEquals(1, updatedPrefixSubnetMap.size());
Ipv6GuestPrefixSubnetNetworkMapVO map = updatedPrefixSubnetMap.get(0);
Assert.assertEquals(Ipv6GuestPrefixSubnetNetworkMap.State.Free, map.getState());
Assert.assertEquals(subnet, map.getSubnet());
Assert.assertEquals(prefixId, map.getPrefixId());
Assert.assertNull(map.getNetworkId());
}
@Test
public void testGetAllocatedIpv6FromVlanRange() {
Vlan vlan = Mockito.mock(Vlan.class);
Mockito.when(vlan.getIp6Cidr()).thenReturn(null);
Mockito.when(vlan.getIp6Gateway()).thenReturn(null);
Assert.assertNull(ipv6Service.getAllocatedIpv6FromVlanRange(vlan));
List<String> addresses = Arrays.asList("fd17:5:8a43:e2a5::1000", "fd17:5:8a43:e2a5::1001");
Vlan vlan1 = Mockito.mock(Vlan.class);
Mockito.when(vlan1.getIp6Cidr()).thenReturn(cidr);
Mockito.when(vlan1.getIp6Gateway()).thenReturn(gateway);
List<NicVO> nics = new ArrayList<>();
for (String address : addresses) {
NicVO nic = new NicVO(publicReserver, 100L, 1L, VirtualMachine.Type.DomainRouter);
nic.setIPv6Address(address);
nics.add(nic);
}
Mockito.when(nicDao.findNicsByIpv6GatewayIpv6CidrAndReserver(gateway, cidr, publicReserver)).thenReturn(nics);
List<String> result = ipv6Service.getAllocatedIpv6FromVlanRange(vlan1);
Assert.assertEquals(addresses.size(), result.size());
for (String address : addresses) {
Assert.assertTrue(result.contains(address));
}
}
@Test
public void testAlreadyExistAssignPublicIpv6ToNetwork() {
Nic nic = Mockito.mock(Nic.class);
Mockito.when(nic.getIPv6Address()).thenReturn(ipv6Address);
Nic assignedNic = ipv6Service.assignPublicIpv6ToNetwork(Mockito.mock(Network.class), nic);
Assert.assertEquals(ipv6Address, assignedNic.getIPv6Address());
}
@Test(expected = CloudRuntimeException.class)
public void testNewErrorAssignPublicIpv6ToNetwork() {
Nic nic = Mockito.mock(Nic.class);
Mockito.when(nic.getIPv6Address()).thenReturn(null);
Mockito.when(nic.getBroadcastUri()).thenReturn(URI.create(vlan));
Mockito.when(vlanDao.listIpv6RangeByPhysicalNetworkIdAndVlanId(1L, "vlan")).thenReturn(new ArrayList<>());
try (TransactionLegacy txn = TransactionLegacy.open("testNewErrorAssignPublicIpv6ToNetwork")) {
ipv6Service.assignPublicIpv6ToNetwork(Mockito.mock(Network.class), nic);
}
}
private List<NicVO> mockPlaceholderNics() {
NicVO placeholderNic = Mockito.mock(NicVO.class);
Mockito.when(placeholderNic.getIPv6Address()).thenReturn(ipv6Address);
Mockito.when(placeholderNic.getIPv6Gateway()).thenReturn(gateway);
Mockito.when(placeholderNic.getIPv6Cidr()).thenReturn(cidr);
Mockito.when(placeholderNic.getReserver()).thenReturn(publicReserver);
List<NicVO> placeholderNics = new ArrayList<>();
placeholderNics.add(placeholderNic);
return placeholderNics;
}
private void prepareMocksForPublicIpv6(boolean fromPlaceholder) {
VlanVO vlanVO = Mockito.mock(VlanVO.class);
Mockito.when(vlanVO.getIp6Cidr()).thenReturn(cidr);
Mockito.when(vlanVO.getIp6Gateway()).thenReturn(gateway);
Mockito.when(vlanVO.getVlanType()).thenReturn(Vlan.VlanType.VirtualNetwork);
List<VlanVO> vlans = new ArrayList<>();
vlans.add(vlanVO);
Mockito.when(vlanDao.listIpv6RangeByPhysicalNetworkIdAndVlanId(Mockito.anyLong(), Mockito.anyString())).thenReturn(vlans);
List<NicVO> placeholderNics = new ArrayList<>();
if (fromPlaceholder) {
placeholderNics = mockPlaceholderNics();
}
Mockito.when(nicDao.listPlaceholderNicsByNetworkIdAndVmType(networkId, VirtualMachine.Type.DomainRouter)).thenReturn(placeholderNics);
Mockito.when(nicDao.createForUpdate(nicId)).thenReturn(new NicVO(publicReserver, 100L, 1L, VirtualMachine.Type.DomainRouter));
PowerMockito.mockStatic(ActionEventUtils.class);
Mockito.when(ActionEventUtils.onCompletedActionEvent(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(), Mockito.anyLong())).thenReturn(1L);
PowerMockito.mockStatic(UsageEventUtils.class);
}
@Test
@DB
public void testNewAssignPublicIpv6ToNetwork() {
NicVO nic = Mockito.mock(NicVO.class);
Mockito.when(nic.getIPv6Address()).thenReturn(null);
Mockito.when(nic.getBroadcastUri()).thenReturn(URI.create(vlan));
Mockito.when(nic.getMacAddress()).thenReturn(macAddress);
Mockito.when(nic.getId()).thenReturn(nicId);
Network network = Mockito.mock(Network.class);
Mockito.when(network.getId()).thenReturn(networkId);
prepareMocksForPublicIpv6(false);
Nic assignedNic;
try (TransactionLegacy txn = TransactionLegacy.open("testNewPreAllocateIpv6SubnetForNetwork")) {
assignedNic = ipv6Service.assignPublicIpv6ToNetwork(network, nic);
}
Assert.assertEquals(ipv6Address, assignedNic.getIPv6Address());
Assert.assertEquals(gateway, assignedNic.getIPv6Gateway());
Assert.assertEquals(cidr, assignedNic.getIPv6Cidr());
}
@Test
public void testFromPlaceholderAssignPublicIpv6ToNetwork() {
NicVO nic = Mockito.mock(NicVO.class);
Mockito.when(nic.getIPv6Address()).thenReturn(null);
Mockito.when(nic.getBroadcastUri()).thenReturn(URI.create(vlan));
Mockito.when(nic.getId()).thenReturn(nicId);
Network network = Mockito.mock(Network.class);
Mockito.when(network.getId()).thenReturn(networkId);
prepareMocksForPublicIpv6(true);
Nic assignedNic = ipv6Service.assignPublicIpv6ToNetwork(network, nic);
Assert.assertEquals(ipv6Address, assignedNic.getIPv6Address());
Assert.assertEquals(gateway, assignedNic.getIPv6Gateway());
Assert.assertEquals(cidr, assignedNic.getIPv6Cidr());
}
@Test
public void testIpv4NetworkUpdateNicIpv6() {
Mockito.when(networkOfferingDao.isIpv6Supported(Mockito.anyLong())).thenReturn(false);
NicProfile nicProfile = new NicProfile();
try {
ipv6Service.updateNicIpv6(nicProfile, Mockito.mock(DataCenter.class), Mockito.mock(Network.class));
} catch (InsufficientAddressCapacityException e) {
Assert.fail("InsufficientAddressCapacityException");
}
Assert.assertNull(nicProfile.getIPv6Address());
Assert.assertNull(nicProfile.getIPv6Gateway());
Assert.assertNull(nicProfile.getIPv6Cidr());
}
@Test
public void testIpv6NetworkUpdateNicIpv6() {
Mockito.when(networkOfferingDao.isIpv6Supported(Mockito.anyLong())).thenReturn(true);
NicProfile nicProfile = new NicProfile();
nicProfile.setBroadcastUri(URI.create(vlan));
nicProfile.setMacAddress(macAddress);
prepareMocksForPublicIpv6(false);
try {
ipv6Service.updateNicIpv6(nicProfile, Mockito.mock(DataCenter.class), Mockito.mock(Network.class));
} catch (InsufficientAddressCapacityException e) {
Assert.fail("InsufficientAddressCapacityException");
}
Assert.assertEquals(ipv6Address, nicProfile.getIPv6Address());
Assert.assertEquals(gateway, nicProfile.getIPv6Gateway());
Assert.assertEquals(cidr, nicProfile.getIPv6Cidr());
}
@Test
public void testIpv6NetworkFromPlaceholderUpdateNicIpv6() {
Mockito.when(networkOfferingDao.isIpv6Supported(Mockito.anyLong())).thenReturn(true);
NicProfile nicProfile = new NicProfile();
nicProfile.setBroadcastUri(URI.create(vlan));
nicProfile.setMacAddress(macAddress);
prepareMocksForPublicIpv6(true);
try {
ipv6Service.updateNicIpv6(nicProfile, Mockito.mock(DataCenter.class), Mockito.mock(Network.class));
} catch (InsufficientAddressCapacityException e) {
Assert.fail("InsufficientAddressCapacityException");
}
Assert.assertEquals(ipv6Address, nicProfile.getIPv6Address());
Assert.assertEquals(gateway, nicProfile.getIPv6Gateway());
Assert.assertEquals(cidr, nicProfile.getIPv6Cidr());
}
@Test
public void testEmptyGetPublicIpv6AddressesForNetwork(){
Mockito.when(domainRouterDao.findByNetwork(Mockito.anyLong())).thenReturn(new ArrayList<>());
List<String> addresses = ipv6Service.getPublicIpv6AddressesForNetwork(Mockito.mock(Network.class));
Assert.assertTrue(CollectionUtils.isEmpty(addresses));
List<DomainRouterVO> routers = List.of(Mockito.mock(DomainRouterVO.class));
Mockito.when(domainRouterDao.findByNetwork(Mockito.anyLong())).thenReturn(routers);
Mockito.when(nicDao.listByVmId(Mockito.anyLong())).thenReturn(new ArrayList<>());
addresses = ipv6Service.getPublicIpv6AddressesForNetwork(Mockito.mock(Network.class));
Assert.assertTrue(CollectionUtils.isEmpty(addresses));
NicVO nic = Mockito.mock(NicVO.class);
Mockito.when(nic.getIPv6Address()).thenReturn(null);
List<NicVO> nics = List.of(nic);
Mockito.when(nicDao.listByVmId(Mockito.anyLong())).thenReturn(nics);
addresses = ipv6Service.getPublicIpv6AddressesForNetwork(Mockito.mock(Network.class));
Assert.assertTrue(CollectionUtils.isEmpty(addresses));
}
@Test
public void testGetPublicIpv6AddressesForNetwork(){
List<DomainRouterVO> routers = List.of(Mockito.mock(DomainRouterVO.class), Mockito.mock(DomainRouterVO.class));
Mockito.when(domainRouterDao.findByNetwork(Mockito.anyLong())).thenReturn(routers);
NicVO nic = Mockito.mock(NicVO.class);
Mockito.when(nic.getIPv6Address()).thenReturn(ipv6Address);
Mockito.when(nic.getReserver()).thenReturn(publicReserver);
List<NicVO> nics = List.of(nic);
Mockito.when(nicDao.listByVmId(Mockito.anyLong())).thenReturn(nics);
List<String> addresses = ipv6Service.getPublicIpv6AddressesForNetwork(Mockito.mock(Network.class));
Assert.assertEquals(1, addresses.size());
Assert.assertEquals(ipv6Address, addresses.get(0));
}
@Test
public void testEmptyUpdateIpv6RoutesForVpcResponse() {
VpcResponse response = new VpcResponse();
Vpc vpc = Mockito.mock(Vpc.class);
List<NetworkVO> networks = new ArrayList<>();
Mockito.doReturn(networks).when(networkModel).listNetworksByVpc(Mockito.anyLong());
ipv6Service.updateIpv6RoutesForVpcResponse(vpc, response);
Assert.assertTrue(CollectionUtils.isEmpty(response.getIpv6Routes()));
}
@Test
public void testUpdateIpv6RoutesForVpcResponse() {
VpcResponse response = new VpcResponse();
Vpc vpc = Mockito.mock(Vpc.class);
List<NetworkVO> networks = new ArrayList<>();
NetworkVO network = Mockito.mock(NetworkVO.class);
Mockito.when(network.getIp6Cidr()).thenReturn(cidr);
networks.add(network);
List<DomainRouterVO> routers = List.of(Mockito.mock(DomainRouterVO.class));
Mockito.when(domainRouterDao.findByNetwork(Mockito.anyLong())).thenReturn(routers);
NicVO nic = Mockito.mock(NicVO.class);
Mockito.when(nic.getIPv6Address()).thenReturn(ipv6Address);
Mockito.when(nic.getReserver()).thenReturn(publicReserver);
Mockito.when(nicDao.listByVmId(Mockito.anyLong())).thenReturn(List.of(nic));
Mockito.doReturn(networks).when(networkModel).listNetworksByVpc(Mockito.anyLong());
Mockito.when(networkOfferingDao.isIpv6Supported(Mockito.anyLong())).thenReturn(true);
ipv6Service.updateIpv6RoutesForVpcResponse(vpc, response);
Assert.assertEquals(1, response.getIpv6Routes().size());
Ipv6RouteResponse routeResponse = new ArrayList<>(response.getIpv6Routes()).get(0);
Assert.assertEquals(ipv6Address, routeResponse.getGateway());
Assert.assertEquals(cidr, routeResponse.getSubnet());
}
@Test
public void testCheckNetworkIpv6UpgradeForNoPrefixes() {
Mockito.when(dataCenterGuestIpv6PrefixDao.listByDataCenterId(Mockito.anyLong())).thenReturn(new ArrayList<>());
try {
ipv6Service.checkNetworkIpv6Upgrade(Mockito.mock(Network.class));
Assert.fail("No ResourceAllocationException");
} catch (InsufficientAddressCapacityException | ResourceAllocationException ignored) {}
}
@Test
public void testCheckNetworkIpv6UpgradeForNoIpv6Vlan() {
final long physicalNetworkId = 1L;
Mockito.when(dataCenterGuestIpv6PrefixDao.listByDataCenterId(Mockito.anyLong())).thenReturn(List.of(Mockito.mock(DataCenterGuestIpv6PrefixVO.class)));
Network network = Mockito.mock(Network.class);
Mockito.when(network.getPhysicalNetworkId()).thenReturn(physicalNetworkId);
Mockito.when(network.getVpcId()).thenReturn(null);
Mockito.when(ipAddressDao.listByAssociatedNetwork(Mockito.anyLong(), Mockito.anyBoolean())).thenReturn(List.of(Mockito.mock(IPAddressVO.class)));
VlanVO vlanVO = Mockito.mock(VlanVO.class);
Mockito.when(vlanVO.getVlanTag()).thenReturn(vlan);
Mockito.when(vlanDao.findById(Mockito.anyLong())).thenReturn(vlanVO);
Mockito.when(vlanDao.listIpv6RangeByPhysicalNetworkIdAndVlanId(Mockito.anyLong(), Mockito.anyString())).thenReturn(new ArrayList<>());
try {
ipv6Service.checkNetworkIpv6Upgrade(network);
Assert.fail("No InsufficientAddressCapacityException");
} catch (InsufficientAddressCapacityException | ResourceAllocationException ignored) {}
}
@Test
public void testCheckNetworkIpv6UpgradeForNetwork() {
final long physicalNetworkId = 1L;
Mockito.when(dataCenterGuestIpv6PrefixDao.listByDataCenterId(Mockito.anyLong())).thenReturn(List.of(Mockito.mock(DataCenterGuestIpv6PrefixVO.class)));
Network network = Mockito.mock(Network.class);
Mockito.when(network.getPhysicalNetworkId()).thenReturn(physicalNetworkId);
Mockito.when(network.getVpcId()).thenReturn(null);
Mockito.when(ipAddressDao.listByAssociatedNetwork(Mockito.anyLong(), Mockito.anyBoolean())).thenReturn(List.of(Mockito.mock(IPAddressVO.class)));
VlanVO vlanVO = Mockito.mock(VlanVO.class);
Mockito.when(vlanVO.getVlanTag()).thenReturn(vlan);
Mockito.when(vlanDao.findById(Mockito.anyLong())).thenReturn(vlanVO);
Mockito.when(vlanDao.listIpv6RangeByPhysicalNetworkIdAndVlanId(physicalNetworkId, vlan)).thenReturn(List.of(vlanVO));
try {
ipv6Service.checkNetworkIpv6Upgrade(network);
} catch (InsufficientAddressCapacityException | ResourceAllocationException e) {
throw new RuntimeException(e);
}
}
@Test
public void testUpdateIpv6FirewallRule() {
final Long firewallRuleId = 1L;
UpdateIpv6FirewallRuleCmd cmd = Mockito.mock(UpdateIpv6FirewallRuleCmd.class);
Mockito.when(cmd.getId()).thenReturn(firewallRuleId);
Mockito.when(firewallDao.findById(firewallRuleId)).thenReturn(null);
try {
ipv6Service.updateIpv6FirewallRule(cmd);
Assert.fail("No InvalidParameterValueException");
} catch (InvalidParameterValueException ignored) {}
FirewallRuleVO ingressFirewallRule = Mockito.mock(FirewallRuleVO.class);
Mockito.when(ingressFirewallRule.getTrafficType()).thenReturn(FirewallRule.TrafficType.Ingress);
Mockito.when(firewallDao.findById(firewallRuleId)).thenReturn(ingressFirewallRule);
try {
ipv6Service.updateIpv6FirewallRule(cmd);
} catch (InvalidParameterValueException e) {
throw new RuntimeException(e);
}
}
@Test
public void testDeleteIpv6FirewallRule() {
final Long firewallRuleId = 1L;
Mockito.when(firewallDao.findById(firewallRuleId)).thenReturn(null);
try {
ipv6Service.revokeIpv6FirewallRule(firewallRuleId);
Assert.fail("No InvalidParameterValueException");
} catch (InvalidParameterValueException ignored) {}
FirewallRuleVO ingressFirewallRule = Mockito.mock(FirewallRuleVO.class);
Mockito.when(ingressFirewallRule.getTrafficType()).thenReturn(FirewallRule.TrafficType.Ingress);
Mockito.when(firewallDao.findById(firewallRuleId)).thenReturn(ingressFirewallRule);
try {
ipv6Service.revokeIpv6FirewallRule(firewallRuleId);
} catch (InvalidParameterValueException e) {
throw new RuntimeException(e);
}
}
@Test
public void testGetIpv6FirewallRule() {
final Long firewallRuleId = 1L;
final String uuid = UUID.randomUUID().toString();
Mockito.when(firewallDao.findById(firewallRuleId)).thenReturn(null);
FirewallRule rule = ipv6Service.getIpv6FirewallRule(firewallRuleId);
Assert.assertNull(rule);
FirewallRuleVO ingressFirewallRule = Mockito.mock(FirewallRuleVO.class);
Mockito.when(ingressFirewallRule.getUuid()).thenReturn(uuid);
Mockito.when(firewallDao.findById(firewallRuleId)).thenReturn(ingressFirewallRule);
rule = ipv6Service.getIpv6FirewallRule(firewallRuleId);
Assert.assertEquals(uuid, rule.getUuid());
}
private void registerCallContext() {
account = new AccountVO("testaccount", 1L, "networkdomain", Account.Type.NORMAL, "uuid");
account.setId(ACCOUNT_ID);
user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone",
UUID.randomUUID().toString(), User.Source.UNKNOWN);
CallContext.register(user, account);
}
@Test(expected = InvalidParameterValueException.class)
public void testInvalidSourceCidrCreateIpv6FirewallRule() {
registerCallContext();
CreateIpv6FirewallRuleCmd cmd = Mockito.mock(CreateIpv6FirewallRuleCmd.class);
Mockito.when(cmd.getSourceCidrList()).thenReturn(List.of("10.1.1.1"));
try {
ipv6Service.createIpv6FirewallRule(cmd);
} catch (NetworkRuleConflictException e) {
throw new RuntimeException(e);
}
}
@Test(expected = InvalidParameterValueException.class)
public void testInvalidDestinationCidrCreateIpv6FirewallRule() {
registerCallContext();
CreateIpv6FirewallRuleCmd cmd = Mockito.mock(CreateIpv6FirewallRuleCmd.class);
Mockito.when(cmd.getDestinationCidrList()).thenReturn(List.of("10.1.1.1"));
try {
ipv6Service.createIpv6FirewallRule(cmd);
} catch (NetworkRuleConflictException e) {
throw new RuntimeException(e);
}
}
@Test(expected = InvalidParameterValueException.class)
public void testStartPortCidrCreateIpv6FirewallRule() {
registerCallContext();
CreateIpv6FirewallRuleCmd cmd = Mockito.mock(CreateIpv6FirewallRuleCmd.class);
Mockito.when(cmd.getSourcePortStart()).thenReturn(800000);
try {
ipv6Service.createIpv6FirewallRule(cmd);
} catch (NetworkRuleConflictException e) {
throw new RuntimeException(e);
}
}
@Test(expected = InvalidParameterValueException.class)
public void testEndPortCidrCreateIpv6FirewallRule() {
registerCallContext();
CreateIpv6FirewallRuleCmd cmd = Mockito.mock(CreateIpv6FirewallRuleCmd.class);
Mockito.when(cmd.getSourcePortEnd()).thenReturn(800000);
try {
ipv6Service.createIpv6FirewallRule(cmd);
} catch (NetworkRuleConflictException e) {
throw new RuntimeException(e);
}
}
@Test(expected = InvalidParameterValueException.class)
public void testPortRangeCidrCreateIpv6FirewallRule() {
registerCallContext();
CreateIpv6FirewallRuleCmd cmd = Mockito.mock(CreateIpv6FirewallRuleCmd.class);
Mockito.when(cmd.getSourcePortStart()).thenReturn(900);
Mockito.when(cmd.getSourcePortEnd()).thenReturn(800);
try {
ipv6Service.createIpv6FirewallRule(cmd);
} catch (NetworkRuleConflictException e) {
throw new RuntimeException(e);
}
}
@Test
public void testRemovePublicIpv6PlaceholderNics() {
Network network = Mockito.mock(NetworkVO.class);
Mockito.when(network.getId()).thenReturn(networkId);
NicVO nic = Mockito.mock(NicVO.class);
Mockito.when(nic.getId()).thenReturn(nicId);
Mockito.when(nic.getIPv6Address()).thenReturn(ipv6Address);
Mockito.when(nic.getIPv6Cidr()).thenReturn(cidr);
Mockito.when(nic.getIPv6Gateway()).thenReturn(gateway);
Mockito.when(nic.getReserver()).thenReturn(publicReserver);
Mockito.when(nicDao.listPlaceholderNicsByNetworkId(Mockito.anyLong())).thenReturn(List.of(nic));
final List<Long> removedNics = new ArrayList<>();
Mockito.when(nicDao.remove(Mockito.anyLong())).thenAnswer((Answer<Boolean>) invocation -> {
removedNics.add((Long)invocation.getArguments()[0]);
return true;
});
PowerMockito.mockStatic(ActionEventUtils.class);
Mockito.when(ActionEventUtils.onCompletedActionEvent(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(), Mockito.anyLong())).thenReturn(1L);
PowerMockito.mockStatic(UsageEventUtils.class);
ipv6Service.removePublicIpv6PlaceholderNics(network);
Assert.assertEquals(1, removedNics.size());
Assert.assertEquals(nicId, removedNics.get(0));
removedNics.clear();
NicVO nic1 = Mockito.mock(NicVO.class);
Mockito.when(nic1.getId()).thenReturn(nicId);
Mockito.when(nic1.getIPv6Address()).thenReturn(null);
Mockito.when(nicDao.listPlaceholderNicsByNetworkId(Mockito.anyLong())).thenReturn(List.of(nic1));
ipv6Service.removePublicIpv6PlaceholderNics(network);
Assert.assertEquals(0, removedNics.size());
}
}

View File

@ -20,31 +20,33 @@ package com.cloud.network.vpc;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import static org.powermock.api.mockito.PowerMockito.when;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.network.NetworkModel;
import com.cloud.network.element.NetworkElement;
import com.cloud.network.Network;
import com.cloud.network.Network.Capability;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.cloudstack.api.command.admin.vpc.CreateVPCOfferingCmd;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import com.cloud.network.Network.Provider;
import com.cloud.network.Network.Service;
import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao;
import org.powermock.reflect.Whitebox;
import static org.mockito.Mockito.mock;
import static org.powermock.api.mockito.PowerMockito.when;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.network.Network;
import com.cloud.network.Network.Capability;
import com.cloud.network.Network.Provider;
import com.cloud.network.Network.Service;
import com.cloud.network.NetworkModel;
import com.cloud.network.element.NetworkElement;
import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao;
import com.cloud.utils.net.NetUtils;
public class VpcManagerImplTest {
@ -162,4 +164,11 @@ public class VpcManagerImplTest {
return providers;
}
@Test(expected = InvalidParameterValueException.class)
public void testDisabledConfigCreateIpv6VpcOffering() {
CreateVPCOfferingCmd cmd = Mockito.mock(CreateVPCOfferingCmd.class);
Mockito.when(cmd.getInternetProtocol()).thenReturn(NetUtils.InternetProtocol.DualStack.toString());
manager.createVpcOffering(cmd);
}
}

View File

@ -0,0 +1,935 @@
# 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.
""" BVT tests for IPv6 Network"""
#Import Local Modules
from marvin.codes import FAILED
from marvin.cloudstackTestCase import cloudstackTestCase
from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
listGuestNetworkIpv6Prefixes,
deleteGuestNetworkIpv6Prefix,
listIpv6FirewallRules,
createIpv6FirewallRule,
deleteIpv6FirewallRule)
from marvin.lib.utils import (random_gen,
get_process_status,
get_host_credentials)
from marvin.lib.base import (Configurations,
Domain,
NetworkOffering,
Account,
PublicIpRange,
Network,
Router,
ServiceOffering,
VirtualMachine,
NIC,
Host)
from marvin.lib.common import (get_domain,
get_zone,
list_hosts,
get_test_template)
from marvin.sshClient import SshClient
from marvin.cloudstackException import CloudstackAPIException
from marvin.lib.decoratorGenerators import skipTestIf
from nose.plugins.attrib import attr
from ipaddress import IPv6Network
from random import getrandbits, choice, randint
import time
import logging
import threading
ipv6_offering_config_name = "ipv6.offering.enabled"
ULA_BASE = IPv6Network("fd00::/8")
PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
FIREWALL_TABLE = "ip6_firewall"
FIREWALL_CHAINS = {
"Ingress": "fw_chain_ingress",
"Egress": "fw_chain_egress"
}
CIDR_IPV6_ANY = "::/0"
ICMPV6_TYPE = {
1: "destination-unreachable",
2: "packet-too-big",
3: "time-exceeded",
4: "parameter-problem",
128: "echo-request",
129: "echo-reply",
130: "mld-listener-query",
131: "mld-listener-report",
132: "mld-listener-done",
133: "nd-router-solicit",
134: "nd-router-advert",
135: "nd-neighbor-solicit",
136: "nd-neighbor-advert",
137: "nd-redirect",
138: "router-renumbering",
141: "ind-neighbor-solicit",
142: "ind-neighbor-advert",
143: "mld2-listener-report"
}
ICMPV6_CODE_TYPE = {
0: "no-route",
1: "admin-prohibited",
3: "addr-unreachable",
4: "port-unreachable",
5: "policy-fail",
6: "reject-route"
}
ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
TCP_UDP_PORT_ANY = "{ 0-65535 }"
SLEEP_BEFORE_VR_CHANGES = 45
PING_RETRIES = 5
PING_SLEEP = 20
class TestIpv6Network(cloudstackTestCase):
@classmethod
def setUpClass(cls):
testClient = super(TestIpv6Network, cls).getClsTestClient()
cls.services = testClient.getParsedTestDataConfig()
cls.apiclient = testClient.getApiClient()
cls.dbclient = testClient.getDbConnection()
cls.test_ipv6_guestprefix = None
cls.initial_ipv6_offering_enabled = None
cls._cleanup = []
cls.routerDetailsMap = {}
cls.logger = logging.getLogger('TestIpv6Network')
cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
cls.services['mode'] = cls.zone.networktype
cls.ipv6NotSupported = False
ipv6_guestprefix = cls.getGuestIpv6Prefix()
if ipv6_guestprefix == None:
cls.ipv6NotSupported = True
if cls.ipv6NotSupported == False:
ipv6_publiciprange = cls.getPublicIpv6Range()
if ipv6_publiciprange == None:
cls.ipv6NotSupported = True
if cls.ipv6NotSupported == False:
cls.initial_ipv6_offering_enabled = Configurations.list(
cls.apiclient,
name=ipv6_offering_config_name)[0].value
Configurations.update(cls.apiclient,
ipv6_offering_config_name,
"true")
cls.domain = get_domain(cls.apiclient)
cls.account = Account.create(
cls.apiclient,
cls.services["account"],
admin=True,
domainid=cls.domain.id
)
cls._cleanup.append(cls.account)
cls.hypervisor = testClient.getHypervisorInfo()
cls.template = get_test_template(
cls.apiclient,
cls.zone.id,
cls.hypervisor)
else:
cls.debug("IPv6 is not supported, skipping tests!")
return
@classmethod
def tearDownClass(cls):
if cls.initial_ipv6_offering_enabled != None:
Configurations.update(cls.apiclient,
ipv6_offering_config_name,
cls.initial_ipv6_offering_enabled)
try:
super(TestIpv6Network, cls).tearDownClass()
finally:
if cls.test_ipv6_guestprefix != None:
cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
cmd.id = cls.test_ipv6_guestprefix.id
cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
@classmethod
def getGuestIpv6Prefix(cls):
cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
cmd.zoneid = cls.zone.id
ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
return ipv6_prefixes_response[0]
ipv6_guestprefix_service = cls.services["guestip6prefix"]
cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
cmd.zoneid = cls.zone.id
cmd.prefix = ipv6_guestprefix_service["prefix"]
ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
cls.test_ipv6_guestprefix = ipv6_guestprefix
return ipv6_guestprefix
@classmethod
def getPublicIpv6Range(cls):
list_public_ip_range_response = PublicIpRange.list(
cls.apiclient,
zoneid=cls.zone.id
)
ipv4_range_vlan = None
if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
for ip_range in list_public_ip_range_response:
if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
return ip_range
if ip_range.netmask != None and ip_range.gateway != None:
vlan = ip_range.vlan
if ipv4_range_vlan == None and vlan.startswith("vlan://"):
vlan = vlan.replace("vlan://", "")
if vlan == "untagged":
ipv4_range_vlan = None
else:
ipv4_range_vlan = int(vlan)
ipv6_publiciprange_service = cls.services["publicip6range"]
ipv6_publiciprange_service["zoneid"] = cls.zone.id
ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
ipv6_publiciprange = PublicIpRange.create(
cls.apiclient,
ipv6_publiciprange_service
)
cls._cleanup.append(ipv6_publiciprange)
return ipv6_publiciprange
def setUp(self):
self.services = self.testClient.getParsedTestDataConfig()
self.apiclient = self.testClient.getApiClient()
self.dbclient = self.testClient.getDbConnection()
self.thread = None
self.cleanup = []
return
def tearDown(self):
try:
if self.thread and self.thread.is_alive():
self.thread.join(5*60)
except Exception as e:
raise Exception("Warning: Exception during cleanup : %s" % e)
finally:
super(TestIpv6Network, self).tearDown()
return
def getRandomIpv6Cidr(self):
prefix_length = choice(PREFIX_OPTIONS)
random_suffix = getrandbits(40) << (128-prefix_length)
base_address = ULA_BASE.network_address + random_suffix
return str(IPv6Network((base_address, prefix_length)))
def createTinyServiceOffering(self):
self.service_offering = ServiceOffering.create(
self.apiclient,
self.services["service_offerings"]["big"],
)
self.cleanup.append(self.service_offering)
def createNetworkOfferingInternal(self, is_redundant, is_ipv6, egressdefaultpolicy=True):
off_service = self.services["network_offering"]
if is_redundant:
off_service = self.services["nw_off_isolated_RVR"]
if is_ipv6:
off_service["internetprotocol"] = "dualstack"
if egressdefaultpolicy:
off_service["egress_policy"] = egressdefaultpolicy
network_offering = NetworkOffering.create(
self.apiclient,
off_service
)
self.cleanup.append(network_offering)
network_offering.update(self.apiclient, state='Enabled')
return network_offering
def createIpv4NetworkOffering(self, is_redundant=False):
self.network_offering = self.createNetworkOfferingInternal(is_redundant, False, False)
def createIpv6NetworkOffering(self, is_redundant=False):
self.network_offering = self.createNetworkOfferingInternal(is_redundant, True, False)
def createIpv6NetworkOfferingForUpdate(self, is_redundant=False):
self.network_offering_update = self.createNetworkOfferingInternal(is_redundant, True)
def deployNetwork(self):
self.services["network"]["networkoffering"] = self.network_offering.id
self.network = Network.create(
self.apiclient,
self.services["network"],
self.account.name,
self.account.domainid,
zoneid=self.zone.id
)
self.cleanup.append(self.network)
def deployNetworkVm(self):
if self.template == FAILED:
assert False, "get_test_template() failed to return template"
self.services["virtual_machine"]["zoneid"] = self.zone.id
self.virtual_machine = VirtualMachine.create(
self.apiclient,
self.services["virtual_machine"],
templateid=self.template.id,
accountid=self.account.name,
domainid=self.account.domainid,
networkids=self.network.id,
serviceofferingid=self.service_offering.id
)
self.cleanup.append(self.virtual_machine)
def checkIpv6NetworkBasic(self):
self.debug("Listing network: %s" % (self.network.name))
ipv6_network = Network.list(self.apiclient,listall="true",id=self.network.id)
self.assertTrue(
isinstance(ipv6_network, list),
"Check listNetworks response returns a valid list"
)
self.assertEqual(
len(ipv6_network),
1,
"Network not found"
)
ipv6_network = ipv6_network[0]
self.assertNotEqual(ipv6_network,
None,
"User is not able to retrieve network details %s" % self.network.id)
self.assertNotEqual(ipv6_network.ip6cidr,
None,
"IPv6 CIDR for network is empty")
self.assertNotEqual(ipv6_network.ip6gateway,
None,
"IPv6 gateway for network is empty")
self.assertNotEqual(ipv6_network.ip6routes,
None,
"IPv6 routes for network is empty")
self.network_ipv6_routes = ipv6_network.ip6routes
def checkIpv6NetworkRoutersBasic(self):
self.debug("Listing routers for network: %s" % self.network.name)
self.routers = Router.list(
self.apiclient,
networkid=self.network.id,
listall=True
)
self.assertTrue(
isinstance(self.routers, list),
"Check listRouters response returns a valid list"
)
self.assertTrue(
len(self.routers) > 0,
"Router for the network isn't found"
)
for router in self.routers:
self.assertFalse(
router.isredundantrouter == True and router.redundantstate == "FAULT",
"Router for the network is in FAULT state"
)
nics = router.nic
for nic in nics:
if (nic.traffictype == 'Guest' and router.isredundantrouter == False) or nic.traffictype == 'Public':
self.assertNotEqual(nic.ip6address,
None,
"IPv6 address for router %s NIC is empty" % nic.traffictype)
self.assertNotEqual(nic.ip6cidr,
None,
"IPv6 CIDR for router %s NIC is empty" % nic.traffictype)
self.assertNotEqual(nic.ip6gateway,
None,
"IPv6 gateway for router %s NIC is empty" % nic.traffictype)
def getRouterProcessStatus(self, router, cmd):
if router.id not in self.routerDetailsMap or self.routerDetailsMap[router.id] is None:
connect_ip = self.apiclient.connection.mgtSvr
connect_user = self.apiclient.connection.user
connect_passwd = self.apiclient.connection.passwd
hypervisor = self.hypervisor
if self.hypervisor.lower() not in ('vmware', 'hyperv'):
hosts = Host.list(
self.apiclient,
zoneid=router.zoneid,
type='Routing',
state='Up',
id=router.hostid
)
self.assertEqual(
isinstance(hosts, list),
True,
"Check list host returns a valid list"
)
host = hosts[0]
connect_ip = host.ipaddress
hypervisor = None
try:
connect_user, connect_passwd= get_host_credentials(
self.config, host.ipaddress)
except KeyError:
self.skipTest(
"Marvin configuration has no host credentials to\
check router services")
details = {}
details['connect_ip'] = connect_ip
details['connect_user'] = connect_user
details['connect_passwd'] = connect_passwd
details['hypervisor'] = hypervisor
self.routerDetailsMap[router.id] = details
result = get_process_status(
self.routerDetailsMap[router.id]['connect_ip'],
22,
self.routerDetailsMap[router.id]['connect_user'],
self.routerDetailsMap[router.id]['connect_passwd'],
router.linklocalip,
cmd,
hypervisor=self.routerDetailsMap[router.id]['hypervisor']
)
self.assertTrue(type(result) == list and len(result) > 0,
"%s on router %s returned invalid result" % (cmd, router.id))
result = '\n'.join(result)
return result
def getNetworkRouter(self, network, red_state="PRIMARY"):
routers = Router.list(
self.apiclient,
networkid=network.id,
listall=True
)
self.assertTrue(
isinstance(routers, list) and len(routers) > 0,
"No routers found for network %s" % network.id
)
if len(routers) == 1:
return routers[0]
for router in routers:
if router.redundantstate == red_state:
return router
def getNetworkGateway(self, network):
ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
self.assertTrue(
isinstance(ipv6_network, list),
"Check listNetworks response returns a valid list"
)
self.assertEqual(
len(ipv6_network),
1,
"Network not found"
)
ipv6_network = ipv6_network[0]
self.assertNotEqual(ipv6_network.ip6gateway,
None,
"IPv6 gateway for network is empty")
return ipv6_network.ip6gateway
def getNetworkRoutes(self, network):
ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
self.assertTrue(
isinstance(ipv6_network, list),
"Check listNetworks response returns a valid list"
)
self.assertEqual(
len(ipv6_network),
1,
"Network not found"
)
ipv6_network = ipv6_network[0]
self.assertNotEqual(ipv6_network.ip6routes,
None,
"IPv6 routes for network is empty")
return ipv6_network.ip6routes
def isNetworkEgressDefaultPolicyAllow(self, network):
ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
if len(ipv6_network) == 1:
ipv6_network = ipv6_network[0]
return ipv6_network.egressdefaultpolicy
return False
def checkRouterNicState(self, router, dev, state):
st = "state %s" % state
cmd = "ip link show %s | grep '%s'" % (dev, st)
res = self.getRouterProcessStatus(router, cmd)
self.assertTrue(type(res) == str and len(res) > 0 and st in res,
"%s failed on router %s" % (cmd, router.id))
def checkIpv6NetworkPrimaryRouter(self, router, network_ip6gateway):
self.checkRouterNicState(router, "eth0", "UP")
guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % ("eth0", network_ip6gateway)
res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
self.assertTrue(type(res) == str and len(res) > 0 and network_ip6gateway in res,
"%s failed on router %s" % (guest_gateway_check_cmd, router.id))
self.assertFalse("dadfailed" in res,
"dadfailed for IPv6 guest gateway on router %s" % router.id)
self.checkRouterNicState(router, "eth2", "UP")
public_ipv6 = None
public_ipv6_gateway = None
nics = router.nic
for nic in nics:
if nic.traffictype == 'Public':
public_ipv6 = nic.ip6address
public_ipv6_gateway = nic.ip6gateway
break
self.assertNotEqual(public_ipv6,
None,
"IPv6 address for router Public NIC is empty")
public_ip_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % ("eth2", public_ipv6)
res = self.getRouterProcessStatus(router, public_ip_check_cmd)
self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6 in res,
"%s failed on router %s" % (public_ip_check_cmd, router.id))
self.assertFalse("dadfailed" in res,
"dadfailed for public IPv6 on router %s" % router.id)
self.assertNotEqual(public_ipv6_gateway,
None,
"IPv6 gateway for router Public NIC is empty")
default_route_check_cmd = "ip -6 route | grep 'default via %s'" % (public_ipv6_gateway)
res = self.getRouterProcessStatus(router, default_route_check_cmd)
self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6_gateway in res,
"%s failed on router %s" % (default_route_check_cmd, router.id))
def checkIpv6NetworkBackupRouter(self, router, network_ip6gateway):
self.checkRouterNicState(router, "eth0", "UP")
guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % ("eth0", network_ip6gateway)
res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
self.assertFalse(type(res) == str and len(res) > 0 and network_ip6gateway in res,
"%s failed on router %s" % (guest_gateway_check_cmd, router.id))
self.checkRouterNicState(router, "eth2", "DOWN")
def checkIpv6NetworkRoutersInternal(self):
network_ip6gateway = self.getNetworkGateway(self.network)
for router in self.routers:
if router.state != "Running":
continue
if router.isredundantrouter == True and router.redundantstate == 'BACKUP':
self.checkIpv6NetworkBackupRouter(router, network_ip6gateway)
continue
self.checkIpv6NetworkPrimaryRouter(router, network_ip6gateway)
def checkIpv6NetworkVm(self):
self.debug("Listing NICS for VM %s in network: %s" % (self.virtual_machine.name, self.network.name))
nics = NIC.list(
self.apiclient,
virtualmachineid=self.virtual_machine.id,
networkid=self.network.id
)
self.assertEqual(
len(nics),
1,
"VM NIC for the network isn't found"
)
nic = nics[0]
self.assertNotEqual(nic.ip6address,
None,
"IPv6 address for VM %s NIC is empty" % nic.traffictype)
self.virtual_machine_ipv6_address = nic.ip6address
self.assertNotEqual(nic.ip6cidr,
None,
"IPv6 CIDR for VM %s NIC is empty" % nic.traffictype)
self.assertNotEqual(nic.ip6gateway,
None,
"IPv6 gateway for VM %s NIC is empty" % nic.traffictype)
def restartNetworkWithCleanup(self):
self.network.restart(self.apiclient, cleanup=True)
time.sleep(SLEEP_BEFORE_VR_CHANGES)
def updateNetworkWithOffering(self):
self.network.update(self.apiclient, networkofferingid=self.network_offering_update.id)
time.sleep(SLEEP_BEFORE_VR_CHANGES)
def createIpv6FirewallRuleInNetwork(self, network_id, traffic_type, source_cidr, dest_cidr, protocol,
start_port, end_port, icmp_type, icmp_code):
cmd = createIpv6FirewallRule.createIpv6FirewallRuleCmd()
cmd.networkid = network_id
cmd.traffictype = traffic_type
if source_cidr:
cmd.cidrlist = source_cidr
if dest_cidr:
cmd.destcidrlist = dest_cidr
if protocol:
cmd.protocol = protocol
if start_port:
cmd.startport = start_port
if end_port:
cmd.endport = end_port
if icmp_type is not None:
cmd.icmptype = icmp_type
if icmp_code is not None:
cmd.icmpcode = icmp_code
fw_rule = self.apiclient.createIpv6FirewallRule(cmd)
return fw_rule
def deployRoutingTestResources(self):
self.routing_test_network_offering = self.createNetworkOfferingInternal(False, True)
self.services["network"]["networkoffering"] = self.routing_test_network_offering.id
self.routing_test_network = Network.create(
self.apiclient,
self.services["network"],
self.account.name,
self.account.domainid,
zoneid=self.zone.id
)
self.cleanup.append(self.routing_test_network)
self.services["virtual_machine"]["zoneid"] = self.zone.id
self.routing_test_vm = VirtualMachine.create(
self.apiclient,
self.services["virtual_machine"],
templateid=self.template.id,
accountid=self.account.name,
domainid=self.account.domainid,
networkids=[self.routing_test_network.id],
serviceofferingid=self.service_offering.id,
mode="advanced"
)
self.cleanup.append(self.routing_test_vm)
def prepareRoutingTestResourcesInBackground(self):
self.thread = threading.Thread(target=self.deployRoutingTestResources, args=())
self.thread.daemon = True
self.thread.start()
def checkIpv6NetworkRouting(self):
if not self.thread:
self.deployRoutingTestResources()
else:
self.thread.join(5*60)
self.assertFalse(not self.routing_test_network or not self.routing_test_vm,
"Routing resources failure")
fw1 = self.createIpv6FirewallRuleInNetwork(self.routing_test_network.id, "Ingress", None, None, "icmp",
None, None, None, None)
fw2 = self.createIpv6FirewallRuleInNetwork(self.network.id, "Ingress", None, None, "icmp",
None, None, None, None)
test_network_router = self.getNetworkRouter(self.routing_test_network)
routes = self.getNetworkRoutes(self.network)
self.logger.debug("Adding network routes in routing_test_network %s" % routes)
for route in routes:
add_route_cmd = "ip -6 route add %s via %s" % (route.subnet, route.gateway)
self.getRouterProcessStatus(test_network_router, add_route_cmd)
network_router = self.getNetworkRouter(self.network)
routes = self.getNetworkRoutes(self.routing_test_network)
self.logger.debug("Adding routing_test_network routes in network %s" % routes)
for route in routes:
add_route_cmd = "ip -6 route add %s via %s" % (route.subnet, route.gateway)
self.getRouterProcessStatus(network_router, add_route_cmd)
ping_cmd = "ping6 -c 4 %s" % self.virtual_machine_ipv6_address
count = 0
while count < PING_RETRIES:
count = count + 1
res = self.getRouterProcessStatus(test_network_router, ping_cmd)
if " 0% packet loss" in res:
break
time.sleep(PING_SLEEP)
self.assertTrue(" 0% packet loss" in res,
"Ping from router %s of network %s to VM %s of network %s is unsuccessful" % (test_network_router.id, self.routing_test_network.id, self.virtual_machine.id, self.network.id))
ssh = self.routing_test_vm.get_ssh_client(retries=5)
count = 0
while count < PING_RETRIES:
count = count + 1
res = ssh.execute(ping_cmd)
if type(res) == list and len(res) > 0 and " 0% packet loss" in '\n'.join(res):
break
time.sleep(PING_SLEEP)
self.assertTrue(type(res) == list and len(res) > 0,
"%s on VM %s returned invalid result" % (ping_cmd, self.routing_test_vm.id))
self.logger.debug(res)
res = '\n'.join(res)
self.assertTrue(" 0% packet loss" in res,
"Ping from VM %s of network %s to VM %s of network %s is unsuccessful" % (self.routing_test_vm.id, self.routing_test_network.id, self.virtual_machine.id, self.network.id))
cmd = deleteIpv6FirewallRule.deleteIpv6FirewallRuleCmd()
cmd.id = fw2.id
self.apiclient.deleteIpv6FirewallRule(cmd)
def createAndVerifyIpv6FirewallRule(self, traffic_type, source_cidr, dest_cidr, protocol,
start_port, end_port, icmp_type, icmp_code, parsed_rule, delete=False):
self.logger.debug("createAndVerifyIpv6FirewallRule - %s" % parsed_rule)
fw_rule = self.createIpv6FirewallRuleInNetwork(self.network.id, traffic_type, source_cidr, dest_cidr, protocol,
start_port, end_port, icmp_type, icmp_code)
cmd = listIpv6FirewallRules.listIpv6FirewallRulesCmd()
cmd.id = fw_rule.id
rules = self.apiclient.listIpv6FirewallRules(cmd)
self.assertTrue(
isinstance(rules, list),
"Check listIpv6FirewallRules response returns a valid list"
)
rule = rules[0]
self.assertEqual(rule.networkid, self.network.id,
"IPv6 firewall rule network ID mismatch %s, %s" % (rule.networkid, self.network.id))
self.assertEqual(rule.traffictype, traffic_type,
"IPv6 firewall rule traffic type mismatch %s, %s" % (rule.traffictype, traffic_type))
if source_cidr:
self.assertEqual(rule.cidrlist, source_cidr,
"IPv6 firewall rule source CIDR mismatch %s, %s" % (rule.cidrlist, source_cidr))
if dest_cidr:
self.assertEqual(rule.destcidrlist, dest_cidr,
"IPv6 firewall rule destination CIDR mismatch %s, %s" % (rule.destcidrlist, dest_cidr))
if protocol:
self.assertEqual(rule.protocol, protocol,
"IPv6 firewall rule protocol mismatch %s, %s" % (rule.protocol, protocol))
if start_port:
self.assertEqual(rule.startport, start_port,
"IPv6 firewall rule start port mismatch %d, %d" % (rule.startport, start_port))
if end_port:
self.assertEqual(rule.endport, end_port,
"IPv6 firewall rule end port mismatch %d, %d" % (rule.endport, end_port))
if icmp_type is not None:
self.assertEqual(rule.icmptype, icmp_type,
"IPv6 firewall rule ICMP type mismatch %d, %d" % (rule.icmptype, icmp_type))
if icmp_code is not None:
self.assertEqual(rule.icmpcode, icmp_code,
"IPv6 firewall rule ICMP code mismatch %d, %d" % (rule.icmpcode, icmp_code))
routerCmd = "nft list chain ip6 %s %s" % (FIREWALL_TABLE, FIREWALL_CHAINS[traffic_type])
res = self.getRouterProcessStatus(self.getNetworkRouter(self.network), routerCmd)
self.assertTrue(parsed_rule in res,
"Listing firewall rule with nft list chain failure for rule: %s" % parsed_rule)
if delete == True:
cmd = deleteIpv6FirewallRule.deleteIpv6FirewallRuleCmd()
cmd.id = fw_rule.id
self.apiclient.deleteIpv6FirewallRule(cmd)
res = self.getRouterProcessStatus(self.getNetworkRouter(self.network), routerCmd)
self.assertFalse(parsed_rule in res,
"Firewall rule present in nft list chain failure despite delete for rule: %s" % parsed_rule)
def checkIpv6FirewallRule(self):
traffic_type = "Ingress"
# Ingress - ip6 saddr SOURCE_CIDR ip6 daddr DEST_CIDR tcp dport { START_PORT-END_PORT } accept
source_cidr = self.getRandomIpv6Cidr()
dest_cidr = self.getRandomIpv6Cidr()
protocol = "tcp"
start_port = randint(3000, 5000)
end_port = start_port + randint(1, 8)
rule = "ip6 saddr %s ip6 daddr %s %s dport { %d-%d } accept" % (source_cidr, dest_cidr, protocol, start_port, end_port)
self.createAndVerifyIpv6FirewallRule(traffic_type, source_cidr, dest_cidr, protocol,
start_port, end_port, None, None, rule, True)
# Ingress - ip6 daddr DEST_CIDR icmpv6 type TYPE code CODE accept
source_cidr = self.getRandomIpv6Cidr()
protocol = "icmp"
icmp_type = choice(list(ICMPV6_TYPE.keys()))
icmp_code = choice(list(ICMPV6_CODE_TYPE.keys()))
rule = "ip6 saddr %s ip6 daddr %s %sv6 type %s %sv6 code %s accept" % (source_cidr, CIDR_IPV6_ANY, protocol, ICMPV6_TYPE[icmp_type], protocol, ICMPV6_CODE_TYPE[icmp_code])
self.createAndVerifyIpv6FirewallRule(traffic_type, source_cidr, None, protocol,
None, None, icmp_type, icmp_code, rule)
action = "accept"
if self.isNetworkEgressDefaultPolicyAllow(self.network):
action = "drop"
traffic_type = "Egress"
# Egress - ip6 saddr ::/0 ip6 daddr ::/0 udp dport { 0-65355 } ACTION
protocol = "udp"
rule = "ip6 saddr %s ip6 daddr %s %s dport %s %s" % (CIDR_IPV6_ANY, CIDR_IPV6_ANY, protocol, TCP_UDP_PORT_ANY, action)
self.createAndVerifyIpv6FirewallRule(traffic_type, None, None, protocol,
None, None, None, None, rule)
# Egress - ip6 saddr ::/0 ip6 daddr ::/0 icmpv6 type ANY_TYPE ACTION
protocol = "icmp"
rule = "ip6 saddr %s ip6 daddr %s %sv6 type %s %s" % (CIDR_IPV6_ANY, CIDR_IPV6_ANY, protocol, ICMPV6_TYPE_ANY, action)
self.createAndVerifyIpv6FirewallRule(traffic_type, None, None, protocol,
None, None, None, None, rule)
# Egress - ip6 saddr ::/0 ip6 daddr DEST_CIDR ACTION
protocol = "all"
dest_cidr = self.getRandomIpv6Cidr()
rule = "ip6 saddr %s ip6 daddr %s %s" % (CIDR_IPV6_ANY, CIDR_IPV6_ANY, action)
self.createAndVerifyIpv6FirewallRule(traffic_type, None, None, protocol,
None, None, None, None, rule)
def checkNetworkVRRedundancy(self):
network_ip6gateway = self.getNetworkGateway(self.network)
primary_router = self.getNetworkRouter(self.network)
Router.stop(
self.apiclient,
id=primary_router.id
)
time.sleep(SLEEP_BEFORE_VR_CHANGES)
new_primary_router = self.getNetworkRouter(self.network)
self.assertNotEqual(new_primary_router.id, primary_router.id,
"Original primary router ID: %s of network is still the primary router after stopping" % (primary_router.id))
self.checkIpv6NetworkPrimaryRouter(new_primary_router, network_ip6gateway)
def checkIpv6Network(self):
self.checkIpv6NetworkBasic()
self.checkIpv6NetworkRoutersBasic()
self.checkIpv6NetworkRoutersInternal()
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
@skipTestIf("ipv6NotSupported")
def test_01_verify_ipv6_network(self):
"""Test to verify IPv6 network
# Validate the following:
# 1. Create IPv6 network, deploy VM
# 2. Verify network has required IPv6 details
# 3. List router for the network and verify it has required IPv6 details for Guest and Public NIC of the VR
# 4. SSH into VR(s) and verify correct details are present for its NICs
# 5. Verify VM in network has required IPv6 details
# 6. Restart network with cleanup and re-verify network details
# 7. Update network with a new offering and re-verify network details
# 8. Deploy another IPv6 network and check routing between two networks and their VM
# 9. Create IPv6 firewall rules and verify in VR if they get implemented
"""
self.createIpv6NetworkOffering()
self.createIpv6NetworkOfferingForUpdate()
self.createTinyServiceOffering()
self.deployNetwork()
self.deployNetworkVm()
self.checkIpv6Network()
self.checkIpv6NetworkVm()
self.prepareRoutingTestResourcesInBackground()
self.restartNetworkWithCleanup()
self.checkIpv6Network()
self.updateNetworkWithOffering()
self.checkIpv6Network()
self.checkIpv6NetworkRouting()
self.checkIpv6FirewallRule()
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
@skipTestIf("ipv6NotSupported")
def test_02_verify_ipv6_network_redundant(self):
"""Test to verify redundant IPv6 network
# Validate the following:
# 1. Create IPv6 network, deploy VM
# 2. Verify network has required IPv6 details
# 3. List VRs for the network and verify it has required IPv6 details for Guest and Public NIC of the VR
# 4. SSH into VR(s) and verify correct details are present for its NICs
# 5. Verify VM in network has required IPv6 details
# 6. Restart network with cleanup and re-verify network details
# 7. Update network with a new offering and re-verify network details
# 8. Deploy another IPv6 network and check routing between two networks and their VM
# 9. Create IPv6 firewall rules and verify in VR if they get implemented
# 10. Stop primary router and verify internals in backup VR
"""
self.createIpv6NetworkOffering(True)
self.createIpv6NetworkOfferingForUpdate(True)
self.createTinyServiceOffering()
self.deployNetwork()
self.deployNetworkVm()
self.checkIpv6Network()
self.checkIpv6NetworkVm()
self.prepareRoutingTestResourcesInBackground()
self.restartNetworkWithCleanup()
self.checkIpv6Network()
self.updateNetworkWithOffering()
self.checkIpv6Network()
self.checkIpv6NetworkRouting()
self.checkIpv6FirewallRule()
self.checkNetworkVRRedundancy()
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
@skipTestIf("ipv6NotSupported")
def test_03_verify_upgraded_ipv6_network(self):
"""Test to verify IPv4 network upgraded to IPv6 network
# Validate the following:
# 1. Create IPv4 network, deploy VM
# 2. Update network to a IPv6 offering
# 3. Verify network has required IPv6 details
# 4. List VRs for the network and verify it has required IPv6 details for Guest and Public NIC of the VR
# 5. SSH into VR(s) and verify correct details are present for its NICs
# 6. Verify VM in network has required IPv6 details
# 7. Restart network with cleanup and re-verify network details
# 8. Deploy another IPv6 network and check routing between two networks and their VM
# 9. Create IPv6 firewall rules and verify in VR if they get implemented
"""
self.createIpv4NetworkOffering(False)
self.createIpv6NetworkOfferingForUpdate(False)
self.createTinyServiceOffering()
self.prepareRoutingTestResourcesInBackground()
self.deployNetwork()
self.deployNetworkVm()
self.updateNetworkWithOffering()
self.checkIpv6Network()
self.checkIpv6NetworkVm()
self.restartNetworkWithCleanup()
self.checkIpv6Network()
self.checkIpv6NetworkRouting()
self.checkIpv6FirewallRule()
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
@skipTestIf("ipv6NotSupported")
def test_04_verify_upgraded_ipv6_network_redundant(self):
"""Test to verify redundant IPv4 network upgraded to redundant IPv6 network
# Validate the following:
# 1. Create IPv4 network, deploy VM
# 2. Update network to a IPv6 offering
# 3. Verify network has required IPv6 details
# 4. List VRs for the network and verify it has required IPv6 details for Guest and Public NIC of the VR
# 5. SSH into VR(s) and verify correct details are present for its NICs
# 6. Verify VM in network has required IPv6 details
# 7. Restart network with cleanup and re-verify network details
# 8. Deploy another IPv6 network and check routing between two networks and their VM
# 9. Create IPv6 firewall rules and verify in VR if they get implemented
# 10. Stop primary router and verify internals in backup VR
"""
self.createIpv4NetworkOffering(True)
self.createIpv6NetworkOfferingForUpdate(True)
self.createTinyServiceOffering()
self.prepareRoutingTestResourcesInBackground()
self.deployNetwork()
self.deployNetworkVm()
self.updateNetworkWithOffering()
self.checkIpv6Network()
self.checkIpv6NetworkVm()
self.restartNetworkWithCleanup()
self.checkIpv6Network()
self.checkIpv6NetworkRouting()
self.checkIpv6FirewallRule()
self.checkNetworkVRRedundancy()

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,488 @@
# 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.
""" BVT tests for IPv6 infra operations"""
#Import Local Modules
from marvin.codes import FAILED
from marvin.cloudstackTestCase import cloudstackTestCase
from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
listGuestNetworkIpv6Prefixes,
deleteGuestNetworkIpv6Prefix)
from marvin.lib.utils import (cleanup_resources)
from marvin.lib.base import (Configurations,
NetworkOffering,
VpcOffering,
PublicIpRange)
from marvin.lib.common import (get_zone)
from marvin.cloudstackException import CloudstackAPIException
from nose.plugins.attrib import attr
import logging
ipv6_offering_config_name = "ipv6.offering.enabled"
class TestCreateIpv6NetworkVpcOffering(cloudstackTestCase):
@classmethod
def setUpClass(cls):
testClient = super(TestCreateIpv6NetworkVpcOffering, cls).getClsTestClient()
cls.apiclient = testClient.getApiClient()
cls.services = testClient.getParsedTestDataConfig()
cls.initial_ipv6_offering_enabled = Configurations.list(
cls.apiclient,
name=ipv6_offering_config_name)[0].value
cls._cleanup = []
return
@classmethod
def tearDownClass(cls):
if cls.initial_ipv6_offering_enabled != None:
Configurations.update(cls.apiclient,
ipv6_offering_config_name,
cls.initial_ipv6_offering_enabled)
super(TestCreateIpv6NetworkVpcOffering, cls).tearDownClass()
def setUp(self):
self.services = self.testClient.getParsedTestDataConfig()
self.apiclient = self.testClient.getApiClient()
self.dbclient = self.testClient.getDbConnection()
self.cleanup = []
return
def tearDown(self):
try:
#Clean up, terminate the created templates
cleanup_resources(self.apiclient, self.cleanup)
except Exception as e:
raise Exception("Warning: Exception during cleanup : %s" % e)
return
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
def test_01_create_ipv6_network_offering(self):
"""Test to create network offering
# Validate the following:
# 1. createNetworkOffering should return valid info for new offering
# 2. The Cloud Database contains the valid information
"""
Configurations.update(self.apiclient,
ipv6_offering_config_name,
"true")
ipv6_service = self.services["network_offering"]
ipv6_service["internetprotocol"] = "dualstack"
network_offering = NetworkOffering.create(
self.apiclient,
ipv6_service
)
self.cleanup.append(network_offering)
self.debug("Created Network offering with ID: %s" % network_offering.id)
list_network_off_response = NetworkOffering.list(self.apiclient,
id=network_offering.id)
self.assertEqual(
isinstance(list_network_off_response, list),
True,
"Check list response returns a valid list"
)
self.assertNotEqual(
len(list_network_off_response),
0,
"Check Network offering is created"
)
network_off_response = list_network_off_response[0]
self.assertEqual(
network_off_response.id,
network_offering.id,
"Check server id in listNetworkOfferings"
)
self.assertEqual(
network_off_response.internetprotocol.lower(),
ipv6_service["internetprotocol"].lower(),
"Check internetprotocol in listNetworkOfferings"
)
return
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
def test_02_create_ipv6_network_offering_fail(self):
"""Test to create network offering
# Validate the following:
# 1. createNetworkOffering should fail
"""
Configurations.update(self.apiclient,
ipv6_offering_config_name,
"false")
ipv6_service = self.services["network_offering"]
ipv6_service["internetprotocol"] = "dualstack"
try:
network_offering = NetworkOffering.create(
self.apiclient,
ipv6_service
)
self.cleanup.append(network_offering)
self.fail("Network offering created despite global setting - %s set to false" % ipv6_offering_config_name)
except CloudstackAPIException as e:
self.debug("Network offering creation failed as expected %s " % e)
return
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
def test_03_create_ipv6_vpc_offering(self):
"""Test to create network offering
# Validate the following:
# 1. createVpcOffering should return valid info for new offering
# 2. The Cloud Database contains the valid information
"""
Configurations.update(self.apiclient,
ipv6_offering_config_name,
"true")
ipv6_service = self.services["vpc_offering"]
ipv6_service["internetprotocol"] = "dualstack"
vpc_offering = VpcOffering.create(
self.apiclient,
ipv6_service
)
self.cleanup.append(vpc_offering)
self.debug("Created VPC offering with ID: %s" % vpc_offering.id)
list_vpc_off_response = VpcOffering.list(self.apiclient,
id=vpc_offering.id)
self.assertEqual(
isinstance(list_vpc_off_response, list),
True,
"Check list response returns a valid list"
)
self.assertNotEqual(
len(list_vpc_off_response),
0,
"Check VPC offering is created"
)
vpc_off_response = list_vpc_off_response[0]
self.assertEqual(
vpc_off_response.id,
vpc_offering.id,
"Check server id in listVpcOfferings"
)
self.assertEqual(
vpc_off_response.internetprotocol.lower(),
ipv6_service["internetprotocol"].lower(),
"Check internetprotocol in listVpcOfferings"
)
return
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
def test_04_create_ipv6_vpc_offering_fail(self):
"""Test to create VPC offering failure
# Validate the following:
# 1. createVpcOffering should fail
"""
Configurations.update(self.apiclient,
ipv6_offering_config_name,
"false")
ipv6_service = self.services["vpc_offering"]
ipv6_service["internetprotocol"] = "dualstack"
try:
vpc_offering = VpcOffering.create(
self.apiclient,
ipv6_service
)
self.cleanup.append(vpc_offering)
self.fail("VPC offering created despite global setting - %s set to false" % ipv6_offering_config_name)
except CloudstackAPIException as e:
self.debug("VPC offering creation failed as expected %s " % e)
return
class TestIpv6PublicIpRange(cloudstackTestCase):
def setUp(self):
self.services = self.testClient.getParsedTestDataConfig()
self.apiclient = self.testClient.getApiClient()
self.dbclient = self.testClient.getDbConnection()
self.cleanup = []
return
def tearDown(self):
try:
#Clean up, terminate the created templates
cleanup_resources(self.apiclient, self.cleanup)
except Exception as e:
raise Exception("Warning: Exception during cleanup : %s" % e)
return
@classmethod
def setUpClass(cls):
testClient = super(TestIpv6PublicIpRange, cls).getClsTestClient()
cls.apiclient = testClient.getApiClient()
cls.services = testClient.getParsedTestDataConfig()
cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
cls._cleanup = []
return
@classmethod
def tearDownClass(cls):
super(TestIpv6PublicIpRange, cls).tearDownClass()
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
def test_01_create_ipv6_public_ip_range(self):
"""Test to add IPv6 public IP range
# Validate the following:
# 1. createVlanIpRange should return valid info for new public range
# 2. The Cloud Database contains the valid information
"""
ipv6_publiciprange_service = self.services["publicip6range"]
ipv6_publiciprange_service["zoneid"] = self.zone.id
ipv6_publiciprange = PublicIpRange.create(
self.apiclient,
ipv6_publiciprange_service
)
self.cleanup.append(ipv6_publiciprange)
self.debug("Created IPv6 public IP range with ID: %s" % ipv6_publiciprange.vlan.id)
ipv6_publiciprange = ipv6_publiciprange.vlan
public_ip_ranges = PublicIpRange.list(
self.apiclient,
id=ipv6_publiciprange.id
)
self.assertEqual(
isinstance(public_ip_ranges, list),
True,
"Check list response returns a valid list"
)
self.assertNotEqual(
len(public_ip_ranges),
0,
"Check public IP range is created"
)
public_ip_range = public_ip_ranges[0]
self.assertEqual(
public_ip_range.id,
ipv6_publiciprange.id,
"Check server id"
)
self.assertEqual(
public_ip_range.ip6cidr,
ipv6_publiciprange_service["ip6cidr"],
"Check ip6cidr for IPv6 public IP range"
)
return
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
def test_02_create_ipv6_public_ip_range_fail(self):
"""Test to add IPv6 public IP range failure
# Validate the following:
# 1. createVlanIpRange should return valid info for new public range
# 2. The Cloud Database contains the valid information
"""
ipv6_publiciprange_service = self.services["publicip6range"]
cidr = ipv6_publiciprange_service["ip6cidr"]
x = cidr.split("/")
x[1] = "72"
cidr = "/".join(x)
ipv6_publiciprange_service["ip6cidr"] = cidr
ipv6_publiciprange_service["zoneid"] = self.zone.id
try:
ipv6_publiciprange = PublicIpRange.create(
self.apiclient,
ipv6_publiciprange_service
)
except Exception as e:
self.debug("IPv6 public range creation failed as expected %s " % e)
ipv6_publiciprange = None
if ipv6_publiciprange != None:
self.debug("Created IPv6 public range with ID: %s. Deleting it before failure" % ipv6_publiciprange.id)
self.cleanup.append(ipv6_publiciprange)
self.fail("IPv6 guest prefix created despite CIDR size greater than 64")
return
class TestIpv6GuestPrefix(cloudstackTestCase):
def setUp(self):
self.services = self.testClient.getParsedTestDataConfig()
self.apiclient = self.testClient.getApiClient()
self.dbclient = self.testClient.getDbConnection()
self.cleanup = []
return
def tearDown(self):
try:
#Clean up, terminate the created templates
cleanup_resources(self.apiclient, self.cleanup)
except Exception as e:
raise Exception("Warning: Exception during cleanup : %s" % e)
return
@classmethod
def setUpClass(cls):
testClient = super(TestIpv6GuestPrefix, cls).getClsTestClient()
cls.apiclient = testClient.getApiClient()
cls.services = testClient.getParsedTestDataConfig()
cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
cls._cleanup = []
return
@classmethod
def tearDownClass(cls):
super(TestIpv6GuestPrefix, cls).tearDownClass()
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
def test_01_create_ipv6_guest_prefix(self):
"""Test to add IPv6 guest prefix
# Validate the following:
# 1. createGuestNetworkIpv6Prefix should return valid info for new IPv6 prefix
# 2. The Cloud Database contains the valid information
"""
ipv6_guestprefix_service = self.services["guestip6prefix"]
cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
cmd.zoneid = self.zone.id
cmd.prefix = ipv6_guestprefix_service["prefix"]
ipv6_guestprefix = self.apiclient.createGuestNetworkIpv6Prefix(cmd)
self.debug("Created IPv6 guest prefix with ID: %s" % ipv6_guestprefix.id)
cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
cmd.id = ipv6_guestprefix.id
ipv6_guestprefixes = self.apiclient.listGuestNetworkIpv6Prefixes(cmd)
self.assertEqual(
isinstance(ipv6_guestprefixes, list),
True,
"Check list response returns a valid list"
)
self.assertNotEqual(
len(ipv6_guestprefixes),
0,
"Check guest IPv6 prefix is created"
)
ipv6_guestprefix_response = ipv6_guestprefixes[0]
self.assertEqual(
ipv6_guestprefix.id,
ipv6_guestprefix_response.id,
"Check server id"
)
self.assertEqual(
ipv6_guestprefix_response.prefix,
ipv6_guestprefix_service["prefix"],
"Check prefix for IPv6"
)
cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
cmd.id = ipv6_guestprefix.id
self.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
return
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
def test_02_create_ipv6_guest_prefix_fail(self):
"""Test to add IPv6 guest prefix failure
# Validate the following:
# 1. createGuestNetworkIpv6Prefix should fail
"""
ipv6_guestprefix_service = self.services["guestip6prefix"]
cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
cmd.zoneid = self.zone.id
prefix = ipv6_guestprefix_service["prefix"]
x = prefix.split("/")
x[1] = "72"
prefix = "/".join(x)
cmd.prefix = prefix
try:
ipv6_guestprefix = self.apiclient.createGuestNetworkIpv6Prefix(cmd)
except Exception as e:
self.debug("IPv6 guest prefix creation failed as expected %s " % e)
ipv6_guestprefix = None
if ipv6_guestprefix != None:
self.debug("Created IPv6 guest prefix with ID: %s. Deleting it before failure" % ipv6_guestprefix.id)
cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
cmd.id = ipv6_guestprefix.id
self.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
self.fail("IPv6 guest prefix created despite CIDR size greater than 64")

View File

@ -14,7 +14,7 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
""" BVT tests for Network offerings"""
""" BVT test for IPv6 Network"""
#Import Local Modules
from marvin.codes import FAILED
@ -25,15 +25,12 @@ from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
listIpv6FirewallRules,
createIpv6FirewallRule,
deleteIpv6FirewallRule)
from marvin.lib.utils import (isAlmostEqual,
cleanup_resources,
random_gen,
from marvin.lib.utils import (random_gen,
get_process_status,
get_host_credentials)
from marvin.lib.base import (Configurations,
Domain,
NetworkOffering,
VpcOffering,
Account,
PublicIpRange,
Network,
@ -45,8 +42,7 @@ from marvin.lib.base import (Configurations,
from marvin.lib.common import (get_domain,
get_zone,
list_hosts,
get_test_template,
get_template)
get_test_template)
from marvin.sshClient import SshClient
from marvin.cloudstackException import CloudstackAPIException
from marvin.lib.decoratorGenerators import skipTestIf
@ -56,6 +52,7 @@ from ipaddress import IPv6Network
from random import getrandbits, choice, randint
import time
import logging
import threading
ipv6_offering_config_name = "ipv6.offering.enabled"
ULA_BASE = IPv6Network("fd00::/8")
@ -96,459 +93,9 @@ ICMPV6_CODE_TYPE = {
}
ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
TCP_UDP_PORT_ANY = "{ 0-65535 }"
class TestCreateIpv6NetworkVpcOffering(cloudstackTestCase):
@classmethod
def setUpClass(cls):
testClient = super(TestCreateIpv6NetworkVpcOffering, cls).getClsTestClient()
cls.apiclient = testClient.getApiClient()
cls.services = testClient.getParsedTestDataConfig()
cls.initial_ipv6_offering_enabled = Configurations.list(
cls.apiclient,
name=ipv6_offering_config_name)[0].value
cls._cleanup = []
return
@classmethod
def tearDownClass(cls):
if cls.initial_ipv6_offering_enabled != None:
Configurations.update(cls.apiclient,
ipv6_offering_config_name,
cls.initial_ipv6_offering_enabled)
super(TestCreateIpv6NetworkVpcOffering, cls).tearDownClass()
def setUp(self):
self.services = self.testClient.getParsedTestDataConfig()
self.apiclient = self.testClient.getApiClient()
self.dbclient = self.testClient.getDbConnection()
self.cleanup = []
return
def tearDown(self):
try:
#Clean up, terminate the created templates
cleanup_resources(self.apiclient, self.cleanup)
except Exception as e:
raise Exception("Warning: Exception during cleanup : %s" % e)
return
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
def test_01_create_ipv6_network_offering(self):
"""Test to create network offering
# Validate the following:
# 1. createNetworkOffering should return valid info for new offering
# 2. The Cloud Database contains the valid information
"""
Configurations.update(self.apiclient,
ipv6_offering_config_name,
"true")
ipv6_service = self.services["network_offering"]
ipv6_service["internetprotocol"] = "dualstack"
network_offering = NetworkOffering.create(
self.apiclient,
ipv6_service
)
self.cleanup.append(network_offering)
self.debug("Created Network offering with ID: %s" % network_offering.id)
list_network_off_response = NetworkOffering.list(self.apiclient,
id=network_offering.id)
self.assertEqual(
isinstance(list_network_off_response, list),
True,
"Check list response returns a valid list"
)
self.assertNotEqual(
len(list_network_off_response),
0,
"Check Network offering is created"
)
network_off_response = list_network_off_response[0]
self.assertEqual(
network_off_response.id,
network_offering.id,
"Check server id in listNetworkOfferings"
)
self.assertEqual(
network_off_response.internetprotocol.lower(),
ipv6_service["internetprotocol"].lower(),
"Check internetprotocol in listNetworkOfferings"
)
return
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
def test_02_create_ipv6_network_offering_fail(self):
"""Test to create network offering
# Validate the following:
# 1. createNetworkOffering should fail
"""
Configurations.update(self.apiclient,
ipv6_offering_config_name,
"false")
ipv6_service = self.services["network_offering"]
ipv6_service["internetprotocol"] = "dualstack"
try:
network_offering = NetworkOffering.create(
self.apiclient,
ipv6_service
)
self.cleanup.append(network_offering)
self.fail("Network offering created despite global setting - %s set to false" % ipv6_offering_config_name)
except CloudstackAPIException as e:
self.debug("Network offering creation failed as expected %s " % e)
return
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
def test_03_create_ipv6_vpc_offering(self):
"""Test to create network offering
# Validate the following:
# 1. createVpcOffering should return valid info for new offering
# 2. The Cloud Database contains the valid information
"""
Configurations.update(self.apiclient,
ipv6_offering_config_name,
"true")
ipv6_service = self.services["vpc_offering"]
ipv6_service["internetprotocol"] = "dualstack"
vpc_offering = VpcOffering.create(
self.apiclient,
ipv6_service
)
self.cleanup.append(vpc_offering)
self.debug("Created VPC offering with ID: %s" % vpc_offering.id)
list_vpc_off_response = VpcOffering.list(self.apiclient,
id=vpc_offering.id)
self.assertEqual(
isinstance(list_vpc_off_response, list),
True,
"Check list response returns a valid list"
)
self.assertNotEqual(
len(list_vpc_off_response),
0,
"Check VPC offering is created"
)
vpc_off_response = list_vpc_off_response[0]
self.assertEqual(
vpc_off_response.id,
vpc_offering.id,
"Check server id in listVpcOfferings"
)
self.assertEqual(
vpc_off_response.internetprotocol.lower(),
ipv6_service["internetprotocol"].lower(),
"Check internetprotocol in listVpcOfferings"
)
return
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
def test_04_create_ipv6_vpc_offering_fail(self):
"""Test to create VPC offering failure
# Validate the following:
# 1. createVpcOffering should fail
"""
Configurations.update(self.apiclient,
ipv6_offering_config_name,
"false")
ipv6_service = self.services["vpc_offering"]
ipv6_service["internetprotocol"] = "dualstack"
try:
vpc_offering = VpcOffering.create(
self.apiclient,
ipv6_service
)
self.cleanup.append(vpc_offering)
self.fail("VPC offering created despite global setting - %s set to false" % ipv6_offering_config_name)
except CloudstackAPIException as e:
self.debug("VPC offering creation failed as expected %s " % e)
return
class TestIpv6PublicIpRange(cloudstackTestCase):
def setUp(self):
self.services = self.testClient.getParsedTestDataConfig()
self.apiclient = self.testClient.getApiClient()
self.dbclient = self.testClient.getDbConnection()
self.cleanup = []
return
def tearDown(self):
try:
#Clean up, terminate the created templates
cleanup_resources(self.apiclient, self.cleanup)
except Exception as e:
raise Exception("Warning: Exception during cleanup : %s" % e)
return
@classmethod
def setUpClass(cls):
testClient = super(TestIpv6PublicIpRange, cls).getClsTestClient()
cls.apiclient = testClient.getApiClient()
cls.services = testClient.getParsedTestDataConfig()
cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
cls._cleanup = []
return
@classmethod
def tearDownClass(cls):
super(TestIpv6PublicIpRange, cls).tearDownClass()
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
def test_01_create_ipv6_public_ip_range(self):
"""Test to add IPv6 public IP range
# Validate the following:
# 1. createVlanIpRange should return valid info for new public range
# 2. The Cloud Database contains the valid information
"""
ipv6_publiciprange_service = self.services["publicip6range"]
ipv6_publiciprange_service["zoneid"] = self.zone.id
ipv6_publiciprange = PublicIpRange.create(
self.apiclient,
ipv6_publiciprange_service
)
self.cleanup.append(ipv6_publiciprange)
self.debug("Created IPv6 public IP range with ID: %s" % ipv6_publiciprange.vlan.id)
ipv6_publiciprange = ipv6_publiciprange.vlan
public_ip_ranges = PublicIpRange.list(
self.apiclient,
id=ipv6_publiciprange.id
)
self.assertEqual(
isinstance(public_ip_ranges, list),
True,
"Check list response returns a valid list"
)
self.assertNotEqual(
len(public_ip_ranges),
0,
"Check public IP range is created"
)
public_ip_range = public_ip_ranges[0]
self.assertEqual(
public_ip_range.id,
ipv6_publiciprange.id,
"Check server id"
)
self.assertEqual(
public_ip_range.ip6cidr,
ipv6_publiciprange_service["ip6cidr"],
"Check ip6cidr for IPv6 public IP range"
)
return
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
def test_02_create_ipv6_public_ip_range_fail(self):
"""Test to add IPv6 public IP range failure
# Validate the following:
# 1. createVlanIpRange should return valid info for new public range
# 2. The Cloud Database contains the valid information
"""
ipv6_publiciprange_service = self.services["publicip6range"]
cidr = ipv6_publiciprange_service["ip6cidr"]
x = cidr.split("/")
x[1] = "72"
cidr = "/".join(x)
ipv6_publiciprange_service["ip6cidr"] = cidr
ipv6_publiciprange_service["zoneid"] = self.zone.id
try:
ipv6_publiciprange = PublicIpRange.create(
self.apiclient,
ipv6_publiciprange_service
)
except Exception as e:
self.debug("IPv6 public range creation failed as expected %s " % e)
ipv6_publiciprange = None
if ipv6_publiciprange != None:
self.debug("Created IPv6 public range with ID: %s. Deleting it before failure" % ipv6_publiciprange.id)
self.cleanup.append(ipv6_publiciprange)
self.fail("IPv6 guest prefix created despite CIDR size greater than 64")
return
class TestIpv6GuestPrefix(cloudstackTestCase):
def setUp(self):
self.services = self.testClient.getParsedTestDataConfig()
self.apiclient = self.testClient.getApiClient()
self.dbclient = self.testClient.getDbConnection()
self.cleanup = []
return
def tearDown(self):
try:
#Clean up, terminate the created templates
cleanup_resources(self.apiclient, self.cleanup)
except Exception as e:
raise Exception("Warning: Exception during cleanup : %s" % e)
return
@classmethod
def setUpClass(cls):
testClient = super(TestIpv6GuestPrefix, cls).getClsTestClient()
cls.apiclient = testClient.getApiClient()
cls.services = testClient.getParsedTestDataConfig()
cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
cls._cleanup = []
return
@classmethod
def tearDownClass(cls):
super(TestIpv6GuestPrefix, cls).tearDownClass()
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
def test_01_create_ipv6_guest_prefix(self):
"""Test to add IPv6 guest prefix
# Validate the following:
# 1. createGuestNetworkIpv6Prefix should return valid info for new IPv6 prefix
# 2. The Cloud Database contains the valid information
"""
ipv6_guestprefix_service = self.services["guestip6prefix"]
cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
cmd.zoneid = self.zone.id
cmd.prefix = ipv6_guestprefix_service["prefix"]
ipv6_guestprefix = self.apiclient.createGuestNetworkIpv6Prefix(cmd)
self.debug("Created IPv6 guest prefix with ID: %s" % ipv6_guestprefix.id)
cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
cmd.id = ipv6_guestprefix.id
ipv6_guestprefixes = self.apiclient.listGuestNetworkIpv6Prefixes(cmd)
self.assertEqual(
isinstance(ipv6_guestprefixes, list),
True,
"Check list response returns a valid list"
)
self.assertNotEqual(
len(ipv6_guestprefixes),
0,
"Check guest IPv6 prefix is created"
)
ipv6_guestprefix_response = ipv6_guestprefixes[0]
self.assertEqual(
ipv6_guestprefix.id,
ipv6_guestprefix_response.id,
"Check server id"
)
self.assertEqual(
ipv6_guestprefix_response.prefix,
ipv6_guestprefix_service["prefix"],
"Check prefix for IPv6"
)
cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
cmd.id = ipv6_guestprefix.id
self.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
return
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
def test_02_create_ipv6_guest_prefix_fail(self):
"""Test to add IPv6 guest prefix failure
# Validate the following:
# 1. createGuestNetworkIpv6Prefix should fail
"""
ipv6_guestprefix_service = self.services["guestip6prefix"]
cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
cmd.zoneid = self.zone.id
prefix = ipv6_guestprefix_service["prefix"]
x = prefix.split("/")
x[1] = "72"
prefix = "/".join(x)
cmd.prefix = prefix
try:
ipv6_guestprefix = self.apiclient.createGuestNetworkIpv6Prefix(cmd)
except Exception as e:
self.debug("IPv6 guest prefix creation failed as expected %s " % e)
ipv6_guestprefix = None
if ipv6_guestprefix != None:
self.debug("Created IPv6 guest prefix with ID: %s. Deleting it before failure" % ipv6_guestprefix.id)
cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
cmd.id = ipv6_guestprefix.id
self.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
self.fail("IPv6 guest prefix created despite CIDR size greater than 64")
return
SLEEP_BEFORE_VR_CHANGES = 45
PING_RETRIES = 5
PING_SLEEP = 20
class TestIpv6Network(cloudstackTestCase):
@ -593,17 +140,10 @@ class TestIpv6Network(cloudstackTestCase):
)
cls._cleanup.append(cls.account)
cls.hypervisor = testClient.getHypervisorInfo()
cls.template = get_template(
cls.apiclient,
cls.zone.id,
cls.services["ostype"]
)
if cls.hypervisor.lower() in ('xenserver'):
# Default Xenserver template has IPv6 disabled
cls.template = get_test_template(
cls.apiclient,
cls.zone.id,
cls.hypervisor)
cls.template = get_test_template(
cls.apiclient,
cls.zone.id,
cls.hypervisor)
else:
cls.debug("IPv6 is not supported, skipping tests!")
return
@ -614,11 +154,13 @@ class TestIpv6Network(cloudstackTestCase):
Configurations.update(cls.apiclient,
ipv6_offering_config_name,
cls.initial_ipv6_offering_enabled)
super(TestIpv6Network, cls).tearDownClass()
if cls.test_ipv6_guestprefix != None:
cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
cmd.id = cls.test_ipv6_guestprefix.id
cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
try:
super(TestIpv6Network, cls).tearDownClass()
finally:
if cls.test_ipv6_guestprefix != None:
cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
cmd.id = cls.test_ipv6_guestprefix.id
cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
@classmethod
def getGuestIpv6Prefix(cls):
@ -650,7 +192,10 @@ class TestIpv6Network(cloudstackTestCase):
vlan = ip_range.vlan
if ipv4_range_vlan == None and vlan.startswith("vlan://"):
vlan = vlan.replace("vlan://", "")
ipv4_range_vlan = int(vlan)
if vlan == "untagged":
ipv4_range_vlan = None
else:
ipv4_range_vlan = int(vlan)
ipv6_publiciprange_service = cls.services["publicip6range"]
ipv6_publiciprange_service["zoneid"] = cls.zone.id
ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
@ -665,16 +210,18 @@ class TestIpv6Network(cloudstackTestCase):
self.services = self.testClient.getParsedTestDataConfig()
self.apiclient = self.testClient.getApiClient()
self.dbclient = self.testClient.getDbConnection()
self.thread = None
self.cleanup = []
return
def tearDown(self):
try:
#Clean up, terminate the created templates
cleanup_resources(self.apiclient, reversed(self.cleanup))
if self.thread and self.thread.is_alive():
self.thread.join(5*60)
except Exception as e:
raise Exception("Warning: Exception during cleanup : %s" % e)
finally:
super(TestIpv6Network, self).tearDown()
return
def getRandomIpv6Cidr(self):
@ -690,30 +237,33 @@ class TestIpv6Network(cloudstackTestCase):
)
self.cleanup.append(self.service_offering)
def createIpv6NetworkOfferingInternal(self, is_redundant, egressdefaultpolicy=True):
ipv6_service = self.services["network_offering"]
def createNetworkOfferingInternal(self, is_redundant, is_ipv6, egressdefaultpolicy=True):
off_service = self.services["network_offering"]
if is_redundant:
ipv6_service = self.services["nw_off_isolated_RVR"]
ipv6_service["internetprotocol"] = "dualstack"
off_service = self.services["nw_off_isolated_RVR"]
if is_ipv6:
off_service["internetprotocol"] = "dualstack"
if egressdefaultpolicy:
ipv6_service["egress_policy"] = egressdefaultpolicy
off_service["egress_policy"] = egressdefaultpolicy
network_offering = NetworkOffering.create(
self.apiclient,
ipv6_service
off_service
)
self.cleanup.append(network_offering)
network_offering.update(self.apiclient, state='Enabled')
return network_offering
def createIpv6NetworkOffering(self, is_redundant):
self.network_offering = self.createIpv6NetworkOfferingInternal(is_redundant, False)
self.cleanup.append(self.network_offering)
def createIpv4NetworkOffering(self, is_redundant=False):
self.network_offering = self.createNetworkOfferingInternal(is_redundant, False, False)
def createIpv6NetworkOfferingForUpdate(self, is_redundant):
self.network_offering_update = self.createIpv6NetworkOfferingInternal(is_redundant)
self.cleanup.append(self.network_offering_update)
def createIpv6NetworkOffering(self, is_redundant=False):
self.network_offering = self.createNetworkOfferingInternal(is_redundant, True, False)
def createIpv6NetworkOfferingForUpdate(self, is_redundant=False):
self.network_offering_update = self.createNetworkOfferingInternal(is_redundant, True)
def deployIpv6Network(self):
def deployNetwork(self):
self.services["network"]["networkoffering"] = self.network_offering.id
self.network = Network.create(
self.apiclient,
@ -724,7 +274,7 @@ class TestIpv6Network(cloudstackTestCase):
)
self.cleanup.append(self.network)
def deployIpv6NetworkVm(self):
def deployNetworkVm(self):
if self.template == FAILED:
assert False, "get_test_template() failed to return template"
self.services["virtual_machine"]["zoneid"] = self.zone.id
@ -844,7 +394,7 @@ class TestIpv6Network(cloudstackTestCase):
cmd,
hypervisor=self.routerDetailsMap[router.id]['hypervisor']
)
self.assertTrue(type(result) == list,
self.assertTrue(type(result) == list and len(result) > 0,
"%s on router %s returned invalid result" % (cmd, router.id))
result = '\n'.join(result)
return result
@ -865,6 +415,23 @@ class TestIpv6Network(cloudstackTestCase):
if router.redundantstate == red_state:
return router
def getNetworkGateway(self, network):
ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
self.assertTrue(
isinstance(ipv6_network, list),
"Check listNetworks response returns a valid list"
)
self.assertEqual(
len(ipv6_network),
1,
"Network not found"
)
ipv6_network = ipv6_network[0]
self.assertNotEqual(ipv6_network.ip6gateway,
None,
"IPv6 gateway for network is empty")
return ipv6_network.ip6gateway
def getNetworkRoutes(self, network):
ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
self.assertTrue(
@ -896,11 +463,11 @@ class TestIpv6Network(cloudstackTestCase):
self.assertTrue(type(res) == str and len(res) > 0 and st in res,
"%s failed on router %s" % (cmd, router.id))
def checkIpv6NetworkPrimaryRouter(self, router):
def checkIpv6NetworkPrimaryRouter(self, router, network_ip6gateway):
self.checkRouterNicState(router, "eth0", "UP")
guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % ("eth0", self.network.ip6gateway)
guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % ("eth0", network_ip6gateway)
res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
self.assertTrue(type(res) == str and len(res) > 0 and self.network.ip6gateway in res,
self.assertTrue(type(res) == str and len(res) > 0 and network_ip6gateway in res,
"%s failed on router %s" % (guest_gateway_check_cmd, router.id))
self.assertFalse("dadfailed" in res,
"dadfailed for IPv6 guest gateway on router %s" % router.id)
@ -930,22 +497,23 @@ class TestIpv6Network(cloudstackTestCase):
self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6_gateway in res,
"%s failed on router %s" % (default_route_check_cmd, router.id))
def checkIpv6NetworkBackupRouter(self, router):
def checkIpv6NetworkBackupRouter(self, router, network_ip6gateway):
self.checkRouterNicState(router, "eth0", "UP")
guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % ("eth0", self.network.ip6gateway)
guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % ("eth0", network_ip6gateway)
res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
self.assertFalse(type(res) == str and len(res) > 0 and self.network.ip6gateway in res,
self.assertFalse(type(res) == str and len(res) > 0 and network_ip6gateway in res,
"%s failed on router %s" % (guest_gateway_check_cmd, router.id))
self.checkRouterNicState(router, "eth2", "DOWN")
def checkIpv6NetworkRoutersInternal(self):
network_ip6gateway = self.getNetworkGateway(self.network)
for router in self.routers:
if router.state != "Running":
continue
if router.isredundantrouter == True and router.redundantstate == 'BACKUP':
self.checkIpv6NetworkBackupRouter(router)
self.checkIpv6NetworkBackupRouter(router, network_ip6gateway)
continue
self.checkIpv6NetworkPrimaryRouter(router)
self.checkIpv6NetworkPrimaryRouter(router, network_ip6gateway)
def checkIpv6NetworkVm(self):
@ -958,7 +526,7 @@ class TestIpv6Network(cloudstackTestCase):
self.assertEqual(
len(nics),
1,
"Router for the network isn't found"
"VM NIC for the network isn't found"
)
nic = nics[0]
self.assertNotEqual(nic.ip6address,
@ -974,9 +542,11 @@ class TestIpv6Network(cloudstackTestCase):
def restartNetworkWithCleanup(self):
self.network.restart(self.apiclient, cleanup=True)
time.sleep(SLEEP_BEFORE_VR_CHANGES)
def updateNetworkWithOffering(self):
self.network.update(self.apiclient, networkofferingid=self.network_offering_update.id)
time.sleep(SLEEP_BEFORE_VR_CHANGES)
def createIpv6FirewallRuleInNetwork(self, network_id, traffic_type, source_cidr, dest_cidr, protocol,
start_port, end_port, icmp_type, icmp_code):
@ -1000,9 +570,8 @@ class TestIpv6Network(cloudstackTestCase):
fw_rule = self.apiclient.createIpv6FirewallRule(cmd)
return fw_rule
def checkNetworkRouting(self):
self.routing_test_network_offering = self.createIpv6NetworkOfferingInternal(False, True)
self.cleanup.append(self.routing_test_network_offering)
def deployRoutingTestResources(self):
self.routing_test_network_offering = self.createNetworkOfferingInternal(False, True)
self.services["network"]["networkoffering"] = self.routing_test_network_offering.id
self.routing_test_network = Network.create(
self.apiclient,
@ -1025,37 +594,62 @@ class TestIpv6Network(cloudstackTestCase):
)
self.cleanup.append(self.routing_test_vm)
def prepareRoutingTestResourcesInBackground(self):
self.thread = threading.Thread(target=self.deployRoutingTestResources, args=())
self.thread.daemon = True
self.thread.start()
def checkIpv6NetworkRouting(self):
if not self.thread:
self.deployRoutingTestResources()
else:
self.thread.join(5*60)
self.assertFalse(not self.routing_test_network or not self.routing_test_vm,
"Routing resources failure")
fw1 = self.createIpv6FirewallRuleInNetwork(self.routing_test_network.id, "Ingress", None, None, "icmp",
None, None, None, None)
fw2 = self.createIpv6FirewallRuleInNetwork(self.network.id, "Ingress", None, None, "icmp",
None, None, None, None)
router = self.getNetworkRouter(self.routing_test_network)
self.logger.debug("Adding network routes in routing_test_network %s" % self.network_ipv6_routes)
for route in self.network_ipv6_routes:
test_network_router = self.getNetworkRouter(self.routing_test_network)
routes = self.getNetworkRoutes(self.network)
self.logger.debug("Adding network routes in routing_test_network %s" % routes)
for route in routes:
add_route_cmd = "ip -6 route add %s via %s" % (route.subnet, route.gateway)
self.getRouterProcessStatus(router, add_route_cmd)
self.getRouterProcessStatus(test_network_router, add_route_cmd)
router = self.getNetworkRouter(self.network)
network_router = self.getNetworkRouter(self.network)
routes = self.getNetworkRoutes(self.routing_test_network)
self.logger.debug("Adding routing_test_network routes in network %s" % routes)
for route in routes:
add_route_cmd = "ip -6 route add %s via %s" % (route.subnet, route.gateway)
self.getRouterProcessStatus(router, add_route_cmd)
time.sleep(self.services["sleep"])
self.getRouterProcessStatus(network_router, add_route_cmd)
ping_cmd = "ping6 -c 4 %s" % self.virtual_machine_ipv6_address
res = self.getRouterProcessStatus(router, ping_cmd)
count = 0
while count < PING_RETRIES:
count = count + 1
res = self.getRouterProcessStatus(test_network_router, ping_cmd)
if " 0% packet loss" in res:
break
time.sleep(PING_SLEEP)
self.assertTrue(" 0% packet loss" in res,
"Ping from router %s of network %s to VM %s of network %s is unsuccessful" % (router.id, self.routing_test_network.id, self.virtual_machine.id, self.network.id))
"Ping from router %s of network %s to VM %s of network %s is unsuccessful" % (test_network_router.id, self.routing_test_network.id, self.virtual_machine.id, self.network.id))
ssh = self.routing_test_vm.get_ssh_client(retries=5)
res = ssh.execute(ping_cmd)
count = 0
while count < PING_RETRIES:
count = count + 1
res = ssh.execute(ping_cmd)
if type(res) == list and len(res) > 0 and " 0% packet loss" in '\n'.join(res):
break
time.sleep(PING_SLEEP)
self.assertTrue(type(res) == list and len(res) > 0,
"%s on VM %s returned invalid result" % (ping_cmd, self.routing_test_vm.id))
self.logger.debug(res)
res = '\n'.join(res)
self.assertTrue(" 0% packet loss" in res,
"Ping from VM %s of network %s to VM %s of network %s is unsuccessful" % (self.routing_test_vm.id, self.routing_test_network.id, self.virtual_machine.id, self.network.id))
@ -1160,17 +754,22 @@ class TestIpv6Network(cloudstackTestCase):
None, None, None, None, rule)
def checkNetworkVRRedundancy(self):
network_ip6gateway = self.getNetworkGateway(self.network)
primary_router = self.getNetworkRouter(self.network)
Router.stop(
self.apiclient,
id=primary_router.id
)
time.sleep(self.services["sleep"]/2)
time.sleep(SLEEP_BEFORE_VR_CHANGES)
new_primary_router = self.getNetworkRouter(self.network)
self.assertNotEqual(new_primary_router.id, primary_router.id,
"Original primary router ID: %s of network is still the primary router after stopping" % (primary_router.id))
print(new_primary_router)
self.checkIpv6NetworkPrimaryRouter(new_primary_router)
self.checkIpv6NetworkPrimaryRouter(new_primary_router, network_ip6gateway)
def checkIpv6Network(self):
self.checkIpv6NetworkBasic()
self.checkIpv6NetworkRoutersBasic()
self.checkIpv6NetworkRoutersInternal()
@attr(
@ -1192,69 +791,23 @@ class TestIpv6Network(cloudstackTestCase):
# 3. List router for the network and verify it has required IPv6 details for Guest and Public NIC of the VR
# 4. SSH into VR(s) and verify correct details are present for its NICs
# 5. Verify VM in network has required IPv6 details
# 6. Restart network with cleanup
# 7. Update network with a new offering
# 8. Again verify network and VR details
# 9. Deploy another IPv6 network and check routing between two networks and their VM
# 10. Create IPv6 firewall rules and verify in VR if they get implemented
# 6. Restart network with cleanup and re-verify network details
# 7. Update network with a new offering and re-verify network details
# 8. Deploy another IPv6 network and check routing between two networks and their VM
# 9. Create IPv6 firewall rules and verify in VR if they get implemented
"""
self.createIpv6NetworkOffering(False)
self.createIpv6NetworkOfferingForUpdate(False)
self.createIpv6NetworkOffering()
self.createIpv6NetworkOfferingForUpdate()
self.createTinyServiceOffering()
self.deployIpv6Network()
self.deployIpv6NetworkVm()
self.checkIpv6NetworkBasic()
self.checkIpv6NetworkRoutersBasic()
self.checkIpv6NetworkRoutersInternal()
self.deployNetwork()
self.deployNetworkVm()
self.checkIpv6Network()
self.checkIpv6NetworkVm()
self.prepareRoutingTestResourcesInBackground()
self.restartNetworkWithCleanup()
self.checkIpv6Network()
self.updateNetworkWithOffering()
self.checkIpv6NetworkBasic()
self.checkIpv6NetworkRoutersBasic()
self.checkNetworkRouting()
self.checkIpv6Network()
self.checkIpv6NetworkRouting()
self.checkIpv6FirewallRule()
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
@skipTestIf("ipv6NotSupported")
def test_02_verify_ipv6_network_redundant(self):
"""Test to verify redundant IPv6 network
# Validate the following:
# 1. Create IPv6 network, deploy VM
# 2. Verify network has required IPv6 details
# 3. List VRs for the network and verify it has required IPv6 details for Guest and Public NIC of the VR
# 4. SSH into VR(s) and verify correct details are present for its NICs
# 5. Verify VM in network has required IPv6 details
# 6. Restart network with cleanup
# 7. Update network with a new offering
# 8. Again verify network and VR details
# 9. Deploy another IPv6 network and check routing between two networks and their VM
# 10. Create IPv6 firewall rules and verify in VR if they get implemented
# 11. Stop primary router and verify internals in backup VR
"""
self.createIpv6NetworkOffering(True)
self.createIpv6NetworkOfferingForUpdate(True)
self.createTinyServiceOffering()
self.deployIpv6Network()
self.deployIpv6NetworkVm()
self.checkIpv6NetworkBasic()
self.checkIpv6NetworkRoutersBasic()
self.checkIpv6NetworkRoutersInternal()
self.checkIpv6NetworkVm()
self.restartNetworkWithCleanup()
self.updateNetworkWithOffering()
self.checkIpv6NetworkBasic()
self.checkIpv6NetworkRoutersBasic()
self.checkNetworkRouting()
self.checkIpv6FirewallRule()
self.checkNetworkVRRedundancy()

View File

@ -0,0 +1,901 @@
# 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.
""" BVT test for IPv6 VPC"""
#Import Local Modules
from marvin.codes import FAILED
from marvin.cloudstackTestCase import cloudstackTestCase
from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
listGuestNetworkIpv6Prefixes,
deleteGuestNetworkIpv6Prefix)
from marvin.lib.utils import (isAlmostEqual,
random_gen,
get_process_status,
get_host_credentials)
from marvin.lib.base import (Configurations,
Domain,
NetworkOffering,
VpcOffering,
Account,
PublicIpRange,
Network,
VPC,
Router,
ServiceOffering,
VirtualMachine,
NIC,
Host,
NetworkACLList,
NetworkACL)
from marvin.lib.common import (get_domain,
get_zone,
get_test_template,
get_template)
from marvin.sshClient import SshClient
from marvin.cloudstackException import CloudstackAPIException
from marvin.lib.decoratorGenerators import skipTestIf
from nose.plugins.attrib import attr
from ipaddress import IPv6Network
from random import getrandbits, choice, randint
import time
import logging
import threading
ipv6_offering_config_name = "ipv6.offering.enabled"
ULA_BASE = IPv6Network("fd00::/8")
PREFIX_OPTIONS = [i for i in range(48, 65, 4)]
ACL_TABLE = "ip6_acl"
ACL_CHAINS_SUFFIX = {
"Ingress": "_ingress_policy",
"Egress": "_egress_policy"
}
CIDR_IPV6_ANY = "::/0"
ICMPV6_TYPE = {
1: "destination-unreachable",
2: "packet-too-big",
3: "time-exceeded",
4: "parameter-problem",
128: "echo-request",
129: "echo-reply",
130: "mld-listener-query",
131: "mld-listener-report",
132: "mld-listener-done",
133: "nd-router-solicit",
134: "nd-router-advert",
135: "nd-neighbor-solicit",
136: "nd-neighbor-advert",
137: "nd-redirect",
138: "router-renumbering",
141: "ind-neighbor-solicit",
142: "ind-neighbor-advert",
143: "mld2-listener-report"
}
ICMPV6_CODE_TYPE = {
0: "no-route",
1: "admin-prohibited",
3: "addr-unreachable",
4: "port-unreachable",
5: "policy-fail",
6: "reject-route"
}
ICMPV6_TYPE_ANY = "{ destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, router-renumbering }"
TCP_UDP_PORT_ANY = "{ 0-65535 }"
VPC_ROUTER_PUBLIC_NIC = "eth1"
VPC_ROUTER_GUEST_NIC = "eth2"
VPC_DATA = {
"cidr": "10.1.0.0/22",
"tier1_gateway": "10.1.1.1",
"tier2_gateway": "10.1.2.1",
"tier_netmask": "255.255.255.0"
}
ROUTE_TEST_VPC_DATA = {
"cidr": "10.2.0.0/22",
"tier1_gateway": "10.2.1.1",
"tier_netmask": "255.255.255.0"
}
SLEEP_BEFORE_VR_CHANGES = 90
PING_RETRIES = 5
PING_SLEEP = 20
class TestIpv6Vpc(cloudstackTestCase):
@classmethod
def setUpClass(cls):
testClient = super(TestIpv6Vpc, cls).getClsTestClient()
cls.services = testClient.getParsedTestDataConfig()
cls.apiclient = testClient.getApiClient()
cls.dbclient = testClient.getDbConnection()
cls.test_ipv6_guestprefix = None
cls.initial_ipv6_offering_enabled = None
cls._cleanup = []
cls.routerDetailsMap = {}
cls.vpcAllowAllAclDetailsMap = {}
cls.logger = logging.getLogger('TestIpv6Vpc')
cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
cls.services['mode'] = cls.zone.networktype
cls.ipv6NotSupported = False
ipv6_guestprefix = cls.getGuestIpv6Prefix()
if ipv6_guestprefix == None:
cls.ipv6NotSupported = True
if cls.ipv6NotSupported == False:
ipv6_publiciprange = cls.getPublicIpv6Range()
if ipv6_publiciprange == None:
cls.ipv6NotSupported = True
if cls.ipv6NotSupported == False:
cls.initial_ipv6_offering_enabled = Configurations.list(
cls.apiclient,
name=ipv6_offering_config_name)[0].value
Configurations.update(cls.apiclient,
ipv6_offering_config_name,
"true")
cls.domain = get_domain(cls.apiclient)
cls.account = Account.create(
cls.apiclient,
cls.services["account"],
admin=True,
domainid=cls.domain.id
)
cls._cleanup.append(cls.account)
cls.hypervisor = testClient.getHypervisorInfo()
cls.template = get_test_template(
cls.apiclient,
cls.zone.id,
cls.hypervisor)
else:
cls.debug("IPv6 is not supported, skipping tests!")
return
@classmethod
def tearDownClass(cls):
if cls.initial_ipv6_offering_enabled != None:
Configurations.update(cls.apiclient,
ipv6_offering_config_name,
cls.initial_ipv6_offering_enabled)
try:
super(TestIpv6Vpc, cls).tearDownClass()
finally:
if cls.test_ipv6_guestprefix != None:
cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
cmd.id = cls.test_ipv6_guestprefix.id
cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
@classmethod
def getGuestIpv6Prefix(cls):
cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
cmd.zoneid = cls.zone.id
ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
return ipv6_prefixes_response[0]
ipv6_guestprefix_service = cls.services["guestip6prefix"]
cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
cmd.zoneid = cls.zone.id
cmd.prefix = ipv6_guestprefix_service["prefix"]
ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
cls.test_ipv6_guestprefix = ipv6_guestprefix
return ipv6_guestprefix
@classmethod
def getPublicIpv6Range(cls):
list_public_ip_range_response = PublicIpRange.list(
cls.apiclient,
zoneid=cls.zone.id
)
ipv4_range_vlan = None
if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
for ip_range in list_public_ip_range_response:
if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
return ip_range
if ip_range.netmask != None and ip_range.gateway != None:
vlan = ip_range.vlan
if ipv4_range_vlan == None and vlan.startswith("vlan://"):
vlan = vlan.replace("vlan://", "")
if vlan == "untagged":
ipv4_range_vlan = None
else:
ipv4_range_vlan = int(vlan)
ipv6_publiciprange_service = cls.services["publicip6range"]
ipv6_publiciprange_service["zoneid"] = cls.zone.id
ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
ipv6_publiciprange = PublicIpRange.create(
cls.apiclient,
ipv6_publiciprange_service
)
cls._cleanup.append(ipv6_publiciprange)
return ipv6_publiciprange
def setUp(self):
self.services = self.testClient.getParsedTestDataConfig()
self.apiclient = self.testClient.getApiClient()
self.dbclient = self.testClient.getDbConnection()
self.thread = None
self.cleanup = []
return
def tearDown(self):
try:
if self.thread and self.thread.is_alive():
self.thread.join(5*60)
except Exception as e:
raise Exception("Warning: Exception during cleanup : %s" % e)
finally:
super(TestIpv6Vpc, self).tearDown()
return
def getRandomIpv6Cidr(self):
prefix_length = choice(PREFIX_OPTIONS)
random_suffix = getrandbits(40) << (128-prefix_length)
base_address = ULA_BASE.network_address + random_suffix
return str(IPv6Network((base_address, prefix_length)))
def createTinyServiceOffering(self):
self.service_offering = ServiceOffering.create(
self.apiclient,
self.services["service_offerings"]["big"],
)
self.cleanup.append(self.service_offering)
def createVpcOfferingInternal(self, is_redundant, is_ipv6):
off_service = self.services["vpc_offering"]
if is_redundant:
off_service["serviceCapabilityList"] = {
"SourceNat": {
"RedundantRouter": 'true'
},
}
if is_ipv6:
off_service["internetprotocol"] = "dualstack"
vpc_offering = VpcOffering.create(
self.apiclient,
off_service
)
self.cleanup.append(vpc_offering)
vpc_offering.update(self.apiclient, state='Enabled')
return vpc_offering
def createIpv4VpcOffering(self, is_redundant=False):
self.vpc_offering = self.createVpcOfferingInternal(is_redundant, False)
def createIpv6VpcOffering(self, is_redundant=False):
self.vpc_offering = self.createVpcOfferingInternal(is_redundant, True)
def createIpv6VpcOfferingForUpdate(self, is_redundant=False):
self.vpc_offering_update = self.createVpcOfferingInternal(is_redundant, True)
def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
off_service = self.services["nw_offering_isolated_vpc"]
if not remove_lb: # Remove Lb service
if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
providers = off_service["serviceProviderList"]
providers.pop("Lb")
off_service["serviceProviderList"] = providers
if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
supportedServices = off_service["supportedservices"].split(",")
supportedServices.remove("Lb")
off_service["supportedservices"] = ",".join(supportedServices)
if is_ipv6:
off_service["internetprotocol"] = "dualstack"
network_offering = NetworkOffering.create(
self.apiclient,
off_service,
conservemode=False
)
self.cleanup.append(network_offering)
network_offering.update(self.apiclient, state='Enabled')
return network_offering
def createIpv4NetworkTierOffering(self):
self.network_offering = self.createNetworkTierOfferingInternal(False)
def createIpv6NetworkTierOffering(self, remove_lb=True):
self.network_offering = self.createNetworkTierOfferingInternal(True)
def createIpv6NetworkTierOfferingForUpdate(self):
self.network_offering_update = self.createNetworkTierOfferingInternal(True)
def deployAllowAllVpcInternal(self, cidr):
service = self.services["vpc"]
service["cidr"] = cidr
vpc = VPC.create(
self.apiclient,
self.services["vpc"],
vpcofferingid=self.vpc_offering.id,
zoneid=self.zone.id,
account=self.account.name,
domainid=self.account.domainid
)
self.cleanup.append(vpc)
acl = NetworkACLList.create(
self.apiclient,
services={},
name="allowall",
description="allowall",
vpcid=vpc.id
)
rule ={
"protocol": "all",
"traffictype": "ingress",
}
NetworkACL.create(self.apiclient,
services=rule,
aclid=acl.id
)
rule["traffictype"] = "egress"
NetworkACL.create(self.apiclient,
services=rule,
aclid=acl.id
)
self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
return vpc
def deployVpc(self):
self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
def deployNetworkTierInternal(self, network_offering_id, vpc_id, tier_gateway, tier_netmask, acl_id=None, tier_name=None):
if not acl_id and vpc_id in self.vpcAllowAllAclDetailsMap:
acl_id = self.vpcAllowAllAclDetailsMap[vpc_id]
service = self.services["ntwk"]
if tier_name:
service["name"] = tier_name
service["displaytext"] = "vpc-%s" % tier_name
network = Network.create(
self.apiclient,
service,
self.account.name,
self.account.domainid,
networkofferingid=network_offering_id,
vpcid=vpc_id,
zoneid=self.zone.id,
gateway=tier_gateway,
netmask=tier_netmask,
aclid=acl_id
)
self.cleanup.append(network)
return network
def deployNetworkTier(self):
self.network = self.deployNetworkTierInternal(
self.network_offering.id,
self.vpc.id,
VPC_DATA["tier1_gateway"],
VPC_DATA["tier_netmask"]
)
def deployNetworkTierVmInternal(self, network):
if self.template == FAILED:
assert False, "get_test_template() failed to return template"
self.services["virtual_machine"]["zoneid"] = self.zone.id
virtual_machine = VirtualMachine.create(
self.apiclient,
self.services["virtual_machine"],
templateid=self.template.id,
accountid=self.account.name,
domainid=self.account.domainid,
networkids=network,
serviceofferingid=self.service_offering.id
)
self.cleanup.append(virtual_machine)
return virtual_machine
def deployNetworkTierVm(self):
self.virtual_machine = self.deployNetworkTierVmInternal(self.network.id)
def checkIpv6Vpc(self):
self.debug("Listing VPC: %s" % (self.vpc.name))
ipv6_vpc = VPC.list(self.apiclient,listall="true",id=self.vpc.id)
self.assertTrue(
isinstance(ipv6_vpc, list),
"Check listVpcs response returns a valid list"
)
self.assertEqual(
len(ipv6_vpc),
1,
"Network not found"
)
ipv6_vpc = ipv6_vpc[0]
self.assertNotEqual(ipv6_vpc.ip6routes,
None,
"IPv6 routes for network is empty")
def checkIpv6NetworkTierBasic(self):
self.debug("Listing network: %s" % (self.network.name))
ipv6_network = Network.list(self.apiclient,listall="true",id=self.network.id)
self.assertTrue(
isinstance(ipv6_network, list),
"Check listNetworks response returns a valid list"
)
self.assertEqual(
len(ipv6_network),
1,
"Network not found"
)
ipv6_network = ipv6_network[0]
self.assertNotEqual(ipv6_network,
None,
"User is not able to retrieve network details %s" % self.network.id)
self.assertNotEqual(ipv6_network.ip6cidr,
None,
"IPv6 CIDR for network is empty")
self.assertNotEqual(ipv6_network.ip6gateway,
None,
"IPv6 gateway for network is empty")
self.assertNotEqual(ipv6_network.ip6routes,
None,
"IPv6 routes for network is empty")
def checkIpv6VpcRoutersBasic(self):
self.debug("Listing routers for VPC: %s" % self.vpc.name)
self.routers = Router.list(
self.apiclient,
vpcid=self.vpc.id,
listall=True
)
self.assertTrue(
isinstance(self.routers, list),
"Check listRouters response returns a valid list"
)
self.assertTrue(
len(self.routers) > 0,
"Router for the network isn't found"
)
for router in self.routers:
self.assertFalse(
router.isredundantrouter == True and router.redundantstate == "FAULT",
"Router for the network is in FAULT state"
)
nics = router.nic
for nic in nics:
if (nic.traffictype == 'Guest' and router.isredundantrouter == False) or nic.traffictype == 'Public':
self.assertNotEqual(nic.ip6address,
None,
"IPv6 address for router %s NIC is empty" % nic.traffictype)
self.assertNotEqual(nic.ip6cidr,
None,
"IPv6 CIDR for router %s NIC is empty" % nic.traffictype)
self.assertNotEqual(nic.ip6gateway,
None,
"IPv6 gateway for router %s NIC is empty" % nic.traffictype)
def getRouterProcessStatus(self, router, cmd):
if router.id not in self.routerDetailsMap or self.routerDetailsMap[router.id] is None:
connect_ip = self.apiclient.connection.mgtSvr
connect_user = self.apiclient.connection.user
connect_passwd = self.apiclient.connection.passwd
hypervisor = self.hypervisor
if self.hypervisor.lower() not in ('vmware', 'hyperv'):
hosts = Host.list(
self.apiclient,
zoneid=router.zoneid,
type='Routing',
state='Up',
id=router.hostid
)
self.assertEqual(
isinstance(hosts, list),
True,
"Check list host returns a valid list"
)
host = hosts[0]
connect_ip = host.ipaddress
hypervisor = None
try:
connect_user, connect_passwd= get_host_credentials(
self.config, host.ipaddress)
except KeyError:
self.skipTest(
"Marvin configuration has no host credentials to\
check router services")
details = {}
details['connect_ip'] = connect_ip
details['connect_user'] = connect_user
details['connect_passwd'] = connect_passwd
details['hypervisor'] = hypervisor
self.routerDetailsMap[router.id] = details
result = get_process_status(
self.routerDetailsMap[router.id]['connect_ip'],
22,
self.routerDetailsMap[router.id]['connect_user'],
self.routerDetailsMap[router.id]['connect_passwd'],
router.linklocalip,
cmd,
hypervisor=self.routerDetailsMap[router.id]['hypervisor']
)
self.assertTrue(type(result) == list and len(result) > 0,
"%s on router %s returned invalid result" % (cmd, router.id))
result = '\n'.join(result)
return result
def getVpcRouter(self, vpc, red_state="PRIMARY"):
routers = Router.list(
self.apiclient,
vpcid=vpc.id,
listall=True
)
self.assertTrue(
isinstance(routers, list) and len(routers) > 0,
"No routers found for VPC %s" % vpc.id
)
if len(routers) == 1:
return routers[0]
for router in routers:
if router.redundantstate == red_state:
return router
def getNetworkGateway(self, network):
ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
self.assertTrue(
isinstance(ipv6_network, list),
"Check listNetworks response returns a valid list"
)
self.assertEqual(
len(ipv6_network),
1,
"Network not found"
)
ipv6_network = ipv6_network[0]
self.assertNotEqual(ipv6_network.ip6gateway,
None,
"IPv6 gateway for network is empty")
return ipv6_network.ip6gateway
def getNetworkRoutes(self, network):
ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
self.assertTrue(
isinstance(ipv6_network, list),
"Check listNetworks response returns a valid list"
)
self.assertEqual(
len(ipv6_network),
1,
"Network not found"
)
ipv6_network = ipv6_network[0]
self.assertNotEqual(ipv6_network.ip6routes,
None,
"IPv6 routes for network is empty")
return ipv6_network.ip6routes
def isNetworkEgressDefaultPolicyAllow(self, network):
ipv6_network = Network.list(self.apiclient,listall="true",id=network.id)
if len(ipv6_network) == 1:
ipv6_network = ipv6_network[0]
return ipv6_network.egressdefaultpolicy
return False
def checkRouterNicState(self, router, dev, state):
st = "state %s" % state
cmd = "ip link show %s | grep '%s'" % (dev, st)
res = self.getRouterProcessStatus(router, cmd)
self.assertTrue(type(res) == str and len(res) > 0 and st in res,
"%s failed on router %s" % (cmd, router.id))
def checkIpv6VpcPrimaryRouter(self, router, network_ip6gateway):
self.checkRouterNicState(router, VPC_ROUTER_GUEST_NIC, "UP")
guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % (VPC_ROUTER_GUEST_NIC, network_ip6gateway)
res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
self.assertTrue(type(res) == str and len(res) > 0 and network_ip6gateway in res,
"%s failed on router %s" % (guest_gateway_check_cmd, router.id))
self.assertFalse("dadfailed" in res,
"dadfailed for IPv6 guest gateway on router %s" % router.id)
self.checkRouterNicState(router, VPC_ROUTER_PUBLIC_NIC, "UP")
public_ipv6 = None
public_ipv6_gateway = None
nics = router.nic
for nic in nics:
if nic.traffictype == 'Public':
public_ipv6 = nic.ip6address
public_ipv6_gateway = nic.ip6gateway
break
self.assertNotEqual(public_ipv6,
None,
"IPv6 address for router Public NIC is empty")
public_ip_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % (VPC_ROUTER_PUBLIC_NIC, public_ipv6)
res = self.getRouterProcessStatus(router, public_ip_check_cmd)
self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6 in res,
"%s failed on router %s" % (public_ip_check_cmd, router.id))
self.assertFalse("dadfailed" in res,
"dadfailed for public IPv6 on router %s" % router.id)
self.assertNotEqual(public_ipv6_gateway,
None,
"IPv6 gateway for router Public NIC is empty")
default_route_check_cmd = "ip -6 route | grep 'default via %s'" % (public_ipv6_gateway)
res = self.getRouterProcessStatus(router, default_route_check_cmd)
self.assertTrue(type(res) == str and len(res) > 0 and public_ipv6_gateway in res,
"%s failed on router %s" % (default_route_check_cmd, router.id))
def checkIpv6VpcBackupRouter(self, router, network_ip6gateway):
self.checkRouterNicState(router, VPC_ROUTER_GUEST_NIC, "UP")
guest_gateway_check_cmd = "ip -6 address show %s | grep 'inet6 %s'" % ("eth0", network_ip6gateway)
res = self.getRouterProcessStatus(router, guest_gateway_check_cmd)
self.assertFalse(type(res) == str and len(res) > 0 and network_ip6gateway in res,
"%s failed on router %s" % (guest_gateway_check_cmd, router.id))
self.checkRouterNicState(router, VPC_ROUTER_PUBLIC_NIC, "DOWN")
def checkIpv6VpcRoutersInternal(self):
network_ip6gateway = self.getNetworkGateway(self.network)
for router in self.routers:
if router.state != "Running":
continue
if router.isredundantrouter == True and router.redundantstate == 'BACKUP':
self.checkIpv6VpcBackupRouter(router, network_ip6gateway)
continue
self.checkIpv6VpcPrimaryRouter(router, network_ip6gateway)
def checkIpv6NetworkTierVm(self):
self.debug("Listing NICS for VM %s in network tier: %s" % (self.virtual_machine.name, self.network.name))
nics = NIC.list(
self.apiclient,
virtualmachineid=self.virtual_machine.id,
networkid=self.network.id
)
self.assertEqual(
len(nics),
1,
"VM NIC for the network tier isn't found"
)
nic = nics[0]
self.assertNotEqual(nic.ip6address,
None,
"IPv6 address for VM %s NIC is empty" % nic.traffictype)
self.virtual_machine_ipv6_address = nic.ip6address
self.assertNotEqual(nic.ip6cidr,
None,
"IPv6 CIDR for VM %s NIC is empty" % nic.traffictype)
self.assertNotEqual(nic.ip6gateway,
None,
"IPv6 gateway for VM %s NIC is empty" % nic.traffictype)
def restartVpcWithCleanup(self):
self.vpc.restart(self.apiclient, cleanup=True)
time.sleep(SLEEP_BEFORE_VR_CHANGES)
def updateNetworkTierWithOffering(self):
self.network.update(self.apiclient, networkofferingid=self.network_offering_update.id)
time.sleep(SLEEP_BEFORE_VR_CHANGES)
def deployRoutingTestResources(self):
self.routing_test_vpc = self.deployAllowAllVpcInternal(ROUTE_TEST_VPC_DATA["cidr"])
self.routing_test_network_offering = self.createNetworkTierOfferingInternal(True)
self.routing_test_network = self.deployNetworkTierInternal(
self.routing_test_network_offering.id,
self.routing_test_vpc.id,
ROUTE_TEST_VPC_DATA["tier1_gateway"],
ROUTE_TEST_VPC_DATA["tier_netmask"]
)
self.services["virtual_machine"]["zoneid"] = self.zone.id
self.routing_test_vm = VirtualMachine.create(
self.apiclient,
self.services["virtual_machine"],
templateid=self.template.id,
accountid=self.account.name,
domainid=self.account.domainid,
networkids=[self.routing_test_network.id],
serviceofferingid=self.service_offering.id,
mode="advanced",
vpcid=self.routing_test_vpc.id
)
self.cleanup.append(self.routing_test_vm)
def prepareRoutingTestResourcesInBackground(self):
self.thread = threading.Thread(target=self.deployRoutingTestResources, args=())
self.thread.daemon = True
self.thread.start()
def checkVpcRouting(self):
if not self.thread:
self.deployRoutingTestResources()
else:
self.thread.join(5*60)
self.assertFalse(not self.routing_test_vpc or not self.routing_test_network or not self.routing_test_vm,
"Routing resources failure")
test_vpc_router = self.getVpcRouter(self.routing_test_vpc)
routes = self.getNetworkRoutes(self.network)
self.logger.debug("Adding vpc routes in routing_test_vpc %s" % routes)
for route in routes:
add_route_cmd = "ip -6 route add %s via %s" % (route.subnet, route.gateway)
self.getRouterProcessStatus(test_vpc_router, add_route_cmd)
vpc_router = self.getVpcRouter(self.vpc)
routes = self.getNetworkRoutes(self.routing_test_network)
self.logger.debug("Adding routing_test_vpc routes in vpc %s" % routes)
for route in routes:
add_route_cmd = "ip -6 route add %s via %s" % (route.subnet, route.gateway)
self.getRouterProcessStatus(vpc_router, add_route_cmd)
ping_cmd = "ping6 -c 4 %s" % self.virtual_machine_ipv6_address
count = 0
while count < PING_RETRIES:
count = count + 1
res = self.getRouterProcessStatus(test_vpc_router, ping_cmd)
if " 0% packet loss" in res:
break
time.sleep(PING_SLEEP)
self.assertTrue(" 0% packet loss" in res,
"Ping from router %s of VPC %s to VM %s of VPC %s is unsuccessful" % (test_vpc_router.id, self.routing_test_vpc.id, self.virtual_machine.id, self.vpc.id))
ssh = self.routing_test_vm.get_ssh_client(retries=5)
count = 0
while count < PING_RETRIES:
count = count + 1
res = ssh.execute(ping_cmd)
if type(res) == list and len(res) > 0 and " 0% packet loss" in '\n'.join(res):
break
time.sleep(PING_SLEEP)
self.assertTrue(type(res) == list and len(res) > 0,
"%s on VM %s returned invalid result" % (ping_cmd, self.routing_test_vm.id))
self.logger.debug(res)
res = '\n'.join(res)
self.assertTrue(" 0% packet loss" in res,
"Ping from VM %s of VPC %s to VM %s of VPC %s is unsuccessful" % (self.routing_test_vm.id, self.routing_test_vpc.id, self.virtual_machine.id, self.vpc.id))
def createNetworkAclRule(self, rule, aclid):
return NetworkACL.create(self.apiclient,
services=rule,
aclid=aclid
)
def verifyAclRulesInRouter(self, nic, rules, router):
for rule in rules:
acl_chain = nic + ACL_CHAINS_SUFFIX[rule["traffictype"]]
routerCmd = "nft list chain ip6 %s %s" % (ACL_TABLE, acl_chain)
res = self.getRouterProcessStatus(router, routerCmd)
self.assertTrue(rule["parsedrule"] in res,
"Listing firewall rule with nft list chain failure for rule: %s" % rule["parsedrule"])
def checkIpv6AclRule(self):
router = self.getVpcRouter(self.vpc)
tier1_acl = NetworkACLList.create(
self.apiclient,
services={},
name="tier1_acl",
description="tier1_acl",
vpcid=self.vpc.id
)
rules = []
# Ingress - ip6 saddr SOURCE_CIDR tcp dport { START_PORT-END_PORT } accept
rule = {}
rule["traffictype"] = "Ingress"
rule["cidrlist"] = self.getRandomIpv6Cidr()
rule["protocol"] = "tcp"
rule["startport"] = randint(3000, 5000)
rule["endport"] = rule["startport"] + randint(1, 8)
parsedrule = "ip6 saddr %s %s dport { %d-%d } accept" % (rule["cidrlist"], rule["protocol"], rule["startport"], rule["endport"])
rules.append({"traffictype": rule["traffictype"], "parsedrule": parsedrule})
self.createNetworkAclRule(rule, tier1_acl.id)
# Egress - ip6 daddr DEST_CIDR icmpv6 type TYPE code CODE accept
rule = {}
rule["traffictype"] = "Egress"
rule["cidrlist"] = self.getRandomIpv6Cidr()
rule["protocol"] = "icmp"
rule["icmptype"] = choice(list(ICMPV6_TYPE.keys()))
rule["icmpcode"] = choice(list(ICMPV6_CODE_TYPE.keys()))
parsedrule = "ip6 daddr %s %sv6 type %s %sv6 code %s accept" % (rule["cidrlist"], rule["protocol"], ICMPV6_TYPE[rule["icmptype"]], rule["protocol"], ICMPV6_CODE_TYPE[rule["icmpcode"]])
rules.append({"traffictype": rule["traffictype"], "parsedrule": parsedrule})
self.createNetworkAclRule(rule, tier1_acl.id)
self.network.replaceACLList(self.apiclient, tier1_acl.id)
self.verifyAclRulesInRouter("eth2", rules, router)
tier2_acl = NetworkACLList.create(
self.apiclient,
services={},
name="tier2_acl",
description="tier2_acl",
vpcid=self.vpc.id
)
rules = []
# Ingress - ip6 saddr ::/0 udp dport { 0-65355 } ACTION
rule = {}
rule["traffictype"] = "Ingress"
rule["cidrlist"] = CIDR_IPV6_ANY
rule["protocol"] = "udp"
parsedrule = "ip6 saddr %s %s dport %s accept" % (rule["cidrlist"], rule["protocol"], TCP_UDP_PORT_ANY)
rules.append({"traffictype": rule["traffictype"], "parsedrule": parsedrule})
self.createNetworkAclRule(rule, tier2_acl.id)
# Egress - ip6 daddr DEST_CIDR icmpv6 type TYPE code CODE accept
rule = {}
rule["traffictype"] = "Egress"
rule["protocol"] = "all"
parsedrule = "ip6 daddr %s accept" % (CIDR_IPV6_ANY)
rules.append({"traffictype": rule["traffictype"], "parsedrule": parsedrule})
self.createNetworkAclRule(rule, tier2_acl.id)
self.network_offering_tier2 = self.createNetworkTierOfferingInternal(True, False)
self.tier2_network = self.deployNetworkTierInternal(
self.network_offering_tier2.id,
self.vpc.id,
VPC_DATA["tier2_gateway"],
VPC_DATA["tier_netmask"],
tier2_acl.id,
"tier2"
)
self.tier2_vm = self.deployNetworkTierVmInternal(self.tier2_network.id)
self.verifyAclRulesInRouter("eth3", rules, router)
def checkVpcVRRedundancy(self):
network_ip6gateway = self.getNetworkGateway(self.network)
primary_router = self.getVpcRouter(self.vpc)
Router.stop(
self.apiclient,
id=primary_router.id
)
time.sleep(self.services["sleep"]/2)
new_primary_router = self.getVpcRouter(self.vpc)
self.assertNotEqual(new_primary_router.id, primary_router.id,
"Original primary router ID: %s of VPC is still the primary router after stopping" % (primary_router.id))
self.checkIpv6VpcPrimaryRouter(new_primary_router, network_ip6gateway)
def checkIpv6VpcNetworking(self, check_vm=False):
self.checkIpv6Vpc()
self.checkIpv6NetworkTierBasic()
self.checkIpv6VpcRoutersBasic()
self.checkIpv6VpcRoutersInternal()
if check_vm:
self.checkIpv6NetworkTierVm()
@attr(
tags=[
"advanced",
"basic",
"eip",
"sg",
"advancedns",
"smoke"],
required_hardware="false")
@skipTestIf("ipv6NotSupported")
def test_01_verify_ipv6_vpc(self):
"""Test to verify IPv6 VPC
# Validate the following:
# 1. Create IPv6 VPC, add tiers, deploy VM
# 2. Verify VPC, tier has required IPv6 details
# 3. List router for the VPC and verify it has required IPv6 details for Guest and Public NIC of the VR
# 4. SSH into VR(s) and verify correct details are present for its NICs
# 5. Verify VM in network tier has required IPv6 details
# 6. Restart VPC with cleanup and re-verify VPC networking
# 7. Update network tier with a new offering and re-verify VPC networking
# 8. Deploy another IPv6 VPC with tier and check routing between two VPC and their VM
# 9. Create IPv6 ACL rules in two different VPC tiers and verify in VR if they get implemented correctly
"""
self.createIpv6VpcOffering()
self.deployVpc()
self.createIpv6NetworkTierOffering()
self.createIpv6NetworkTierOfferingForUpdate()
self.createTinyServiceOffering()
self.deployNetworkTier()
self.deployNetworkTierVm()
self.checkIpv6VpcNetworking(True)
self.prepareRoutingTestResourcesInBackground()
self.restartVpcWithCleanup()
self.checkIpv6VpcNetworking()
self.updateNetworkTierWithOffering()
self.checkIpv6VpcNetworking()
self.checkVpcRouting()
self.checkIpv6AclRule()

View File

@ -3292,6 +3292,14 @@ class Network:
cmd.resume = resume
return (apiclient.migrateNetwork(cmd))
def replaceACLList(self, apiclient, aclid, gatewayid=None):
cmd = replaceNetworkACLList.replaceNetworkACLListCmd()
cmd.networkid = self.id
cmd.aclid = aclid
if gatewayid:
cmd.gatewayid = gatewayid
return (apiclient.replaceNetworkACLList(cmd))
@classmethod
def list(cls, apiclient, **kwargs):
"""List all Networks matching criteria"""
@ -3329,6 +3337,11 @@ class NetworkACL:
elif protocol:
cmd.protocol = protocol
if "icmptype" in services:
cmd.icmptype = services["icmptype"]
if "icmpcode" in services:
cmd.icmpcode = services["icmpcode"]
if "startport" in services:
cmd.startport = services["startport"]
if "endport" in services:

View File

@ -61,9 +61,9 @@ class SshClient(object):
self.retryCnt = 0
self.delay = 0
self.timeout = 3.0
ch = logging.StreamHandler()
ch.setLevel(log_lvl)
self.logger.addHandler(ch)
self.ch = logging.StreamHandler()
self.ch.setLevel(log_lvl)
self.logger.addHandler(self.ch)
# Check invalid host value and raise exception
# Atleast host is required for connection
@ -205,6 +205,8 @@ class SshClient(object):
if self.ssh is not None:
self.ssh.close()
self.ssh = None
if self.ch is not None:
self.logger.removeHandler(self.ch)
if __name__ == "__main__":

View File

@ -226,9 +226,6 @@ export default {
}
},
handleChangeIntervalType (e) {
this.form.intervaltype = e.target.value
this.resetForm()
switch (this.form.intervaltype) {
case 'weekly':
this.fetchDayOfWeek()

View File

@ -0,0 +1,41 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.utils.security;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
public class ParserUtils {
public static DocumentBuilderFactory getSaferDocumentBuilderFactory() throws ParserConfigurationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// REDHAT https://www.blackhat.com/docs/us-15/materials/us-15-Wang-FileCry-The-New-Age-Of-XXE-java-wp.pdf
// OWASP https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
// and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
factory.setXIncludeAware(false);
factory.setExpandEntityReferences(false);
return factory;
}
}