Skip to content

Commit

Permalink
feat: create proxy directory plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremylvln committed Mar 5, 2022
1 parent 11aae37 commit 791a4d9
Show file tree
Hide file tree
Showing 11 changed files with 204 additions and 39 deletions.
35 changes: 29 additions & 6 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ on:
branches:
- main

permissions:
contents: read
packages: write

jobs:
build-operator:
deploy-operator:
runs-on: ubuntu-latest

permissions:
contents: read
packages: write

steps:
- name: Checkout
uses: actions/checkout@v2
Expand All @@ -21,7 +21,7 @@ jobs:
uses: docker/setup-buildx-action@v1

- name: Login to GitHub Container Registry
uses: docker/login-action@v1
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.actor }}
Expand All @@ -34,3 +34,26 @@ jobs:
tags: ghcr.io/iamblueslime/shulker-operator:latest
cache-from: type=registry,ref=ghcr.io/iamblueslime/shulker-operator:latest
cache-to: type=inline

deploy-plugins:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v2

- name: Setup Java
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'adopt'

- name: Validate Gradle wrapper
uses: gradle/wrapper-validation-action@v1

- name: Publish packages
uses: gradle/gradle-build-action@v2
with:
arguments: publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
13 changes: 13 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,17 @@ configure(subprojects.findAll {
dependencies {
testImplementation 'junit:junit:4.13'
}

publishing {
repositories {
maven {
name = "GitHubPackages"
url = "https://maven.pkg.github.com/IamBlueSlime/${it.name}"
credentials {
username = System.getenv("GITHUB_ACTOR")
password = System.getenv("GITHUB_TOKEN")
}
}
}
}
}
7 changes: 7 additions & 0 deletions internal/resource/proxy/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,13 @@ func (b *ProxyDeploymentDeploymentBuilder) getDeploymentEnv() []corev1.EnvVar {
},
}

if b.Instance.Spec.ClusterRef != nil {
env = append(env, corev1.EnvVar{
Name: "SHULKER_CLUSTER_NAME",
Value: b.Instance.Spec.ClusterRef.Name,
})
}

env = append(env, b.Instance.Spec.PodOverrides.Env...)

return env
Expand Down
1 change: 0 additions & 1 deletion support/settings.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
include ':support:shulker-api'
include ':support:shulker-crds'
include ':support:shulker-proxy-directory'
23 changes: 0 additions & 23 deletions support/shulker-api/build.gradle

This file was deleted.

This file was deleted.

4 changes: 4 additions & 0 deletions support/shulker-crds/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
archivesBaseName = "ShulkerCrds"
version = '0.0.1'

dependencies {
compileOnly group: 'io.kubernetes', name: 'client-java', version: '10.0.0'
}

task generateCrds(type: Exec) {
commandLine 'bash ./generate-crds.sh'
}
Expand Down
4 changes: 3 additions & 1 deletion support/shulker-proxy-directory/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ archivesBaseName = "ShulkerProxyDirectory"
version = '0.0.1'

dependencies {
implementation project(':support:shulker-api')
implementation project(':support:shulker-crds')
compileOnly group: 'net.md-5', name: 'bungeecord-api', version: '1.18-R0.1-SNAPSHOT'
implementation group: 'io.kubernetes', name: 'client-java', version: '10.0.0'
}

