Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/src/main/java/com/cloud/event/EventTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,7 @@ public class EventTypes {
public static final String EVENT_EXTENSION_DELETE = "EXTENSION.DELETE";
public static final String EVENT_EXTENSION_RESOURCE_REGISTER = "EXTENSION.RESOURCE.REGISTER";
public static final String EVENT_EXTENSION_RESOURCE_UNREGISTER = "EXTENSION.RESOURCE.UNREGISTER";
public static final String EVENT_EXTENSION_RESOURCE_UPDATE = "EXTENSION.RESOURCE.UPDATE";
public static final String EVENT_EXTENSION_CUSTOM_ACTION_ADD = "EXTENSION.CUSTOM.ACTION.ADD";
public static final String EVENT_EXTENSION_CUSTOM_ACTION_UPDATE = "EXTENSION.CUSTOM.ACTION.UPDATE";
public static final String EVENT_EXTENSION_CUSTOM_ACTION_DELETE = "EXTENSION.CUSTOM.ACTION.DELETE";
Expand Down
37 changes: 37 additions & 0 deletions api/src/main/java/com/cloud/network/Network.java
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ public static class Provider {

public static final Provider Nsx = new Provider("Nsx", false);
public static final Provider Netris = new Provider("Netris", false);
public static final Provider NetworkExtension = new Provider("NetworkExtension", false, true);

private final String name;
private final boolean isExternal;
Expand Down Expand Up @@ -250,11 +251,47 @@ public static Provider getProvider(String providerName) {
return null;
}

/** Private constructor for transient (non-registered) providers. */
private Provider(String name) {
this.name = name;
this.isExternal = false;
this.needCleanupOnShutdown = true;
// intentionally NOT added to supportedProviders
}

/**
* Creates a transient (non-registered) {@link Provider} with the given name.
*
* <p>The new instance is <em>not</em> added to {@code supportedProviders}, so it
* will never be returned by {@link #getProvider(String)} and will not pollute the
* global provider registry. Use this for dynamic / extension-backed providers
* whose names are only known at runtime (e.g. NetworkOrchestrator extensions).</p>
*
* @param name the provider name (typically the extension name)
* @return a transient {@link Provider} instance with the given name
*/
public static Provider createTransientProvider(String name) {
return new Provider(name);
}

@Override public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("name", name)
.toString();
}

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof Provider)) return false;
Provider provider = (Provider) obj;
return this.name.equals(provider.name);
}

@Override
public int hashCode() {
return name.hashCode();
}
}

