Skip to content

Commit

Permalink
Merge branch 'main' into develop/v3
Browse files Browse the repository at this point in the history
# Conflicts:
#	README.md
#	pom.xml
#	src/main/java/net/azisaba/kuvel/Kuvel.java
#	src/main/java/net/azisaba/kuvel/KuvelServiceHandler.java
#	src/main/java/net/azisaba/kuvel/config/KuvelConfig.java
#	src/main/java/net/azisaba/kuvel/discovery/impl/redis/RedisLoadBalancerDiscovery.java
#	src/main/java/net/azisaba/kuvel/discovery/impl/redis/RedisServerDiscovery.java
  • Loading branch information
acrylic-style committed Aug 17, 2024
2 parents c8165b2 + 4a8e59c commit d600a4b
Show file tree
Hide file tree
Showing 11 changed files with 119 additions and 49 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ jobs:
permissions:
contents: read
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: "17"
distribution: "adopt"
Expand Down
11 changes: 10 additions & 1 deletion 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: "develop" # Redisサーバーが同じかつgroup-nameが同じサーバー間でのみ名前同期が行われます
connection:
Expand All @@ -29,6 +30,14 @@ label-selectors:
- "kuvel.azisaba.net/enable-server-discovery=true"
```
環境変数を指定してKuvelを設定することもできます。環境変数はconfig.ymlよりも優先され、以下の項目が設定可能です:
- `KUVEL_NAMESPACE`
- `KUVEL_REDIS_GROUPNAME`
- `KUVEL_REDIS_CONNECTION_HOSTNAME`
- `KUVEL_REDIS_CONNECTION_PORT`
- `KUVEL_REDIS_CONNECTION_USERNAME`
- `KUVEL_REDIS_CONNECTION_PASSWORD`

Kuvelがサーバーを監視するためには、Kubernetesに対して権限を要求しなければなりません。VelocityのPodに対してPodとReplicaSetのget/list/watchを許可してください

```yml
Expand Down Expand Up @@ -167,4 +176,4 @@ Kubernetesクラスター内ではPodがほぼ同時に作成されることが

## ライセンス

[GNU General Public License v3.0](LICENSE)
[GNU General Public License v3.0](LICENSE)
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. The config file requires initial setup as seen below.

```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 instances.
redis:
group-name: "develop"
Expand All @@ -33,6 +35,10 @@ label-selectors:
- "kuvel.azisaba.net/enable-server-discovery=true"
```
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. For Velocity pods, please allow get/list/watch to Pods
and ReplicaSets.

Expand Down
22 changes: 14 additions & 8 deletions 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>3.0.0-rc.2</version>
<version>3.0.0-rc3</version>
<packaging>jar</packaging>

<name>${project.artifactId}</name>
Expand All @@ -32,7 +32,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<version>3.13.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
Expand All @@ -41,7 +41,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.1</version>
<version>3.6.0</version>
<executions>
<execution>
<phase>package</phase>
Expand Down Expand Up @@ -74,28 +74,34 @@
<dependency>
<groupId>com.velocitypowered</groupId>
<artifactId>velocity-api</artifactId>
<version>3.1.0</version>
<version>3.1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-client-api</artifactId>
<version>6.13.3</version>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-client</artifactId>
<version>6.3.1</version>
<version>6.13.3</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.3.1</version>
<version>5.1.4</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
<version>3.16.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<version>1.18.34</version>
<scope>provided</scope>
</dependency>
</dependencies>
Expand Down
25 changes: 17 additions & 8 deletions src/main/java/net/azisaba/kuvel/Kuvel.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,19 @@
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 io.fabric8.kubernetes.client.KubernetesClientBuilder;
import java.util.Map.Entry;

import java.io.File;
import java.nio.file.Path;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

