Skip to content

Commit

Permalink
Merge pull request #43 from Phoenix616/configurable-namespace
Browse files Browse the repository at this point in the history
  • Loading branch information
acrylic-style authored Mar 24, 2024
2 parents 0ad67e1 + 352dd29 commit babf766
Show file tree
Hide file tree
Showing 10 changed files with 73 additions and 21 deletions.
1 change: 1 addition & 0 deletions README-JP.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Pluginは [Releases](https://github.com/AzisabaNetwork/Kuvel/releases/latest)
からダウンロードできます。 `Kuvel.jar` をダウンロードしVelocityに導入してください。ダウンロード後、コンフィグの設定を行ってください。

```yml
namespace: ""
redis:
group-name: "production" # Redisサーバーが同じかつgroup-nameが同じサーバー間でのみ名前同期が行われます
connection:
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ from [Releases](https://github.com/AzisabaNetwork/Kuvel/releases/latest). Downlo
install it into Velocity plugins directory. Also, you have to fill in the configuration file.

```yml
# The kubernetes namespace to use for the server discovery.
namespace: ""
# Server name synchronization by Redis is required in load-balanced environments using multiple Velocity.
redis:
group-name: "production"
Expand All @@ -29,6 +31,10 @@ redis:
password: "password"
```
Alternatively you can use environment variables to configure Kuvel. The environment variable will override
the config.yml and are `KUVEL_NAMESPACE`, `KUVEL_REDIS_GROUPNAME`, `KUVEL_REDIS_CONNECTION_HOSTNAME`,
`KUVEL_REDIS_CONNECTION_PORT`, `KUVEL_REDIS_CONNECTION_USERNAME`, and `KUVEL_REDIS_CONNECTION_PASSWORD`.

In order for Kuvel to monitor the server, you must request permission from Kubernetes to allow
Velocity pods discovery Minecraft servers. For Velocity pods, please allow get/list/watch to Pods
and ReplicaSets.
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>net.azisaba</groupId>
<artifactId>Kuvel</artifactId>
<version>2.0.2</version>
<version>2.1.0</version>
<packaging>jar</packaging>

<name>${project.artifactId}</name>
Expand Down
19 changes: 13 additions & 6 deletions src/main/java/net/azisaba/kuvel/Kuvel.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.plugin.annotation.DataDirectory;
import com.velocitypowered.api.proxy.ProxyServer;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient;

import java.io.File;
import java.nio.file.Path;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import lombok.Getter;
import net.azisaba.kuvel.config.KuvelConfig;
import net.azisaba.kuvel.discovery.impl.redis.RedisLoadBalancerDiscovery;
Expand All @@ -20,11 +23,12 @@
import net.azisaba.kuvel.redis.ProxyIdProvider;
import net.azisaba.kuvel.redis.RedisConnectionLeader;
import net.azisaba.kuvel.redis.RedisSubscriberExecutor;
import org.slf4j.Logger;

@Plugin(
id = "kuvel",
name = "Kuvel",
version = "2.0.2",
version = "2.1.0",
url = "https://github.com/AzisabaNetwork/Kuvel",
description =
"Server-discovery Velocity plugin for Minecraft servers running in a Kubernetes cluster.",
Expand All @@ -34,6 +38,7 @@ public class Kuvel {

private final ProxyServer proxy;
private final Logger logger;
private final File dataDirectory;

private KubernetesClient client;
private KuvelServiceHandler kuvelServiceHandler;
Expand All @@ -44,9 +49,10 @@ public class Kuvel {
private KuvelConfig kuvelConfig;

@Inject
public Kuvel(ProxyServer server, Logger logger) {
public Kuvel(ProxyServer server, Logger logger, @DataDirectory Path dataDirectory) {
this.proxy = server;
this.logger = logger;
this.dataDirectory = dataDirectory.toFile();
}

@Subscribe
Expand All @@ -57,12 +63,11 @@ public void onProxyInitialization(ProxyInitializeEvent event) {
try {
kuvelConfig.load();
} catch (Exception e) {
logger.severe("Failed to load config file. Plugin feature will be disabled.");
e.printStackTrace();
logger.error("Failed to load config file. Plugin feature will be disabled.", e);
return;
}

kuvelServiceHandler = new KuvelServiceHandler(this, client);
kuvelServiceHandler = new KuvelServiceHandler(this, client, kuvelConfig.getNamespace());

Objects.requireNonNull(kuvelConfig.getRedisConnectionData());
Objects.requireNonNull(kuvelConfig.getProxyGroupName());
Expand All @@ -88,6 +93,7 @@ public void onProxyInitialization(ProxyInitializeEvent event) {
new RedisLoadBalancerDiscovery(
client,
this,
kuvelConfig.getNamespace(),
kuvelConfig.getRedisConnectionData().createJedisPool(),
kuvelConfig.getProxyGroupName(),
redisConnectionLeader,
Expand All @@ -97,6 +103,7 @@ public void onProxyInitialization(ProxyInitializeEvent event) {
new RedisServerDiscovery(
client,
this,
kuvelConfig.getNamespace(),
kuvelConfig.getRedisConnectionData().createJedisPool(),
kuvelConfig.getProxyGroupName(),
redisConnectionLeader,
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/net/azisaba/kuvel/KuvelServiceHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public class KuvelServiceHandler {

private final Kuvel plugin;
private final KubernetesClient client;
private final String namespace;
private final HashMap<String, LoadBalancer> loadBalancerServerMap = new HashMap<>();

private final UidAndServerNameMap podUidAndServerNameMap = new UidAndServerNameMap();
Expand Down Expand Up @@ -125,7 +126,7 @@ private void updateLoadBalancerEndpoints(LoadBalancer loadBalancer) {
List<Pod> pods =
client
.pods()
.inAnyNamespace()
.inNamespace(namespace)
.withLabel(LabelKeys.ENABLE_SERVER_DISCOVERY.getKey(), "true")
.list()
.getItems();
Expand Down Expand Up @@ -251,7 +252,7 @@ public void registerPod(String podUid, String serverName) {
Optional<Pod> pod =
client
.pods()
.inAnyNamespace()
.inNamespace(namespace)
.withLabel(LabelKeys.ENABLE_SERVER_DISCOVERY.getKey(), "true")
.list()
.getItems()
Expand Down
45 changes: 38 additions & 7 deletions src/main/java/net/azisaba/kuvel/config/KuvelConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.File;
import java.io.IOException;
import java.util.Map;
import javax.annotation.Nullable;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
Expand All @@ -14,31 +15,61 @@ public class KuvelConfig {

private final Kuvel plugin;

private static final String CONFIG_FILE_PATH = "./plugins/Kuvel/config.yml";
private static final String CONFIG_FILE_NAME = "config.yml";

@Nullable private String namespace;
private boolean redisEnabled;
@Nullable private RedisConnectionData redisConnectionData;
@Nullable private String proxyGroupName;

public void load() throws IOException {
VelocityConfigLoader conf = VelocityConfigLoader.load(new File(CONFIG_FILE_PATH));
File uppercaseDataFolder = new File(plugin.getDataDirectory().getParentFile(), "Kuvel");
if (uppercaseDataFolder.exists() && !plugin.getDataDirectory().exists()) {
if (uppercaseDataFolder.renameTo(plugin.getDataDirectory())) {
plugin
.getLogger()
.info(
"Successfully renamed the data folder to use a lowercase name.");
} else {
plugin
.getLogger()
.warn(
"Failed to rename the data folder to be lowercase. Please manually rename the data folder to 'kuvel'.");
}
}

VelocityConfigLoader conf = VelocityConfigLoader.load(new File(plugin.getDataDirectory(), CONFIG_FILE_NAME));
conf.saveDefaultConfig();

String hostname = conf.getString("redis.connection.hostname");
Map<String, String> env = System.getenv();

namespace = env.getOrDefault("KUVEL_NAMESPACE", conf.getString("namespace", null));

String hostname = env.getOrDefault("KUVEL_REDIS_CONNECTION_HOSTNAME", conf.getString("redis.connection.hostname"));
int port = conf.getInt("redis.connection.port", -1);
String username = conf.getString("redis.connection.username");
String password = conf.getString("redis.connection.password");
if (env.containsKey("KUVEL_REDIS_CONNECTION_PORT")) {
try {
port = Integer.parseInt(env.get("KUVEL_REDIS_CONNECTION_PORT"));
} catch (NumberFormatException e) {
plugin
.getLogger()
.warn(
"Invalid port number for Redis connection specified in KUVEL_REDIS_CONNECTION_PORT environment variable. Using port " + port + " from config.yml.");
}
}
String username = env.getOrDefault("KUVEL_REDIS_CONNECTION_USERNAME", conf.getString("redis.connection.username"));
String password = env.getOrDefault("KUVEL_REDIS_CONNECTION_PASSWORD", conf.getString("redis.connection.password"));

if (hostname == null || port <= 0) {
redisEnabled = false;
plugin
.getLogger()
.warning(
.warn(
"Redis is enabled, but hostname or port is invalid. Redis sync will be disabled.");
} else {
redisConnectionData = new RedisConnectionData(hostname, port, username, password);
}

proxyGroupName = conf.getString("redis.group-name", null);
proxyGroupName = env.getOrDefault("KUVEL_REDIS_GROUPNAME", conf.getString("redis.group-name", null));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class RedisLoadBalancerDiscovery implements LoadBalancerDiscovery {

private final KubernetesClient client;
private final Kuvel plugin;
private final String namespace;
private final JedisPool jedisPool;
private final String groupName;
private final RedisConnectionLeader redisConnectionLeader;
Expand All @@ -55,7 +56,7 @@ public void start() {
client
.apps()
.replicaSets()
.inAnyNamespace()
.inNamespace(namespace)
.withLabel(LabelKeys.ENABLE_SERVER_DISCOVERY.getKey(), "true")
.withLabel(LabelKeys.PREFERRED_SERVER_NAME.getKey())
.list()
Expand Down Expand Up @@ -241,7 +242,7 @@ public void registerLoadBalancersForStartup() {
client
.apps()
.replicaSets()
.inAnyNamespace()
.inNamespace(namespace)
.withLabel(LabelKeys.ENABLE_SERVER_DISCOVERY.getKey(), "true")
.withLabel(LabelKeys.PREFERRED_SERVER_NAME.getKey())
.list()
Expand Down Expand Up @@ -272,7 +273,7 @@ private ReplicaSet getReplicaSetFromUid(String uid) {
return client
.apps()
.replicaSets()
.inAnyNamespace()
.inNamespace(namespace)
.withLabel(LabelKeys.ENABLE_SERVER_DISCOVERY.getKey(), "true")
.withLabel(LabelKeys.PREFERRED_SERVER_NAME.getKey())
.list()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class RedisServerDiscovery implements ServerDiscovery {

private final KubernetesClient client;
private final Kuvel plugin;
private final String namespace;
private final JedisPool jedisPool;
private final String groupName;
private final RedisConnectionLeader redisConnectionLeader;
Expand All @@ -52,7 +53,7 @@ public void start() {
List<Pod> podList =
client
.pods()
.inAnyNamespace()
.inNamespace(namespace)
.withLabel(LabelKeys.ENABLE_SERVER_DISCOVERY.getKey(), "true")
.list()
.getItems();
Expand Down Expand Up @@ -113,7 +114,7 @@ public HashMap<String, Pod> getServersForStartup() {

client
.pods()
.inAnyNamespace()
.inNamespace(namespace)
.withLabel(LabelKeys.ENABLE_SERVER_DISCOVERY.getKey(), "true")
.withField("status.phase", "Running")
.list()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ private void runDiscoveryTask() {
new RedisLoadBalancerDiscovery(
plugin.getClient(),
plugin,
plugin.getKuvelConfig().getNamespace(),
plugin.getKuvelConfig().getRedisConnectionData().createJedisPool(),
plugin.getKuvelConfig().getProxyGroupName(),
this,
Expand All @@ -131,6 +132,7 @@ private void runDiscoveryTask() {
new RedisServerDiscovery(
plugin.getClient(),
plugin,
plugin.getKuvelConfig().getNamespace(),
plugin.getKuvelConfig().getRedisConnectionData().createJedisPool(),
plugin.getKuvelConfig().getProxyGroupName(),
this,
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/config.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# The kubernetes namespace to use for the server discovery.
namespace: ""
# Server name synchronization by Redis is required in load-balanced environments using multiple Velocity.
redis:
group-name: "production"
Expand Down

0 comments on commit babf766

Please sign in to comment.