Inital commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
mc-tool
|
||||||
30
config/config.go
Normal file
30
config/config.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Cfg Config = Config{
|
||||||
|
Name: "minecraft-server",
|
||||||
|
Version: "1.21.1",
|
||||||
|
Type: "VANILLA",
|
||||||
|
Ram: "2G",
|
||||||
|
MOTD: "This server was created using mc-tool",
|
||||||
|
RestartPolicy: "never",
|
||||||
|
Ports: []string{"25565:25565"},
|
||||||
|
}
|
||||||
|
var Data Resources
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Name string
|
||||||
|
Version string
|
||||||
|
Type string
|
||||||
|
Ram string
|
||||||
|
MOTD string
|
||||||
|
RestartPolicy string
|
||||||
|
Ports []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Resources struct {
|
||||||
|
DockerCompose *template.Template
|
||||||
|
}
|
||||||
67
docker/docker.go
Normal file
67
docker/docker.go
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
package docker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Port struct {
|
||||||
|
In string
|
||||||
|
Out string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
FORGE ServerType = iota
|
||||||
|
FABRIC
|
||||||
|
NEOFORGE
|
||||||
|
VANILLA
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p Port) String() string {
|
||||||
|
return fmt.Sprintf("%s:%s", p.In, p.Out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t ServerType) String() string {
|
||||||
|
switch t {
|
||||||
|
case FORGE:
|
||||||
|
return "FORGE"
|
||||||
|
case NEOFORGE:
|
||||||
|
return "NEOFORGE"
|
||||||
|
case VANILLA:
|
||||||
|
return "VANILLA"
|
||||||
|
}
|
||||||
|
log.Panicln("unreachable")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func PortFromString(port string) Port {
|
||||||
|
parts := strings.Split(port, ":")
|
||||||
|
return Port{
|
||||||
|
In: parts[0],
|
||||||
|
Out: parts[1],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PortsFromStrings(ports []string) (r []Port) {
|
||||||
|
for _, port := range ports {
|
||||||
|
r = append(r, PortFromString(port))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func TypeFromString(in string) ServerType {
|
||||||
|
switch in {
|
||||||
|
case "FORGE":
|
||||||
|
return FORGE
|
||||||
|
case "NEOFORGE":
|
||||||
|
return NEOFORGE
|
||||||
|
case "VANILLA":
|
||||||
|
return VANILLA
|
||||||
|
default:
|
||||||
|
log.Fatalf("unknown server type \"%s\"", in)
|
||||||
|
}
|
||||||
|
return VANILLA
|
||||||
|
}
|
||||||
39
docker/docker_compose.go
Normal file
39
docker/docker_compose.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package docker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"mc-tool/config"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Dockercompose struct {
|
||||||
|
Name string
|
||||||
|
Ports []Port
|
||||||
|
Version string
|
||||||
|
Type string
|
||||||
|
Ram string
|
||||||
|
MOTD string
|
||||||
|
RestartPolicy string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCompose(name string) Dockercompose {
|
||||||
|
return Dockercompose{
|
||||||
|
Name: name,
|
||||||
|
Ports: PortsFromStrings(config.Cfg.Ports),
|
||||||
|
Version: config.Cfg.Version,
|
||||||
|
Type: TypeFromString(config.Cfg.Type).String(),
|
||||||
|
Ram: config.Cfg.Ram,
|
||||||
|
MOTD: config.Cfg.MOTD,
|
||||||
|
RestartPolicy: config.Cfg.RestartPolicy,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dc Dockercompose) String() string {
|
||||||
|
b := new(strings.Builder)
|
||||||
|
|
||||||
|
err := config.Data.DockerCompose.ExecuteTemplate(b, "compose", dc)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
9
go.mod
Normal file
9
go.mod
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
module mc-tool
|
||||||
|
|
||||||
|
go 1.26.4
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
|
github.com/spf13/cobra v1.10.2 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.10 // indirect
|
||||||
|
)
|
||||||
11
go.sum
Normal file
11
go.sum
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
|
||||||
|
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
|
||||||
|
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||||
|
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
90
main.go
Normal file
90
main.go
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
"log"
|
||||||
|
"mc-tool/config"
|
||||||
|
"mc-tool/server"
|
||||||
|
"os"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var rootCmd = &cobra.Command{
|
||||||
|
Use: "mc-tool [command]",
|
||||||
|
Short: "Minecraft Management Tool",
|
||||||
|
Long: "mc-tool simplifies common server administration actions",
|
||||||
|
Args: cobra.MinimumNArgs(1),
|
||||||
|
}
|
||||||
|
|
||||||
|
var createCmd = &cobra.Command{
|
||||||
|
Use: "create",
|
||||||
|
Short: "Creates a new minecraft server",
|
||||||
|
Run: server.New,
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
}
|
||||||
|
|
||||||
|
var startCmd = &cobra.Command{
|
||||||
|
Use: "start",
|
||||||
|
Short: "Start the minecraft server",
|
||||||
|
Run: server.Start,
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
}
|
||||||
|
|
||||||
|
var stopCmd = &cobra.Command{
|
||||||
|
Use: "stop",
|
||||||
|
Short: "Stop the minecraft server",
|
||||||
|
Run: server.Stop,
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
}
|
||||||
|
|
||||||
|
var restartCmd = &cobra.Command{
|
||||||
|
Use: "restart",
|
||||||
|
Short: "Restart the minecraft server",
|
||||||
|
Run: server.Restart,
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
}
|
||||||
|
|
||||||
|
var shellCmd = &cobra.Command{
|
||||||
|
Use: "shell",
|
||||||
|
Short: "Access RCON shell",
|
||||||
|
Run: server.Shell,
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:embed templates/docker-compose.yml
|
||||||
|
var dockerCompose string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
createCmd.Flags().StringVarP(&config.Cfg.Name, "name", "n", "minecraft-server", "set the name of the server")
|
||||||
|
createCmd.Flags().StringVarP(&config.Cfg.Version, "version", "v", "1.21.1", "set the version of the server")
|
||||||
|
createCmd.Flags().StringVarP(&config.Cfg.Type, "type", "t", "VANILLA", "set the type of the server")
|
||||||
|
createCmd.Flags().StringVarP(&config.Cfg.Ram, "ram", "r", "2G", "set the memory limit of the server")
|
||||||
|
createCmd.Flags().StringVarP(&config.Cfg.MOTD, "motd", "m", "This server was created using mc-tool", "set the message of the day for the server")
|
||||||
|
createCmd.Flags().StringVarP(&config.Cfg.RestartPolicy, "restart", "R", "never", "what to do when the server fails or host turns off")
|
||||||
|
createCmd.Flags().FuncP("port", "p", "set additional ports for the container to expose", func(s string) error {
|
||||||
|
config.Cfg.Ports = append(config.Cfg.Ports, s)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
rootCmd.AddCommand(createCmd)
|
||||||
|
rootCmd.AddCommand(startCmd)
|
||||||
|
rootCmd.AddCommand(stopCmd)
|
||||||
|
rootCmd.AddCommand(restartCmd)
|
||||||
|
rootCmd.AddCommand(shellCmd)
|
||||||
|
|
||||||
|
t, err := template.New("compose").Parse(dockerCompose)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
config.Data.DockerCompose = t
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.SetFlags(0)
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
37
server/container.go
Normal file
37
server/container.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getServerName(dir string) string {
|
||||||
|
if err := os.Chdir(dir); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open("docker-compose.yml")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
|
||||||
|
name := dir
|
||||||
|
for scanner.Scan() {
|
||||||
|
txt := scanner.Text()
|
||||||
|
txt = strings.TrimSpace(txt)
|
||||||
|
s, found := strings.CutPrefix(txt, "container_name: ")
|
||||||
|
if found {
|
||||||
|
name = s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
47
server/new.go
Normal file
47
server/new.go
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"mc-tool/docker"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func New(cmd *cobra.Command, args []string) {
|
||||||
|
dir := args[0]
|
||||||
|
if err := os.Mkdir(dir, 0755); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.Chdir(dir); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
compose := docker.NewCompose(dir)
|
||||||
|
|
||||||
|
if compose.Type != docker.VANILLA.String() {
|
||||||
|
if err := os.MkdirAll("data/mods", 0755); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll("data/config", 0755); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll("data/world", 0755); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := writeFile("docker-compose.yml", compose.String()); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeFile(path string, data string) error {
|
||||||
|
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return os.WriteFile(path, []byte(data), 0644)
|
||||||
|
}
|
||||||
21
server/restart.go
Normal file
21
server/restart.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Restart(cmd *cobra.Command, args []string) {
|
||||||
|
dir := args[0]
|
||||||
|
if err := os.Chdir(dir); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
start_cmd := exec.Command("docker", "compose", "restart")
|
||||||
|
if err := start_cmd.Run(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
31
server/shell.go
Normal file
31
server/shell.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Shell(cmd *cobra.Command, args []string) {
|
||||||
|
dir := args[0]
|
||||||
|
|
||||||
|
name := getServerName(dir)
|
||||||
|
|
||||||
|
start_cmd := exec.Command("docker", "exec", name, "rcon-cli")
|
||||||
|
if err := start_cmd.Run(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Say(cmd *cobra.Command, args []string) {
|
||||||
|
dir := args[0]
|
||||||
|
|
||||||
|
name := getServerName(dir)
|
||||||
|
|
||||||
|
start_cmd := exec.Command("docker", "exec", name, "rcon-cli", strings.Join(args[1:], " "))
|
||||||
|
if err := start_cmd.Run(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
21
server/start.go
Normal file
21
server/start.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Start(cmd *cobra.Command, args []string) {
|
||||||
|
dir := args[0]
|
||||||
|
if err := os.Chdir(dir); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
start_cmd := exec.Command("docker", "compose", "up", "-d")
|
||||||
|
if err := start_cmd.Run(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
28
server/status.go
Normal file
28
server/status.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Status(cmd *cobra.Command, args []string) {
|
||||||
|
dir := args[0]
|
||||||
|
|
||||||
|
name := getServerName(dir)
|
||||||
|
|
||||||
|
start_cmd := exec.Command("docker", "exec", name, "rcon-cli", "list")
|
||||||
|
var outb, errb bytes.Buffer
|
||||||
|
|
||||||
|
start_cmd.Stdout = &outb
|
||||||
|
start_cmd.Stderr = &errb
|
||||||
|
|
||||||
|
if err := start_cmd.Run(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(outb.String())
|
||||||
|
}
|
||||||
21
server/stop.go
Normal file
21
server/stop.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Stop(cmd *cobra.Command, args []string) {
|
||||||
|
dir := args[0]
|
||||||
|
if err := os.Chdir(dir); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
start_cmd := exec.Command("docker", "compose", "down")
|
||||||
|
if err := start_cmd.Run(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
18
templates/docker-compose.yml
Normal file
18
templates/docker-compose.yml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
service:
|
||||||
|
mc:
|
||||||
|
image: itzg/minecraft-server:latest
|
||||||
|
container_name: {{.Name}}
|
||||||
|
tty: true
|
||||||
|
stdin_open: true
|
||||||
|
ports:
|
||||||
|
{{range .Ports}}- "{{.In}}:{{.Out}}"
|
||||||
|
{{end}}
|
||||||
|
environment:
|
||||||
|
EULA: "TRUE"
|
||||||
|
VERSION: "{{.Version}}"
|
||||||
|
TYPE: {{.Type}}
|
||||||
|
MEMORY: "{{.Ram}}"
|
||||||
|
MOTD: "{{.MOTD}}"
|
||||||
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
|
restart: "{{.RestartPolicy}}"
|
||||||
Reference in New Issue
Block a user