Skip to content

Commit 63c8b5f

Browse files
api/server: support deploy-as-is template as VNF template (#12499)
1 parent 7536516 commit 63c8b5f

File tree

12 files changed

+85
-14
lines changed

12 files changed

+85
-14
lines changed

api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVnfApplianceCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
public class DeployVnfApplianceCmd extends DeployVMCmd implements UserCmd {
4444

4545
@Parameter(name = ApiConstants.VNF_CONFIGURE_MANAGEMENT, type = CommandType.BOOLEAN, required = false,
46-
description = "True by default, security group or network rules (source nat and firewall rules) will be configured for VNF management interfaces. False otherwise. " +
46+
description = "False by default, security group or network rules (source nat and firewall rules) will be configured for VNF management interfaces. True otherwise. " +
4747
"Network rules are configured if management network is an isolated network or shared network with security groups.")
4848
private Boolean vnfConfigureManagement;
4949

api/src/main/java/org/apache/cloudstack/storage/template/VnfTemplateManager.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.apache.cloudstack.api.command.user.vm.DeployVnfApplianceCmd;
3030
import org.apache.cloudstack.framework.config.ConfigKey;
3131
import java.util.List;
32+
import java.util.Map;
3233

3334
public interface VnfTemplateManager {
3435

@@ -42,11 +43,12 @@ public interface VnfTemplateManager {
4243

4344
void updateVnfTemplate(long templateId, UpdateVnfTemplateCmd cmd);
4445

45-
void validateVnfApplianceNics(VirtualMachineTemplate template, List<Long> networkIds);
46+
void validateVnfApplianceNics(VirtualMachineTemplate template, List<Long> networkIds, Map<Integer, Long> vmNetworkMap);
4647

4748
SecurityGroup createSecurityGroupForVnfAppliance(DataCenter zone, VirtualMachineTemplate template, Account owner, DeployVnfApplianceCmd cmd);
4849

4950
void createIsolatedNetworkRulesForVnfAppliance(DataCenter zone, VirtualMachineTemplate template, Account owner,
5051
UserVm vm, DeployVnfApplianceCmd cmd)
5152
throws InsufficientAddressCapacityException, ResourceAllocationException, ResourceUnavailableException;
53+
5254
}

api/src/main/java/org/apache/cloudstack/storage/template/VnfTemplateUtils.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// under the License.
1717
package org.apache.cloudstack.storage.template;
1818

19+
import com.cloud.agent.api.to.deployasis.OVFNetworkTO;
1920
import com.cloud.exception.InvalidParameterValueException;
2021
import com.cloud.network.VNF;
2122
import com.cloud.storage.Storage;
@@ -124,6 +125,9 @@ public static void validateVnfNics(List<VNF.VnfNic> nicsList) {
124125
public static void validateApiCommandParams(BaseCmd cmd, VirtualMachineTemplate template) {
125126
if (cmd instanceof RegisterVnfTemplateCmd) {
126127
RegisterVnfTemplateCmd registerCmd = (RegisterVnfTemplateCmd) cmd;
128+
if (registerCmd.isDeployAsIs() && CollectionUtils.isNotEmpty(registerCmd.getVnfNics())) {
129+
throw new InvalidParameterValueException("VNF nics cannot be specified when register a deploy-as-is Template. Please wait until Template settings are read from OVA.");
130+
}
127131
validateApiCommandParams(registerCmd.getVnfDetails(), registerCmd.getVnfNics(), registerCmd.getTemplateType());
128132
} else if (cmd instanceof UpdateVnfTemplateCmd) {
129133
UpdateVnfTemplateCmd updateCmd = (UpdateVnfTemplateCmd) cmd;
@@ -149,4 +153,18 @@ public static void validateVnfCidrList(List<String> cidrList) {
149153
}
150154
}
151155
}
156+
157+
public static void validateDeployAsIsTemplateVnfNics(List<OVFNetworkTO> ovfNetworks, List<VNF.VnfNic> vnfNics) {
158+
if (CollectionUtils.isEmpty(vnfNics)) {
159+
return;
160+
}
161+
if (CollectionUtils.isEmpty(ovfNetworks)) {
162+
throw new InvalidParameterValueException("The list of networks read from OVA is empty. Please wait until the template is fully downloaded and processed.");
163+
}
164+
for (VNF.VnfNic vnfNic : vnfNics) {
165+
if (vnfNic.getDeviceId() < ovfNetworks.size() && !vnfNic.isRequired()) {
166+
throw new InvalidParameterValueException(String.format("The VNF nic [device ID: %s ] is required as it is defined in the OVA template.", vnfNic.getDeviceId()));
167+
}
168+
}
169+
}
152170
}

server/src/main/java/com/cloud/template/TemplateManagerImpl.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@
122122
import com.cloud.agent.api.to.DiskTO;
123123
import com.cloud.agent.api.to.NfsTO;
124124
import com.cloud.agent.api.to.VirtualMachineTO;
125+
import com.cloud.agent.api.to.deployasis.OVFNetworkTO;
125126
import com.cloud.api.ApiDBUtils;
126127
import com.cloud.api.query.dao.UserVmJoinDao;
127128
import com.cloud.api.query.vo.UserVmJoinVO;
@@ -131,6 +132,7 @@
131132
import com.cloud.dc.DataCenterVO;
132133
import com.cloud.dc.dao.DataCenterDao;
133134
import com.cloud.deploy.DeployDestination;
135+
import com.cloud.deployasis.dao.TemplateDeployAsIsDetailsDao;
134136
import com.cloud.domain.Domain;
135137
import com.cloud.domain.dao.DomainDao;
136138
import com.cloud.event.ActionEvent;
@@ -313,6 +315,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
313315
protected SnapshotHelper snapshotHelper;
314316
@Inject
315317
VnfTemplateManager vnfTemplateManager;
318+
@Inject
319+
TemplateDeployAsIsDetailsDao templateDeployAsIsDetailsDao;
316320

317321
@Inject
318322
private SecondaryStorageHeuristicDao secondaryStorageHeuristicDao;
@@ -2172,6 +2176,11 @@ private VMTemplateVO updateTemplateOrIso(BaseUpdateTemplateOrIsoCmd cmd) {
21722176
templateType = validateTemplateType(cmd, isAdmin, template.isCrossZones());
21732177
if (cmd instanceof UpdateVnfTemplateCmd) {
21742178
VnfTemplateUtils.validateApiCommandParams(cmd, template);
2179+
UpdateVnfTemplateCmd updateCmd = (UpdateVnfTemplateCmd) cmd;
2180+
if (template.isDeployAsIs() && CollectionUtils.isNotEmpty(updateCmd.getVnfNics())) {
2181+
List<OVFNetworkTO> ovfNetworks = templateDeployAsIsDetailsDao.listNetworkRequirementsByTemplateId(template.getId());
2182+
VnfTemplateUtils.validateDeployAsIsTemplateVnfNics(ovfNetworks, updateCmd.getVnfNics());
2183+
}
21752184
vnfTemplateManager.updateVnfTemplate(template.getId(), (UpdateVnfTemplateCmd) cmd);
21762185
}
21772186
templateTag = ((UpdateTemplateCmd)cmd).getTemplateTag();

server/src/main/java/com/cloud/vm/UserVmManagerImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6127,7 +6127,7 @@ public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityE
61276127
throw new InvalidParameterValueException("Unable to use template " + templateId);
61286128
}
61296129
if (TemplateType.VNF.equals(template.getTemplateType())) {
6130-
vnfTemplateManager.validateVnfApplianceNics(template, cmd.getNetworkIds());
6130+
vnfTemplateManager.validateVnfApplianceNics(template, cmd.getNetworkIds(), cmd.getVmNetworkMap());
61316131
} else if (cmd instanceof DeployVnfApplianceCmd) {
61326132
throw new InvalidParameterValueException("Can't deploy VNF appliance from a non-VNF template");
61336133
}

server/src/main/java/org/apache/cloudstack/storage/template/VnfTemplateManagerImpl.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,14 @@ public ConfigKey<?>[] getConfigKeys() {
201201
}
202202

203203
@Override
204-
public void validateVnfApplianceNics(VirtualMachineTemplate template, List<Long> networkIds) {
204+
public void validateVnfApplianceNics(VirtualMachineTemplate template, List<Long> networkIds, Map<Integer, Long> vmNetworkMap) {
205+
if (template.isDeployAsIs()) {
206+
if (CollectionUtils.isNotEmpty(networkIds)) {
207+
throw new InvalidParameterValueException("VNF nics mappings should be empty for deploy-as-is templates");
208+
}
209+
validateVnfApplianceNetworksMap(template, vmNetworkMap);
210+
return;
211+
}
205212
if (CollectionUtils.isEmpty(networkIds)) {
206213
throw new InvalidParameterValueException("VNF nics list is empty");
207214
}
@@ -213,6 +220,18 @@ public void validateVnfApplianceNics(VirtualMachineTemplate template, List<Long>
213220
}
214221
}
215222

223+
private void validateVnfApplianceNetworksMap(VirtualMachineTemplate template, Map<Integer, Long> vmNetworkMap) {
224+
if (MapUtils.isEmpty(vmNetworkMap)) {
225+
throw new InvalidParameterValueException("VNF networks map is empty");
226+
}
227+
List<VnfTemplateNicVO> vnfNics = vnfTemplateNicDao.listByTemplateId(template.getId());
228+
for (VnfTemplateNicVO vnfNic : vnfNics) {
229+
if (vnfNic.isRequired() && vmNetworkMap.size() <= vnfNic.getDeviceId()) {
230+
throw new InvalidParameterValueException("VNF nic is required but not found: " + vnfNic);
231+
}
232+
}
233+
}
234+
216235
protected Set<Integer> getOpenPortsForVnfAppliance(VirtualMachineTemplate template) {
217236
Set<Integer> ports = new HashSet<>();
218237
VnfTemplateDetailVO accessMethodsDetail = vnfTemplateDetailsDao.findDetail(template.getId(), VNF.AccessDetail.ACCESS_METHODS.name().toLowerCase());

server/src/test/java/com/cloud/template/TemplateManagerImplTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.cloud.api.query.dao.UserVmJoinDao;
2424
import com.cloud.configuration.Resource;
2525
import com.cloud.dc.dao.DataCenterDao;
26+
import com.cloud.deployasis.dao.TemplateDeployAsIsDetailsDao;
2627
import com.cloud.domain.dao.DomainDao;
2728
import com.cloud.event.dao.UsageEventDao;
2829
import com.cloud.exception.InvalidParameterValueException;
@@ -204,6 +205,8 @@ public class TemplateManagerImplTest {
204205
AccountManager _accountMgr;
205206
@Inject
206207
VnfTemplateManager vnfTemplateManager;
208+
@Inject
209+
TemplateDeployAsIsDetailsDao templateDeployAsIsDetailsDao;
207210

208211
@Inject
209212
HeuristicRuleHelper heuristicRuleHelperMock;
@@ -956,6 +959,11 @@ public VnfTemplateManager vnfTemplateManager() {
956959
return Mockito.mock(VnfTemplateManager.class);
957960
}
958961

962+
@Bean
963+
public TemplateDeployAsIsDetailsDao templateDeployAsIsDetailsDao() {
964+
return Mockito.mock(TemplateDeployAsIsDetailsDao.class);
965+
}
966+
959967
@Bean
960968
public SnapshotHelper snapshotHelper() {
961969
return Mockito.mock(SnapshotHelper.class);

server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,7 +1079,7 @@ public void createVirtualMachine() throws ResourceUnavailableException, Insuffic
10791079
when(templateMock.isDeployAsIs()).thenReturn(false);
10801080
when(templateMock.getFormat()).thenReturn(Storage.ImageFormat.QCOW2);
10811081
when(templateMock.getUserDataId()).thenReturn(null);
1082-
Mockito.doNothing().when(vnfTemplateManager).validateVnfApplianceNics(any(), nullable(List.class));
1082+
Mockito.doNothing().when(vnfTemplateManager).validateVnfApplianceNics(any(), nullable(List.class), nullable(Map.class));
10831083

10841084
ServiceOfferingJoinVO svcOfferingMock = Mockito.mock(ServiceOfferingJoinVO.class);
10851085
when(serviceOfferingJoinDao.findById(anyLong())).thenReturn(svcOfferingMock);
@@ -1091,7 +1091,7 @@ public void createVirtualMachine() throws ResourceUnavailableException, Insuffic
10911091

10921092
UserVm result = userVmManagerImpl.createVirtualMachine(deployVMCmd);
10931093
assertEquals(userVmVoMock, result);
1094-
Mockito.verify(vnfTemplateManager).validateVnfApplianceNics(templateMock, null);
1094+
Mockito.verify(vnfTemplateManager).validateVnfApplianceNics(templateMock, null, null);
10951095
Mockito.verify(userVmManagerImpl).createBasicSecurityGroupVirtualMachine(any(), any(), any(), any(), any(), any(), any(),
10961096
any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), nullable(Boolean.class), any(), any(), any(),
10971097
any(), any(), any(), any(), eq(true), any());
@@ -1335,7 +1335,7 @@ public void createVirtualMachineWithCloudRuntimeException() throws ResourceUnava
13351335
when(templateMock.isDeployAsIs()).thenReturn(false);
13361336
when(templateMock.getFormat()).thenReturn(Storage.ImageFormat.QCOW2);
13371337
when(templateMock.getUserDataId()).thenReturn(null);
1338-
Mockito.doNothing().when(vnfTemplateManager).validateVnfApplianceNics(any(), nullable(List.class));
1338+
Mockito.doNothing().when(vnfTemplateManager).validateVnfApplianceNics(any(), nullable(List.class), nullable(Map.class));
13391339

13401340
ServiceOfferingJoinVO svcOfferingMock = Mockito.mock(ServiceOfferingJoinVO.class);
13411341
when(serviceOfferingJoinDao.findById(anyLong())).thenReturn(svcOfferingMock);

server/src/test/java/org/apache/cloudstack/storage/template/VnfTemplateManagerImplTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,25 +228,25 @@ public void testPersistVnfTemplateUpdateWithoutDetails() {
228228
@Test
229229
public void testValidateVnfApplianceNicsWithRequiredNics() {
230230
List<Long> networkIds = Arrays.asList(200L, 201L);
231-
vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds);
231+
vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds, null);
232232
}
233233

234234
@Test
235235
public void testValidateVnfApplianceNicsWithAllNics() {
236236
List<Long> networkIds = Arrays.asList(200L, 201L, 202L);
237-
vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds);
237+
vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds, null);
238238
}
239239

240240
@Test(expected = InvalidParameterValueException.class)
241241
public void testValidateVnfApplianceNicsWithEmptyList() {
242242
List<Long> networkIds = new ArrayList<>();
243-
vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds);
243+
vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds, null);
244244
}
245245

246246
@Test(expected = InvalidParameterValueException.class)
247247
public void testValidateVnfApplianceNicsWithMissingNetworkId() {
248248
List<Long> networkIds = Arrays.asList(200L);
249-
vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds);
249+
vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds, null);
250250
}
251251

