2024-09-11 11:14:27 +02:00
|
|
|
package commands
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"slices"
|
2024-09-12 00:18:40 +02:00
|
|
|
"strings"
|
2024-09-11 11:14:27 +02:00
|
|
|
|
2024-09-11 11:30:48 +02:00
|
|
|
"gitea.codeblob.work/pk/hoster/internals/conf"
|
|
|
|
"gitea.codeblob.work/pk/hoster/internals/helpers"
|
|
|
|
"gitea.codeblob.work/pk/hoster/internals/templates"
|
|
|
|
"gitea.codeblob.work/pk/hoster/internals/types"
|
|
|
|
|
2024-09-11 11:14:27 +02:00
|
|
|
"github.com/gookit/goutil/fsutil"
|
|
|
|
"github.com/gookit/goutil/sysutil/cmdr"
|
|
|
|
"github.com/kataras/golog"
|
|
|
|
"github.com/urfave/cli/v2"
|
|
|
|
)
|
|
|
|
|
|
|
|
func CmdNew(c *cli.Context) error {
|
2024-09-13 17:09:21 +02:00
|
|
|
if os.Getuid() != 0 {
|
|
|
|
golog.Fatalf("You need to run this command as root.")
|
|
|
|
}
|
|
|
|
|
2024-09-12 00:18:40 +02:00
|
|
|
name := strings.TrimSpace(c.String("name"))
|
|
|
|
domain := strings.TrimSpace(c.String("domain"))
|
2024-09-12 00:22:42 +02:00
|
|
|
customProjectPath := strings.TrimSpace(c.String("custom-path"))
|
2024-09-11 11:14:27 +02:00
|
|
|
projectRoot := conf.App.MustString("projects.root")
|
|
|
|
sitesAvail := conf.App.MustString("nginx.sitesAvailable")
|
|
|
|
sitesEnabled := conf.App.MustString("nginx.sitesEnabled")
|
|
|
|
nginxFile := filepath.Join(sitesAvail, name)
|
|
|
|
|
|
|
|
projectFolder := filepath.Join(projectRoot, name)
|
|
|
|
|
2024-09-12 00:23:50 +02:00
|
|
|
if customProjectPath != "" {
|
2024-09-12 00:18:40 +02:00
|
|
|
projectFolder = customProjectPath
|
|
|
|
}
|
|
|
|
|
2024-09-11 11:14:27 +02:00
|
|
|
existingProjects, err := helpers.FindHostConfigs(sitesAvail)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
usedPorts := []int{}
|
|
|
|
for _, project := range existingProjects {
|
|
|
|
usedPorts = append(usedPorts, project.InternalPort)
|
|
|
|
}
|
|
|
|
|
|
|
|
port := conf.App.Int("nginx.portRangeStart")
|
|
|
|
freePort := 0
|
|
|
|
for port <= conf.App.Int("nginx.portRangeEnd") {
|
|
|
|
if !slices.Contains(usedPorts, port) && helpers.IsFreePort(port) {
|
|
|
|
freePort = port
|
|
|
|
break
|
|
|
|
}
|
|
|
|
port++
|
|
|
|
}
|
|
|
|
|
|
|
|
if freePort == 0 {
|
|
|
|
return fmt.Errorf("no free port available")
|
|
|
|
}
|
|
|
|
|
|
|
|
if !fsutil.IsDir(projectFolder) {
|
|
|
|
golog.Infof("Creating project folder '%s'", projectFolder)
|
|
|
|
err := os.MkdirAll(projectFolder, 0755)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if fsutil.IsFile(nginxFile) {
|
|
|
|
return fmt.Errorf("the nginx config file '%s' already exists", nginxFile)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set owner and group of project folder
|
|
|
|
err = os.Chown(projectFolder, conf.App.Int("projects.owner"), conf.App.Int("projects.group"))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
project := types.Project{
|
|
|
|
Name: name,
|
|
|
|
Domain: domain,
|
|
|
|
InternalPort: freePort,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create nginx config file
|
|
|
|
err = templates.Execute("nginx", nginxFile, project)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Symlink nginx config file
|
|
|
|
err = os.Symlink(nginxFile, filepath.Join(sitesEnabled, name))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Execute certbot command: "systemctl stop nginx && sudo certbot certonly --standalone --preferred-challenges http -d {domain} && sudo systemctl start nginx"
|
|
|
|
|
|
|
|
com := cmdr.NewCmd("systemctl").
|
|
|
|
WithArgs([]string{"stop", "nginx"})
|
|
|
|
|
|
|
|
_, err = com.Output()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
com = cmdr.NewCmd("certbot").
|
|
|
|
WithArgs([]string{"certonly", "--standalone", "--preferred-challenges", "http", "-d", domain})
|
|
|
|
_, err = com.Output()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
com = cmdr.NewCmd("systemctl").
|
|
|
|
WithArgs([]string{"start", "nginx"})
|
|
|
|
_, err = com.Output()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
golog.Infof("Project successfully '%s' created. Uses port %d.", name, freePort)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|