fix(ssl): Add --non-interactive flag to certbot commands by nfebe · Pull Request #109 · flatrun/agent · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/api/ssl_deletion_test.go
35 changes: 33 additions & 2 deletions internal/docker/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type composeFile struct {
type composeService struct {
Image string `yaml:"image"`
Ports []interface{} `yaml:"ports"`
Expose []interface{} `yaml:"expose"`
Networks []string `yaml:"networks"`
Volumes []string `yaml:"volumes"`
}
Expand Down Expand Up @@ -196,6 +197,12 @@ func (d *Discovery) parseComposeServices(composePath string) ([]models.Service,
service.Ports = append(service.Ports, portStr)
}
}
for _, p := range svc.Expose {
portStr := d.parsePort(p)
if portStr != "" {
service.Ports = append(service.Ports, portStr)
}
}

services = append(services, service)
}
Expand Down Expand Up @@ -538,7 +545,25 @@ func (d *Discovery) UpdateComposeFile(name string, content string) error {
_ = os.WriteFile(backup, data, 0644)
}

return os.WriteFile(composePath, []byte(content), 0644)
if err := os.WriteFile(composePath, []byte(content), 0644); err != nil {
return err
}

metadataPath := filepath.Join(dirPath, "service.yml")
if _, err := os.Stat(metadataPath); err == nil {
if newMeta := d.generateMetadataFromCompose(composePath, name); newMeta != nil {
existing, err := d.loadMetadata(metadataPath)
if err == nil {
existing.Networking.ContainerPort = newMeta.Networking.ContainerPort
if newMeta.Networking.Service != "" {
existing.Networking.Service = newMeta.Networking.Service
}
d.SaveMetadata(name, existing)
Comment thread
nfebe marked this conversation as resolved.
}
}
}

return nil
}

func (d *Discovery) SaveMetadata(name string, metadata *models.ServiceMetadata) error {
Expand Down Expand Up @@ -602,6 +627,12 @@ func (d *Discovery) generateMetadataFromCompose(composePath, name string) *model
metadata.Networking.ContainerPort = port
}
}
} else if len(svc.Expose) > 0 {
if portStr := d.parsePort(svc.Expose[0]); portStr != "" {
if port := d.extractContainerPort(portStr); port > 0 {
metadata.Networking.ContainerPort = port
}
}
}
}