252252
@Test

ui/public/locales/en.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2529,7 +2529,7 @@
25292529
"label.vnf.cidr.list": "CIDR from which access to the VNF appliance's Management interface should be allowed from",
25302530
"label.vnf.cidr.list.tooltip": "the CIDR list to forward traffic from to the VNF management interface. Multiple entries must be separated by a single comma character (,). The default value is 0.0.0.0/0.",
25312531
"label.vnf.configure.management": "Configure network rules for VNF's management interfaces",
2532-
"label.vnf.configure.management.tooltip": "True by default, security group or network rules (source nat and firewall rules) will be configured for VNF management interfaces. False otherwise. Learn what rules are configured at http://docs.cloudstack.apache.org/en/latest/adminguide/networking/vnf_templates_appliances.html#deploying-vnf-appliances",
2532+
"label.vnf.configure.management.tooltip": "False by default, security group or network rules (source nat and firewall rules) will be configured for VNF management interfaces. True otherwise. Learn what rules are configured at http://docs.cloudstack.apache.org/en/latest/adminguide/networking/vnf_templates_appliances.html#deploying-vnf-appliances",
25332533
"label.vnf.detail.add": "Add VNF detail",
25342534
"label.vnf.detail.remove": "Remove VNF detail",
25352535
"label.vnf.details": "VNF Details",

0 commit comments

Comments
 (0)