Skip to content

Commit d94fafd

Browse files
committed
NSX: complete segment profile validation and hierarchy
1 parent 9e46c65 commit d94fafd

8 files changed

Lines changed: 263 additions & 40 deletions

File tree

PendingReleaseNotes

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,9 @@ example.ver.1 > example.ver.2:
3939
which can now be attached to Instances. This is to prevent the Secondary
4040
Storage to grow to enormous sizes as Linux Distributions keep growing in
4141
size while a stripped down Linux should fit on a 2.88MB floppy.
42+
43+
4.22.1.0 > 4.23.0.0:
44+
* NSX network offerings can reference existing IP discovery, MAC discovery,
45+
and segment security profiles. New NSX segments bind selected profiles in
46+
the same hierarchical request as segment creation. Existing networks are
47+
not silently reconfigured when profile bindings change.

api/src/main/java/org/apache/cloudstack/api/command/admin/network/NetworkOfferingBaseCmd.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,9 @@ public abstract class NetworkOfferingBaseCmd extends BaseCmd {
166166

167167
@Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, since = "4.2.0", description = "Network offering details in key/value pairs."
168168
+ " Supported keys are internallbprovider/publiclbprovider with service provider as a value, and"
169-
+ " promiscuousmode/macaddresschanges/forgedtransmits with true/false as value to accept/reject the security settings if available for a nic/portgroup")
169+
+ " promiscuousmode/macaddresschanges/forgedtransmits with true/false as value to accept/reject the security settings if available for a nic/portgroup."
170+
+ " NSX offerings also support nsxipdiscoveryprofileid, nsxmacdiscoveryprofileid, and nsxsegmentsecurityprofileid."
171+
+ " Values are IDs of existing operator-managed NSX profiles to bind to segments created from the offering.")
170172
protected Map details;
171173

