-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.go
More file actions
157 lines (134 loc) · 3.66 KB
/
server.go
File metadata and controls
157 lines (134 loc) · 3.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package webhookdeploy
import (
"context"
"errors"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"gopkg.in/yaml.v3"
)
type Deployments struct {
Secret string `yaml:"secret"`
Remote Remote `yaml:"remote"`
Commands []string `yaml:"commands"`
}
type Remote struct {
User string `yaml:"user"`
ServerIP string `yaml:"server_ip"`
PrivateKey string `yaml:"private_key"`
}
type WebInterface struct {
Enabled bool `yaml:"enabled"`
Listen string `yaml:"listen,omitempty"`
Username string `yaml:"username"`
Password string `yaml:"password"`
}
type Config struct {
Listen string `yaml:"listen,omitempty"`
KnowHosts string `yaml:"ssh-known-hosts"`
WebInterface WebInterface `yaml:"web-interface,omitempty"`
Deployments map[string]Deployments `yaml:"deployments"`
}
func loadConfig(config *Config, configPath string) error {
data, err := os.ReadFile(configPath)
if err != nil {
if !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("failed to read config file: %w", err)
}
log.Println("Warning: config file not found")
}
err = yaml.Unmarshal(data, config)
return err
}
type Option func(*Config) error
func WithConfigFile(path string) Option {
return func(c *Config) error {
return loadConfig(c, path)
}
}
// NewConfig creates a Config instance with optional settings
func NewConfig(opts ...Option) (*Config, error) {
// Set defaults
cfg := &Config{
Listen: "127.0.0.1:8080",
KnowHosts: "/etc/webhook-deploy/known_hosts",
WebInterface: WebInterface{
Enabled: false,
Listen: "127.0.0.1:9080",
Username: "",
Password: "",
},
}
// Apply options
for _, opt := range opts {
if err := opt(cfg); err != nil {
return nil, err
}
}
return cfg, nil
}
func Start(opts ...Option) error {
// Create config from options
conf, err := NewConfig(opts...)
if err != nil {
return err
}
// Initialize HTTP router
router, webInterface := newApp(conf)
// Channel to listen for errors from either server
serverErrChan := make(chan error, 1)
// Start webhook server
server := &http.Server{
Addr: conf.Listen,
Handler: router,
}
go func() {
log.Printf("Webhook server listening on %s", conf.Listen)
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
serverErrChan <- fmt.Errorf("Webhook error: %w", err)
}
}()
// Start web interface server if enabled
var webServer *http.Server
if conf.WebInterface.Enabled {
webServer = &http.Server{
Addr: conf.WebInterface.Listen,
Handler: webInterface,
}
go func() {
log.Printf("Web interface server listening on %s", conf.WebInterface.Listen)
if err := webServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
serverErrChan <- fmt.Errorf("Web interface error: %w", err)
}
}()
}
// Wait for a shutdown signal or a server error
quitChan := make(chan os.Signal, 1)
signal.Notify(quitChan, syscall.SIGINT, syscall.SIGTERM)
select {
case err := <-serverErrChan:
log.Printf("A server has failed: %v", err)
case sig := <-quitChan:
log.Printf("Received signal %v. Shutting down...", sig)
}
// Create a context with a timeout for shutdown
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
// Shutdown the servers
log.Println("Shutting down webhook server...")
if err := server.Shutdown(ctx); err != nil {
log.Printf("Webhook server shutdown failed: %v", err)
}
if webServer != nil {
log.Println("Shutting down web interface server...")
if err := webServer.Shutdown(ctx); err != nil {
log.Printf("Web interface server shutdown failed: %v", err)
}
}
log.Println("Shutdown complete.")
return nil
}