jar {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package io.shulkermc.directory;

import io.kubernetes.client.informer.ResourceEventHandler;
import io.kubernetes.client.informer.SharedIndexInformer;
import io.kubernetes.client.informer.SharedInformerFactory;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.Configuration;
import io.kubernetes.client.openapi.apis.CustomObjectsApi;
import io.kubernetes.client.util.CallGeneratorParams;
import io.kubernetes.client.util.ClientBuilder;
import io.shulkermc.models.V1alpha1MinecraftCluster;
import io.shulkermc.models.V1alpha1MinecraftClusterList;
import io.shulkermc.models.V1alpha1MinecraftClusterStatus;
import io.shulkermc.models.V1alpha1MinecraftClusterStatusServerPool;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.plugin.Plugin;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.Map;

public class ShulkerProxyDirectory extends Plugin {
private final ProxyServer proxyServer;

private String shulkerClusterName;
private CustomObjectsApi kubernetesObjectApi;
private SharedInformerFactory kubernetesInformerFactory;

public ShulkerProxyDirectory() {
this.proxyServer = ProxyServer.getInstance();
}

@Override
public void onEnable() {
this.shulkerClusterName = System.getenv("SHULKER_CLUSTER_NAME");

if (this.shulkerClusterName == null) {
this.getLogger().warning("No SHULKER_CLUSTER_NAME found in environment. Halting.");
this.proxyServer.stop();
return;
}

ApiClient kubernetesClient;
try {
kubernetesClient = ClientBuilder.cluster().build();
Configuration.setDefaultApiClient(kubernetesClient);
} catch (IOException ex) {
this.getLogger().severe("Failed to create Kubernetes client");
ex.printStackTrace();

this.proxyServer.stop();
return;
}

this.kubernetesObjectApi = new CustomObjectsApi(kubernetesClient);
this.kubernetesInformerFactory = new SharedInformerFactory();

this.createInformer();

try {
this.syncServerDirectory();
} catch (ApiException ex) {
this.getLogger().severe("Failed to synchronize server directory");
ex.printStackTrace();
}

this.kubernetesInformerFactory.startAllRegisteredInformers();
}

@Override
public void onDisable() {
this.kubernetesInformerFactory.stopAllRegisteredInformers();
}

private void syncServerDirectory() throws ApiException {
V1alpha1MinecraftClusterStatus status = (V1alpha1MinecraftClusterStatus) this.kubernetesObjectApi.getClusterCustomObjectStatus(
"shulkermc.io", "v1alpha1", "minecraftclusters", this.shulkerClusterName);
this.updateServerDirectory(status.getServerPool());
}

private void updateServerDirectory(List<V1alpha1MinecraftClusterStatusServerPool> serverPool) {
Map<String, ServerInfo> proxyServers = this.proxyServer.getServers();

List<String> serverPoolNames = serverPool.parallelStream()
.map(V1alpha1MinecraftClusterStatusServerPool::getName).toList();

serverPool.parallelStream()
.filter((server) -> server != null && server.getName() != null && server.getAddress() != null)
.map((server) -> {
InetSocketAddress socketAddress = new InetSocketAddress(server.getAddress(), 25565);
return this.proxyServer.constructServerInfo(server.getName(), socketAddress, null, false);
})
.peek((serverInfo) -> this.getLogger().info(String.format("Adding server %s (%s) to directory", serverInfo.getName(), serverInfo.getSocketAddress())))
.forEach((serverInfo) -> proxyServers.put(serverInfo.getName(), serverInfo));

proxyServers.keySet().stream()
.filter((serverName) -> !serverPoolNames.contains(serverName))
.peek((serverName) -> this.getLogger().info(String.format("Removing server %s from directory", serverName)))
.forEach(proxyServers::remove);
}

private void createInformer() {
SharedIndexInformer<V1alpha1MinecraftCluster> minecraftClusterInformer =
this.kubernetesInformerFactory.sharedIndexInformerFor(
(CallGeneratorParams params) -> this.kubernetesObjectApi.listClusterCustomObjectCall(
"shulkermc.io",
"v1alpha1",
"minecraftclusters",
null,
null,
null,
null,
null,
params.resourceVersion,
params.timeoutSeconds,
params.watch,
null),
V1alpha1MinecraftCluster.class,
V1alpha1MinecraftClusterList.class);

minecraftClusterInformer.addEventHandler(new ResourceEventHandler<>() {
@Override
public void onAdd(V1alpha1MinecraftCluster obj) {}

@Override
public void onUpdate(V1alpha1MinecraftCluster oldObj, V1alpha1MinecraftCluster newObj) {
if (oldObj.getMetadata() == null
|| oldObj.getMetadata().getName() == null
|| !oldObj.getMetadata().getName().equals(ShulkerProxyDirectory.this.shulkerClusterName)) return;

V1alpha1MinecraftClusterStatus clusterStatus = newObj.getStatus();
if (clusterStatus == null) return;

ShulkerProxyDirectory.this.updateServerDirectory(clusterStatus.getServerPool());
}

@Override
public void onDelete(V1alpha1MinecraftCluster obj, boolean deletedFinalStateUnknown) {}
});
}
}
4 changes: 4 additions & 0 deletions support/shulker-proxy-directory/src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name: ShulkerProxyDirectory
main: io.shulkermc.directory.ShulkerProxyDirectory
version: 0.0.1
author: Jérémy Levilain <jeremy@jeremylvln.fr>

0 comments on commit 791a4d9

Please sign in to comment.