public static class Capability {
Expand Down
14 changes: 14 additions & 0 deletions api/src/main/java/com/cloud/network/NetworkModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ public interface NetworkModel {

boolean canElementEnableIndividualServices(Provider provider);

boolean canElementEnableIndividualServicesByName(String providerName);

boolean areServicesSupportedInNetwork(long networkId, Service... services);

boolean isNetworkSystem(Network network);
Expand Down Expand Up @@ -237,6 +239,18 @@ public interface NetworkModel {

String getDefaultGuestTrafficLabel(long dcId, HypervisorType vmware);

/**
* Resolves a provider name to a {@link Provider} instance.
* For known static providers, delegates to {@link Provider#getProvider(String)}.
* For dynamically-registered NetworkOrchestrator extension providers whose names
* are not in the static registry, returns a transient {@link Provider} with the
* given name so callers can still dispatch correctly.
*
* @param providerName the provider name from {@code ntwk_service_map} or similar
* @return a {@link Provider} instance, or {@code null} if not resolvable
*/
Provider resolveProvider(String providerName);

/**
* @param providerName
* @return
Expand Down
2 changes: 1 addition & 1 deletion api/src/main/java/com/cloud/network/NetworkService.java
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ PhysicalNetwork createPhysicalNetwork(Long zoneId, String vnetRange, String netw

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

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

boolean deletePhysicalNetwork(Long id);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,8 @@ boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, Reser
* @return true/false
*/
boolean verifyServicesCombination(Set<Service> services);

default boolean rollingRestartSupported() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.apache.cloudstack.api.command.admin.network;

import java.util.List;
import java.util.Map;


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

@Parameter(name = ApiConstants.EXTERNAL_DETAILS,
type = CommandType.MAP,
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",
since = "4.23.0")
protected Map externalDetails;

/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
Expand All @@ -77,6 +84,10 @@ public String getVlan() {
return vlan;
}

public Map<String, String> getExternalDetails() {
return convertDetailsToMap(externalDetails);
}

/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
Expand All @@ -88,7 +99,7 @@ public long getEntityOwnerId() {

@Override
public void execute() {
PhysicalNetwork result = _networkService.updatePhysicalNetwork(getId(), getNetworkSpeed(), getTags(), getVlan(), getState());
PhysicalNetwork result = _networkService.updatePhysicalNetwork(getId(), getNetworkSpeed(), getTags(), getVlan(), getState(), getExternalDetails());
if (result != null) {
PhysicalNetworkResponse response = _responseGenerator.createPhysicalNetworkResponse(result);
response.setResponseName(getCommandName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,12 @@ public Boolean getSuccess() {
public void setResult(Map<String, String> result) {
this.result = result;
}

public Map<String, String> getResult() {
return result;
}

public boolean isSuccess() {
return Boolean.TRUE.equals(success);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@

public interface Extension extends InternalIdentity, Identity {
enum Type {
Orchestrator
Orchestrator,
NetworkOrchestrator
}
enum State {
Enabled, Disabled;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@

public interface ExtensionCustomAction extends InternalIdentity, Identity {
enum ResourceType {
VirtualMachine(com.cloud.vm.VirtualMachine.class);
VirtualMachine(com.cloud.vm.VirtualMachine.class),
Network(com.cloud.network.Network.class);

private final Class<?> clazz;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,99 @@
package org.apache.cloudstack.extension;

import java.util.List;
import java.util.Map;

import com.cloud.network.Network.Capability;
import com.cloud.network.Network.Service;

public interface ExtensionHelper {
Long getExtensionIdForCluster(long clusterId);
Extension getExtension(long id);
Extension getExtensionForCluster(long clusterId);
List<String> getExtensionReservedResourceDetails(long extensionId);

/**
* Detail key used to store the comma-separated list of network services provided
* by a NetworkOrchestrator extension (e.g. {@code "SourceNat,StaticNat,Firewall"}).
*/
String NETWORK_SERVICES_DETAIL_KEY = "network.services";

/**
* Detail key used to store a JSON object mapping each service name to its
* CloudStack {@link com.cloud.network.Network.Capability} key/value pairs.
* Example: {@code {"SourceNat":{"SupportedSourceNatTypes":"peraccount"}}}.
* Used together with {@link #NETWORK_SERVICES_DETAIL_KEY}.
*/
String NETWORK_SERVICE_CAPABILITIES_DETAIL_KEY = "network.service.capabilities";

Long getExtensionIdForPhysicalNetwork(long physicalNetworkId);
Extension getExtensionForPhysicalNetwork(long physicalNetworkId);
String getExtensionScriptPath(Extension extension);
Map<String, String> getExtensionDetails(long extensionId);

/**
* Finds the extension registered with the given physical network whose name
* matches the given provider name (case-insensitive). Returns {@code null}
* if no matching extension is found.
*
* <p>This is the preferred lookup when multiple extensions are registered on
* the same physical network: the provider name stored in
* {@code ntwk_service_map} is used to pinpoint the exact extension that
* handles a given network.</p>
*
* @param physicalNetworkId the physical network ID
* @param providerName the provider name (must equal the extension name)
* @return the matching {@link Extension}, or {@code null}
*/
Extension getExtensionForPhysicalNetworkAndProvider(long physicalNetworkId, String providerName);

/**
* Returns ALL {@code extension_resource_map_details} (including hidden) for
* the specific extension registered on the given physical network. Used by
* {@code NetworkExtensionElement} to inject device credentials into the script
* environment for the correct extension when multiple different extensions are
* registered on the same physical network.
*
* @param physicalNetworkId the physical network ID
* @param extensionId the extension ID
* @return all key/value details including non-display ones, or an empty map
*/
Map<String, String> getAllResourceMapDetailsForExtensionOnPhysicalNetwork(long physicalNetworkId, long extensionId);

/**
* Returns {@code true} if the given provider name is backed by a
* {@code NetworkOrchestrator} extension registered on any physical network.
* This is used by {@code NetworkModelImpl} to detect extension-backed providers
* that are not in the static {@code s_providerToNetworkElementMap}.
*
* @param providerName the provider / extension name
* @return true if the provider is a NetworkExtension provider
*/
boolean isNetworkExtensionProvider(String providerName);

/**
* List all registered extensions filtered by extension {@link Extension.Type}.
* Useful for callers that need to discover available providers of a given
* type (e.g. Orchestrator, NetworkOrchestrator).
*
* @param type extension type to filter by
* @return list of matching {@link Extension} instances (empty list if none)
*/
List<Extension> listExtensionsByType(Extension.Type type);

/**
* Returns the effective {@link Service} → ({@link Capability} → value) capabilities
* for the given external network provider, looking it up by name on the given
* physical network.
*
* <p>If {@code physicalNetworkId} is {@code null}, the method searches across all
* physical networks that have extensions registered and returns the capabilities for
* the first matching extension.</p>
*
* @param physicalNetworkId physical network ID, or {@code null} for offering-level queries
* @param providerName provider / extension name
* @return capabilities map, or the default capabilities if no matching extension is found
*/
Map<Service, Map<Capability, String>> getNetworkCapabilitiesForProvider(Long physicalNetworkId, String providerName);

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@

public interface ExtensionResourceMap extends InternalIdentity, Identity {
enum ResourceType {
Cluster
Cluster,
PhysicalNetwork
}

long getExtensionId();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package org.apache.cloudstack.extension;

import java.util.Map;

import com.cloud.network.Network;

/**
* Implemented by network elements that support running custom actions on a
* managed network (e.g. NetworkExtensionElement).
*
* <p>This interface is looked up by {@code ExtensionsManagerImpl} to dispatch
* {@code runCustomAction} requests whose resource type is {@code Network}.</p>
*/
public interface NetworkCustomActionProvider {

/**
* Returns {@code true} if this provider handles networks whose physical
* network has an ExternalNetwork service provider registered.
*
* @param network the target network
* @return {@code true} if this provider can handle the network
*/
boolean canHandleCustomAction(Network network);

/**
* Runs a named custom action against the external network device that
* manages the given network.
*
* @param network the CloudStack network on which to run the action
* @param actionName the action name (e.g. {@code "reboot-device"}, {@code "dump-config"})
* @param parameters optional parameters supplied by the caller
* @return output from the action script, or {@code null} on failure
*/
String runCustomAction(Network network, String actionName, Map<String, Object> parameters);
}
Loading
Loading