diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/AgentCoreEntrance.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/AgentCoreEntrance.java index 3802c9405e..94a253b8bb 100644 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/AgentCoreEntrance.java +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/AgentCoreEntrance.java @@ -26,6 +26,7 @@ import com.huaweicloud.sermant.core.notification.NotificationManager; import com.huaweicloud.sermant.core.notification.SermantNotificationType; import com.huaweicloud.sermant.core.operation.OperationManager; +import com.huaweicloud.sermant.core.plugin.PluginManager; import com.huaweicloud.sermant.core.plugin.PluginSystemEntrance; import com.huaweicloud.sermant.core.plugin.agent.ByteEnhanceManager; import com.huaweicloud.sermant.core.plugin.agent.adviser.AdviserScheduler; @@ -99,4 +100,11 @@ public static void install(String artifact, Map argsMap, Instrum NotificationManager.doNotify(new NotificationInfo(SermantNotificationType.LOAD_COMPLETE, null)); } } + + /** + * agent卸载方法 + */ + public static void unInstall() { + PluginManager.unInstallAll(); + } } diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/command/AgentUnInstallCommandExecutor.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/command/AgentUnInstallCommandExecutor.java new file mode 100644 index 0000000000..cf52c9a794 --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/command/AgentUnInstallCommandExecutor.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. 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 com.huaweicloud.sermant.core.command; + +import com.huaweicloud.sermant.core.AgentCoreEntrance; +import com.huaweicloud.sermant.core.common.LoggerFactory; + +import java.util.logging.Logger; + +/** + * Agent卸载命令执行器 + * + * @author zhp + * @since 2023-09-09 + */ +public class AgentUnInstallCommandExecutor implements CommandExecutor { + private static final Logger LOGGER = LoggerFactory.getLogger(); + + @Override + public void execute(String commandContent) { + AgentCoreEntrance.unInstall(); + } +} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/command/Command.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/command/Command.java new file mode 100644 index 0000000000..53c6111a68 --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/command/Command.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. 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 com.huaweicloud.sermant.core.command; + +/** + * 动态安装卸载的指令枚举 + * + * @author zhp + * @since 2023-09-09 + */ +public enum Command { + /** + * 卸载agent指令 + */ + UNINSTALL_AGENT("UNINSTALL-AGENT", "卸载agent"), + /** + * 安装插件指令 + */ + INSTALL_PLUGINS("INSTALL-PLUGINS", "安装插件"), + /** + * 卸载插件指令 + */ + UNINSTALL_PLUGINS("UNINSTALL-PLUGINS", "卸载插件"); + private final String code; + + private final String desc; + + Command(String code, String desc) { + this.code = code; + this.desc = desc; + } + + public String getCode() { + return code; + } + + public String getDesc() { + return desc; + } +} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/command/CommandExecutor.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/command/CommandExecutor.java new file mode 100644 index 0000000000..dca3750535 --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/command/CommandExecutor.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. 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 com.huaweicloud.sermant.core.command; + +/** + * 指令执行器 + * + * @author zhp + * @since 2023-09-09 + */ +public interface CommandExecutor { + + /** + * 执行指令 + * + * @param commandContent 指令的具体内容 + */ + void execute(String commandContent); +} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/command/CommandProcessor.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/command/CommandProcessor.java new file mode 100644 index 0000000000..cf297706b3 --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/command/CommandProcessor.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. 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 com.huaweicloud.sermant.core.command; + +import com.huaweicloud.sermant.core.common.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * 命令处理器 + * + * @author zhp + * @since 2023-09-09 + */ +public class CommandProcessor { + /** + * 命令执行器Map + */ + private static final Map COMMAND_EXECUTOR_MAP = new HashMap<>(); + + private static final Logger LOGGER = LoggerFactory.getLogger(); + + static { + COMMAND_EXECUTOR_MAP.put(Command.INSTALL_PLUGINS.getCode(), new PluginsInstallCommandExecutor()); + COMMAND_EXECUTOR_MAP.put(Command.UNINSTALL_AGENT.getCode(), new AgentUnInstallCommandExecutor()); + COMMAND_EXECUTOR_MAP.put(Command.UNINSTALL_PLUGINS.getCode(), new PluginsUnInstallCommandExecutor()); + } + + /** + * 构造函数 + */ + private CommandProcessor() { + } + + /** + * 处理指令 + * + * @param command 指令 + * @param commandContent 指令内容 + */ + public static void process(String command, String commandContent) { + CommandExecutor commandExecutor = chooseExecutor(command); + if (commandExecutor == null) { + LOGGER.log(Level.SEVERE, "No corresponding command executor found"); + return; + } + commandExecutor.execute(commandContent); + } + + /** + * 选择命令执行器 + * + * @param command 命令 + * @return 命令执行器 + */ + public static CommandExecutor chooseExecutor(String command) { + return COMMAND_EXECUTOR_MAP.get(command); + } +} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/command/PluginsInstallCommandExecutor.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/command/PluginsInstallCommandExecutor.java new file mode 100644 index 0000000000..2b26cde5b2 --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/command/PluginsInstallCommandExecutor.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. 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 com.huaweicloud.sermant.core.command; + +import com.huaweicloud.sermant.core.common.LoggerFactory; +import com.huaweicloud.sermant.core.plugin.PluginManager; +import com.huaweicloud.sermant.core.utils.StringUtils; + +import java.util.Arrays; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +/** + * 插件安装命令执行器 + * + * @author zhp + * @since 2023-09-09 + */ +public class PluginsInstallCommandExecutor implements CommandExecutor { + private static final Logger LOGGER = LoggerFactory.getLogger(); + + @Override + public void execute(String commandContent) { + if (StringUtils.isEmpty(commandContent)) { + LOGGER.log(Level.FINER, "The installed plugin information is empty"); + return; + } + String[] pluginNames = commandContent.split(","); + PluginManager.install(Arrays.stream(pluginNames).collect(Collectors.toSet())); + } +} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/command/PluginsUnInstallCommandExecutor.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/command/PluginsUnInstallCommandExecutor.java new file mode 100644 index 0000000000..a68fa61ee4 --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/command/PluginsUnInstallCommandExecutor.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. 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 com.huaweicloud.sermant.core.command; + +import com.huaweicloud.sermant.core.common.LoggerFactory; +import com.huaweicloud.sermant.core.plugin.PluginManager; +import com.huaweicloud.sermant.core.utils.StringUtils; + +import java.util.Arrays; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +/** + * 插件卸载命令执行器 + * + * @author zhp + * @since 2023-09-09 + */ +public class PluginsUnInstallCommandExecutor implements CommandExecutor { + private static final Logger LOGGER = LoggerFactory.getLogger(); + + @Override + public void execute(String commandContent) { + if (StringUtils.isEmpty(commandContent)) { + LOGGER.log(Level.FINER, "The unInstalled plugin information is empty"); + return; + } + String[] pluginNames = commandContent.split(","); + PluginManager.unInstall(Arrays.stream(pluginNames).collect(Collectors.toSet())); + } +} diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/PluginManager.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/PluginManager.java index 551fffd693..da5f717638 100644 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/PluginManager.java +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/PluginManager.java @@ -275,6 +275,31 @@ private static File getServiceDir(String pluginPath) { return new File(pluginPath + File.separatorChar + PluginConstant.SERVICE_DIR_NAME); } + /** + * 安装插件 + * + * @param plugins 插件名称集合 + */ + public static void install(Set plugins) { + LOGGER.info("The following is the specific logic for plugin installation"); + } + + /** + * 卸载插件 + * + * @param plugins 插件名称集合 + */ + public static void unInstall(Set plugins) { + LOGGER.info("The following is the specific logic for uninstalling plugins"); + } + + /** + * 卸载所有插件 + */ + public static void unInstallAll() { + LOGGER.info("The following is the specific logic for uninstalling all plugins"); + } + /** * JarFile消费者 * diff --git a/sermant-agentcore/sermant-agentcore-premain/src/main/java/com/huaweicloud/sermant/premain/AgentLauncher.java b/sermant-agentcore/sermant-agentcore-premain/src/main/java/com/huaweicloud/sermant/premain/AgentLauncher.java index ee73740aaf..6cd574b9d4 100644 --- a/sermant-agentcore/sermant-agentcore-premain/src/main/java/com/huaweicloud/sermant/premain/AgentLauncher.java +++ b/sermant-agentcore/sermant-agentcore-premain/src/main/java/com/huaweicloud/sermant/premain/AgentLauncher.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.lang.instrument.Instrumentation; import java.net.URL; +import java.net.URLClassLoader; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -93,9 +94,13 @@ private static void launchAgent(String agentArgs, Instrumentation instrumentatio // agent core入口 LOGGER.log(Level.INFO, "Loading sermant agent, artifact is: " + artifact); - sermantClassLoader.loadClass("com.huaweicloud.sermant.core.AgentCoreEntrance") - .getDeclaredMethod("install", String.class, Map.class, Instrumentation.class, boolean.class) - .invoke(null, artifact, argsMap, instrumentation, isDynamic); + if (isDynamic) { + processDynamicInstructions(argsMap, sermantClassLoader); + } else { + sermantClassLoader.loadClass("com.huaweicloud.sermant.core.AgentCoreEntrance") + .getDeclaredMethod("install", String.class, Map.class, Instrumentation.class, boolean.class) + .invoke(null, artifact, argsMap, instrumentation, isDynamic); + } LOGGER.log(Level.INFO, "Load sermant done, artifact is: " + artifact); SermantManager.updateSermantStatus(artifact, true); } catch (Exception e) { @@ -137,4 +142,26 @@ private static void loadGodLib(Instrumentation instrumentation) throws IOExcepti } } } + + /** + * 动态安装卸载命令解析 + * + * @param argsMap 参数Map + * @param sermantClassLoader sermant类加载器 + * @throws Exception 方法调用异常 + */ + private static void processDynamicInstructions(Map argsMap, URLClassLoader sermantClassLoader) + throws Exception { + String[] instructions = {"UNINSTALL-AGENT", "UNINSTALL-PLUGINS", "INSTALL-PLUGINS"}; + for (String instruction : instructions) { + if (argsMap.containsKey(instruction)) { + String value = argsMap.get(instruction) == null ? null : argsMap.get(instruction).toString(); + sermantClassLoader.loadClass("com.huaweicloud.sermant.core.command.CommandProcessor") + .getDeclaredMethod("process", String.class, String.class) + .invoke(null, instruction, value); + return; + } + } + LOGGER.warning("dynamic installation and uninstallation instructions not recognized"); + } } \ No newline at end of file diff --git a/sermant-agentcore/sermant-agentcore-premain/src/main/java/com/huaweicloud/sermant/premain/common/BootArgsBuilder.java b/sermant-agentcore/sermant-agentcore-premain/src/main/java/com/huaweicloud/sermant/premain/common/BootArgsBuilder.java index b52c71474d..0c9206c5b8 100644 --- a/sermant-agentcore/sermant-agentcore-premain/src/main/java/com/huaweicloud/sermant/premain/common/BootArgsBuilder.java +++ b/sermant-agentcore/sermant-agentcore-premain/src/main/java/com/huaweicloud/sermant/premain/common/BootArgsBuilder.java @@ -26,6 +26,8 @@ import java.util.Map; import java.util.Properties; import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * 启动参数构建器 @@ -37,6 +39,16 @@ public abstract class BootArgsBuilder { private static final Logger LOGGER = LoggerUtils.getLogger(); + /** + * 参数值的下标 + */ + private static final int VALUE_INDEX = 2; + + /** + * 参数编码得下标 + */ + private static final int KEY_INDEX = 1; + /** * 构建启动参数 * @@ -69,6 +81,13 @@ private static Map toArgsMap(String args) { argsMap.put(arg.substring(0, index).trim(), arg.substring(index + 1).trim()); } } + Pattern arrayPattern = Pattern.compile("([\\w-]+):\\[([^\\]]+)]"); + Matcher arrayMatcher = arrayPattern.matcher(args); + while (arrayMatcher.find()) { + String arrayKey = arrayMatcher.group(KEY_INDEX); + String arrayValue = arrayMatcher.group(VALUE_INDEX); + argsMap.put(arrayKey, arrayValue); + } return argsMap; } diff --git a/sermant-agentcore/sermant-agentcore-premain/src/test/java/com/huaweicloud/sermant/premain/common/BootArgsBuilderTest.java b/sermant-agentcore/sermant-agentcore-premain/src/test/java/com/huaweicloud/sermant/premain/common/BootArgsBuilderTest.java index 696ee70a15..aa2aa7fdc6 100644 --- a/sermant-agentcore/sermant-agentcore-premain/src/test/java/com/huaweicloud/sermant/premain/common/BootArgsBuilderTest.java +++ b/sermant-agentcore/sermant-agentcore-premain/src/test/java/com/huaweicloud/sermant/premain/common/BootArgsBuilderTest.java @@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals; import org.junit.AfterClass; +import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; @@ -105,4 +106,17 @@ private static void setEnv(Map envMap) throws NoSuchFieldException, IllegalAcces } } } + + /** + * 测试参数解析 + */ + @Test + public void testParseArgs(){ + String agentArgs = "UNINSTALL-PLUGINS:[monitor],appName=test,INSTALL-PLUGINS=removal,server.port=9000"; + Map argsMap = BootArgsBuilder.build(agentArgs); + Assert.assertEquals("monitor", argsMap.get("UNINSTALL-PLUGINS")); + Assert.assertEquals("test", argsMap.get("appName")); + Assert.assertEquals("9000", argsMap.get("server.port")); + Assert.assertEquals("removal", argsMap.get("INSTALL-PLUGINS")); + } } \ No newline at end of file