Skip to content

Commit

Permalink
Add hot plugging configuration listeners and execution services
Browse files Browse the repository at this point in the history
Signed-off-by: hanbingleixue <[email protected]>
  • Loading branch information
hanbingleixue committed Sep 11, 2024
1 parent a61202c commit 9eeefec
Show file tree
Hide file tree
Showing 24 changed files with 862 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ agent.service.dynamic.config.enable=true
agent.service.httpserver.enable=false
# xDS service switch
agent.service.xds.service.enable=false
# dynamic mount service switch
agent.service.hot.plugging.service.enable=false
#============================= Event configuration =============================#
# Event switch
event.enable=false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public static void install(String artifact, Map<String, Object> argsMap, Instrum
LoggerFactory.init(artifact);

// Build the path index by startup configuration
BootArgsIndexer.build(argsMap);
BootArgsIndexer.build(argsMap, isDynamic);

// Initialize the unified configuration
ConfigManager.initialize(argsMap);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ public enum Command {
*/
UNINSTALL_PLUGINS("UNINSTALL-PLUGINS"),

/**
* Update plugin instruction
*/
UPDATE_PLUGINS("UPDATE-PLUGINS"),
/**
* Enhancement query instruction
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class CommandProcessor {
COMMAND_EXECUTOR_MAP.put(Command.INSTALL_PLUGINS.getValue(), new PluginsInstallCommandExecutor());
COMMAND_EXECUTOR_MAP.put(Command.UNINSTALL_AGENT.getValue(), new AgentUnInstallCommandExecutor());
COMMAND_EXECUTOR_MAP.put(Command.UNINSTALL_PLUGINS.getValue(), new PluginsUnInstallCommandExecutor());
COMMAND_EXECUTOR_MAP.put(Command.UPDATE_PLUGINS.getValue(), new PluginsUpdateCommandExecutor());
COMMAND_EXECUTOR_MAP.put(Command.CHECK_ENHANCEMENT.getValue(), new CheckEnhancementsCommandExecutor());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package io.sermant.core.command;

import io.sermant.core.common.LoggerFactory;
import io.sermant.core.event.collector.FrameworkEventCollector;
import io.sermant.core.event.collector.FrameworkEventDefinitions;
import io.sermant.core.plugin.PluginManager;
import io.sermant.core.utils.StringUtils;

Expand All @@ -42,5 +44,8 @@ public void execute(String args) {
}
String[] pluginNames = args.split("/");
PluginManager.install(Arrays.stream(pluginNames).collect(Collectors.toSet()));
FrameworkEventCollector.getInstance().collectdHotPluggingEvent(FrameworkEventDefinitions.SERMANT_PLUGIN_INSTALL,
"Hot plugging command[INSTALL-PLUGINS] has been processed. Installed plugins are "
+ Arrays.toString(pluginNames) + ".");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package io.sermant.core.command;

import io.sermant.core.common.LoggerFactory;
import io.sermant.core.event.collector.FrameworkEventCollector;
import io.sermant.core.event.collector.FrameworkEventDefinitions;
import io.sermant.core.plugin.PluginManager;
import io.sermant.core.utils.StringUtils;

Expand All @@ -42,5 +44,9 @@ public void execute(String args) {
}
String[] pluginNames = args.split("/");
PluginManager.uninstall(Arrays.stream(pluginNames).collect(Collectors.toSet()));
FrameworkEventCollector.getInstance().collectdHotPluggingEvent(
FrameworkEventDefinitions.SERMANT_PLUGIN_UNINSTALL,
"Hot plugging command[UNINSTALL-PLUGINS] has been processed. Uninstalled plugins are "
+ Arrays.toString(pluginNames) + ".");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (C) 2024-2024 Sermant Authors. All rights reserved.
*
* Licensed 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 io.sermant.core.command;

import io.sermant.core.common.LoggerFactory;
import io.sermant.core.event.collector.FrameworkEventCollector;
import io.sermant.core.event.collector.FrameworkEventDefinitions;
import io.sermant.core.plugin.PluginManager;
import io.sermant.core.utils.StringUtils;

import java.util.Arrays;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

/**
* Plugin update command executor
*
* @author zhp
* @since 2024-08-26
*/
public class PluginsUpdateCommandExecutor implements CommandExecutor {
private static final Logger LOGGER = LoggerFactory.getLogger();

@Override
public void execute(String args) {
if (StringUtils.isEmpty(args)) {
LOGGER.log(Level.WARNING, "The argument of command[UPDATE-PLUGINS] is empty.");
return;
}
String[] pluginNames = args.split("/");
Set<String> pluginSet = Arrays.stream(pluginNames).collect(Collectors.toSet());
PluginManager.uninstall(pluginSet);
PluginManager.initPlugins(pluginSet, true);
FrameworkEventCollector.getInstance().collectdHotPluggingEvent(FrameworkEventDefinitions.SERMANT_PLUGIN_UPDATE,
"Hot plugging command[UPDATE-PLUGINS] has been processed. Update plugins are "
+ Arrays.toString(pluginNames));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@

import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.util.Map;
import java.util.UUID;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
Expand Down Expand Up @@ -78,6 +80,12 @@ public class BootArgsIndexer {

private static String instanceId;

private static String artifact;

private static String processId;

private static boolean dynamicInstall;

private BootArgsIndexer() {
}

Expand Down Expand Up @@ -121,12 +129,25 @@ public static String getInstanceId() {
return instanceId;
}

public static String getArtifact() {
return artifact;
}

public static String getProcessId() {
return processId;
}

public static boolean isDynamicInstall() {
return dynamicInstall;
}

/**
* 构建路径索引器
* Build Path Indexer
*
* @param argsMap 启动参数
* @param argsMap Startup Parameters
* @param isDynamic is Dynamic installation
*/
public static void build(Map<String, Object> argsMap) {
public static void build(Map<String, Object> argsMap, boolean isDynamic) {
implementDir = new File(FileUtils.validatePath(argsMap.get(CommonConstant.CORE_IMPLEMENT_DIR_KEY).toString()));
if (!implementDir.isDirectory()) {
LOGGER.warning("Implement directory not found! ");
Expand Down Expand Up @@ -158,14 +179,25 @@ public static void build(Map<String, Object> argsMap) {
serviceName = argsMap.get(CommonConstant.SERVICE_NAME_KEY).toString();

instanceId = UUID.randomUUID().toString();

artifact = argsMap.get(CommonConstant.ARTIFACT_NAME_KEY).toString();

setProcessId();

BootArgsIndexer.dynamicInstall = isDynamic;
}

private static void setProcessId() {
String name = ManagementFactory.getRuntimeMXBean().getName();
processId = name.split("@")[0];
}

static {
final String currentFile = BootArgsIndexer.class.getProtectionDomain().getCodeSource().getLocation().getPath();
try (JarFile jarFile = new JarFile(currentFile)) {
CORE_VERSION = JarFileUtils.getManifestAttr(jarFile, CommonConstant.CORE_VERSION_KEY).toString();
} catch (IOException e) {
LOGGER.severe("Failed to read the core version from the manifest file: " + currentFile);
LOGGER.log(Level.SEVERE, "Failed to read the core version from the manifest file: " + currentFile, e);
throw new SchemaException(SchemaException.MISSING_VERSION, currentFile);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ public class CommonConstant {
*/
public static final String ENHANCED_CLASS_OUTPUT_PARENT_DIR = "enhancedClasses";

/**
* The key of artifact in agent arguments
*/
public static final String ARTIFACT_NAME_KEY = "artifact";

private CommonConstant() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,19 @@ public void collectTransformFailureEvent(String transformDescription) {
FrameworkEventDefinitions.SERMANT_TRANSFORM_FAILURE.getEventType(),
new EventInfo(FrameworkEventDefinitions.SERMANT_TRANSFORM_FAILURE.getName(), transformDescription)));
}

/**
* Collect hot plugging events
*
* @param frameworkEventDefinitions Event definition for framework events
* @param description description
*/
public void collectdHotPluggingEvent(FrameworkEventDefinitions frameworkEventDefinitions, String description) {
if (!eventConfig.isEnable()) {
return;
}
offerEvent(new Event(frameworkEventDefinitions.getScope(), frameworkEventDefinitions.getEventLevel(),
frameworkEventDefinitions.getEventType(),
new EventInfo(frameworkEventDefinitions.getName(), description)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,22 @@ public enum FrameworkEventDefinitions {
/**
* Sermant stop event definition
*/
SERMANT_STOP("SERMANT_STOP", EventType.OPERATION, EventLevel.NORMAL);
SERMANT_STOP("SERMANT_STOP", EventType.OPERATION, EventLevel.NORMAL),

/**
* Sermant plugin installation event definition
*/
SERMANT_PLUGIN_INSTALL("SERMANT_PLUGIN_INSTALL", EventType.OPERATION, EventLevel.NORMAL),

/**
* Sermant plugin uninstallation event definition
*/
SERMANT_PLUGIN_UNINSTALL("SERMANT_PLUGIN_UNINSTALL", EventType.OPERATION, EventLevel.NORMAL),

/**
* Sermant plugin update event definition
*/
SERMANT_PLUGIN_UPDATE("SERMANT_PLUGIN_UPDATE", EventType.OPERATION, EventLevel.NORMAL);

/**
* event name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

/**
* Plugin manager, where plugin-related resources or operations are managed
Expand Down Expand Up @@ -88,17 +89,18 @@ public static void install(Set<String> pluginNames) {
*/
public static void uninstall(Set<String> pluginNames) {
if (CollectionUtils.isEmpty(pluginNames)) {
LOGGER.log(Level.WARNING, "No plugin is configured to be uninstall.");
LOGGER.log(Level.WARNING, "[UNINSTALL-PLUGINS] No plugin is configured to be uninstall.");
return;
}
for (String name : pluginNames) {
Plugin plugin = PLUGIN_MAP.get(name);
if (plugin == null) {
LOGGER.log(Level.INFO, "Plugin {0} has not been installed.", name);
LOGGER.log(Level.INFO, "[UNINSTALL-PLUGINS] [{0}] Plugin {0} has not been installed.", name);
continue;
}
if (!plugin.isDynamic()) {
LOGGER.log(Level.INFO, "Plugin {0} is static-support-plugin,can not be uninstalled.", name);
LOGGER.log(Level.INFO, "[UNINSTALL-PLUGINS] [{0}] Plugin {0} is static-support-plugin,can not be "
+ "uninstalled.", name);
continue;
}

Expand Down Expand Up @@ -156,20 +158,22 @@ public static void uninstallAll() {
*/
public static void initPlugins(Set<String> pluginNames, boolean isDynamic) {
if (CollectionUtils.isEmpty(pluginNames)) {
LOGGER.log(Level.WARNING, "Non plugin is configured to be initialized.");
LOGGER.log(Level.WARNING, "[INSTALL-PLUGINS] Non plugin is configured to be initialized.");
return;
}
final String pluginPackage;
try {
pluginPackage = BootArgsIndexer.getPluginPackageDir().getCanonicalPath();
} catch (IOException ioException) {
LOGGER.log(Level.SEVERE, "Resolve plugin package failed.", ioException);
String names = pluginNames.stream().map(String::valueOf).collect(Collectors.joining(", "));
LOGGER.log(Level.SEVERE, "[INSTALL-PLUGINS] [{0}] Resolve plugin package failed.", names);
LOGGER.log(Level.SEVERE, "An exception occurred while parsing the plugin package.", ioException);
return;
}
for (String pluginName : pluginNames) {
if (PLUGIN_MAP.containsKey(pluginName)) {
LOGGER.log(Level.WARNING, "Plugin: {0} has bean installed. It cannot be installed repeatedly.",
pluginName);
LOGGER.log(Level.WARNING, "[INSTALL-PLUGINS] [{0}] Plugin: {0} has bean installed. "
+ "It cannot be installed repeatedly.", pluginName);
continue;
}
executeInit(isDynamic, pluginPackage, pluginName);
Expand All @@ -181,14 +185,15 @@ private static void executeInit(boolean isDynamic, String pluginPackage, String
// Remove the copy tag of the plugin name to obtain the actual resource directory
final String pluginPath = pluginPackage + File.separatorChar + getRealPluginName(pluginName);
if (!new File(pluginPath).exists()) {
LOGGER.log(Level.WARNING, "Plugin directory {0} does not exist, so skip initializing {1}. ",
new String[]{pluginPath, pluginName});
LOGGER.log(Level.WARNING, "[INSTALL-PLUGINS] [{0}] Plugin directory {1} does not exist, so skip "
+ "initializing {0}. ", new String[]{pluginName, pluginPath});
return;
}
doInitPlugin(
new Plugin(pluginName, pluginPath, isDynamic, ClassLoaderManager.createPluginClassLoader()));
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, "Load plugin failed, plugin name: " + pluginName, ex);
LOGGER.log(Level.SEVERE, "[INSTALL-PLUGINS] [{0}] Load plugin failed, plugin name: {0}.", pluginName);
LOGGER.log(Level.SEVERE, "An exception occurred while loading plugin.", ex);
}
}

Expand Down Expand Up @@ -382,15 +387,17 @@ private static void closePluginLoaders(Plugin plugin) {
serviceClassLoader.close();
}
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Failed to close ServiceClassLoader for plugin:{0}", plugin.getName());
LOGGER.log(Level.SEVERE, "[UNINSTALL-PLUGIN] [{0}] Failed to close ServiceClassLoader for plugin:{0}",
plugin.getName());
}
try {
PluginClassLoader pluginClassLoader = plugin.getPluginClassLoader();
if (pluginClassLoader != null) {
pluginClassLoader.close();
}
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Failed to close PluginClassLoader for plugin:{0}", plugin.getName());
LOGGER.log(Level.SEVERE, "[UNINSTALL-PLUGIN] [{0}] Failed to close PluginClassLoader for plugin:{0}",
plugin.getName());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ public class ServiceConfig implements BaseConfig {
@ConfigFieldKey("xds.service.enable")
private boolean xdsServiceEnable = false;

@ConfigFieldKey("hot.plugging.service.enable")
private boolean hotPluggingServiceEnable = false;

public boolean isHeartBeatEnable() {
return heartBeatEnable;
}
Expand Down Expand Up @@ -105,6 +108,14 @@ public void setXdsServiceEnable(boolean xdsServiceEnable) {
this.xdsServiceEnable = xdsServiceEnable;
}

public boolean isHotPluggingServiceEnable() {
return hotPluggingServiceEnable;
}

public void setHotPluggingServiceEnable(boolean hotPluggingServiceEnable) {

Check warning on line 115 in sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/ServiceConfig.java

View workflow job for this annotation

GitHub Actions / Checkstyle

[Checkstyle Check] reported by reviewdog 🐶 编程规范-建议1.2 布尔变量名或方法以is开头(has have does do did will should can may must could等疑问助动词也可以,Android允许m作为疑问助动词前缀) Raw Output: /home/runner/work/Sermant/Sermant/./sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/ServiceConfig.java:115:0: warning: 编程规范-建议1.2 布尔变量名或方法以is开头(has have does do did will should can may must could等疑问助动词也可以,Android允许m作为疑问助动词前缀) (com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineCheck)
this.hotPluggingServiceEnable = hotPluggingServiceEnable;
}

/**
* Check whether the service of the given class name is enabled.
*
Expand Down Expand Up @@ -133,6 +144,9 @@ public boolean checkServiceEnable(String serviceName) {
if (ServiceManager.XDS_CORE_SERVICE_IMPL.equals(serviceName)) {
return isXdsServiceEnable();
}
if (ServiceManager.HOT_PLUGGING_SERVICE_IMPL.equals(serviceName)) {
return isHotPluggingServiceEnable();
}
return false;
}
}
Loading

0 comments on commit 9eeefec

Please sign in to comment.