172174
@Parameter(name = ApiConstants.EGRESS_DEFAULT_POLICY,

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

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import com.vmware.nsx.model.ControllerClusterStatus;
2626
import com.vmware.nsx.model.TransportZone;
2727
import com.vmware.nsx.model.TransportZoneListResult;
28+
import com.vmware.nsx_policy.Infra;
2829
import com.vmware.nsx_policy.infra.DhcpRelayConfigs;
2930
import com.vmware.nsx_policy.infra.IpDiscoveryProfiles;
3031
import com.vmware.nsx_policy.infra.LbAppProfiles;
@@ -42,12 +43,13 @@
4243
import com.vmware.nsx_policy.infra.domains.SecurityPolicies;
4344
import com.vmware.nsx_policy.infra.domains.groups.members.SegmentPorts;
4445
import com.vmware.nsx_policy.infra.domains.security_policies.Rules;
45-
import com.vmware.nsx_policy.infra.segments.SegmentDiscoveryProfileBindingMaps;
46-
import com.vmware.nsx_policy.infra.segments.SegmentSecurityProfileBindingMaps;
4746
import com.vmware.nsx_policy.infra.sites.EnforcementPoints;
4847
import com.vmware.nsx_policy.infra.tier_0s.LocaleServices;
4948
import com.vmware.nsx_policy.infra.tier_1s.nat.NatRules;
5049
import com.vmware.nsx_policy.model.ApiError;
50+
import com.vmware.nsx_policy.model.ChildSegment;
51+
import com.vmware.nsx_policy.model.ChildSegmentDiscoveryProfileBindingMap;
52+
import com.vmware.nsx_policy.model.ChildSegmentSecurityProfileBindingMap;
5153
import com.vmware.nsx_policy.model.DhcpRelayConfig;
5254
import com.vmware.nsx_policy.model.EnforcementPoint;
5355
import com.vmware.nsx_policy.model.EnforcementPointListResult;
@@ -139,6 +141,9 @@ public class NsxApiClient {
139141
private static final String TIER_1_RESOURCE_TYPE = "Tier1";
140142
private static final String TIER_1_LOCALE_SERVICE_ID = "default";
141143
private static final String SEGMENT_RESOURCE_TYPE = "Segment";
144+
private static final String INFRA_RESOURCE_TYPE = "Infra";
145+
private static final String SEGMENT_DISCOVERY_PROFILE_BINDING_RESOURCE_TYPE = "SegmentDiscoveryProfileBindingMap";
146+
private static final String SEGMENT_SECURITY_PROFILE_BINDING_RESOURCE_TYPE = "SegmentSecurityProfileBindingMap";
142147
private static final String SEGMENT_DISCOVERY_PROFILE_BINDING_ID = "cloudstack-discovery-profile-binding";
143148
private static final String SEGMENT_SECURITY_PROFILE_BINDING_ID = "cloudstack-security-profile-binding";
144149
private static final String TIER_0_GATEWAY_PATH_PREFIX = "/infra/tier-0s/";
@@ -489,7 +494,6 @@ public void createSegment(String segmentName, String tier1GatewayName, String ga
489494
String ipDiscoveryProfilePath = getIpDiscoveryProfilePath(ipDiscoveryProfileId);
490495
String macDiscoveryProfilePath = getMacDiscoveryProfilePath(macDiscoveryProfileId);
491496
String segmentSecurityProfilePath = getSegmentSecurityProfilePath(segmentSecurityProfileId);
492-
Segments segmentService = (Segments) nsxService.apply(Segments.class);
493497
SegmentSubnet subnet = new SegmentSubnet.Builder()
494498
.setGatewayAddress(gatewayAddress)
495499
.build();
@@ -502,8 +506,24 @@ public void createSegment(String segmentName, String tier1GatewayName, String ga
502506
.setSubnets(List.of(subnet))
503507
.setTransportZonePath(enforcementPointPath + "/transport-zones/" + transportZones.get(0).getId())
504508
.build();
505-
segmentService.patch(segmentName, segment);
506-
bindSegmentProfiles(segmentName, ipDiscoveryProfilePath, macDiscoveryProfilePath, segmentSecurityProfilePath);
509+
List<Structure> profileBindings = getSegmentProfileBindings(ipDiscoveryProfilePath, macDiscoveryProfilePath,
510+
segmentSecurityProfilePath);
511+
if (profileBindings.isEmpty()) {
512+
Segments segmentService = (Segments) nsxService.apply(Segments.class);
513+
segmentService.patch(segmentName, segment);
514+
} else {
515+
segment.setChildren(profileBindings);
516+
ChildSegment childSegment = new ChildSegment.Builder()
517+
.setId(segmentName)
518+
.setSegment(segment)
519+
.build();
520+
com.vmware.nsx_policy.model.Infra infra = new com.vmware.nsx_policy.model.Infra.Builder()
521+
.setResourceType(INFRA_RESOURCE_TYPE)
522+
.setChildren(List.of(childSegment))
523+
.build();
524+
Infra infraService = (Infra) nsxService.apply(Infra.class);
525+
infraService.patch(infra, false);
526+
}
507527
} catch (Error error) {
508528
ApiError ae = error.getData()._convertTo(ApiError.class);
509529
String msg = String.format("Error creating segment %s: %s", segmentName, ae.getErrorMessage());
@@ -518,7 +538,7 @@ protected String getIpDiscoveryProfilePath(String profileId) {
518538
}
519539
IpDiscoveryProfiles profiles = (IpDiscoveryProfiles) nsxService.apply(IpDiscoveryProfiles.class);
520540
IPDiscoveryProfile profile = profiles.get(profileId);
521-
return validateProfilePath(profileId, profile.getPath());
541+
return validateProfile(profileId, profile.getId(), profile.getPath(), "/infra/ip-discovery-profiles/", profile.getMarkedForDelete());
522542
}
523543

524544
protected String getMacDiscoveryProfilePath(String profileId) {
@@ -527,7 +547,7 @@ protected String getMacDiscoveryProfilePath(String profileId) {
527547
}
528548
MacDiscoveryProfiles profiles = (MacDiscoveryProfiles) nsxService.apply(MacDiscoveryProfiles.class);
529549
MacDiscoveryProfile profile = profiles.get(profileId);
530-
return validateProfilePath(profileId, profile.getPath());
550+
return validateProfile(profileId, profile.getId(), profile.getPath(), "/infra/mac-discovery-profiles/", profile.getMarkedForDelete());
531551
}
532552

533553
protected String getSegmentSecurityProfilePath(String profileId) {
@@ -536,37 +556,50 @@ protected String getSegmentSecurityProfilePath(String profileId) {
536556
}
537557
SegmentSecurityProfiles profiles = (SegmentSecurityProfiles) nsxService.apply(SegmentSecurityProfiles.class);
538558
SegmentSecurityProfile profile = profiles.get(profileId);
539-
return validateProfilePath(profileId, profile.getPath());
559+
return validateProfile(profileId, profile.getId(), profile.getPath(), "/infra/segment-security-profiles/", profile.getMarkedForDelete());
540560
}
541561

542-
protected String validateProfilePath(String profileId, String profilePath) {
543-
if (StringUtils.isBlank(profilePath)) {
544-
throw new CloudRuntimeException(String.format("NSX profile %s did not return a canonical resource path", profileId));
562+
protected String validateProfile(String requestedId, String resolvedId, String profilePath,
563+
String expectedPathPrefix, Boolean markedForDelete) {
564+
if (!Objects.equals(requestedId, resolvedId)) {
565+
throw new CloudRuntimeException(String.format("NSX returned profile %s while resolving requested profile %s", resolvedId, requestedId));
566+
}
567+
if (!Objects.equals(expectedPathPrefix + requestedId, profilePath)) {
568+
throw new CloudRuntimeException(String.format("NSX profile %s did not return a canonical resource path of the expected type", requestedId));
569+
}
570+
if (Boolean.TRUE.equals(markedForDelete)) {
571+
throw new CloudRuntimeException(String.format("NSX profile %s is marked for deletion", requestedId));
545572
}
546573
return profilePath;
547574
}
548575

549-
protected void bindSegmentProfiles(String segmentName, String ipDiscoveryProfilePath, String macDiscoveryProfilePath,
550-
String segmentSecurityProfilePath) {
576+
protected List<Structure> getSegmentProfileBindings(String ipDiscoveryProfilePath, String macDiscoveryProfilePath,
577+
String segmentSecurityProfilePath) {
578+
List<Structure> bindings = new ArrayList<>();
551579
if (StringUtils.isNotBlank(ipDiscoveryProfilePath) || StringUtils.isNotBlank(macDiscoveryProfilePath)) {
552-
SegmentDiscoveryProfileBindingMaps discoveryBindings =
553-
(SegmentDiscoveryProfileBindingMaps) nsxService.apply(SegmentDiscoveryProfileBindingMaps.class);
554580
SegmentDiscoveryProfileBindingMap binding = new SegmentDiscoveryProfileBindingMap.Builder()
581+
.setResourceType(SEGMENT_DISCOVERY_PROFILE_BINDING_RESOURCE_TYPE)
555582
.setId(SEGMENT_DISCOVERY_PROFILE_BINDING_ID)
556583
.setIpDiscoveryProfilePath(ipDiscoveryProfilePath)
557584
.setMacDiscoveryProfilePath(macDiscoveryProfilePath)
558585
.build();
559-
discoveryBindings.patch(segmentName, SEGMENT_DISCOVERY_PROFILE_BINDING_ID, binding);
586+
bindings.add(new ChildSegmentDiscoveryProfileBindingMap.Builder()
587+
.setId(SEGMENT_DISCOVERY_PROFILE_BINDING_ID)
588+
.setSegmentDiscoveryProfileBindingMap(binding)
589+
.build());
560590
}
561591
if (StringUtils.isNotBlank(segmentSecurityProfilePath)) {
562-
SegmentSecurityProfileBindingMaps securityBindings =
563-
(SegmentSecurityProfileBindingMaps) nsxService.apply(SegmentSecurityProfileBindingMaps.class);
564592
SegmentSecurityProfileBindingMap binding = new SegmentSecurityProfileBindingMap.Builder()
593+
.setResourceType(SEGMENT_SECURITY_PROFILE_BINDING_RESOURCE_TYPE)
565594
.setId(SEGMENT_SECURITY_PROFILE_BINDING_ID)
566595
.setSegmentSecurityProfilePath(segmentSecurityProfilePath)
567596
.build();
568-
securityBindings.patch(segmentName, SEGMENT_SECURITY_PROFILE_BINDING_ID, binding);
597+
bindings.add(new ChildSegmentSecurityProfileBindingMap.Builder()
598+
.setId(SEGMENT_SECURITY_PROFILE_BINDING_ID)
599+
.setSegmentSecurityProfileBindingMap(binding)
600+
.build());
569601
}
602+
return bindings;
570603
}
571604

572605
public void deleteSegment(long zoneId, long domainId, long accountId, Long vpcId, long networkId, String segmentName) {

0 commit comments

Comments
 (0)