Skip to content

Commit d27753e

Browse files
committed
Network Extension: Orchestrate external Network devices
1 parent 82bfa9f commit d27753e

File tree

70 files changed

+9173
-217
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+9173
-217
lines changed

api/src/main/java/com/cloud/event/EventTypes.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,7 @@ public class EventTypes {
854854
public static final String EVENT_EXTENSION_DELETE = "EXTENSION.DELETE";
855855
public static final String EVENT_EXTENSION_RESOURCE_REGISTER = "EXTENSION.RESOURCE.REGISTER";
856856
public static final String EVENT_EXTENSION_RESOURCE_UNREGISTER = "EXTENSION.RESOURCE.UNREGISTER";
857+
public static final String EVENT_EXTENSION_RESOURCE_UPDATE = "EXTENSION.RESOURCE.UPDATE";
857858
public static final String EVENT_EXTENSION_CUSTOM_ACTION_ADD = "EXTENSION.CUSTOM.ACTION.ADD";
858859
public static final String EVENT_EXTENSION_CUSTOM_ACTION_UPDATE = "EXTENSION.CUSTOM.ACTION.UPDATE";
859860
public static final String EVENT_EXTENSION_CUSTOM_ACTION_DELETE = "EXTENSION.CUSTOM.ACTION.DELETE";

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ public static class Provider {
207207

208208
public static final Provider Nsx = new Provider("Nsx", false);
209209
public static final Provider Netris = new Provider("Netris", false);
210+
public static final Provider NetworkExtension = new Provider("NetworkExtension", false, true);
210211

211212
private final String name;
212213
private final boolean isExternal;
@@ -250,11 +251,47 @@ public static Provider getProvider(String providerName) {
250251
return null;
251252
}
252253

254+
/** Private constructor for transient (non-registered) providers. */
255+
private Provider(String name) {
256+
this.name = name;
257+
this.isExternal = false;
258+
this.needCleanupOnShutdown = true;
259+
// intentionally NOT added to supportedProviders
260+
}
261+
262+
/**
263+
* Creates a transient (non-registered) {@link Provider} with the given name.
264+
*
265+
* <p>The new instance is <em>not</em> added to {@code supportedProviders}, so it
266+
* will never be returned by {@link #getProvider(String)} and will not pollute the
267+
* global provider registry. Use this for dynamic / extension-backed providers
268+
* whose names are only known at runtime (e.g. NetworkOrchestrator extensions).</p>
269+
*
270+
* @param name the provider name (typically the extension name)
271+
* @return a transient {@link Provider} instance with the given name
272+
*/
273+
public static Provider createTransientProvider(String name) {
274+
return new Provider(name);
275+
}
276+
253277
@Override public String toString() {
254278
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
255279
.append("name", name)
256280
.toString();
257281
}
282+
283+
@Override
284+
public boolean equals(Object obj) {
285+
if (this == obj) return true;
286+
if (!(obj instanceof Provider)) return false;
287+
Provider provider = (Provider) obj;
288+
return this.name.equals(provider.name);
289+
}
290+
291+
@Override
292+
public int hashCode() {
293+
return name.hashCode();
294+
}
258295
}
259296

260297
public static class Capability {

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,8 @@ public interface NetworkModel {
187187

188188
boolean canElementEnableIndividualServices(Provider provider);
189189

190+
boolean canElementEnableIndividualServicesByName(String providerName);
191+
190192
boolean areServicesSupportedInNetwork(long networkId, Service... services);
191193

192194
boolean isNetworkSystem(Network network);
@@ -237,6 +239,18 @@ public interface NetworkModel {
237239

238240
String getDefaultGuestTrafficLabel(long dcId, HypervisorType vmware);
239241

242+
/**
243+
* Resolves a provider name to a {@link Provider} instance.
244+
* For known static providers, delegates to {@link Provider#getProvider(String)}.
245+
* For dynamically-registered NetworkOrchestrator extension providers whose names
246+
* are not in the static registry, returns a transient {@link Provider} with the
247+
* given name so callers can still dispatch correctly.
248+
*
249+
* @param providerName the provider name from {@code ntwk_service_map} or similar
250+
* @return a {@link Provider} instance, or {@code null} if not resolvable
251+
*/
252+
Provider resolveProvider(String providerName);
253+
240254
/**
241255
* @param providerName
242256
* @return

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ PhysicalNetwork createPhysicalNetwork(Long zoneId, String vnetRange, String netw
155155

156156
Pair<List<? extends PhysicalNetwork>, Integer> searchPhysicalNetworks(Long id, Long zoneId, String keyword, Long startIndex, Long pageSize, String name);
157157

158-
PhysicalNetwork updatePhysicalNetwork(Long id, String networkSpeed, List<String> tags, String newVnetRangeString, String state);
158+
PhysicalNetwork updatePhysicalNetwork(Long id, String networkSpeed, List<String> tags, String newVnetRangeString, String state, Map<String, String> externalDetails);
159159

160160
boolean deletePhysicalNetwork(Long id);
161161

api/src/main/java/com/cloud/network/element/NetworkElement.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,4 +146,8 @@ boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, Reser
146146
* @return true/false
147147
*/
148148
boolean verifyServicesCombination(Set<Service> services);
149+
150+
default boolean rollingRestartSupported() {
151+
return true;
152+
}
149153
}

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.apache.cloudstack.api.command.admin.network;
1818

1919
import java.util.List;
20+
import java.util.Map;
2021

2122

2223
import org.apache.cloudstack.api.APICommand;
@@ -53,6 +54,12 @@ public class UpdatePhysicalNetworkCmd extends BaseAsyncCmd {
5354
@Parameter(name = ApiConstants.VLAN, type = CommandType.STRING, description = "The VLAN for the physical Network")
5455
private String vlan;
5556

57+
@Parameter(name = ApiConstants.EXTERNAL_DETAILS,
58+
type = CommandType.MAP,
59+
description = "Details in key/value pairs to be added to the extension-resource mapping. Use the format externaldetails[i].<key>=<value>. Example: externaldetails[0].endpoint.url=https://example.com",
60+
since = "4.23.0")
61+
protected Map externalDetails;
62+
5663
/////////////////////////////////////////////////////
5764
/////////////////// Accessors ///////////////////////
5865
/////////////////////////////////////////////////////
@@ -77,6 +84,10 @@ public String getVlan() {
7784
return vlan;
7885
}
7986

87+
public Map<String, String> getExternalDetails() {
88+
return convertDetailsToMap(externalDetails);
89+
}
90+
8091
/////////////////////////////////////////////////////
8192
/////////////// API Implementation///////////////////
8293
/////////////////////////////////////////////////////
@@ -88,7 +99,7 @@ public long getEntityOwnerId() {
8899

89100
@Override
90101
public void execute() {
91-
PhysicalNetwork result = _networkService.updatePhysicalNetwork(getId(), getNetworkSpeed(), getTags(), getVlan(), getState());
102+
PhysicalNetwork result = _networkService.updatePhysicalNetwork(getId(), getNetworkSpeed(), getTags(), getVlan(), getState(), getExternalDetails());
92103
if (result != null) {
93104
PhysicalNetworkResponse response = _responseGenerator.createPhysicalNetworkResponse(result);
94105
response.setResponseName(getCommandName());

api/src/main/java/org/apache/cloudstack/extension/CustomActionResultResponse.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,12 @@ public Boolean getSuccess() {
6262
public void setResult(Map<String, String> result) {
6363
this.result = result;
6464
}
65+
66+
public Map<String, String> getResult() {
67+
return result;
68+
}
69+
70+
public boolean isSuccess() {
71+
return Boolean.TRUE.equals(success);
72+
}
6573
}

api/src/main/java/org/apache/cloudstack/extension/Extension.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424

2525
public interface Extension extends InternalIdentity, Identity {
2626
enum Type {
27-
Orchestrator
27+
Orchestrator,
28+
NetworkOrchestrator
2829
}
2930
enum State {
3031
Enabled, Disabled;

api/src/main/java/org/apache/cloudstack/extension/ExtensionCustomAction.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@
4848

4949
public interface ExtensionCustomAction extends InternalIdentity, Identity {
5050
enum ResourceType {
51-
VirtualMachine(com.cloud.vm.VirtualMachine.class);
51+
VirtualMachine(com.cloud.vm.VirtualMachine.class),
52+
Network(com.cloud.network.Network.class);
5253

5354
private final Class<?> clazz;
5455

api/src/main/java/org/apache/cloudstack/extension/ExtensionHelper.java

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,99 @@
1818
package org.apache.cloudstack.extension;
1919

2020
import java.util.List;
21+
import java.util.Map;
22+
23+
import com.cloud.network.Network.Capability;
24+
import com.cloud.network.Network.Service;
2125

2226
public interface ExtensionHelper {
2327
Long getExtensionIdForCluster(long clusterId);
2428
Extension getExtension(long id);
2529
Extension getExtensionForCluster(long clusterId);
2630
List<String> getExtensionReservedResourceDetails(long extensionId);
31+
32+
/**
33+
* Detail key used to store the comma-separated list of network services provided
34+
* by a NetworkOrchestrator extension (e.g. {@code "SourceNat,StaticNat,Firewall"}).
35+
*/
36+
String NETWORK_SERVICES_DETAIL_KEY = "network.services";
37+
38+
/**
39+
* Detail key used to store a JSON object mapping each service name to its
40+
* CloudStack {@link com.cloud.network.Network.Capability} key/value pairs.
41+
* Example: {@code {"SourceNat":{"SupportedSourceNatTypes":"peraccount"}}}.
42+
* Used together with {@link #NETWORK_SERVICES_DETAIL_KEY}.
43+
*/
44+
String NETWORK_SERVICE_CAPABILITIES_DETAIL_KEY = "network.service.capabilities";
45+
46+
Long getExtensionIdForPhysicalNetwork(long physicalNetworkId);
47+
Extension getExtensionForPhysicalNetwork(long physicalNetworkId);
48+
String getExtensionScriptPath(Extension extension);
49+
Map<String, String> getExtensionDetails(long extensionId);
50+
51+
/**
52+
* Finds the extension registered with the given physical network whose name
53+
* matches the given provider name (case-insensitive). Returns {@code null}
54+
* if no matching extension is found.
55+
*
56+
* <p>This is the preferred lookup when multiple extensions are registered on
57+
* the same physical network: the provider name stored in
58+
* {@code ntwk_service_map} is used to pinpoint the exact extension that
59+
* handles a given network.</p>
60+
*
61+
* @param physicalNetworkId the physical network ID
62+
* @param providerName the provider name (must equal the extension name)
63+
* @return the matching {@link Extension}, or {@code null}
64+
*/
65+
Extension getExtensionForPhysicalNetworkAndProvider(long physicalNetworkId, String providerName);
66+
67+
/**
68+
* Returns ALL {@code extension_resource_map_details} (including hidden) for
69+
* the specific extension registered on the given physical network. Used by
70+
* {@code NetworkExtensionElement} to inject device credentials into the script
71+
* environment for the correct extension when multiple different extensions are
72+
* registered on the same physical network.
73+
*
74+
* @param physicalNetworkId the physical network ID
75+
* @param extensionId the extension ID
76+
* @return all key/value details including non-display ones, or an empty map
77+
*/
78+
Map<String, String> getAllResourceMapDetailsForExtensionOnPhysicalNetwork(long physicalNetworkId, long extensionId);
79+
80+
/**
81+
* Returns {@code true} if the given provider name is backed by a
82+
* {@code NetworkOrchestrator} extension registered on any physical network.
83+
* This is used by {@code NetworkModelImpl} to detect extension-backed providers
84+
* that are not in the static {@code s_providerToNetworkElementMap}.
85+
*
86+
* @param providerName the provider / extension name
87+
* @return true if the provider is a NetworkExtension provider
88+
*/
89+
boolean isNetworkExtensionProvider(String providerName);
90+
91+
/**
92+
* List all registered extensions filtered by extension {@link Extension.Type}.
93+
* Useful for callers that need to discover available providers of a given
94+
* type (e.g. Orchestrator, NetworkOrchestrator).
95+
*
96+
* @param type extension type to filter by
97+
* @return list of matching {@link Extension} instances (empty list if none)
98+
*/
99+
List<Extension> listExtensionsByType(Extension.Type type);
100+
101+
/**
102+
* Returns the effective {@link Service} → ({@link Capability} → value) capabilities
103+
* for the given external network provider, looking it up by name on the given
104+
* physical network.
105+
*
106+
* <p>If {@code physicalNetworkId} is {@code null}, the method searches across all
107+
* physical networks that have extensions registered and returns the capabilities for
108+
* the first matching extension.</p>
109+
*
110+
* @param physicalNetworkId physical network ID, or {@code null} for offering-level queries
111+
* @param providerName provider / extension name
112+
* @return capabilities map, or the default capabilities if no matching extension is found
113+
*/
114+
Map<Service, Map<Capability, String>> getNetworkCapabilitiesForProvider(Long physicalNetworkId, String providerName);
115+
27116
}

0 commit comments

Comments
 (0)