Skip to content

Commit 773870a

Browse files
Pearl1594nvazquez
andcommitted
Add support to delete VNets and Subnets (#13)
* Add support to delete VNets and Subnets * Add support to delete vnet resources * Add support to delete vnet resources * extract code to method --------- Co-authored-by: nvazquez <[email protected]>
1 parent 294fa06 commit 773870a

File tree

8 files changed

+237
-8
lines changed

8 files changed

+237
-8
lines changed

api/src/main/java/com/cloud/network/netris/NetrisService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ public interface NetrisService {
2222
boolean createVpcResource(long zoneId, long accountId, long domainId, Long vpcId, String vpcName, boolean sourceNatEnabled, String cidr, boolean isVpcNetwork);
2323
boolean deleteVpcResource(long zoneId, long accountId, long domainId, Vpc vpc);
2424
boolean createVnetResource(Long zoneId, long accountId, long domainId, String vpcName, Long vpcId, String networkName, Long networkId, String cidr);
25+
boolean deleteVnetResource(long zoneId, long accountId, long domainId, String vpcName, Long vpcId, String networkName, Long networkId, String cidr);
2526
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package org.apache.cloudstack.agent.api;
18+
19+
public class DeleteNetrisVnetCommand extends NetrisCommand {
20+
private String vpcName;
21+
private Long vpcId;
22+
private final String vNetCidr;
23+
24+
public DeleteNetrisVnetCommand(long zoneId, long accountId, long domainId, String name, long id, String vpcName, Long vpcId, String vNetCidr, boolean isVpc) {
25+
super(zoneId, accountId, domainId, name, id, isVpc);
26+
this.vpcName = vpcName;
27+
this.vpcId = vpcId;
28+
this.vNetCidr = vNetCidr;
29+
}
30+
31+
public String getVpcName() {
32+
return vpcName;
33+
}
34+
35+
public Long getVpcId() {
36+
return vpcId;
37+
}
38+
39+
public String getVNetCidr() {
40+
return vNetCidr;
41+
}
42+
}

plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResource.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import com.cloud.utils.exception.CloudRuntimeException;
3131
import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand;
3232
import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand;
33+
import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand;
3334
import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand;
3435
import org.apache.cloudstack.agent.api.NetrisAnswer;
3536
import org.apache.cloudstack.StartupNetrisCommand;
@@ -91,6 +92,8 @@ public Answer executeRequest(Command cmd) {
9192
return executeRequest((DeleteNetrisVpcCommand) cmd);
9293
} else if (cmd instanceof CreateNetrisVnetCommand) {
9394
return executeRequest((CreateNetrisVnetCommand) cmd);
95+
} else if (cmd instanceof DeleteNetrisVnetCommand) {
96+
return executeRequest((DeleteNetrisVnetCommand) cmd);
9497
} else {
9598
return Answer.createUnsupportedCommandAnswer(cmd);
9699
}
@@ -224,6 +227,21 @@ private Answer executeRequest(CreateNetrisVnetCommand cmd) {
224227
}
225228
}
226229

230+
private Answer executeRequest(DeleteNetrisVnetCommand cmd) {
231+
try {
232+
String networkName = cmd.getName();
233+
boolean result = netrisApiClient.deleteVnet(cmd);
234+
if (!result) {
235+
return new NetrisAnswer(cmd, false, String.format("Netris vNet: %s deletion failed", networkName));
236+
}
237+
return new NetrisAnswer(cmd, true, "OK");
238+
} catch (CloudRuntimeException e) {
239+
String msg = String.format("Error deleting Netris vNet: %s", e.getMessage());
240+
logger.error(msg, e);
241+
return new NetrisAnswer(cmd, new CloudRuntimeException(msg));
242+
}
243+
}
244+
227245
private Answer executeRequest(DeleteNetrisVpcCommand cmd) {
228246
boolean result = netrisApiClient.deleteVpc(cmd);
229247
if (!result) {

plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResourceObjectUtils.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,11 @@ public static String retrieveNetrisResourceObjectName(NetrisCommand cmd, NetrisO
4646
}
4747
break;
4848
case IPAM_ALLOCATION:
49-
case IPAM_SUBNET:
5049
stringBuilder.append(String.format("%s%s", prefix, objectId));
5150
break;
51+
case IPAM_SUBNET:
52+
stringBuilder.append(String.format("-N%s", objectId));
53+
break;
5254
case VNET:
5355
break;
5456
default:

plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClient.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import io.netris.model.response.TenantResponse;
2323
import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand;
2424
import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand;
25+
import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand;
2526
import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand;
2627

2728
import java.util.List;
@@ -47,4 +48,6 @@ public interface NetrisApiClient {
4748
boolean deleteVpc(DeleteNetrisVpcCommand cmd);
4849

4950
boolean createVnet(CreateNetrisVnetCommand cmd);
51+
52+
boolean deleteVnet(DeleteNetrisVnetCommand cmd);
5053
}

plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java

Lines changed: 109 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,16 @@
2929
import io.netris.api.v2.VpcApi;
3030
import io.netris.model.AllocationBody;
3131
import io.netris.model.AllocationBodyVpc;
32+
import io.netris.model.FilterBySites;
33+
import io.netris.model.FilterByVpc;
3234
import io.netris.model.GetSiteBody;
3335
import io.netris.model.InlineResponse2004;
3436
import io.netris.model.IpTreeAllocationTenant;
37+
import io.netris.model.IpTreeSubnet;
3538
import io.netris.model.IpTreeSubnetSites;
3639
import io.netris.model.SitesResponseOK;
3740
import io.netris.model.SubnetBody;
41+
import io.netris.model.SubnetResBody;
3842
import io.netris.model.VPCAdminTenant;
3943
import io.netris.model.VPCCreate;
4044
import io.netris.model.VPCListing;
@@ -49,11 +53,15 @@
4953
import io.netris.model.VnetAddBodyGateways;
5054
import io.netris.model.VnetAddBodyVpc;
5155
import io.netris.model.VnetResAddBody;
56+
import io.netris.model.VnetResDeleteBody;
57+
import io.netris.model.VnetResListBody;
58+
import io.netris.model.VnetsBody;
5259
import io.netris.model.response.AuthResponse;
5360
import io.netris.model.response.TenantResponse;
5461
import io.netris.model.response.TenantsResponse;
5562
import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand;
5663
import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand;
64+
import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand;
5765
import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand;
5866
import org.apache.cloudstack.resource.NetrisResourceObjectUtils;
5967
import org.apache.commons.collections.CollectionUtils;
@@ -63,6 +71,7 @@
6371
import java.math.BigDecimal;
6472
import java.util.ArrayList;
6573
import java.util.List;
74+
import java.util.Objects;
6675
import java.util.stream.Collectors;
6776

6877
public class NetrisApiClientImpl implements NetrisApiClient {
@@ -238,6 +247,10 @@ private void deleteVpcIpamAllocationInternal(VPCListing vpcResource, String vpcC
238247
VpcApi vpcApi = apiClient.getApiStubForMethod(VpcApi.class);
239248
VPCResponseResourceOK vpcResourcesResponse = vpcApi.apiV2VpcVpcIdResourcesGet(vpcResource.getId());
240249
VPCResourceIpam vpcAllocationResource = getVpcAllocationResource(vpcResourcesResponse);
250+
if (Objects.isNull(vpcAllocationResource)) {
251+
logger.info("No VPC IPAM Allocation found for VPC {}", vpcCidr);
252+
return;
253+
}
241254
IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class);
242255
logger.debug("Removing the IPAM allocation {} with ID {}", vpcAllocationResource.getName(), vpcAllocationResource.getId());
243256
ipamApi.apiV2IpamTypeIdDelete("allocation", vpcAllocationResource.getId());
@@ -304,11 +317,11 @@ public boolean createVnet(CreateNetrisVnetCommand cmd) {
304317
String vnetCidr = cmd.getCidr();
305318
boolean isVpc = cmd.isVpc();
306319

307-
String suffix = String.format("%s-%s", vpcId, vpcName);
320+
String suffix = getNetrisVpcNameSuffix(vpcId, vpcName, networkId, networkName, isVpc);
308321
String netrisVpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC, suffix);
309322
VPCListing associatedVpc = getVpcByNameAndTenant(netrisVpcName);
310323
if (associatedVpc == null) {
311-
logger.error(String.format("Failed to find Netris VPC with name: %s, to create the corresponding vNet for network %s", vpcName, networkName));
324+
logger.error("Failed to find Netris VPC with name: {}, to create the corresponding vNet for network {}", netrisVpcName, networkName);
312325
return false;
313326
}
314327

@@ -324,20 +337,102 @@ public boolean createVnet(CreateNetrisVnetCommand cmd) {
324337
InlineResponse2004 subnetResponse = createVpcSubnetInternal(associatedVpc, vNetName, vnetCidr, netrisSubnetName);
325338
if (subnetResponse == null || !subnetResponse.isIsSuccess()) {
326339
String reason = subnetResponse == null ? "Empty response" : "Operation failed on Netris";
327-
logger.debug("The Netris Subnet {} for VPC {} for network {} creation failed: {}", vnetCidr, vpcName, networkName, reason);
340+
logger.debug("The Netris Subnet {} for network {} creation failed: {}", vnetCidr, networkName, reason);
328341
return false;
329342
}
330-
logger.debug("Successfully created VPC {} and its IPAM Subnet {} on Netris", vpcName, vnetCidr);
343+
logger.debug("Successfully created IPAM Subnet {} for network {} on Netris", netrisSubnetName, networkName);
331344

332345
VnetResAddBody vnetResponse = createVnetInternal(associatedVpc, netrisVnetName, vnetCidr);
333346
if (vnetResponse == null || !vnetResponse.isIsSuccess()) {
334347
String reason = vnetResponse == null ? "Empty response" : "Operation failed on Netris";
335-
logger.debug("The Netris vNet creation {} for VPC {} failed: {}", vNetName, vpcName, reason);
348+
logger.debug("The Netris vNet creation {} failed: {}", vNetName, reason);
336349
return false;
337350
}
338351
return true;
339352
}
340353

354+
@Override
355+
public boolean deleteVnet(DeleteNetrisVnetCommand cmd) {
356+
String vpcName = cmd.getVpcName();
357+
Long vpcId = cmd.getVpcId();
358+
String networkName = cmd.getName();
359+
Long networkId = cmd.getId();
360+
boolean isVpc = cmd.isVpc();
361+
String vnetCidr = cmd.getVNetCidr();
362+
try {
363+
String suffix = getNetrisVpcNameSuffix(vpcId, vpcName, networkId, networkName, isVpc);
364+
String netrisVpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC, suffix);
365+
VPCListing associatedVpc = getVpcByNameAndTenant(netrisVpcName);
366+
if (associatedVpc == null) {
367+
logger.error("Failed to find Netris VPC with name: {}, to create the corresponding vNet for network {}", netrisVpcName, networkName);
368+
return false;
369+
}
370+
371+
String vNetName;
372+
if (isVpc) {
373+
vNetName = String.format("V%s-N%s-%s", vpcId, networkId, networkName);
374+
} else {
375+
vNetName = String.format("N%s-%s", networkId, networkName);
376+
}
377+
378+
String netrisVnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VNET, vNetName) ;
379+
String netrisSubnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_SUBNET, vnetCidr) ;
380+
FilterByVpc vpcFilter = new FilterByVpc();
381+
vpcFilter.add(associatedVpc.getId());
382+
FilterBySites siteFilter = new FilterBySites();
383+
siteFilter.add(siteId);
384+
deleteVnetInternal(associatedVpc, siteFilter, vpcFilter, netrisVnetName, vNetName);
385+
386+
logger.debug("Successfully deleted vNet {}", vNetName);
387+
deleteSubnetInternal(vpcFilter, netrisVnetName, netrisSubnetName);
388+
389+
} catch (Exception e) {
390+
throw new CloudRuntimeException(String.format("Failed to delete Netris vNet %s", networkName), e);
391+
}
392+
return true;
393+
}
394+
395+
private void deleteVnetInternal(VPCListing associatedVpc, FilterBySites siteFilter, FilterByVpc vpcFilter, String netrisVnetName, String vNetName) {
396+
try {
397+
VNetApi vNetApi = apiClient.getApiStubForMethod(VNetApi.class);
398+
VnetResListBody vnetList = vNetApi.apiV2VnetGet(siteFilter, vpcFilter);
399+
if (vnetList == null || !vnetList.isIsSuccess()) {
400+
throw new CloudRuntimeException(String.format("Failed to list vNets for the given VPC: %s and site: %s", associatedVpc.getName(), siteName));
401+
}
402+
List<VnetsBody> vnetsList = vnetList.getData().stream().filter(vnet -> vnet.getName().equals(netrisVnetName)).collect(Collectors.toList());
403+
if (CollectionUtils.isEmpty(vnetsList)) {
404+
logger.debug("vNet: {} for the given VPC: {} appears to already be deleted on Netris", vNetName, associatedVpc.getName());
405+
return;
406+
}
407+
VnetsBody vnetsBody = vnetsList.get(0);
408+
409+
VnetResDeleteBody deleteVnetResponse = vNetApi.apiV2VnetIdDelete(vnetsBody.getId().intValue());
410+
if (deleteVnetResponse == null || !deleteVnetResponse.isIsSuccess()) {
411+
throw new CloudRuntimeException(String.format("Failed to delete vNet: %s", vNetName));
412+
}
413+
} catch (ApiException e) {
414+
logAndThrowException(String.format("Failed to delete vNet: %s", netrisVnetName), e);
415+
}
416+
}
417+
418+
private void deleteSubnetInternal(FilterByVpc vpcFilter, String netrisVnetName, String netrisSubnetName) {
419+
try {
420+
logger.debug("Deleting Netris VPC IPAM Subnet {} for vNet: {}", netrisSubnetName, netrisVnetName);
421+
IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class);
422+
SubnetResBody subnetsResponse = ipamApi.apiV2IpamSubnetsGet(vpcFilter);
423+
List<IpTreeSubnet> subnets = subnetsResponse.getData();
424+
List<IpTreeSubnet> matchedSubnets = subnets.stream().filter(subnet -> subnet.getName().equals(netrisSubnetName)).collect(Collectors.toList());
425+
if (CollectionUtils.isEmpty(matchedSubnets)) {
426+
logger.debug("IPAM subnet: {} for the given vNet: {} appears to already be deleted on Netris", netrisSubnetName, netrisVnetName);
427+
return;
428+
}
429+
430+
ipamApi.apiV2IpamTypeIdDelete("subnet", matchedSubnets.get(0).getId().intValue());
431+
} catch (ApiException e) {
432+
logAndThrowException(String.format("Failed to delete vNet: %s", netrisVnetName), e);
433+
}
434+
}
435+
341436
private InlineResponse2004 createVpcSubnetInternal(VPCListing associatedVpc, String vNetName, String vNetCidr, String netrisSubnetName) {
342437
logger.debug("Creating Netris VPC Subnet {} for VPC {} for vNet {}", vNetCidr, associatedVpc.getName(), vNetName);
343438
try {
@@ -427,4 +522,13 @@ VnetResAddBody createVnetInternal(VPCListing associatedVpc, String netrisVnetNam
427522
return null;
428523
}
429524
}
525+
526+
private String getNetrisVpcNameSuffix(Long vpcId, String vpcName, Long networkId, String networkName, boolean isVpc) {
527+
String suffix = null;
528+
if (isVpc) {
529+
suffix = String.format("%s-%s", vpcId, vpcName);
530+
} else {
531+
suffix = String.format("%s-%s", networkId, networkName);
532+
}
533+
}
430534
}

0 commit comments

Comments
 (0)