123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- package handlers
- import (
- "encoding/json"
- "fmt"
- "log"
- "net/http"
- "sync"
- "time"
- "git.linuxforward.com/byop/byop-engine/models"
- "github.com/gin-gonic/gin"
- )
- // AutoDeployHandler handles auto-deployment related operations
- type AutoDeployHandler struct {
- autoDeploySettings *models.AutoDeploySettings
- settingsMutex sync.RWMutex
- deploymentQueue chan *models.AutoDeployRequest
- }
- // NewAutoDeployHandler creates a new AutoDeployHandler
- func NewAutoDeployHandler() *AutoDeployHandler {
- return &AutoDeployHandler{}
- }
- // RegisterRoutes registers routes for auto-deployment operations
- func (h *AutoDeployHandler) RegisterRoutes(r *gin.RouterGroup) {
- r.POST("/client", h.AutoDeployClient)
- r.POST("/webhook", h.AutoDeployWebhook)
- r.PUT("/settings", h.UpdateAutoDeploySettings)
- r.GET("/settings", h.GetAutoDeploySettings)
- }
- // AutoDeployClient handles requests to deploy for a client
- func (h *AutoDeployHandler) AutoDeployClient(c *gin.Context) {
- // Parse the request
- var request *models.AutoDeployRequest
- if err := c.ShouldBindJSON(&request); err != nil {
- c.JSON(http.StatusBadRequest, gin.H{
- "error": "Invalid request body",
- })
- return
- }
- // Check if auto-deployment is enabled
- h.settingsMutex.RLock()
- enabled := h.autoDeploySettings.Enabled
- h.settingsMutex.RUnlock()
- if !enabled {
- c.JSON(http.StatusServiceUnavailable, gin.H{
- "error": "Auto-deployment is currently disabled",
- })
- return
- }
- // Queue the deployment request
- select {
- case h.deploymentQueue <- request:
- // Successfully queued
- default:
- // Queue is full
- c.JSON(http.StatusServiceUnavailable, gin.H{
- "error": "Deployment queue is full, try again later",
- })
- return
- }
- // Return a success response
- c.JSON(http.StatusAccepted, gin.H{
- "status": "queued",
- "message": "Deployment request has been queued",
- "clientId": request.ClientID,
- "queuedAt": time.Now(),
- })
- }
- // AutoDeployWebhook handles webhook triggers for auto-deployment
- func (h *AutoDeployHandler) AutoDeployWebhook(c *gin.Context) {
- // Parse the webhook payload
- var payload *models.WebhookPayload
- if err := c.ShouldBindJSON(&payload); err != nil {
- c.JSON(http.StatusBadRequest, gin.H{
- "error": "Invalid webhook payload",
- })
- return
- }
- // Validate the webhook signature
- h.settingsMutex.RLock()
- secret := h.autoDeploySettings.WebhookSecret
- enabled := h.autoDeploySettings.Enabled
- h.settingsMutex.RUnlock()
- // This is a simplified signature check, in production use HMAC
- if c.GetHeader("X-Webhook-Signature") != secret {
- c.JSON(http.StatusUnauthorized, gin.H{
- "error": "Invalid webhook signature",
- })
- return
- }
- if !enabled {
- c.JSON(http.StatusServiceUnavailable, gin.H{
- "error": "Auto-deployment is currently disabled",
- })
- return
- }
- // Handle different event types
- switch payload.Event {
- case "client.created":
- // Check if we should auto-deploy for new clients
- h.settingsMutex.RLock()
- autoDeploy := h.autoDeploySettings.AutoDeployNewClients
- h.settingsMutex.RUnlock()
- if autoDeploy && payload.ClientID != "" {
- // Queue a deployment request
- request := &models.AutoDeployRequest{
- ClientID: payload.ClientID,
- // Use defaults for other fields
- }
- select {
- case h.deploymentQueue <- request:
- // Successfully queued
- default:
- // Queue is full
- log.Printf("Deployment queue is full, skipping auto-deployment for client %s", payload.ClientID)
- }
- }
- case "deployment.requested":
- // Handle explicit deployment requests
- if payload.ClientID == "" {
- c.JSON(http.StatusBadRequest, gin.H{
- "error": "client_id is required for deployment requests",
- })
- return
- }
- // Parse the deployment data
- var deployData struct {
- TemplateID string `json:"template_id"`
- ProviderID string `json:"provider_id"`
- Region string `json:"region"`
- Tags map[string]string `json:"tags"`
- }
- if err := json.Unmarshal(payload.Data, &deployData); err != nil {
- c.JSON(http.StatusBadRequest, gin.H{
- "error": "Invalid deployment data",
- })
- return
- }
- // Queue the deployment
- request := &models.AutoDeployRequest{
- ClientID: payload.ClientID,
- TemplateID: deployData.TemplateID,
- ProviderID: deployData.ProviderID,
- Region: deployData.Region,
- Tags: deployData.Tags,
- }
- select {
- case h.deploymentQueue <- request:
- // Successfully queued
- default:
- // Queue is full
- c.JSON(http.StatusServiceUnavailable, gin.H{
- "error": "Deployment queue is full, try again later",
- })
- return
- }
- default:
- // Unknown event type
- c.JSON(http.StatusBadRequest, gin.H{
- "error": fmt.Sprintf("Unsupported event type: %s", payload.Event),
- })
- return
- }
- // Return a success response
- c.JSON(http.StatusOK, gin.H{
- "status": "received",
- "event": payload.Event,
- "timestamp": time.Now(),
- "requestId": payload.RequestID,
- })
- }
- // UpdateAutoDeploySettings updates the auto-deployment settings
- func (h *AutoDeployHandler) UpdateAutoDeploySettings(c *gin.Context) {
- // Parse the settings
- var settings *models.AutoDeploySettings
- if err := c.ShouldBindJSON(&settings); err != nil {
- c.JSON(http.StatusBadRequest, gin.H{
- "error": "Invalid settings format",
- })
- return
- }
- // Validate settings
- if settings.DefaultProviderID == "" {
- c.JSON(http.StatusBadRequest, gin.H{
- "error": "default_provider_id is required",
- })
- return
- }
- if settings.DefaultTemplateID == "" {
- c.JSON(http.StatusBadRequest, gin.H{
- "error": "default_template_id is required",
- })
- return
- }
- // Update the settings
- h.settingsMutex.Lock()
- // Keep the webhook secret if not provided
- if settings.WebhookSecret == "" {
- settings.WebhookSecret = h.autoDeploySettings.WebhookSecret
- }
- h.autoDeploySettings = settings
- h.settingsMutex.Unlock()
- // Return the updated settings (without sensitive fields)
- h.settingsMutex.RLock()
- responseSettings := h.autoDeploySettings
- responseSettings.WebhookSecret = "********" // Hide the actual secret
- h.settingsMutex.RUnlock()
- c.JSON(http.StatusOK, responseSettings)
- }
- // GetAutoDeploySettings returns the current auto-deployment settings
- func (h *AutoDeployHandler) GetAutoDeploySettings(c *gin.Context) {
- // Get a copy of the settings
- h.settingsMutex.RLock()
- settings := h.autoDeploySettings
- settings.WebhookSecret = "********" // Hide the actual secret
- h.settingsMutex.RUnlock()
- // Return the settings
- c.JSON(http.StatusOK, settings)
- }
|