Server and Client daemons functional
This commit is contained in:
217
util.go
217
util.go
@@ -4,12 +4,20 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"git.nevets.tech/Steven/ezconf"
|
||||
"github.com/google/go-github/v55/github"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrorPIDInUse = errors.New("daemon is already running")
|
||||
ErrLockFailed = errors.New("failed to acquire a lock on the PID file")
|
||||
)
|
||||
|
||||
type Domain struct {
|
||||
name *string
|
||||
config *ezconf.Configuration
|
||||
@@ -18,17 +26,144 @@ type Domain struct {
|
||||
gtClient *gitea.Client
|
||||
}
|
||||
|
||||
type GlobalConfig struct {
|
||||
Git struct {
|
||||
Host string
|
||||
Endpoint string
|
||||
Username string
|
||||
Password string
|
||||
ApiToken string
|
||||
// 0x01
|
||||
func createPIDFile() {
|
||||
file, err := os.Create("/var/run/certman.pid")
|
||||
if err != nil {
|
||||
fmt.Printf("0x01: Error creating PID file: %v\n", err)
|
||||
return
|
||||
}
|
||||
err = file.Close()
|
||||
if err != nil {
|
||||
fmt.Printf("0x01: Error closing PID file: %v\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type DomainConfig struct {
|
||||
// 0x02
|
||||
func clearPIDFile() {
|
||||
file, err := os.OpenFile("/var/run/certman.pid", os.O_RDWR|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
fmt.Printf("0x02: Error opening PID file: %v\n", err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
err = file.Truncate(0)
|
||||
if err != nil {
|
||||
fmt.Printf("0x02: Error writing PID file: %v\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 0x03
|
||||
func createOrUpdatePIDFile(filename string) error {
|
||||
pidBytes, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
fmt.Printf("0x03: Error reading PID file: %v\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
pidStr := strings.TrimSpace(string(pidBytes))
|
||||
isPidFileEmpty := pidStr == ""
|
||||
|
||||
if !isPidFileEmpty {
|
||||
pid, err := strconv.Atoi(pidStr)
|
||||
if err != nil {
|
||||
fmt.Printf("0x03: Error parsing PID file: %v\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
isProcActive, err := isProcessActive(pid)
|
||||
if err != nil {
|
||||
fmt.Printf("0x03: Error checking if process is active: %v\n", err)
|
||||
return err
|
||||
|
||||
}
|
||||
if isProcActive {
|
||||
return ErrorPIDInUse
|
||||
}
|
||||
}
|
||||
|
||||
pidFile, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
createPIDFile()
|
||||
} else {
|
||||
fmt.Printf("0x03: Error opening PID file: %v\n", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
defer pidFile.Close()
|
||||
|
||||
if err := syscall.Flock(int(pidFile.Fd()), syscall.LOCK_EX|syscall.LOCK_NB); err != nil {
|
||||
if errors.Is(err, syscall.EWOULDBLOCK) {
|
||||
return ErrLockFailed
|
||||
}
|
||||
return fmt.Errorf("error locking PID file: %w", err)
|
||||
}
|
||||
curPid := os.Getpid()
|
||||
if _, err := pidFile.Write([]byte(strconv.Itoa(curPid))); err != nil {
|
||||
return fmt.Errorf("error writing pid to PID file: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 0x04
|
||||
// isProcessActive checks whether the process with the provided PID is running.
|
||||
func isProcessActive(pid int) (bool, error) {
|
||||
if pid <= 0 {
|
||||
return false, errors.New("invalid process ID")
|
||||
}
|
||||
process, err := os.FindProcess(pid)
|
||||
if err != nil {
|
||||
// On Unix systems, os.FindProcess always succeeds and returns a process with the given pid, irrespective of whether the process exists.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
err = process.Signal(syscall.Signal(0))
|
||||
if err != nil {
|
||||
if errors.Is(err, syscall.ESRCH) {
|
||||
// The process does not exist
|
||||
return false, nil
|
||||
} else if errors.Is(err, os.ErrProcessDone) {
|
||||
return false, nil
|
||||
}
|
||||
// Some other unexpected error
|
||||
return false, err
|
||||
}
|
||||
|
||||
// The process exists and is active
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// 0x05
|
||||
func getDaemonProcess() (*os.Process, error) {
|
||||
pidBytes, err := os.ReadFile("/var/run/certman.pid")
|
||||
if err != nil {
|
||||
fmt.Printf("0x05: Error getting PID from /var/run/certman.pid: %v\n", err)
|
||||
return nil, err
|
||||
}
|
||||
pidStr := strings.TrimSpace(string(pidBytes))
|
||||
daemonPid, err := strconv.Atoi(pidStr)
|
||||
if err != nil {
|
||||
fmt.Printf("0x05: Error converting PID string to int (%s): %v\n", pidStr, err)
|
||||
return nil, err
|
||||
}
|
||||
isProcActive, err := isProcessActive(daemonPid)
|
||||
if err != nil {
|
||||
fmt.Printf("0x05: Error checking if process is active: %v\n", err)
|
||||
}
|
||||
if !isProcActive {
|
||||
return nil, errors.New("process is not active")
|
||||
}
|
||||
proc, err := os.FindProcess(daemonPid)
|
||||
if err != nil {
|
||||
fmt.Printf("0x05: Error finding process with PID %d: %v\n", daemonPid, err)
|
||||
return nil, err
|
||||
}
|
||||
return proc, nil
|
||||
}
|
||||
|
||||
func createFile(fileName string, filePermission os.FileMode, data []byte) {
|
||||
@@ -71,16 +206,18 @@ func createFile(fileName string, filePermission os.FileMode, data []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
func fileExists(filePath string) bool {
|
||||
if _, err := os.Stat(filePath); err == nil {
|
||||
return true
|
||||
} else if errors.Is(err, os.ErrNotExist) {
|
||||
return false
|
||||
} else {
|
||||
fmt.Println("Error checking file existence: ", err)
|
||||
os.Exit(1)
|
||||
return false
|
||||
func linkFile(source, target string) error {
|
||||
err := os.Symlink(source, target)
|
||||
if err != nil {
|
||||
fmt.Println("Error creating symlink:", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func fileExists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func contains(slice []string, value string) (sliceHas bool, index int) {
|
||||
@@ -100,44 +237,8 @@ func insert(a []string, index int, value string) []string {
|
||||
return a
|
||||
}
|
||||
|
||||
const defaultConfig = `[App]
|
||||
mode = {mode}
|
||||
|
||||
[Git]
|
||||
host = gitea
|
||||
server = https://gitea.instance.com
|
||||
username = user
|
||||
org_name = org
|
||||
template_name = template
|
||||
|
||||
[Certificates]
|
||||
email = user@example.com
|
||||
data_root = /var/local/certman
|
||||
request_method = dns
|
||||
|
||||
[Cloudflare]
|
||||
cf_email = email@example.com
|
||||
|
||||
`
|
||||
|
||||
const defaultDomainConfig = `[Domain]
|
||||
domain_name = {domain}
|
||||
; default (use system dns) or IPv4 Address (1.1.1.1)
|
||||
dns_server = default
|
||||
; optionally use /path/to/directory
|
||||
file_location = default
|
||||
|
||||
[Certificates]
|
||||
subdomains =
|
||||
expiry = 90
|
||||
cert_symlink =
|
||||
key_symlink =
|
||||
|
||||
[Repo]
|
||||
repo_suffix = -certificates
|
||||
|
||||
; Don't change setting below here unless you know what you're doing!
|
||||
[Internal]
|
||||
last_issued = never
|
||||
|
||||
`
|
||||
func sanitizeDomainKey(s string) string {
|
||||
s = strings.TrimSpace(strings.ToLower(s))
|
||||
r := strings.NewReplacer("/", "_", "\\", "_", " ", "_", ":", "_")
|
||||
return r.Replace(s)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user