mirror of
https://github.com/GayPizzaSpecifications/foundation.git
synced 2025-08-02 13:10:55 +00:00
Initial work on scheduled backups.
This commit is contained in:
parent
b2851d13b9
commit
c1f621aa7b
@ -2,4 +2,5 @@ dependencies {
|
|||||||
// TODO: might be able to ship all dependencies in core? are we duplicating classes in JARs?
|
// TODO: might be able to ship all dependencies in core? are we duplicating classes in JARs?
|
||||||
|
|
||||||
implementation("software.amazon.awssdk:s3:2.17.102")
|
implementation("software.amazon.awssdk:s3:2.17.102")
|
||||||
|
implementation("org.quartz-scheduler:quartz:2.3.2")
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import cloud.kubelet.foundation.core.features.stats.StatsFeature
|
|||||||
import cloud.kubelet.foundation.core.features.update.UpdateFeature
|
import cloud.kubelet.foundation.core.features.update.UpdateFeature
|
||||||
import cloud.kubelet.foundation.core.features.world.WorldFeature
|
import cloud.kubelet.foundation.core.features.world.WorldFeature
|
||||||
import cloud.kubelet.foundation.core.features.persist.PersistenceFeature
|
import cloud.kubelet.foundation.core.features.persist.PersistenceFeature
|
||||||
|
import cloud.kubelet.foundation.core.features.scheduler.SchedulerFeature
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
@ -38,6 +39,7 @@ class FoundationCorePlugin : FoundationPlugin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun createFeatures() = listOf(
|
override fun createFeatures() = listOf(
|
||||||
|
SchedulerFeature(),
|
||||||
PersistenceFeature(),
|
PersistenceFeature(),
|
||||||
BackupFeature(),
|
BackupFeature(),
|
||||||
DevFeature(),
|
DevFeature(),
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package cloud.kubelet.foundation.core.abstraction
|
||||||
|
|
||||||
|
interface CoreFeature {
|
||||||
|
fun enable()
|
||||||
|
fun disable()
|
||||||
|
fun module() = org.koin.dsl.module {}
|
||||||
|
}
|
@ -7,13 +7,15 @@ import org.bukkit.event.Listener
|
|||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
import org.quartz.Scheduler
|
||||||
|
|
||||||
abstract class Feature : KoinComponent, Listener {
|
abstract class Feature : CoreFeature, KoinComponent, Listener {
|
||||||
private val plugin by inject<FoundationCorePlugin>()
|
private val plugin by inject<FoundationCorePlugin>()
|
||||||
|
protected val scheduler by inject<Scheduler>()
|
||||||
|
|
||||||
open fun enable() {}
|
override fun enable() {}
|
||||||
open fun disable() {}
|
override fun disable() {}
|
||||||
open fun module() = module {}
|
override fun module() = module {}
|
||||||
|
|
||||||
protected fun registerCommandExecutor(name: String, executor: CommandExecutor) {
|
protected fun registerCommandExecutor(name: String, executor: CommandExecutor) {
|
||||||
registerCommandExecutor(listOf(name), executor)
|
registerCommandExecutor(listOf(name), executor)
|
||||||
|
@ -10,7 +10,7 @@ import org.koin.dsl.module
|
|||||||
abstract class FoundationPlugin : JavaPlugin() {
|
abstract class FoundationPlugin : JavaPlugin() {
|
||||||
private lateinit var pluginModule: Module
|
private lateinit var pluginModule: Module
|
||||||
private lateinit var pluginApplication: KoinApplication
|
private lateinit var pluginApplication: KoinApplication
|
||||||
private lateinit var features: List<Feature>
|
private lateinit var features: List<CoreFeature>
|
||||||
private lateinit var module: Module
|
private lateinit var module: Module
|
||||||
|
|
||||||
override fun onEnable() {
|
override fun onEnable() {
|
||||||
@ -45,7 +45,10 @@ abstract class FoundationPlugin : JavaPlugin() {
|
|||||||
try {
|
try {
|
||||||
slF4JLogger.info("Enabling feature: ${it.javaClass.simpleName}")
|
slF4JLogger.info("Enabling feature: ${it.javaClass.simpleName}")
|
||||||
it.enable()
|
it.enable()
|
||||||
|
// TODO: May replace this check with a method in the interface, CoreFeature would no-op.
|
||||||
|
if (it is Feature) {
|
||||||
server.pluginManager.registerEvents(it, this)
|
server.pluginManager.registerEvents(it, this)
|
||||||
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
slF4JLogger.error("Failed to enable feature: ${it.javaClass.simpleName}", e)
|
slF4JLogger.error("Failed to enable feature: ${it.javaClass.simpleName}", e)
|
||||||
}
|
}
|
||||||
@ -61,5 +64,5 @@ abstract class FoundationPlugin : JavaPlugin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected open fun createModule() = module {}
|
protected open fun createModule() = module {}
|
||||||
protected abstract fun createFeatures(): List<Feature>
|
protected abstract fun createFeatures(): List<CoreFeature>
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,15 @@ import kotlinx.serialization.Serializable
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class BackupConfig(
|
data class BackupConfig(
|
||||||
|
val schedule: ScheduleConfig = ScheduleConfig(),
|
||||||
val s3: S3Config = S3Config(),
|
val s3: S3Config = S3Config(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ScheduleConfig(
|
||||||
|
val cron: String = "",
|
||||||
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class S3Config(
|
data class S3Config(
|
||||||
val accessKeyId: String = "",
|
val accessKeyId: String = "",
|
||||||
|
@ -3,8 +3,9 @@ package cloud.kubelet.foundation.core.features.backup
|
|||||||
import cloud.kubelet.foundation.core.FoundationCorePlugin
|
import cloud.kubelet.foundation.core.FoundationCorePlugin
|
||||||
import cloud.kubelet.foundation.core.Util
|
import cloud.kubelet.foundation.core.Util
|
||||||
import cloud.kubelet.foundation.core.abstraction.Feature
|
import cloud.kubelet.foundation.core.abstraction.Feature
|
||||||
|
import cloud.kubelet.foundation.core.features.scheduler.cancel
|
||||||
|
import cloud.kubelet.foundation.core.features.scheduler.cron
|
||||||
import com.charleskorn.kaml.Yaml
|
import com.charleskorn.kaml.Yaml
|
||||||
import org.koin.core.KoinApplication
|
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials
|
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials
|
||||||
@ -18,6 +19,7 @@ class BackupFeature : Feature() {
|
|||||||
private val plugin by inject<FoundationCorePlugin>()
|
private val plugin by inject<FoundationCorePlugin>()
|
||||||
private val s3Client by inject<S3Client>()
|
private val s3Client by inject<S3Client>()
|
||||||
private val config by inject<BackupConfig>()
|
private val config by inject<BackupConfig>()
|
||||||
|
private lateinit var scheduleId: String
|
||||||
|
|
||||||
override fun enable() {
|
override fun enable() {
|
||||||
// Create backup directory.
|
// Create backup directory.
|
||||||
@ -25,6 +27,20 @@ class BackupFeature : Feature() {
|
|||||||
backupPath.toFile().mkdir()
|
backupPath.toFile().mkdir()
|
||||||
|
|
||||||
registerCommandExecutor("fbackup", BackupCommand(plugin, backupPath, config, s3Client))
|
registerCommandExecutor("fbackup", BackupCommand(plugin, backupPath, config, s3Client))
|
||||||
|
|
||||||
|
if (config.schedule.cron.isNotEmpty()) {
|
||||||
|
scheduleId = scheduler.cron("${config.schedule.cron} ?") {
|
||||||
|
plugin.server.scheduler.runTask(plugin) { ->
|
||||||
|
plugin.server.dispatchCommand(plugin.server.consoleSender, "fbackup")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun disable() {
|
||||||
|
if (::scheduleId.isInitialized) {
|
||||||
|
scheduler.cancel(scheduleId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun module() = module {
|
override fun module() = module {
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
package cloud.kubelet.foundation.core.features.scheduler
|
||||||
|
|
||||||
|
import org.quartz.CronScheduleBuilder.cronSchedule
|
||||||
|
import org.quartz.JobBuilder.newJob
|
||||||
|
import org.quartz.JobDataMap
|
||||||
|
import org.quartz.Scheduler
|
||||||
|
import org.quartz.TriggerBuilder.newTrigger
|
||||||
|
import org.quartz.TriggerKey.triggerKey
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
fun Scheduler.cron(cronExpression: String, f: () -> Unit): String {
|
||||||
|
val id = UUID.randomUUID().toString()
|
||||||
|
val job = newJob(SchedulerRunner::class.java).apply {
|
||||||
|
setJobData(JobDataMap().apply {
|
||||||
|
set("function", f)
|
||||||
|
})
|
||||||
|
}.build()
|
||||||
|
|
||||||
|
val trigger = newTrigger()
|
||||||
|
.withIdentity(triggerKey(id))
|
||||||
|
.withSchedule(cronSchedule(cronExpression))
|
||||||
|
.build()
|
||||||
|
|
||||||
|
scheduleJob(job, trigger)
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Scheduler.cancel(id: String) {
|
||||||
|
unscheduleJob(triggerKey(id))
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package cloud.kubelet.foundation.core.features.scheduler
|
||||||
|
|
||||||
|
import cloud.kubelet.foundation.core.abstraction.CoreFeature
|
||||||
|
import org.koin.dsl.module
|
||||||
|
import org.quartz.Scheduler
|
||||||
|
import org.quartz.impl.StdSchedulerFactory
|
||||||
|
|
||||||
|
class SchedulerFeature : CoreFeature {
|
||||||
|
private val scheduler: Scheduler = StdSchedulerFactory.getDefaultScheduler()
|
||||||
|
|
||||||
|
override fun enable() {
|
||||||
|
scheduler.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun disable() {
|
||||||
|
scheduler.shutdown(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun module() = module {
|
||||||
|
single { scheduler }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package cloud.kubelet.foundation.core.features.scheduler
|
||||||
|
|
||||||
|
import org.quartz.Job
|
||||||
|
import org.quartz.JobExecutionContext
|
||||||
|
|
||||||
|
class SchedulerRunner : Job {
|
||||||
|
override fun execute(context: JobExecutionContext) {
|
||||||
|
val f = context.jobDetail.jobDataMap["function"] as () -> Unit
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,11 @@
|
|||||||
|
# Configuration of backup scheduling, expressed by cron expressions.
|
||||||
|
schedule:
|
||||||
|
# Cron expression to use for the backup schedule.
|
||||||
|
# Examples:
|
||||||
|
# "0 3 * * *" -> every day at 3 AM
|
||||||
|
# "0 3 * * SUN" -> every Sunday at 3 AM
|
||||||
|
cron: ""
|
||||||
|
|
||||||
# Configuration of S3 service to upload back-ups to.
|
# Configuration of S3 service to upload back-ups to.
|
||||||
s3:
|
s3:
|
||||||
# The access key ID from your S3-compliant storage provider.
|
# The access key ID from your S3-compliant storage provider.
|
||||||
|
3
foundation-core/src/main/resources/quartz.properties
Normal file
3
foundation-core/src/main/resources/quartz.properties
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
org.quartz.scheduler.instanceName = Foundation
|
||||||
|
org.quartz.threadPool.threadCount = 2
|
||||||
|
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
|
Loading…
Reference in New Issue
Block a user