This is an automated email from the ASF dual-hosted git repository.
dahn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/main by this push:
new 72d0546d8b0 Shared Network Firewall (Security groups) in Advanced zone
without security groups (#9415)
72d0546d8b0 is described below
commit 72d0546d8b0cdbe51dac1a21eb45f0187a01adf6
Author: Vishesh <[email protected]>
AuthorDate: Thu Sep 5 14:05:05 2024 +0530
Shared Network Firewall (Security groups) in Advanced zone without security
groups (#9415)
---
.../main/java/com/cloud/network/NetworkModel.java | 4 +
.../api/command/user/vm/AddIpToVmNicCmd.java | 2 +-
.../api/command/user/vm/RemoveIpFromVmNicCmd.java | 2 +-
.../cloudstack/api/response/ZoneResponse.java | 20 ++-
.../xenserver/discoverer/XcpServerDiscoverer.java | 4 +-
...ernetesClusterResourceModifierActionWorker.java | 2 +-
.../KubernetesClusterStartWorker.java | 7 +-
.../java/com/cloud/network/NetworkModelImpl.java | 38 ++++-
.../com/cloud/network/as/AutoScaleManagerImpl.java | 7 +-
.../main/java/com/cloud/vm/UserVmManagerImpl.java | 10 +-
.../storage/template/VnfTemplateManagerImpl.java | 2 +-
.../com/cloud/network/MockNetworkModelImpl.java | 10 ++
.../cloud/network/as/AutoScaleManagerImplTest.java | 8 +-
.../java/com/cloud/vpc/MockNetworkModelImpl.java | 10 ++
.../SecondaryStorageManagerTest.java | 6 +
.../component/test_advancedsg_networks.py | 186 +++++++++++++++------
test/integration/component/test_security_groups.py | 48 ++++--
ui/public/locales/en.json | 1 +
ui/src/config/section/network.js | 5 +-
ui/src/store/getters.js | 1 +
ui/src/store/modules/user.js | 19 +++
ui/src/store/mutation-types.js | 1 +
ui/src/views/compute/DeployVM.vue | 14 +-
ui/src/views/compute/InstanceTab.vue | 56 ++++++-
.../compute/wizard/SecurityGroupSelection.vue | 2 +-
ui/src/views/infra/network/ServiceProvidersTab.vue | 36 +++-
26 files changed, 402 insertions(+), 99 deletions(-)
diff --git a/api/src/main/java/com/cloud/network/NetworkModel.java
b/api/src/main/java/com/cloud/network/NetworkModel.java
index 699dcbf6c50..0d81495489c 100644
--- a/api/src/main/java/com/cloud/network/NetworkModel.java
+++ b/api/src/main/java/com/cloud/network/NetworkModel.java
@@ -356,4 +356,8 @@ public interface NetworkModel {
void verifyIp6DnsPair(final String ip6Dns1, final String ip6Dns2);
+ boolean isSecurityGroupSupportedForZone(Long zoneId);
+
+ boolean checkSecurityGroupSupportForNetwork(DataCenter zone, List<Long>
networkIds,
+ List<Long> securityGroupsIds);
}
diff --git
a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java
b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java
index 0dc3dcdbdcc..e76a75ae398 100644
---
a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java
+++
b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java
@@ -79,7 +79,7 @@ public class AddIpToVmNicCmd extends BaseAsyncCreateCmd {
private boolean isZoneSGEnabled() {
Network ntwk = _entityMgr.findById(Network.class, getNetworkId());
DataCenter dc = _entityMgr.findById(DataCenter.class,
ntwk.getDataCenterId());
- return dc.isSecurityGroupEnabled();
+ return dc.isSecurityGroupEnabled() ||
_ntwkModel.isSecurityGroupSupportedForZone(dc.getId());
}
@Override
diff --git
a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java
b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java
index a4cd6159dfc..2f53c3d4e4c 100644
---
a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java
+++
b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java
@@ -127,7 +127,7 @@ public class RemoveIpFromVmNicCmd extends BaseAsyncCmd {
private boolean isZoneSGEnabled() {
Network ntwk = _entityMgr.findById(Network.class, getNetworkId());
DataCenter dc = _entityMgr.findById(DataCenter.class,
ntwk.getDataCenterId());
- return dc.isSecurityGroupEnabled();
+ return dc.isSecurityGroupEnabled() ||
_ntwkModel.isSecurityGroupSupportedForZone(dc.getId());
}
@Override
diff --git
a/api/src/main/java/org/apache/cloudstack/api/response/ZoneResponse.java
b/api/src/main/java/org/apache/cloudstack/api/response/ZoneResponse.java
index 0d76fd2d3f9..ff43fb697b5 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/ZoneResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/ZoneResponse.java
@@ -312,10 +312,6 @@ public class ZoneResponse extends
BaseResponseWithAnnotations implements SetReso
return networkType;
}
- public boolean isSecurityGroupsEnabled() {
- return securityGroupsEnabled;
- }
-
public String getAllocationState() {
return allocationState;
}
@@ -332,10 +328,6 @@ public class ZoneResponse extends
BaseResponseWithAnnotations implements SetReso
return capacities;
}
- public boolean isLocalStorageEnabled() {
- return localStorageEnabled;
- }
-
public Set<ResourceTagResponse> getTags() {
return tags;
}
@@ -344,6 +336,14 @@ public class ZoneResponse extends
BaseResponseWithAnnotations implements SetReso
return resourceDetails;
}
+ public boolean isSecurityGroupsEnabled() {
+ return securityGroupsEnabled;
+ }
+
+ public boolean isLocalStorageEnabled() {
+ return localStorageEnabled;
+ }
+
public Boolean getAllowUserSpecifyVRMtu() {
return allowUserSpecifyVRMtu;
}
@@ -356,6 +356,10 @@ public class ZoneResponse extends
BaseResponseWithAnnotations implements SetReso
return routerPublicInterfaceMaxMtu;
}
+ public boolean isNsxEnabled() {
+ return nsxEnabled;
+ }
+
@Override
public void setResourceIconResponse(ResourceIconResponse
resourceIconResponse) {
this.resourceIconResponse = resourceIconResponse;
diff --git
a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/discoverer/XcpServerDiscoverer.java
b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/discoverer/XcpServerDiscoverer.java
index 2e98b68bc44..8a5e59e4373 100644
---
a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/discoverer/XcpServerDiscoverer.java
+++
b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/discoverer/XcpServerDiscoverer.java
@@ -346,7 +346,7 @@ public class XcpServerDiscoverer extends DiscovererBase
implements Discoverer, L
}
DataCenterVO zone = _dcDao.findById(dcId);
- boolean securityGroupEnabled = zone.isSecurityGroupEnabled();
+ boolean securityGroupEnabled = zone.isSecurityGroupEnabled()
|| _networkMgr.isSecurityGroupSupportedForZone(zone.getId());
params.put("securitygroupenabled",
Boolean.toString(securityGroupEnabled));
params.put("router.aggregation.command.each.timeout",
_configDao.getValue(Config.RouterAggregationCommandEachTimeout.toString()));
@@ -695,7 +695,7 @@ public class XcpServerDiscoverer extends DiscovererBase
implements Discoverer, L
HashMap<String, Object> params = super.buildConfigParams(host);
DataCenterVO zone = _dcDao.findById(host.getDataCenterId());
if (zone != null) {
- boolean securityGroupEnabled = zone.isSecurityGroupEnabled();
+ boolean securityGroupEnabled = zone.isSecurityGroupEnabled() ||
_networkMgr.isSecurityGroupSupportedForZone(zone.getId());
params.put("securitygroupenabled",
Boolean.toString(securityGroupEnabled));
}
return params;
diff --git
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java
index 41a2925e402..92a0315efb5 100644
---
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java
+++
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java
@@ -401,7 +401,7 @@ public class KubernetesClusterResourceModifierActionWorker
extends KubernetesClu
if (StringUtils.isNotBlank(kubernetesCluster.getKeyPair())) {
keypairs.add(kubernetesCluster.getKeyPair());
}
- if (zone.isSecurityGroupEnabled()) {
+ if (kubernetesCluster.getSecurityGroupId() != null &&
networkModel.checkSecurityGroupSupportForNetwork(zone, networkIds,
List.of(kubernetesCluster.getSecurityGroupId()))) {
List<Long> securityGroupIds = new ArrayList<>();
securityGroupIds.add(kubernetesCluster.getSecurityGroupId());
nodeVm =
userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering,
clusterTemplate, networkIds, securityGroupIds, owner,
diff --git
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java
index b2fbbd31f6b..9e8a43791e8 100644
---
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java
+++
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java
@@ -215,7 +215,9 @@ public class KubernetesClusterStartWorker extends
KubernetesClusterResourceModif
if (StringUtils.isNotBlank(kubernetesCluster.getKeyPair())) {
keypairs.add(kubernetesCluster.getKeyPair());
}
- if (zone.isSecurityGroupEnabled()) {
+ if (kubernetesCluster.getSecurityGroupId() != null &&
+ networkModel.checkSecurityGroupSupportForNetwork(zone,
networkIds,
+ List.of(kubernetesCluster.getSecurityGroupId()))) {
List<Long> securityGroupIds = new ArrayList<>();
securityGroupIds.add(kubernetesCluster.getSecurityGroupId());
controlVm =
userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering,
clusterTemplate, networkIds, securityGroupIds, owner,
@@ -289,7 +291,8 @@ public class KubernetesClusterStartWorker extends
KubernetesClusterResourceModif
if (StringUtils.isNotBlank(kubernetesCluster.getKeyPair())) {
keypairs.add(kubernetesCluster.getKeyPair());
}
- if (zone.isSecurityGroupEnabled()) {
+ if (kubernetesCluster.getSecurityGroupId() != null &&
+ networkModel.checkSecurityGroupSupportForNetwork(zone,
networkIds, List.of(kubernetesCluster.getSecurityGroupId()))) {
List<Long> securityGroupIds = new ArrayList<>();
securityGroupIds.add(kubernetesCluster.getSecurityGroupId());
additionalControlVm =
userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering,
clusterTemplate, networkIds, securityGroupIds, owner,
diff --git a/server/src/main/java/com/cloud/network/NetworkModelImpl.java
b/server/src/main/java/com/cloud/network/NetworkModelImpl.java
index 0c6e826a589..fb6433b5f6b 100644
--- a/server/src/main/java/com/cloud/network/NetworkModelImpl.java
+++ b/server/src/main/java/com/cloud/network/NetworkModelImpl.java
@@ -145,6 +145,8 @@ import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.NicSecondaryIpDao;
import com.cloud.vm.dao.VMInstanceDao;
+import static com.cloud.network.Network.Service.SecurityGroup;
+
public class NetworkModelImpl extends ManagerBase implements NetworkModel,
Configurable {
public static final String UNABLE_TO_USE_NETWORK = "Unable to use network
with id= %s, permission denied";
@Inject
@@ -1262,7 +1264,7 @@ public class NetworkModelImpl extends ManagerBase
implements NetworkModel, Confi
physicalNetworkId =
findPhysicalNetworkId(network.getDataCenterId(), null, null);
}
- return isServiceEnabledInNetwork(physicalNetworkId, network.getId(),
Service.SecurityGroup);
+ return isServiceEnabledInNetwork(physicalNetworkId, network.getId(),
SecurityGroup);
}
@Override
@@ -2755,4 +2757,38 @@ public class NetworkModelImpl extends ManagerBase
implements NetworkModel, Confi
throw new InvalidParameterValueException("Invalid IPv6 for IPv6
DNS2");
}
}
+
+ @Override
+ public boolean isSecurityGroupSupportedForZone(Long zoneId) {
+ List<? extends PhysicalNetwork> networks =
getPhysicalNtwksSupportingTrafficType(zoneId, TrafficType.Guest);
+ for (PhysicalNetwork network : networks ) {
+ if (_pNSPDao.isServiceProviderEnabled(network.getId(),
Provider.SecurityGroupProvider.getName(), Service.SecurityGroup.getName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean checkSecurityGroupSupportForNetwork(DataCenter zone,
List<Long> networkIds,
+ List<Long>
securityGroupsIds) {
+ if (zone.isSecurityGroupEnabled()) {
+ return true;
+ }
+ if (CollectionUtils.isNotEmpty(networkIds)) {
+ for (Long networkId : networkIds) {
+ Network network = _networksDao.findById(networkId);
+ if (network == null) {
+ throw new InvalidParameterValueException("Unable to find
network by id " + networkId);
+ }
+ if (network.getGuestType() == Network.GuestType.Shared &&
isSecurityGroupSupportedInNetwork(network)) {
+ return true;
+ }
+ }
+ } else if (CollectionUtils.isNotEmpty(securityGroupsIds)) {
+ Network networkWithSecurityGroup =
getNetworkWithSGWithFreeIPs(zone.getId());
+ return networkWithSecurityGroup != null;
+ }
+ return false;
+ }
}
diff --git
a/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java
b/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java
index 4776cfc6246..05dba6802cb 100644
--- a/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java
@@ -19,6 +19,7 @@ package com.cloud.network.as;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@@ -37,6 +38,7 @@ import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
+import com.cloud.network.NetworkModel;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.affinity.AffinityGroupVO;
import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
@@ -251,6 +253,8 @@ public class AutoScaleManagerImpl extends ManagerBase
implements AutoScaleManage
@Inject
NetworkOrchestrationService networkMgr;
@Inject
+ NetworkModel networkModel;
+ @Inject
private UserVmManager userVmMgr;
@Inject
private UserDataManager userDataMgr;
@@ -1808,7 +1812,8 @@ public class AutoScaleManagerImpl extends ManagerBase
implements AutoScaleManage
null, null, true, null, affinityGroupIdList,
customParameters, null, null, null,
null, true, overrideDiskOfferingId);
} else {
- if (zone.isSecurityGroupEnabled()) {
+ if (networkModel.checkSecurityGroupSupportForNetwork(zone,
networkIds,
+ Collections.emptyList())) {
vm =
userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering,
template, networkIds, null,
owner, vmHostName,vmHostName, diskOfferingId,
dataDiskSize, null,
hypervisorType, HTTPMethod.GET, userData,
userDataId, userDataDetails, sshKeyPairs,
diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
index 0dc0e84cbd4..f6aabb4081a 100644
--- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
@@ -27,6 +27,7 @@ import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -3094,7 +3095,7 @@ public class UserVmManagerImpl extends ManagerBase
implements UserVmManager, Vir
if (zone.getNetworkType() == NetworkType.Basic) {
// Get default guest network in Basic zone
defaultNetwork =
_networkModel.getExclusiveGuestNetwork(zone.getId());
- } else if (zone.isSecurityGroupEnabled()) {
+ } else if
(_networkModel.checkSecurityGroupSupportForNetwork(zone,
Collections.emptyList(), securityGroupIdList)) {
NicVO defaultNic = _nicDao.findDefaultNicForVM(vm.getId());
if (defaultNic != null) {
defaultNetwork =
_networkDao.findById(defaultNic.getNetworkId());
@@ -6153,7 +6154,8 @@ public class UserVmManagerImpl extends ManagerBase
implements UserVmManager, Vir
dataDiskTemplateToDiskOfferingMap,
userVmOVFProperties, dynamicScalingEnabled, overrideDiskOfferingId);
}
} else {
- if (zone.isSecurityGroupEnabled()) {
+ if (_networkModel.checkSecurityGroupSupportForNetwork(zone,
networkIds,
+ cmd.getSecurityGroupIdList())) {
vm = createAdvancedSecurityGroupVirtualMachine(zone,
serviceOffering, template, networkIds, getSecurityGroupIdList(cmd, zone,
template, owner), owner, name,
displayName, diskOfferingId, size, group,
cmd.getHypervisor(), cmd.getHttpMethod(), userData, userDataId,
userDataDetails, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm,
keyboard,
cmd.getAffinityGroupIdList(), cmd.getDetails(),
cmd.getCustomId(), cmd.getDhcpOptionsMap(),
@@ -7573,7 +7575,7 @@ public class UserVmManagerImpl extends ManagerBase
implements UserVmManager, Vir
Set<NetworkVO> applicableNetworks = new LinkedHashSet<>();
Map<Long, String> requestedIPv4ForNics = new HashMap<>();
Map<Long, String> requestedIPv6ForNics = new HashMap<>();
- if (zone.isSecurityGroupEnabled()) { // advanced zone with
security groups
+ if (_networkModel.checkSecurityGroupSupportForNetwork(zone,
networkIdList, securityGroupIdList)) { // advanced zone with security groups
// cleanup the old security groups
_securityGroupMgr.removeInstanceFromGroups(cmd.getVmId());
// if networkIdList is null and the first network of vm is
shared network, then keep it if possible
@@ -8794,7 +8796,7 @@ public class UserVmManagerImpl extends ManagerBase
implements UserVmManager, Vir
private Network getNetworkForOvfNetworkMapping(DataCenter zone, Account
owner) throws InsufficientCapacityException, ResourceAllocationException {
Network network = null;
- if (zone.isSecurityGroupEnabled()) {
+ if (zone.isSecurityGroupEnabled() ||
_networkModel.isSecurityGroupSupportedForZone(zone.getId())) {
network = _networkModel.getNetworkWithSGWithFreeIPs(zone.getId());
if (network == null) {
throw new InvalidParameterValueException("No network with
security enabled is found in zone ID: " + zone.getUuid());
diff --git
a/server/src/main/java/org/apache/cloudstack/storage/template/VnfTemplateManagerImpl.java
b/server/src/main/java/org/apache/cloudstack/storage/template/VnfTemplateManagerImpl.java
index a0078d812ae..6a34ca2d0e5 100644
---
a/server/src/main/java/org/apache/cloudstack/storage/template/VnfTemplateManagerImpl.java
+++
b/server/src/main/java/org/apache/cloudstack/storage/template/VnfTemplateManagerImpl.java
@@ -291,7 +291,7 @@ public class VnfTemplateManagerImpl extends ManagerBase
implements VnfTemplateMa
@Override
public SecurityGroup createSecurityGroupForVnfAppliance(DataCenter zone,
VirtualMachineTemplate template, Account owner,
DeployVnfApplianceCmd cmd) {
- if (zone == null || !zone.isSecurityGroupEnabled()) {
+ if (zone == null || !(zone.isSecurityGroupEnabled() ||
networkModel.isSecurityGroupSupportedForZone(zone.getId()))) {
return null;
}
if (!cmd.getVnfConfigureManagement()) {
diff --git a/server/src/test/java/com/cloud/network/MockNetworkModelImpl.java
b/server/src/test/java/com/cloud/network/MockNetworkModelImpl.java
index 395be635aea..ec594f185c4 100644
--- a/server/src/test/java/com/cloud/network/MockNetworkModelImpl.java
+++ b/server/src/test/java/com/cloud/network/MockNetworkModelImpl.java
@@ -938,4 +938,14 @@ public class MockNetworkModelImpl extends ManagerBase
implements NetworkModel {
@Override
public void verifyIp6DnsPair(String ip4Dns1, String ip4Dns2) {}
+
+ @Override
+ public boolean isSecurityGroupSupportedForZone(Long zoneId) {
+ return false;
+ }
+
+ @Override
+ public boolean checkSecurityGroupSupportForNetwork(DataCenter zone,
List<Long> networkIds, List<Long> securityGroupsIds) {
+ return false;
+ }
}
diff --git
a/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java
b/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java
index 60277740daa..386cf65aed3 100644
--- a/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java
+++ b/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java
@@ -42,6 +42,7 @@ import com.cloud.exception.ResourceUnavailableException;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.network.Network;
+import com.cloud.network.NetworkModel;
import com.cloud.network.as.dao.AutoScalePolicyConditionMapDao;
import com.cloud.network.as.dao.AutoScalePolicyDao;
import com.cloud.network.as.dao.AutoScaleVmGroupDao;
@@ -139,6 +140,7 @@ import org.springframework.test.util.ReflectionTestUtils;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
@@ -355,6 +357,8 @@ public class AutoScaleManagerImplTest {
@Mock
NetworkVO networkMock;
@Mock
+ NetworkModel networkModel;
+ @Mock
NetworkOfferingVO networkOfferingMock;
@Mock
CounterVO counterMock;
@@ -1311,10 +1315,10 @@ public class AutoScaleManagerImplTest {
when(userVmMock.getId()).thenReturn(virtualMachineId);
when(zoneMock.getNetworkType()).thenReturn(DataCenter.NetworkType.Advanced);
- when(zoneMock.isSecurityGroupEnabled()).thenReturn(true);
when(userVmService.createAdvancedSecurityGroupVirtualMachine(any(),
any(), any(), any(), any(), any(), any(),
any(), any(), any(), any(), any(), any(), eq(userData),
eq(userDataId), eq(userDataDetails.toString()), any(), any(), any(), any(),
any(), any(),
any(), any(), any(), any(), any(), eq(true), any(),
any())).thenReturn(userVmMock);
+ when(networkModel.checkSecurityGroupSupportForNetwork(zoneMock,
List.of(networkId), Collections.emptyList())).thenReturn(true);
long result = autoScaleManagerImplSpy.createNewVM(asVmGroupMock);
@@ -1360,10 +1364,10 @@ public class AutoScaleManagerImplTest {
when(userVmMock.getId()).thenReturn(virtualMachineId);
when(zoneMock.getNetworkType()).thenReturn(DataCenter.NetworkType.Advanced);
- when(zoneMock.isSecurityGroupEnabled()).thenReturn(false);
when(userVmService.createAdvancedVirtualMachine(any(), any(), any(),
any(), any(), any(), any(),
any(), any(), any(), any(), any(), eq(userData),
eq(userDataId), eq(userDataDetails.toString()), any(), any(), any(), eq(true),
any(), any(), any(),
any(), any(), any(), any(), eq(true), any(),
any())).thenReturn(userVmMock);
+ when(networkModel.checkSecurityGroupSupportForNetwork(zoneMock,
List.of(networkId), Collections.emptyList())).thenReturn(false);
long result = autoScaleManagerImplSpy.createNewVM(asVmGroupMock);
diff --git a/server/src/test/java/com/cloud/vpc/MockNetworkModelImpl.java
b/server/src/test/java/com/cloud/vpc/MockNetworkModelImpl.java
index ad332c00fa4..5802b88a6cf 100644
--- a/server/src/test/java/com/cloud/vpc/MockNetworkModelImpl.java
+++ b/server/src/test/java/com/cloud/vpc/MockNetworkModelImpl.java
@@ -954,4 +954,14 @@ public class MockNetworkModelImpl extends ManagerBase
implements NetworkModel {
@Override
public void verifyIp6DnsPair(String ip4Dns1, String ip4Dns2) {}
+
+ @Override
+ public boolean isSecurityGroupSupportedForZone(Long zoneId) {
+ return false;
+ }
+
+ @Override
+ public boolean checkSecurityGroupSupportForNetwork(DataCenter zone,
List<Long> networkIds, List<Long> securityGroupsIds) {
+ return false;
+ }
}
diff --git
a/services/secondary-storage/controller/src/test/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerTest.java
b/services/secondary-storage/controller/src/test/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerTest.java
index feae8719f27..2d48451f43e 100644
---
a/services/secondary-storage/controller/src/test/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerTest.java
+++
b/services/secondary-storage/controller/src/test/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerTest.java
@@ -29,6 +29,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import com.cloud.network.NetworkModel;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -56,6 +57,9 @@ public class SecondaryStorageManagerTest {
@Mock
NetworkDao _networkDao;
+ @Mock
+ NetworkModel _networkModel;
+
@InjectMocks
SecondaryStorageManagerImpl _ssMgr = new SecondaryStorageManagerImpl();
@@ -76,6 +80,7 @@ public class SecondaryStorageManagerTest {
DataCenterVO dc = mock(DataCenterVO.class);
when(dc.getNetworkType()).thenReturn(NetworkType.Advanced);
when(dc.isSecurityGroupEnabled()).thenReturn(false);
+
when(_networkModel.isSecurityGroupSupportedForZone(anyLong())).thenReturn(false);
when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc);
@@ -102,6 +107,7 @@ public class SecondaryStorageManagerTest {
DataCenterVO dc = Mockito.mock(DataCenterVO.class);
when(dc.getNetworkType()).thenReturn(NetworkType.Advanced);
when(dc.isSecurityGroupEnabled()).thenReturn(true);
+
when(_networkModel.isSecurityGroupSupportedForZone(anyLong())).thenReturn(true);
when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc);
diff --git a/test/integration/component/test_advancedsg_networks.py
b/test/integration/component/test_advancedsg_networks.py
index 60567ae82fd..fb9e146eb07 100644
--- a/test/integration/component/test_advancedsg_networks.py
+++ b/test/integration/component/test_advancedsg_networks.py
@@ -21,17 +21,19 @@ from marvin.cloudstackTestCase import cloudstackTestCase
import unittest
from ddt import ddt, data
from marvin.lib.base import (Zone,
- ServiceOffering,
- Account,
- NetworkOffering,
- Network,
- VirtualMachine,
- Domain,
- VpcOffering,
- VPC,
- SecurityGroup,
- Host,
- )
+ ServiceOffering,
+ Account,
+ NetworkOffering,
+ Network,
+ VirtualMachine,
+ Domain,
+ VpcOffering,
+ VPC,
+ SecurityGroup,
+ Host,
+ NetworkServiceProvider,
+ PhysicalNetwork,
+ TrafficType)
from marvin.lib.common import (get_domain,
get_zone,
@@ -158,7 +160,9 @@ class TestCreateZoneSG(cloudstackTestCase):
return
class TestNetworksInAdvancedSG(cloudstackTestCase):
- """Test Creation of different types of networks in SG enabled advanced
zone"""
+ """Test Creation of different types of networks in
+ - SG enabled advanced zone, or
+ - advanced zone without SG but with SG provider enabled"""
@classmethod
def setUpClass(cls):
@@ -169,6 +173,26 @@ class TestNetworksInAdvancedSG(cloudstackTestCase):
# Get Zone, Domain and templates
cls.domain = get_domain(cls.api_client)
cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
+ if cls.zone.securitygroupsenabled is False:
+ physical_networks = PhysicalNetwork.list(cls.api_client,
zoneid=cls.zone.id)
+ selected_physical_network = None
+ for net in physical_networks:
+ traffic_types = TrafficType.list(cls.api_client,
physicalnetworkid=net.id)
+ for traffic_type in traffic_types:
+ if traffic_type.traffictype == 'Guest':
+ selected_physical_network = net
+ break
+ if selected_physical_network is not None:
+ break
+ if selected_physical_network is None:
+ raise Exception("No physical network found with guest traffic
type")
+
+ # Enable security group provider for physical network
+ nsps = NetworkServiceProvider.list(cls.api_client,
physicalnetworkid=selected_physical_network.id, name='SecurityGroupProvider')
+ if len(nsps) == 0:
+ raise Exception("No security group provider found for physical
network")
+ NetworkServiceProvider.update(cls.api_client, nsps[0].id,
state='Enabled')
+
cls.template = get_template(cls.api_client, cls.zone.id,
cls.services["ostype"])
@@ -294,7 +318,7 @@ class TestNetworksInAdvancedSG(cloudstackTestCase):
return
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test_03_createIsolatedNetwork(self):
""" Test Isolated Network """
@@ -311,7 +335,7 @@ class TestNetworksInAdvancedSG(cloudstackTestCase):
self.isolated_network_offering =
NetworkOffering.create(self.api_client,
self.services["isolated_network_offering"],
conservemode=False)
- self.cleanup.append(self.isolated_network_offering)
+ self.cleanup_nwOfferings.append(self.isolated_network_offering)
self.debug("Isolated Network offering created: %s" %
self.isolated_network_offering.id)
@@ -374,7 +398,7 @@ class TestNetworksInAdvancedSG(cloudstackTestCase):
Exception: %s" % e)
return
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test_05_deployVM_SharedwithSG(self):
""" Test VM deployment in shared networks with SecurityGroup Provider
"""
@@ -453,7 +477,7 @@ class TestNetworksInAdvancedSG(cloudstackTestCase):
self.debug("Virtual Machine created: %s" % virtual_machine.id)
return
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test_06_SharedNwSGAccountSpecific(self):
""" Test Account specific shared network creation with SG"""
@@ -535,7 +559,7 @@ class TestNetworksInAdvancedSG(cloudstackTestCase):
return
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test_07_SharedNwSG_DomainWide_SubdomainAcccess(self):
""" Test Domain wide shared network with SG, with subdomain access set
True"""
@@ -556,7 +580,7 @@ class TestNetworksInAdvancedSG(cloudstackTestCase):
self.debug("Created domain %s" % self.parent_domain.id)
self.debug("Creating child domain under this domain")
self.child_domain =
Domain.create(self.api_client,services=self.services["domain"],
- parentdomainid=self.parent_domain)
+ parentdomainid=self.parent_domain.id)
self.debug("Created child domain: %s" % self.child_domain.id)
@@ -753,7 +777,7 @@ class TestNetworksInAdvancedSG(cloudstackTestCase):
return
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test_10_deleteSharedNwSGAccountSpecific_InUse(self):
""" Test delete Account specific shared network creation with SG which
is in use"""
@@ -806,7 +830,7 @@ class TestNetworksInAdvancedSG(cloudstackTestCase):
return
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test_11_deleteSharedNwSG_DomainWide_InUse(self):
""" Test delete Domain wide shared network with SG which is in use"""
@@ -861,7 +885,7 @@ class TestNetworksInAdvancedSG(cloudstackTestCase):
return
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test_29_deleteSharedNwSG_ZoneWide_InUse(self):
""" Test delete Zone wide shared network with SG which is in use"""
@@ -908,7 +932,7 @@ class TestNetworksInAdvancedSG(cloudstackTestCase):
self.cleanup_vms.append(vm)
return
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test_12_deleteSharedNwSGAccountSpecific_NotInUse(self):
""" Test delete Account specific shared network creation with SG which
is not in use"""
@@ -950,7 +974,7 @@ class TestNetworksInAdvancedSG(cloudstackTestCase):
return
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test_13_deleteSharedNwSG_DomainWide_NotInUse(self):
""" Test delete Domain wide shared network with SG which is not in
use"""
@@ -994,7 +1018,7 @@ class TestNetworksInAdvancedSG(cloudstackTestCase):
return
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test_30_deleteSharedNwSG_ZoneWide_NotInUse(self):
""" Test delete zone wide shared network with SG which is not in use"""
@@ -1031,7 +1055,7 @@ class TestNetworksInAdvancedSG(cloudstackTestCase):
return
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test__14_createSharedNwWithSG_withoutParams(self):
""" Test create shared network with SG without specifying necessary
parameters"""
@@ -1076,7 +1100,7 @@ class TestNetworksInAdvancedSG(cloudstackTestCase):
return
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test__15_createVPC(self):
""" Test create VPC in advanced SG enabled zone"""
@@ -1116,6 +1140,26 @@ class
TestNetworksInAdvancedSG_VmOperations(cloudstackTestCase):
# Get Zone, Domain and templates
cls.domain = get_domain(cls.api_client)
cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
+ if cls.zone.securitygroupsenabled is False:
+ physical_networks = PhysicalNetwork.list(cls.api_client,
zoneid=cls.zone.id)
+ selected_physical_network = None
+ for net in physical_networks:
+ traffic_types = TrafficType.list(cls.api_client,
physicalnetworkid=net.id)
+ for traffic_type in traffic_types:
+ if traffic_type.traffictype == 'Guest':
+ selected_physical_network = net
+ break
+ if selected_physical_network is not None:
+ break
+ if selected_physical_network is None:
+ raise Exception("No physical network found with guest traffic
type")
+
+ # Enable security group provider for physical network
+ nsps = NetworkServiceProvider.list(cls.api_client,
physicalnetworkid=selected_physical_network.id, name='SecurityGroupProvider')
+ if len(nsps) == 0:
+ raise Exception("No security group provider found for physical
network")
+ NetworkServiceProvider.update(cls.api_client, nsps[0].id,
state='Enabled')
+
cls.template =
get_template(cls.api_client,cls.zone.id,cls.services["ostype"])
cls.services["virtual_machine"]["zoneid"] = cls.zone.id
@@ -1314,7 +1358,7 @@ class
TestNetworksInAdvancedSG_VmOperations(cloudstackTestCase):
status = os.system("%s -i %s" %(file2, config_file))
return status
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test__16_AccountSpecificNwAccess(self):
""" Test account specific network access of users"""
@@ -1409,7 +1453,7 @@ class
TestNetworksInAdvancedSG_VmOperations(cloudstackTestCase):
return
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test__17_DomainSpecificNwAccess(self):
""" Test domain specific network access of users"""
@@ -1520,7 +1564,7 @@ class
TestNetworksInAdvancedSG_VmOperations(cloudstackTestCase):
return
@data("account", "domain")
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test_18_DeployVM_NoFreeIPs(self, value):
""" Test deploy VM in account/domain specific SG enabled shared
network when no free IPs are available"""
@@ -1624,7 +1668,7 @@ class
TestNetworksInAdvancedSG_VmOperations(cloudstackTestCase):
return
@data("default", "custom")
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test_20_DeployVM_SecGrp_sharedNetwork(self, value):
""" Test deploy VM in default/custom security group and shared
network"""
@@ -1680,7 +1724,7 @@ class
TestNetworksInAdvancedSG_VmOperations(cloudstackTestCase):
return
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test_24_DeployVM_Multiple_Shared_Networks(self):
""" Test deploy VM in multiple zone wide shared networks"""
@@ -1728,7 +1772,7 @@ class
TestNetworksInAdvancedSG_VmOperations(cloudstackTestCase):
return
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test_25_Deploy_Multiple_VM_Different_Shared_Networks_Same_SG(self):
""" Test deploy Multiple VMs in different shared networks but same
security group"""
@@ -1796,7 +1840,7 @@ class
TestNetworksInAdvancedSG_VmOperations(cloudstackTestCase):
return
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test_26_Destroy_Deploy_VM_NoFreeIPs(self):
""" Test destroy VM in zone wide shared nw when IPs are full and then
try to deploy vm"""
@@ -1903,7 +1947,7 @@ class
TestNetworksInAdvancedSG_VmOperations(cloudstackTestCase):
# Should be able to SSH VM
try:
self.debug("SSH into VM: %s" % vm.nic[0].ipaddress)
- vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress)
+ vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress, retries=5)
self.debug("SSH to VM successful, proceeding for %s operation" %
value)
@@ -1914,7 +1958,7 @@ class
TestNetworksInAdvancedSG_VmOperations(cloudstackTestCase):
vm.reboot(self.api_client)
self.debug("SSH into VM: %s" % vm.nic[0].ipaddress)
- vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress)
+ vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress, retries=5)
except Exception as e:
self.fail("SSH Access failed for %s: %s, failed at line %s" % \
@@ -1972,7 +2016,7 @@ class
TestNetworksInAdvancedSG_VmOperations(cloudstackTestCase):
# Should be able to SSH VM
try:
self.debug("SSH into VM: %s" % vm.nic[0].ipaddress)
- vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress)
+ vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress, retries=5)
self.debug("SSH to VM successful, proceeding for %s operation" %
value)
vm.delete(self.api_client, expunge=False)
if value == "recover":
@@ -1989,7 +2033,7 @@ class
TestNetworksInAdvancedSG_VmOperations(cloudstackTestCase):
retriesCount -= 1
time.sleep(10)
self.debug("SSH into VM: %s" % vm.nic[0].ipaddress)
- vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress)
+ vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress, retries=5)
self.debug("SSH successful")
self.cleanup_vms.append(vm)
elif value == "expunge":
@@ -2003,7 +2047,7 @@ class
TestNetworksInAdvancedSG_VmOperations(cloudstackTestCase):
try:
self.debug("SSH into VM: %s, this should fail" %
vm.nic[0].ipaddress)
- vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress)
+ vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress, retries=5)
self.fail("SSH should have failed, instead it succeeded")
except Exception as e:
self.debug("SSH failed as expected with exception: %s" % e)
@@ -2019,7 +2063,7 @@ class
TestNetworksInAdvancedSG_VmOperations(cloudstackTestCase):
return
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test_31_Deploy_VM_multiple_shared_networks_sg(self):
""" Test deploy VM in multiple SG enabled shared networks"""
@@ -2069,7 +2113,7 @@ class
TestNetworksInAdvancedSG_VmOperations(cloudstackTestCase):
@unittest.skip("Testing pending on multihost setup")
@data("account","domain","zone")
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test_33_VM_Migrate_SharedNwSG(self, value):
""" Test migration of VM deployed in Account specific shared network"""
@@ -2280,6 +2324,26 @@ class TestSecurityGroups_BasicSanity(cloudstackTestCase):
# Get Zone, Domain and templates
cls.domain = get_domain(cls.api_client)
cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
+ if cls.zone.securitygroupsenabled is False:
+ physical_networks = PhysicalNetwork.list(cls.api_client,
zoneid=cls.zone.id)
+ selected_physical_network = None
+ for net in physical_networks:
+ traffic_types = TrafficType.list(cls.api_client,
physicalnetworkid=net.id)
+ for traffic_type in traffic_types:
+ if traffic_type.traffictype == 'Guest':
+ selected_physical_network = net
+ break
+ if selected_physical_network is not None:
+ break
+ if selected_physical_network is None:
+ raise Exception("No physical network found with guest traffic
type")
+
+ # Enable security group provider for physical network
+ nsps = NetworkServiceProvider.list(cls.api_client,
physicalnetworkid=selected_physical_network.id, name='SecurityGroupProvider')
+ if len(nsps) == 0:
+ raise Exception("No security group provider found for physical
network")
+ NetworkServiceProvider.update(cls.api_client, nsps[0].id,
state='Enabled')
+
cls.template =
get_template(cls.api_client,cls.zone.id,cls.services["ostype"])
cls.services["virtual_machine"]["zoneid"] = cls.zone.id
@@ -2488,7 +2552,7 @@ class TestSecurityGroups_BasicSanity(cloudstackTestCase):
# Should be able to SSH VM
try:
self.debug("SSH into VM: %s" % vm.nic[0].ipaddress)
- ssh = vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress)
+ ssh = vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress, retries=5)
# Ping to outsite world
res = ssh.execute("ping -c 1 www.google.com")
@@ -2580,7 +2644,7 @@ class TestSecurityGroups_BasicSanity(cloudstackTestCase):
# Should be able to SSH VM
try:
self.debug("SSH into VM: %s" % vm.nic[0].ipaddress)
- ssh = vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress)
+ ssh = vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress, retries=5)
# Ping to outsite world
res = ssh.execute("ping -c 1 www.google.com")
@@ -2673,7 +2737,7 @@ class TestSecurityGroups_BasicSanity(cloudstackTestCase):
# Should be able to SSH VM
try:
self.debug("SSH into VM: %s" % vm.ssh_ip)
- ssh = vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress)
+ ssh = vm.get_ssh_client(ipaddress=vm.nic[0].ipaddress, retries=5)
# Ping to outsite world
res = ssh.execute("ping -c 1 www.google.com")
@@ -2695,7 +2759,7 @@ class TestSecurityGroups_BasicSanity(cloudstackTestCase):
)
return
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test_32_delete_default_security_group(self):
""" Test Delete the default security group when No VMs are deployed"""
@@ -2741,6 +2805,26 @@ class TestSharedNetworkOperations(cloudstackTestCase):
# Get Zone, Domain and templates
cls.domain = get_domain(cls.api_client)
cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
+ if cls.zone.securitygroupsenabled is False:
+ physical_networks = PhysicalNetwork.list(cls.api_client,
zoneid=cls.zone.id)
+ selected_physical_network = None
+ for net in physical_networks:
+ traffic_types = TrafficType.list(cls.api_client,
physicalnetworkid=net.id)
+ for traffic_type in traffic_types:
+ if traffic_type.traffictype == 'Guest':
+ selected_physical_network = net
+ break
+ if selected_physical_network is not None:
+ break
+ if selected_physical_network is None:
+ raise Exception("No physical network found with guest traffic
type")
+
+ # Enable security group provider for physical network
+ nsps = NetworkServiceProvider.list(cls.api_client,
physicalnetworkid=selected_physical_network.id, name='SecurityGroupProvider')
+ if len(nsps) == 0:
+ raise Exception("No security group provider found for physical
network")
+ NetworkServiceProvider.update(cls.api_client, nsps[0].id,
state='Enabled')
+
cls.template =
get_template(cls.api_client,cls.zone.id,cls.services["ostype"])
cls.services["virtual_machine"]["zoneid"] = cls.zone.id
@@ -2864,7 +2948,7 @@ class TestSharedNetworkOperations(cloudstackTestCase):
return
@data("account","domain","zone")
- @attr(tags = ["advancedsg"])
+ @attr(tags = ["advancedsg", "advanced"])
def test_34_restart_shared_network_sg(self, value):
""" Test restart account/domain/zone wide shared network"""
@@ -3196,7 +3280,7 @@ class TestAccountBasedIngressRules(cloudstackTestCase):
self.api_client.authorizeSecurityGroupIngress(cmd)
self.debug("Getting SSH client of virtual machine 1: %s" %
self.virtual_machine_1.id)
- sshClient =
self.virtual_machine_1.get_ssh_client(ipaddress=self.virtual_machine_1.nic[0].ipaddress)
+ sshClient =
self.virtual_machine_1.get_ssh_client(ipaddress=self.virtual_machine_1.nic[0].ipaddress,
retries=5)
try:
if value == "accessByIp":
self.debug("SSHing into vm_2 %s from vm_1 %s" %
(self.virtual_machine_2.nic[0].ipaddress,self.virtual_machine_1.nic[0].ipaddress))
@@ -3255,7 +3339,7 @@ class TestAccountBasedIngressRules(cloudstackTestCase):
self.api_client.authorizeSecurityGroupIngress(cmd)
self.debug("Getting SSH client of virtual machine 1: %s" %
self.virtual_machine_1.id)
- sshClient =
self.virtual_machine_1.get_ssh_client(ipaddress=self.virtual_machine_1.nic[0].ipaddress)
+ sshClient =
self.virtual_machine_1.get_ssh_client(ipaddress=self.virtual_machine_1.nic[0].ipaddress,
retries=5)
try:
self.debug("SSHing into vm_2 %s from vm_1 %s" %
(self.virtual_machine_2.nic[0].ipaddress,self.virtual_machine_1.nic[0].ipaddress))
command = "ping -c 1 %s" % self.virtual_machine_2.nic[0].ipaddress
@@ -3317,7 +3401,7 @@ class TestAccountBasedIngressRules(cloudstackTestCase):
self.debug("Deployed vm: %s" % self.virtual_machine_4.id)
self.debug("Getting SSH client of virtual machine 1: %s" %
self.virtual_machine_3.id)
- sshClient =
self.virtual_machine_3.get_ssh_client(ipaddress=self.virtual_machine_3.nic[0].ipaddress)
+ sshClient =
self.virtual_machine_3.get_ssh_client(ipaddress=self.virtual_machine_3.nic[0].ipaddress,
retries=5)
try:
if value == "accessByIp":
self.debug("SSHing into vm_4 %s from vm_3 %s" %
(self.virtual_machine_4.nic[0].ipaddress,self.virtual_machine_3.nic[0].ipaddress))
@@ -3386,7 +3470,7 @@ class TestAccountBasedIngressRules(cloudstackTestCase):
self.debug("Deployed vm: %s" % self.virtual_machine_3.id)
self.debug("Getting SSH client of virtual machine 1: %s" %
self.virtual_machine_3.id)
- sshClient =
self.virtual_machine_3.get_ssh_client(ipaddress=self.virtual_machine_3.nic[0].ipaddress)
+ sshClient =
self.virtual_machine_3.get_ssh_client(ipaddress=self.virtual_machine_3.nic[0].ipaddress,
retries=5)
try:
if value == "accessByIp":
self.debug("SSHing into vm_2 %s from vm_3 %s" %
(self.virtual_machine_2.nic[0].ipaddress,self.virtual_machine_3.nic[0].ipaddress))
@@ -3446,7 +3530,7 @@ class TestAccountBasedIngressRules(cloudstackTestCase):
self.debug("Getting SSH client of virtual machine 1: %s" %
self.virtual_machine_1.id)
try:
- sshClient =
self.virtual_machine_1.get_ssh_client(ipaddress=self.virtual_machine_1.nic[0].ipaddress)
+ sshClient =
self.virtual_machine_1.get_ssh_client(ipaddress=self.virtual_machine_1.nic[0].ipaddress,
retries=5)
self.debug("SSHing into vm_2 %s from vm_1 %s" %
(self.virtual_machine_2.nic[0].ipaddress,self.virtual_machine_1.nic[0].ipaddress))
command = "ssh -t -t root@%s" %
self.virtual_machine_2.nic[0].ipaddress
self.debug("command: --> %s" % command)
@@ -3468,7 +3552,7 @@ class TestAccountBasedIngressRules(cloudstackTestCase):
self.debug("Getting SSH client of virtual machine 1: %s" %
self.virtual_machine_1.id)
try:
- sshClient =
self.virtual_machine_1.get_ssh_client(ipaddress=self.virtual_machine_1.nic[0].ipaddress)
+ sshClient =
self.virtual_machine_1.get_ssh_client(ipaddress=self.virtual_machine_1.nic[0].ipaddress,
retries=5)
self.debug("SSHing into vm_2 %s from vm_1 %s" %
(self.virtual_machine_2.nic[0].ipaddress,self.virtual_machine_1.nic[0].ipaddress))
command = "ssh -t -t root@%s" %
self.virtual_machine_2.nic[0].ipaddress
self.debug("command: --> %s" % command)
diff --git a/test/integration/component/test_security_groups.py
b/test/integration/component/test_security_groups.py
index 1a268d692eb..449fe10cb28 100644
--- a/test/integration/component/test_security_groups.py
+++ b/test/integration/component/test_security_groups.py
@@ -28,7 +28,10 @@ from marvin.lib.base import (Account,
SecurityGroup,
Router,
Host,
- Network)
+ Network,
+ PhysicalNetwork,
+ TrafficType,
+ NetworkServiceProvider)
from marvin.lib.common import (get_domain,
get_zone,
get_template,
@@ -73,6 +76,26 @@ class TestDefaultSecurityGroup(cloudstackTestCase):
# Get Zone, Domain and templates
cls.domain = get_domain(cls.api_client)
cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
+ if cls.zone.securitygroupsenabled is False:
+ physical_networks = PhysicalNetwork.list(cls.api_client,
zoneid=cls.zone.id)
+ selected_physical_network = None
+ for net in physical_networks:
+ traffic_types = TrafficType.list(cls.api_client,
physicalnetworkid=net.id)
+ for traffic_type in traffic_types:
+ if traffic_type.traffictype == 'Guest':
+ selected_physical_network = net
+ break
+ if selected_physical_network is not None:
+ break
+ if selected_physical_network is None:
+ raise Exception("No physical network found with guest traffic
type")
+
+ # Enable security group provider for physical network
+ nsps = NetworkServiceProvider.list(cls.api_client,
physicalnetworkid=selected_physical_network.id, name='SecurityGroupProvider')
+ if len(nsps) == 0:
+ raise Exception("No security group provider found for physical
network")
+ NetworkServiceProvider.update(cls.api_client, nsps[0].id,
state='Enabled')
+
cls.testdata['mode'] = cls.zone.networktype
template = get_template(
@@ -115,7 +138,7 @@ class TestDefaultSecurityGroup(cloudstackTestCase):
return
- @attr(tags=["sg", "basic", "eip", "advancedsg"])
+ @attr(tags=["sg", "basic", "eip", "advancedsg", "advanced"])
def test_01_deployVM_InDefaultSecurityGroup(self):
"""Test deploy VM in default security group
"""
@@ -193,7 +216,7 @@ class TestDefaultSecurityGroup(cloudstackTestCase):
)
return
- @attr(tags=["sg", "basic", "eip", "advancedsg"])
+ @attr(tags=["sg", "basic", "eip", "advancedsg", "advanced"])
def test_02_listSecurityGroups(self):
"""Test list security groups for admin account
"""
@@ -228,7 +251,7 @@ class TestDefaultSecurityGroup(cloudstackTestCase):
)
return
- @attr(tags=["sg", "basic", "eip", "advancedsg"])
+ @attr(tags=["sg", "basic", "eip", "advancedsg", "advanced"])
def test_03_accessInDefaultSecurityGroup(self):
"""Test access in default security group
"""
@@ -314,7 +337,8 @@ class TestDefaultSecurityGroup(cloudstackTestCase):
self.virtual_machine.ssh_ip,
self.virtual_machine.ssh_port,
self.virtual_machine.username,
- self.virtual_machine.password
+ self.virtual_machine.password,
+ retries=5
)
return
@@ -453,7 +477,7 @@ class TestAuthorizeIngressRule(cloudstackTestCase):
# Should be able to SSH VM
try:
self.debug("SSH into VM: %s" % self.virtual_machine.id)
- self.virtual_machine.get_ssh_client()
+ self.virtual_machine.get_ssh_client(retries=5)
except Exception as e:
self.fail("SSH Access failed for %s: %s" %
(self.virtual_machine.ipaddress, e)
@@ -604,7 +628,7 @@ class TestRevokeIngressRule(cloudstackTestCase):
# Should be able to SSH VM
try:
self.debug("SSH into VM: %s" % self.virtual_machine.id)
- self.virtual_machine.get_ssh_client()
+ self.virtual_machine.get_ssh_client(retries=5)
except Exception as e:
self.fail("SSH Access failed for %s: %s" %
(self.virtual_machine.ipaddress, e)
@@ -937,7 +961,7 @@ class TestdeployVMWithUserData(cloudstackTestCase):
% self.virtual_machine.ssh_ip
)
- ssh = self.virtual_machine.get_ssh_client()
+ ssh = self.virtual_machine.get_ssh_client(retries=5)
except Exception as e:
self.fail("SSH Access failed for %s: %s" %
(self.virtual_machine.ipaddress, e)
@@ -1348,7 +1372,7 @@ class TestIngressRule(cloudstackTestCase):
self.virtual_machine.ssh_ip,
self.testdata["ingress_rule"]["endport"]
))
- self.virtual_machine.get_ssh_client()
+ self.virtual_machine.get_ssh_client(retries=5)
except Exception as e:
self.fail("SSH access failed for ingress rule ID: %s, %s"
@@ -1476,7 +1500,7 @@ class TestIngressRule(cloudstackTestCase):
self.virtual_machine.ssh_ip,
self.testdata["ingress_rule"]["endport"]
))
- self.virtual_machine.get_ssh_client()
+ self.virtual_machine.get_ssh_client(retries=5)
except Exception as e:
self.fail("SSH access failed for ingress rule ID: %s, %s"
@@ -1623,7 +1647,7 @@ class TestIngressRule(cloudstackTestCase):
self.debug(
"Trying to SSH into VM %s" %
self.virtual_machine.ssh_ip)
- self.virtual_machine.get_ssh_client()
+ self.virtual_machine.get_ssh_client(retries=5)
except Exception as e:
self.fail("SSH access failed for ingress rule ID: %s"
% ingress_rule["id"]
@@ -1642,7 +1666,7 @@ class TestIngressRule(cloudstackTestCase):
self.debug(
"Trying to SSH into VM %s" %
self.virtual_machine.ssh_ip)
- self.virtual_machine.get_ssh_client()
+ self.virtual_machine.get_ssh_client(retries=5)
except Exception as e:
self.fail("SSH access failed for ingress rule ID: %s"
% ingress_rule["id"]
diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index 7ebf9e25734..5098f6794f5 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -209,6 +209,7 @@
"label.action.unmanage.volume": "Unmanage Volume",
"label.action.unmanage.volumes": "Unmanage Volumes",
"label.action.update.host": "Update host",
+"label.action.update.security.groups": "Update security groups",
"label.action.update.offering.access": "Update offering access",
"label.action.update.resource.count": "Update resource count",
"label.action.value": "Action/Value",
diff --git a/ui/src/config/section/network.js b/ui/src/config/section/network.js
index 1ff704a306f..68d02dff313 100644
--- a/ui/src/config/section/network.js
+++ b/ui/src/config/section/network.js
@@ -307,10 +307,7 @@ export default {
return false
}
const listZoneHaveSGEnabled = store.getters.zones.filter(zone =>
zone.securitygroupsenabled === true)
- if (!listZoneHaveSGEnabled || listZoneHaveSGEnabled.length === 0) {
- return false
- }
- return true
+ return (listZoneHaveSGEnabled && listZoneHaveSGEnabled.length > 0) ||
store.getters.showSecurityGroups
},
actions: [
{
diff --git a/ui/src/store/getters.js b/ui/src/store/getters.js
index 405fd11bad1..645d031fc3e 100644
--- a/ui/src/store/getters.js
+++ b/ui/src/store/getters.js
@@ -36,6 +36,7 @@ const getters = {
isLdapEnabled: state => state.user.isLdapEnabled,
cloudian: state => state.user.cloudian,
zones: state => state.user.zones,
+ showSecurityGroups: state => state.user.showSecurityGroups,
timezoneoffset: state => state.user.timezoneoffset,
usebrowsertimezone: state => state.user.usebrowsertimezone,
server: state => state.app.server,
diff --git a/ui/src/store/modules/user.js b/ui/src/store/modules/user.js
index a5b48acf99d..22a2fab959d 100644
--- a/ui/src/store/modules/user.js
+++ b/ui/src/store/modules/user.js
@@ -34,6 +34,7 @@ import {
DEFAULT_THEME,
APIS,
ZONES,
+ SHOW_SECURTIY_GROUPS,
TIMEZONE_OFFSET,
USE_BROWSER_TIMEZONE,
HEADER_NOTICES,
@@ -124,6 +125,10 @@ const user = {
state.zones = zones
vueProps.$localStorage.set(ZONES, zones)
},
+ SET_SHOW_SECURITY_GROUPS: (state, show) => {
+ state.showSecurityGroups = show
+ vueProps.$localStorage.set(SHOW_SECURTIY_GROUPS, show)
+ },
SET_DOMAIN_STORE (state, domainStore) {
state.domainStore = domainStore
vueProps.$localStorage.set(DOMAIN_STORE, domainStore)
@@ -290,6 +295,7 @@ const user = {
const cachedUseBrowserTimezone =
vueProps.$localStorage.get(USE_BROWSER_TIMEZONE, false)
const cachedCustomColumns = vueProps.$localStorage.get(CUSTOM_COLUMNS,
{})
const domainStore = vueProps.$localStorage.get(DOMAIN_STORE, {})
+ const cachedShowSecurityGroups =
vueProps.$localStorage.get(SHOW_SECURTIY_GROUPS, false)
const darkMode = vueProps.$localStorage.get(DARK_MODE, false)
const latestVersion = vueProps.$localStorage.get(LATEST_CS_VERSION, {
version: '', fetchedTs: 0 })
const hasAuth = Object.keys(cachedApis).length > 0
@@ -300,6 +306,7 @@ const user = {
if (hasAuth) {
console.log('Login detected, using cached APIs')
commit('SET_ZONES', cachedZones)
+ commit('SET_SHOW_SECURITY_GROUPS', cachedShowSecurityGroups)
commit('SET_APIS', cachedApis)
commit('SET_TIMEZONE_OFFSET', cachedTimezoneOffset)
commit('SET_USE_BROWSER_TIMEZONE', cachedUseBrowserTimezone)
@@ -388,6 +395,15 @@ const user = {
reject(error)
})
+ api(
+ 'listNetworkServiceProviders',
+ { name: 'SecurityGroupProvider', state: 'Enabled' }
+ ).then(response => {
+ const showSecurityGroups =
response.listnetworkserviceprovidersresponse.count > 0
+ commit('SET_SHOW_SECURITY_GROUPS', showSecurityGroups)
+ }).catch(ignored => {
+ })
+
api('listCapabilities').then(response => {
const result = response.listcapabilitiesresponse.capability
commit('SET_FEATURES', result)
@@ -397,6 +413,9 @@ const user = {
if (result && result.customhypervisordisplayname) {
commit('SET_CUSTOM_HYPERVISOR_NAME',
result.customhypervisordisplayname)
}
+ if (result && result.securitygroupsenabled) {
+ commit('SET_SHOW_SECURITY_GROUPS', result.securitygroupsenabled)
+ }
}).catch(error => {
reject(error)
})
diff --git a/ui/src/store/mutation-types.js b/ui/src/store/mutation-types.js
index 93dfc9fbc20..94f28beabdf 100644
--- a/ui/src/store/mutation-types.js
+++ b/ui/src/store/mutation-types.js
@@ -29,6 +29,7 @@ export const DEFAULT_CONTENT_WIDTH_TYPE =
'DEFAULT_CONTENT_WIDTH_TYPE'
export const DEFAULT_MULTI_TAB = 'DEFAULT_MULTI_TAB'
export const APIS = 'APIS'
export const ZONES = 'ZONES'
+export const SHOW_SECURTIY_GROUPS = 'SHOW_SECURITY_GROUPS'
export const HEADER_NOTICES = 'HEADER_NOTICES'
export const TIMEZONE_OFFSET = 'TIMEZONE_OFFSET'
export const USE_BROWSER_TIMEZONE = 'USE_BROWSER_TIMEZONE'
diff --git a/ui/src/views/compute/DeployVM.vue
b/ui/src/views/compute/DeployVM.vue
index 5720e545b24..7d661aa9dc3 100644
--- a/ui/src/views/compute/DeployVM.vue
+++ b/ui/src/views/compute/DeployVM.vue
@@ -1369,7 +1369,19 @@ export default {
return tabList
},
showSecurityGroupSection () {
- return (this.networks.length > 0 && this.zone?.securitygroupsenabled) ||
(this.zone?.networktype === 'Basic')
+ if (this.networks.length < 1) {
+ return false
+ }
+ for (const network of this.options.networks) {
+ if (this.form.networkids && this.form.networkids.includes(network.id))
{
+ for (const service of network.service) {
+ if (service.name === 'SecurityGroup') {
+ return true
+ }
+ }
+ }
+ }
+ return false
},
isUserAllowedToListSshKeys () {
return Boolean('listSSHKeyPairs' in this.$store.getters.apis)
diff --git a/ui/src/views/compute/InstanceTab.vue
b/ui/src/views/compute/InstanceTab.vue
index 5f08145a4ce..dd2e110d384 100644
--- a/ui/src/views/compute/InstanceTab.vue
+++ b/ui/src/views/compute/InstanceTab.vue
@@ -117,7 +117,14 @@
:routerlinks="(record) => { return { id: '/backup/' + record.id } }"
:showSearch="false"/>
</a-tab-pane>
- <a-tab-pane :tab="$t('label.securitygroups')" key="securitygroups"
v-if="dataResource.securitygroup && dataResource.securitygroup.length > 0">
+ <a-tab-pane :tab="$t('label.securitygroups')" key="securitygroups"
v-if="dataResource.securitygroup && dataResource.securitygroup.length > 0 ||
$store.getters.showSecurityGroups">
+ <a-button
+ type="primary"
+ style="width: 100%; margin-bottom: 10px"
+ @click="showUpdateSGModal"
+ :loading="loading">
+ <template #icon><edit-outlined /></template> {{
$t('label.action.update.security.groups') }}
+ </a-button>
<ListResourceTable
:items="dataResource.securitygroup"
:columns="['name', 'description']"
@@ -143,6 +150,21 @@
</a-tab-pane>
</a-tabs>
+ <a-modal
+ :visible="showUpdateSecurityGroupsModal"
+ :title="$t('label.action.update.security.groups')"
+ :maskClosable="false"
+ :closable="true"
+ @ok="updateSecurityGroups"
+ @cancel="closeModals">
+ <security-group-selection
+ :zoneId="this.vm.zoneid"
+ :value="securitygroupids"
+ :loading="false"
+ :preFillContent="dataPreFill"
+ @select-security-group-item="($event) =>
updateSecurityGroupsSelection($event)"></security-group-selection>
+ </a-modal>
+
<a-modal
:visible="showAddVolumeModal"
:title="$t('label.action.create.volume.add')"
@@ -320,6 +342,7 @@ import TooltipButton from
'@/components/widgets/TooltipButton'
import ResourceIcon from '@/components/view/ResourceIcon'
import AnnotationsTab from '@/components/view/AnnotationsTab'
import VolumesTab from '@/components/view/VolumesTab.vue'
+import SecurityGroupSelection from
'@views/compute/wizard/SecurityGroupSelection'
export default {
name: 'InstanceTab',
@@ -333,6 +356,7 @@ export default {
NicsTable,
InstanceSchedules,
ListResourceTable,
+ SecurityGroupSelection,
TooltipButton,
ResourceIcon,
AnnotationsTab,
@@ -359,6 +383,7 @@ export default {
showAddNetworkModal: false,
showUpdateIpModal: false,
showSecondaryIpModal: false,
+ showUpdateSecurityGroupsModal: false,
diskOfferings: [],
addNetworkData: {
allNetworks: [],
@@ -366,6 +391,7 @@ export default {
ip: ''
},
loadingNic: false,
+ loadingSG: false,
editIpAddressNic: '',
editIpAddressValue: '',
editNetworkId: '',
@@ -378,7 +404,9 @@ export default {
opts: []
},
annotations: [],
- dataResource: {}
+ dataResource: {},
+ dataPreFill: {},
+ securitygroupids: []
}
},
created () {
@@ -501,11 +529,24 @@ export default {
this.showAddNetworkModal = true
this.listNetworks()
},
+ showUpdateSGModal () {
+ this.loadingSG = true
+ if (this.vm.securitygroup && this.vm.securitygroup?.length > 0) {
+ this.securitygroupids = []
+ for (const sg of this.vm.securitygroup) {
+ this.securitygroupids.push(sg.id)
+ }
+ this.dataPreFill = { securitygroupids: this.securitygroupids }
+ }
+ this.showUpdateSecurityGroupsModal = true
+ this.loadingSG = false
+ },
closeModals () {
this.showAddVolumeModal = false
this.showAddNetworkModal = false
this.showUpdateIpModal = false
this.showSecondaryIpModal = false
+ this.showUpdateSecurityGroupsModal = false
this.addNetworkData.network = ''
this.addNetworkData.ip = ''
this.editIpAddressValue = ''
@@ -730,6 +771,17 @@ export default {
this.loadingNic = false
this.fetchSecondaryIPs(this.selectedNicId)
})
+ },
+ updateSecurityGroupsSelection (securitygroupids) {
+ this.securitygroupids = securitygroupids || []
+ },
+ updateSecurityGroups () {
+ api('updateVirtualMachine', { id: this.vm.id, securitygroupids:
this.securitygroupids.join(',') }).catch(error => {
+ this.$notifyError(error)
+ }).finally(() => {
+ this.closeModals()
+ this.parentFetchData()
+ })
}
}
}
diff --git a/ui/src/views/compute/wizard/SecurityGroupSelection.vue
b/ui/src/views/compute/wizard/SecurityGroupSelection.vue
index 51f96a569ad..87bf62ddac2 100644
--- a/ui/src/views/compute/wizard/SecurityGroupSelection.vue
+++ b/ui/src/views/compute/wizard/SecurityGroupSelection.vue
@@ -94,7 +94,7 @@ export default {
}
],
items: [],
- selectedRowKeys: [],
+ selectedRowKeys: this?.preFillContent?.securitygroupids || [],
page: 1,
pageSize: 10,
keyword: null,
diff --git a/ui/src/views/infra/network/ServiceProvidersTab.vue
b/ui/src/views/infra/network/ServiceProvidersTab.vue
index b01f543478b..5eb8e3dbcce 100644
--- a/ui/src/views/infra/network/ServiceProvidersTab.vue
+++ b/ui/src/views/infra/network/ServiceProvidersTab.vue
@@ -937,10 +937,38 @@ export default {
}
]
},
- // {
- // title: 'SecurityGroupProvider',
- // details: ['name', 'state', 'id', 'servicelist'],
- // },
+ {
+ title: 'SecurityGroupProvider',
+ details: ['name', 'state', 'id', 'servicelist'],
+ actions: [
+ {
+ api: 'updateNetworkServiceProvider',
+ icon: 'stop-outlined',
+ listView: true,
+ label: 'label.disable.provider',
+ confirm: 'message.confirm.disable.provider',
+ show: (record) => { return record && record.id && record.state
=== 'Enabled' },
+ mapping: {
+ state: {
+ value: (record) => { return 'Disabled' }
+ }
+ }
+ },
+ {
+ api: 'updateNetworkServiceProvider',
+ icon: 'play-circle-outlined',
+ listView: true,
+ label: 'label.enable.provider',
+ confirm: 'message.confirm.enable.provider',
+ show: (record) => { return record && record.id && record.state
=== 'Disabled' },
+ mapping: {
+ state: {
+ value: (record) => { return 'Enabled' }
+ }
+ }
+ }
+ ]
+ },
{
title: 'VirtualRouter',
actions: [