mirror of https://github.com/halo-dev/halo
refactor: initialize default config value by settings after plugin installation (#3161)
#### What type of PR is this? /kind improvement /area core /milestone 2.2.x #### What this PR does / why we need it: 插件安装后根据配置的 settingName 读取默认值创建 ConfigMap 如果配置了 settingName 而没有配置 configMapName 则会自动填充为 uuid 并创建一个 ConfigMap #### Which issue(s) this PR fixes: Fixes #3160 #### Special notes for your reviewer: /cc @halo-dev/sig-halo #### Does this PR introduce a user-facing change? ```release-note 插件安装后自动初始化 Setting 的默认值 ```pull/3142/head^2
parent
2241c08371
commit
ca4e93d4bb
|
@ -18,9 +18,14 @@ import org.pf4j.PluginRuntimeException;
|
|||
import org.pf4j.PluginState;
|
||||
import org.pf4j.PluginWrapper;
|
||||
import org.pf4j.RuntimeMode;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
import run.halo.app.core.extension.Plugin;
|
||||
import run.halo.app.core.extension.ReverseProxy;
|
||||
import run.halo.app.core.extension.Setting;
|
||||
import run.halo.app.core.extension.theme.SettingUtils;
|
||||
import run.halo.app.extension.ConfigMap;
|
||||
import run.halo.app.extension.ExtensionClient;
|
||||
import run.halo.app.extension.Metadata;
|
||||
import run.halo.app.extension.controller.Controller;
|
||||
|
@ -32,6 +37,7 @@ import run.halo.app.infra.utils.PathUtils;
|
|||
import run.halo.app.plugin.HaloPluginManager;
|
||||
import run.halo.app.plugin.PluginConst;
|
||||
import run.halo.app.plugin.PluginStartingError;
|
||||
import run.halo.app.plugin.event.PluginCreatedEvent;
|
||||
import run.halo.app.plugin.resources.BundleResourceUtils;
|
||||
|
||||
/**
|
||||
|
@ -47,6 +53,7 @@ public class PluginReconciler implements Reconciler<Request> {
|
|||
private static final String FINALIZER_NAME = "plugin-protection";
|
||||
private final ExtensionClient client;
|
||||
private final HaloPluginManager haloPluginManager;
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
|
||||
@Override
|
||||
public Result reconcile(Request request) {
|
||||
|
@ -146,6 +153,8 @@ public class PluginReconciler implements Reconciler<Request> {
|
|||
plugin.statusNonNull().setLastStartTime(Instant.now());
|
||||
}
|
||||
|
||||
settingDefaultConfig(plugin);
|
||||
|
||||
Plugin.PluginStatus status = plugin.statusNonNull();
|
||||
String jsBundlePath =
|
||||
BundleResourceUtils.getJsBundlePath(haloPluginManager, pluginName);
|
||||
|
@ -257,6 +266,9 @@ public class PluginReconciler implements Reconciler<Request> {
|
|||
}
|
||||
newFinalizers.add(FINALIZER_NAME);
|
||||
client.update(plugin);
|
||||
|
||||
eventPublisher.publishEvent(
|
||||
new PluginCreatedEvent(this, plugin.getMetadata().getName()));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -321,6 +333,35 @@ public class PluginReconciler implements Reconciler<Request> {
|
|||
}, () -> client.create(reverseProxy));
|
||||
}
|
||||
|
||||
private void settingDefaultConfig(Plugin plugin) {
|
||||
Assert.notNull(plugin, "The plugin must not be null.");
|
||||
if (StringUtils.isBlank(plugin.getSpec().getSettingName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String configMapNameToUse = plugin.getSpec().getConfigMapName();
|
||||
if (StringUtils.isBlank(configMapNameToUse)) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean existConfigMap = client.fetch(ConfigMap.class, configMapNameToUse)
|
||||
.isPresent();
|
||||
if (existConfigMap) {
|
||||
return;
|
||||
}
|
||||
|
||||
client.fetch(Setting.class, plugin.getSpec().getSettingName())
|
||||
.ifPresent(setting -> {
|
||||
var data = SettingUtils.settingDefinedDefaultValueMap(setting);
|
||||
// Create with or without default value
|
||||
ConfigMap configMap = new ConfigMap();
|
||||
configMap.setMetadata(new Metadata());
|
||||
configMap.getMetadata().setName(configMapNameToUse);
|
||||
configMap.setData(data);
|
||||
client.create(configMap);
|
||||
});
|
||||
}
|
||||
|
||||
static String initialReverseProxyName(String pluginName) {
|
||||
return pluginName + "-system-generated-reverse-proxy";
|
||||
}
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
package run.halo.app.plugin;
|
||||
|
||||
import io.micrometer.common.util.StringUtils;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
import reactor.core.Exceptions;
|
||||
import reactor.core.publisher.Mono;
|
||||
import run.halo.app.core.extension.Plugin;
|
||||
import run.halo.app.extension.ReactiveExtensionClient;
|
||||
import run.halo.app.extension.controller.Controller;
|
||||
import run.halo.app.extension.controller.ControllerBuilder;
|
||||
import run.halo.app.extension.controller.DefaultController;
|
||||
import run.halo.app.extension.controller.DefaultDelayQueue;
|
||||
import run.halo.app.extension.controller.Reconciler;
|
||||
import run.halo.app.extension.controller.RequestQueue;
|
||||
import run.halo.app.plugin.event.PluginCreatedEvent;
|
||||
|
||||
/**
|
||||
* Plugin event reconciler.
|
||||
* If other plugin events need to be reconciled, consider sharing this reconciler.
|
||||
*
|
||||
* @author guqing
|
||||
* @since 2.2.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class PluginCreatedEventReconciler
|
||||
implements Reconciler<PluginCreatedEvent>, SmartLifecycle {
|
||||
|
||||
private final RequestQueue<PluginCreatedEvent> pluginEventQueue;
|
||||
|
||||
private final ReactiveExtensionClient client;
|
||||
|
||||
private final Controller pluginEventController;
|
||||
|
||||
private boolean running = false;
|
||||
|
||||
public PluginCreatedEventReconciler(ReactiveExtensionClient client) {
|
||||
this.client = client;
|
||||
pluginEventQueue = new DefaultDelayQueue<>(Instant::now);
|
||||
pluginEventController = this.setupWith(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result reconcile(PluginCreatedEvent pluginCreatedEvent) {
|
||||
String pluginName = pluginCreatedEvent.getPluginName();
|
||||
try {
|
||||
ensureConfigMapNameNotEmptyIfSettingIsNotBlank(pluginName);
|
||||
} catch (InterruptedException e) {
|
||||
throw Exceptions.propagate(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Controller setupWith(ControllerBuilder builder) {
|
||||
return new DefaultController<>(
|
||||
this.getClass().getName(),
|
||||
this,
|
||||
pluginEventQueue,
|
||||
null,
|
||||
Duration.ofMillis(100),
|
||||
Duration.ofSeconds(1000)
|
||||
);
|
||||
}
|
||||
|
||||
@EventListener(PluginCreatedEvent.class)
|
||||
public void handlePluginCreated(PluginCreatedEvent pluginCreatedEvent) {
|
||||
pluginEventQueue.addImmediately(pluginCreatedEvent);
|
||||
}
|
||||
|
||||
void ensureConfigMapNameNotEmptyIfSettingIsNotBlank(String pluginName)
|
||||
throws InterruptedException {
|
||||
client.fetch(Plugin.class, pluginName)
|
||||
.switchIfEmpty(Mono.error(new IllegalStateException("Plugin not found: " + pluginName)))
|
||||
.filter(plugin -> StringUtils.isNotBlank(plugin.getSpec().getSettingName()))
|
||||
.filter(plugin -> StringUtils.isBlank(plugin.getSpec().getConfigMapName()))
|
||||
.doOnNext(plugin -> {
|
||||
// has settingName value but configMapName not configured
|
||||
plugin.getSpec().setConfigMapName(UUID.randomUUID().toString());
|
||||
})
|
||||
.flatMap(client::update)
|
||||
.block();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
pluginEventController.start();
|
||||
running = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
running = false;
|
||||
pluginEventController.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return running;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package run.halo.app.plugin.event;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import run.halo.app.core.extension.Plugin;
|
||||
|
||||
/**
|
||||
* The {@link Plugin} created event.
|
||||
*
|
||||
* @author guqing
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Getter
|
||||
public class PluginCreatedEvent extends ApplicationEvent {
|
||||
private final String pluginName;
|
||||
|
||||
public PluginCreatedEvent(Object source, String pluginName) {
|
||||
super(source);
|
||||
this.pluginName = pluginName;
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ import org.pf4j.PluginState;
|
|||
import org.pf4j.PluginWrapper;
|
||||
import org.pf4j.RuntimeMode;
|
||||
import org.skyscreamer.jsonassert.JSONAssert;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import run.halo.app.core.extension.Plugin;
|
||||
import run.halo.app.core.extension.ReverseProxy;
|
||||
import run.halo.app.extension.ExtensionClient;
|
||||
|
@ -55,11 +56,14 @@ class PluginReconcilerTest {
|
|||
@Mock
|
||||
PluginWrapper pluginWrapper;
|
||||
|
||||
@Mock
|
||||
ApplicationEventPublisher eventPublisher;
|
||||
|
||||
PluginReconciler pluginReconciler;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
pluginReconciler = new PluginReconciler(extensionClient, haloPluginManager);
|
||||
pluginReconciler = new PluginReconciler(extensionClient, haloPluginManager, eventPublisher);
|
||||
lenient().when(haloPluginManager.validatePluginVersion(any())).thenReturn(true);
|
||||
lenient().when(haloPluginManager.getSystemVersion()).thenReturn("0.0.0");
|
||||
lenient().when(haloPluginManager.getPlugin(any())).thenReturn(pluginWrapper);
|
||||
|
|
Loading…
Reference in New Issue