import io.fabric8.kubernetes.client.KubernetesClientBuilder;
import lombok.Getter;
import net.azisaba.kuvel.config.KuvelConfig;
import net.azisaba.kuvel.discovery.impl.redis.RedisLoadBalancerDiscovery;
Expand All @@ -25,7 +31,7 @@
@Plugin(
id = "kuvel",
name = "Kuvel",
version = "3.0.0-rc",
version = "3.0.0-rc2",
url = "https://github.com/AzisabaNetwork/Kuvel",
description =
"Server-discovery Velocity plugin for Minecraft servers running in a Kubernetes cluster.",
Expand All @@ -35,6 +41,7 @@ public class Kuvel {

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

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

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

@Subscribe
Expand All @@ -64,8 +72,7 @@ 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;
}

Expand All @@ -75,11 +82,11 @@ public void onProxyInitialization(ProxyInitializeEvent event) {
}

getLogger().info("Loaded " + kuvelConfig.getLabelSelectors().size() + " selectors:");
for (Entry<String, String> entry : kuvelConfig.getLabelSelectors().entrySet()) {
for (Map.Entry<String, String> entry : kuvelConfig.getLabelSelectors().entrySet()) {
getLogger().info(" - " + entry.getKey() + ": " + entry.getValue());
}

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

Objects.requireNonNull(kuvelConfig.getRedisConnectionData());
Objects.requireNonNull(kuvelConfig.getProxyGroupName());
Expand All @@ -105,6 +112,7 @@ public void onProxyInitialization(ProxyInitializeEvent event) {
new RedisLoadBalancerDiscovery(
client,
this,
kuvelConfig.getNamespace(),
kuvelConfig.getRedisConnectionData().createJedisPool(),
kuvelConfig.getProxyGroupName(),
redisConnectionLeader,
Expand All @@ -114,6 +122,7 @@ public void onProxyInitialization(ProxyInitializeEvent event) {
new RedisServerDiscovery(
client,
this,
kuvelConfig.getNamespace(),
kuvelConfig.getRedisConnectionData().createJedisPool(),
kuvelConfig.getProxyGroupName(),
redisConnectionLeader,
Expand Down
9 changes: 5 additions & 4 deletions src/main/java/net/azisaba/kuvel/KuvelServiceHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.PodList;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.dsl.FilterWatchListDeletable;
import io.fabric8.kubernetes.client.dsl.PodResource;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
Expand All @@ -16,6 +14,8 @@
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Nullable;

import io.fabric8.kubernetes.client.dsl.PodResource;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import net.azisaba.kuvel.discovery.LoadBalancerDiscovery;
Expand All @@ -30,6 +30,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 @@ -128,7 +129,7 @@ public Optional<LoadBalancer> getLoadBalancer(String serverName) {
private void updateLoadBalancerEndpoints(LoadBalancer loadBalancer) {
// TODO: This may be replaced by more improved function
FilterWatchListDeletable<Pod, PodList, PodResource> request = client.pods()
.inAnyNamespace();
.inNamespace(namespace);

for (Entry<String, String> e : plugin.getKuvelConfig().getLabelSelectors().entrySet()) {
request = request.withLabel(e.getKey(), e.getValue());
Expand Down Expand Up @@ -264,7 +265,7 @@ public boolean registerPod(Pod pod, String serverName) {
*/
public void registerPod(String podUid, String serverName) {
FilterWatchListDeletable<Pod, PodList, PodResource> request = client.pods()
.inAnyNamespace();
.inNamespace(namespace);

for (Entry<String, String> e : plugin.getKuvelConfig().getLabelSelectors().entrySet()) {
request = request.withLabel(e.getKey(), e.getValue());
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 @@ -4,6 +4,7 @@
import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import javax.annotation.Nullable;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
Expand All @@ -16,8 +17,9 @@ 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;
Expand All @@ -26,25 +28,54 @@ public class KuvelConfig {
private final HashMap<String, String> labelSelectors = new HashMap<>();

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));

if (conf.isSet("label-selectors")) {
conf.getStringList("label-selectors").forEach(s -> {
Expand Down
Loading

0 comments on commit d600a4b

Please sign in to comment.