Skip to content

Commit 37d6344

Browse files
committed
add create/delete segment and UI integration
1 parent 2cccd53 commit 37d6344

File tree

13 files changed

+422
-24
lines changed

13 files changed

+422
-24
lines changed

api/src/main/java/com/cloud/network/Network.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,8 @@ public void setIp6Address(String ip6Address) {
430430

431431
long getDataCenterId();
432432

433+
long getAccountId();
434+
433435
long getNetworkOfferingId();
434436

435437
@Override

engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,10 @@ public Mode getMode() {
369369
return mode;
370370
}
371371

372+
public void setAccountId(long accountId) {
373+
this.accountId = accountId;
374+
}
375+
372376
@Override
373377
public long getAccountId() {
374378
return accountId;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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+
import com.cloud.network.dao.NetworkVO;
20+
21+
public class CreateNsxSegmentCommand extends CreateNsxTier1GatewayCommand {
22+
private NetworkVO tierNetwork;
23+
public CreateNsxSegmentCommand(String zoneName, Long zoneId, String accountName, Long accountId, String vpcName, NetworkVO tierNetwork) {
24+
super(zoneName, zoneId, accountName, accountId, vpcName);
25+
this.tierNetwork = tierNetwork;
26+
}
27+
28+
public NetworkVO getTierNetwork() {
29+
return tierNetwork;
30+
}
31+
32+
public void setTierNetwork(NetworkVO tierNetwork) {
33+
this.tierNetwork = tierNetwork;
34+
}
35+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.apache.cloudstack.agent.api;
2+
3+
import com.cloud.network.dao.NetworkVO;
4+
5+
public class DeleteNsxSegmentCommand extends CreateNsxSegmentCommand {
6+
public DeleteNsxSegmentCommand(String accountName, NetworkVO network) {
7+
super(null, network.getDataCenterId(), accountName, network.getAccountId(), null, network);
8+
}
9+
}

plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java

Lines changed: 89 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,47 +16,60 @@
1616
// under the License.
1717
package org.apache.cloudstack.resource;
1818

19-
import static org.apache.cloudstack.utils.NsxApiClientUtils.PoolAllocation.ROUTING;
20-
import static org.apache.cloudstack.utils.NsxApiClientUtils.HAMode.ACTIVE_STANDBY;
21-
import static org.apache.cloudstack.utils.NsxApiClientUtils.createApiClient;
22-
2319
import com.cloud.agent.IAgentControl;
24-
import com.cloud.agent.api.StartupCommand;
25-
import com.cloud.agent.api.Command;
26-
import com.cloud.agent.api.ReadyCommand;
27-
import com.cloud.agent.api.ReadyAnswer;
2820
import com.cloud.agent.api.Answer;
21+
import com.cloud.agent.api.Command;
2922
import com.cloud.agent.api.PingCommand;
23+
import com.cloud.agent.api.ReadyAnswer;
24+
import com.cloud.agent.api.ReadyCommand;
25+
import com.cloud.agent.api.StartupCommand;
3026
import com.cloud.exception.InvalidParameterValueException;
3127
import com.cloud.host.Host;
3228
import com.cloud.resource.ServerResource;
3329
import com.cloud.utils.exception.CloudRuntimeException;
30+
import com.vmware.nsx.EdgeClusters;
31+
import com.vmware.nsx.model.EdgeCluster;
32+
import com.vmware.nsx_policy.infra.Segments;
3433
import com.vmware.nsx_policy.infra.Tier1s;
34+
import com.vmware.nsx_policy.infra.segments.ServiceSegments;
3535
import com.vmware.nsx_policy.infra.tier_0s.LocaleServices;
3636
import com.vmware.nsx_policy.model.ApiError;
3737
import com.vmware.nsx_policy.model.ChildLocaleServices;
3838
import com.vmware.nsx_policy.model.LocaleServicesListResult;
39+
import com.vmware.nsx_policy.model.Segment;
40+
import com.vmware.nsx_policy.model.SegmentSubnet;
41+
import com.vmware.nsx_policy.model.ServiceSegmentListResult;
3942
import com.vmware.nsx_policy.model.Tier1;
4043
import com.vmware.vapi.bindings.Service;
4144
import com.vmware.vapi.std.errors.Error;
4245
import org.apache.cloudstack.NsxAnswer;
4346
import org.apache.cloudstack.StartupNsxCommand;
47+
import org.apache.cloudstack.agent.api.CreateNsxSegmentCommand;
4448
import org.apache.cloudstack.agent.api.CreateNsxTier1GatewayCommand;
49+
import org.apache.cloudstack.agent.api.DeleteNsxSegmentCommand;
4550
import org.apache.cloudstack.agent.api.DeleteNsxTier1GatewayCommand;
4651
import org.apache.cloudstack.service.NsxApi;
52+
import org.apache.cloudstack.utils.NsxApiClientUtils;
4753
import org.apache.log4j.Logger;
4854

49-
5055
import javax.naming.ConfigurationException;
5156
import java.util.List;
5257
import java.util.Map;
5358
import java.util.function.Function;
5459

60+
import static java.util.Objects.isNull;
61+
import static org.apache.cloudstack.utils.NsxApiClientUtils.HAMode.ACTIVE_STANDBY;
62+
import static org.apache.cloudstack.utils.NsxApiClientUtils.FailoverMode.PREEMPTIVE;
63+
import static org.apache.cloudstack.utils.NsxApiClientUtils.PoolAllocation.ROUTING;
64+
import static org.apache.cloudstack.utils.NsxApiClientUtils.createApiClient;
65+
5566
public class NsxResource implements ServerResource {
5667
private static final Logger LOGGER = Logger.getLogger(NsxResource.class);
5768
private static final String TIER_0_GATEWAY_PATH_PREFIX = "/infra/tier-0s/";
69+
private static final String TIER_1_GATEWAY_PATH_PREFIX = "/infra/tier-1s/";
5870
private static final String TIER_1_RESOURCE_TYPE = "Tier1";
59-
// private static final String ROUTING = "ROUTING";
71+
private static final String SEGMENT_RESOURCE_TYPE = "Segment";
72+
6073
private String name;
6174
protected String hostname;
6275
protected String username;
@@ -98,7 +111,11 @@ public Answer executeRequest(Command cmd) {
98111
return executeRequest((ReadyCommand) cmd);
99112
} else if (cmd instanceof DeleteNsxTier1GatewayCommand) {
100113
return executeRequest((DeleteNsxTier1GatewayCommand) cmd);
101-
} else if (cmd instanceof CreateNsxTier1GatewayCommand) {
114+
} else if (cmd instanceof DeleteNsxSegmentCommand) {
115+
return executeRequest((DeleteNsxSegmentCommand) cmd);
116+
} else if (cmd instanceof CreateNsxSegmentCommand) {
117+
return executeRequest((CreateNsxSegmentCommand) cmd);
118+
} else if (cmd instanceof CreateNsxTier1GatewayCommand) {
102119
return executeRequest((CreateNsxTier1GatewayCommand) cmd);
103120
} else {
104121
return Answer.createUnsupportedCommandAnswer(cmd);
@@ -206,15 +223,13 @@ private Answer executeRequest(ReadyCommand cmd) {
206223
}
207224

208225
private Function<Class, Service> nsxService = svcClass -> { return nsxApi.getApiClient().createStub(svcClass); };
209-
private Service getService(Class svcClass) {
210-
return nsxApi.getApiClient().createStub(svcClass);
211-
}
212226
private Answer executeRequest(CreateNsxTier1GatewayCommand cmd) {
213227
String name = getTier1GatewayName(cmd);
214228
Tier1 tier1 = getTier1Gateway(name);
215229
if (tier1 != null) {
216230
throw new InvalidParameterValueException(String.format("VPC network with name %s exists in NSX zone: %s and account %s", name, cmd.getZoneName(), cmd.getAccountName()));
217231
}
232+
218233
List<com.vmware.nsx_policy.model.LocaleServices> localeServices = getTier0LocalServices(tier0Gateway);
219234
String tier0GatewayPath = TIER_0_GATEWAY_PATH_PREFIX + tier0Gateway;
220235

@@ -224,14 +239,15 @@ private Answer executeRequest(CreateNsxTier1GatewayCommand cmd) {
224239
.setResourceType(TIER_1_RESOURCE_TYPE)
225240
.setPoolAllocation(ROUTING.name())
226241
.setHaMode(ACTIVE_STANDBY.name())
242+
.setFailoverMode(PREEMPTIVE.name())
227243
.setId(name)
228244
.setDisplayName(name)
229245
.setChildren(
230246
List.of(new ChildLocaleServices.Builder("ChildLocaleServices")
231247
.setLocaleServices(
232248
new com.vmware.nsx_policy.model.LocaleServices.Builder()
233249
.setEdgeClusterPath(localeServices.get(0).getEdgeClusterPath())
234-
.setId(localeServices.get(0).getId())
250+
.setParentPath(TIER_1_GATEWAY_PATH_PREFIX + getTier1GatewayName(cmd))
235251
.setResourceType("LocaleServices")
236252
.build()
237253
).build())).build();
@@ -254,16 +270,69 @@ private Answer executeRequest(DeleteNsxTier1GatewayCommand cmd) {
254270
return new NsxAnswer(cmd, true, null);
255271
}
256272

273+
private Answer executeRequest(CreateNsxSegmentCommand cmd) {
274+
try {
275+
String segmentName = getSegmentName(cmd);
276+
Segments segmentService = (Segments) nsxService.apply(Segments.class);
277+
SegmentSubnet subnet = new SegmentSubnet.Builder()
278+
.setGatewayAddress(cmd.getTierNetwork().getGateway() + "/" + cmd.getTierNetwork().getCidr().split("/")[1]).build();
279+
Segment segment = new Segment.Builder()
280+
.setResourceType(SEGMENT_RESOURCE_TYPE)
281+
.setId(segmentName)
282+
.setDisplayName(segmentName)
283+
.setConnectivityPath(isNull(cmd.getVpcName()) ? TIER_0_GATEWAY_PATH_PREFIX + tier0Gateway
284+
: TIER_1_GATEWAY_PATH_PREFIX + getTier1GatewayName(cmd))
285+
.setAdminState(NsxApiClientUtils.AdminState.UP.name())
286+
.setSubnets(List.of(subnet))
287+
.build();
288+
segmentService.patch(segmentName, segment);
289+
} catch (Exception e) {
290+
LOGGER.error(String.format("Failed to create network: %s", cmd.getTierNetwork().getName()));
291+
return new NsxAnswer(cmd, new CloudRuntimeException(e.getMessage()));
292+
}
293+
return new NsxAnswer(cmd, true, null);
294+
}
295+
296+
private NsxAnswer executeRequest(DeleteNsxSegmentCommand cmd) {
297+
try {
298+
String segmentName = getSegmentName(cmd);
299+
Segments segmentService = (Segments) nsxService.apply(Segments.class);
300+
segmentService.delete(segmentName);
301+
} catch (Exception e) {
302+
LOGGER.error(String.format("Failed to delete NSX segment: %s", getSegmentName(cmd)) );
303+
return new NsxAnswer(cmd, new CloudRuntimeException(e.getMessage()));
304+
}
305+
return new NsxAnswer(cmd, true, null);
306+
}
307+
257308
private List<com.vmware.nsx_policy.model.LocaleServices> getTier0LocalServices(String tier0Gateway) {
258309
try {
259310
LocaleServices tier0LocaleServices = (LocaleServices) nsxService.apply(LocaleServices.class);
260-
LocaleServicesListResult result =tier0LocaleServices.list(tier0Gateway, null, false, null, null, null, null);
311+
LocaleServicesListResult result = tier0LocaleServices.list(tier0Gateway, null, false, null, null, null, null);
261312
return result.getResults();
262313
} catch (Exception e) {
263314
throw new CloudRuntimeException(String.format("Failed to fetch locale services for tier gateway %s due to %s", tier0Gateway, e.getMessage()));
264315
}
265316
}
266317

318+
private EdgeCluster getEdgeClusterDetails(String edgeClusterName) {
319+
try {
320+
EdgeClusters edgeClusterService = (EdgeClusters) nsxService.apply(EdgeClusters.class);
321+
return edgeClusterService.get(edgeClusterName);
322+
} catch (Exception e) {
323+
throw new CloudRuntimeException(String.format("Failed to fetch details of edge cluster: %s, due to: %s", edgeClusterName, e.getMessage()));
324+
}
325+
}
326+
327+
private ServiceSegmentListResult listServiceSegments() {
328+
try {
329+
ServiceSegments serviceSegmentSvc = (ServiceSegments) nsxService.apply(ServiceSegments.class);
330+
return serviceSegmentSvc.list(null, null, null, true, null);
331+
} catch (Exception e) {
332+
throw new CloudRuntimeException(String.format("Failed to fetch service segment list due to %s", e.getMessage()));
333+
}
334+
}
335+
267336
private Tier1 getTier1Gateway(String tier1GatewayId) {
268337
try {
269338
Tier1s tier1service = (Tier1s) nsxService.apply(Tier1s.class);
@@ -278,6 +347,10 @@ private String getTier1GatewayName(CreateNsxTier1GatewayCommand cmd) {
278347
return cmd.getZoneName() + "-" + cmd.getAccountName() + "-" + cmd.getVpcName();
279348
}
280349

350+
private String getSegmentName(CreateNsxSegmentCommand cmd) {
351+
return cmd.getAccountName() + "-" + cmd.getTierNetwork().getName();
352+
}
353+
281354
@Override
282355
public boolean start() {
283356
return true;

plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@
3636
import com.cloud.host.HostVO;
3737
import com.cloud.host.Status;
3838
import com.cloud.network.Network;
39+
import com.cloud.network.NetworkModel;
3940
import com.cloud.network.Networks;
4041
import com.cloud.network.PhysicalNetworkServiceProvider;
42+
import com.cloud.network.dao.NetworkDao;
43+
import com.cloud.network.dao.NetworkVO;
4144
import com.cloud.network.dao.PhysicalNetworkDao;
4245
import com.cloud.network.dao.PhysicalNetworkVO;
4346
import com.cloud.network.element.DhcpServiceProvider;
@@ -84,11 +87,15 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsS
8487
@Inject
8588
DataCenterDao dataCenterDao;
8689
@Inject
90+
NetworkDao networkDao;
91+
@Inject
8792
AgentManager agentManager;
8893
@Inject
8994
ResourceManager resourceManager;
9095
@Inject
9196
PhysicalNetworkDao physicalNetworkDao;
97+
@Inject
98+
NetworkModel networkModel;
9299

93100
private static final Logger LOGGER = Logger.getLogger(NsxElement.class);
94101

@@ -97,12 +104,21 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsS
97104

98105
private static Map<Network.Service, Map<Network.Capability, String>> initCapabilities() {
99106
Map<Network.Service, Map<Network.Capability, String>> capabilities = new HashMap<>();
107+
100108
Map<Network.Capability, String> dhcpCapabilities = Map.of(Network.Capability.DhcpAccrossMultipleSubnets, "true");
101109
capabilities.put(Network.Service.Dhcp, dhcpCapabilities);
110+
102111
Map<Network.Capability, String> dnsCapabilities = new HashMap<>();
103112
dnsCapabilities.put(Network.Capability.AllowDnsSuffixModification, "true");
104113
capabilities.put(Network.Service.Dns, dnsCapabilities);
105-
capabilities.put(Network.Service.Connectivity, null);
114+
115+
// capabilities.put(Network.Service.Connectivity, null);
116+
capabilities.put(Network.Service.StaticNat, null);
117+
118+
Map<Network.Capability, String> sourceNatCapabilities = new HashMap<>();
119+
sourceNatCapabilities.put(Network.Capability.RedundantRouter, "true");
120+
sourceNatCapabilities.put(Network.Capability.SupportedSourceNatTypes, "peraccount");
121+
capabilities.put(Network.Service.SourceNat, sourceNatCapabilities);
106122
return capabilities;
107123
}
108124
@Override
@@ -172,12 +188,14 @@ public boolean release(Network network, NicProfile nic, VirtualMachineProfile vm
172188

173189
@Override
174190
public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException {
175-
return false;
191+
return canHandle(network, Network.Service.Connectivity);
176192
}
177193

178194
@Override
179195
public boolean destroy(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException {
180-
return false;
196+
Account account = accountMgr.getAccount(network.getAccountId());
197+
NetworkVO networkVO = networkDao.findById(network.getId());
198+
return nsxService.deleteNetwork(account.getAccountName(), networkVO);
181199
}
182200

183201
@Override
@@ -192,7 +210,7 @@ public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider
192210

193211
@Override
194212
public boolean canEnableIndividualServices() {
195-
return false;
213+
return true;
196214
}
197215

198216
@Override
@@ -357,5 +375,17 @@ public boolean processTimeout(long agentId, long seq) {
357375
return false;
358376
}
359377

378+
protected boolean canHandle(Network network, Network.Service service) {
379+
LOGGER.debug("Checking if Nsx Element can handle service " + service.getName() + " on network "
380+
+ network.getDisplayText());
381+
382+
if (!networkModel.isProviderForNetwork(getProvider(), network.getId())) {
383+
LOGGER.debug("Nsx Element is not a provider for network " + network.getDisplayText());
384+
return false;
385+
}
386+
387+
return true;
388+
}
389+
360390
private final Function<Long, DataCenterVO> zoneFunction = zoneId -> { return dataCenterDao.findById(zoneId); };
361391
}

0 commit comments

Comments
 (0)