Expand All @@ -618,7 +649,7 @@ func (d *Discovery) pickPrimaryService(services map[string]composeService) (stri
}
}
for name, svc := range services {
if len(svc.Ports) > 0 {
Comment thread
nfebe marked this conversation as resolved.
if len(svc.Ports) > 0 || len(svc.Expose) > 0 {
return name, svc
}
}
Expand Down
135 changes: 135 additions & 0 deletions internal/docker/discovery_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import (
"path/filepath"
"sort"
"testing"

"github.com/flatrun/agent/pkg/models"
"gopkg.in/yaml.v3"
)

func TestExtractBindMountPath(t *testing.T) {
Expand Down Expand Up @@ -408,6 +411,138 @@ func TestGenerateMetadataFromCompose_ServiceName(t *testing.T) {
}
}

func TestGenerateMetadataFromCompose_Expose(t *testing.T) {
tests := []struct {
name string
compose string
wantPort int
}{
{
name: "expose sets container port",
compose: `services:
app:
image: myapp:latest
expose:
- "80"
`,
wantPort: 80,
},
{
name: "ports takes precedence over expose",
compose: `services:
app:
image: myapp:latest
ports:
- "8080:3000"
expose:
- "80"
`,
wantPort: 3000,
},
{
name: "expose picks primary service in multi-service",
compose: `services:
app:
image: myapp:latest
expose:
- "8080"
db:
image: postgres:15
`,
wantPort: 8080,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "expose-test-*")
if err != nil {
t.Fatalf("Failed to create temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)

composePath := filepath.Join(tmpDir, "docker-compose.yml")
if err := os.WriteFile(composePath, []byte(tt.compose), 0644); err != nil {
t.Fatalf("Failed to write compose file: %v", err)
}

d := NewDiscovery(tmpDir)
metadata := d.generateMetadataFromCompose(composePath, "test")
if metadata == nil {
t.Fatal("generateMetadataFromCompose returned nil")
}

if metadata.Networking.ContainerPort != tt.wantPort {
t.Errorf("ContainerPort = %d, want %d", metadata.Networking.ContainerPort, tt.wantPort)
}
})
}
}

func TestUpdateComposeFile_SyncsMetadata(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "sync-test-*")
if err != nil {
t.Fatalf("Failed to create temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)

deployDir := filepath.Join(tmpDir, "myapp")
if err := os.MkdirAll(deployDir, 0755); err != nil {
t.Fatalf("Failed to create deploy dir: %v", err)
}

compose := `services:
app:
image: myapp:latest
expose:
- "3000"
`
composePath := filepath.Join(deployDir, "docker-compose.yml")
if err := os.WriteFile(composePath, []byte(compose), 0644); err != nil {
t.Fatalf("Failed to write compose: %v", err)
}

d := NewDiscovery(tmpDir)
metadata := &models.ServiceMetadata{
Name: "myapp",
Networking: models.NetworkingConfig{
ContainerPort: 3000,
Expose: true,
},
}
if err := d.SaveMetadata("myapp", metadata); err != nil {
t.Fatalf("Failed to save metadata: %v", err)
}

updatedCompose := `services:
app:
image: myapp:latest
expose:
- "8080"
`
if err := d.UpdateComposeFile("myapp", updatedCompose); err != nil {
t.Fatalf("UpdateComposeFile failed: %v", err)
}

metadataPath := filepath.Join(deployDir, "service.yml")
data, err := os.ReadFile(metadataPath)
if err != nil {
t.Fatalf("Failed to read service.yml: %v", err)
}

var updated models.ServiceMetadata
if err := yaml.Unmarshal(data, &updated); err != nil {
t.Fatalf("Failed to parse service.yml: %v", err)
}

if updated.Networking.ContainerPort != 8080 {
t.Errorf("ContainerPort = %d, want 8080", updated.Networking.ContainerPort)
}
if !updated.Networking.Expose {
t.Error("Expose should be preserved as true")
}
}

func TestExtractBindMounts(t *testing.T) {
tests := []struct {
name string
Expand Down
2 changes: 1 addition & 1 deletion internal/proxy/orchestrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type Orchestrator struct {
func NewOrchestrator(cfg *config.Config) *Orchestrator {
return &Orchestrator{
nginx: nginx.NewManager(&cfg.Nginx, cfg.DeploymentsPath, cfg.Certbot.WebrootPath),
ssl: ssl.NewManager(&cfg.Certbot, cfg.DeploymentsPath),
ssl: ssl.NewManager(&cfg.Certbot, cfg.DeploymentsPath, nil),
}
}

Expand Down
22 changes: 16 additions & 6 deletions internal/setup/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package setup
import (
"net"
"net/http"
"net/mail"
"time"

"github.com/flatrun/agent/internal/auth"
Expand Down Expand Up @@ -94,9 +95,10 @@ func (h *Handlers) VerifyDNS(c *gin.Context) {

func (h *Handlers) ConfigureSettings(c *gin.Context) {
var req struct {
Domain string `json:"domain"`
AutoSSL *bool `json:"auto_ssl"`
CORSOrigins []string `json:"cors_origins"`
Domain string `json:"domain"`
AutoSSL *bool `json:"auto_ssl"`
CertbotEmail string `json:"certbot_email"`
CORSOrigins []string `json:"cors_origins"`
}

if err := c.ShouldBindJSON(&req); err != nil {
Expand All @@ -111,6 +113,13 @@ func (h *Handlers) ConfigureSettings(c *gin.Context) {
if req.AutoSSL != nil {
cfg.Domain.AutoSSL = *req.AutoSSL
}
if req.CertbotEmail != "" {
Comment thread
nfebe marked this conversation as resolved.
if _, err := mail.ParseAddress(req.CertbotEmail); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid email format"})
return
}
cfg.Certbot.Email = req.CertbotEmail
}
if len(req.CORSOrigins) > 0 {
originMap := make(map[string]bool)
for _, e := range cfg.API.AllowedOrigins {
Expand All @@ -130,9 +139,10 @@ func (h *Handlers) ConfigureSettings(c *gin.Context) {
}

c.JSON(http.StatusOK, gin.H{
"message": "Settings configured",
"domain": cfg.Domain.DefaultDomain,
"auto_ssl": cfg.Domain.AutoSSL,
"message": "Settings configured",
"domain": cfg.Domain.DefaultDomain,
"auto_ssl": cfg.Domain.AutoSSL,
"certbot_email": cfg.Certbot.Email,
})
}

Expand Down
31 changes: 27 additions & 4 deletions internal/ssl/manager.go
Loading
Loading