implemented gitops controller + drift detection
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
package gitops
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/forgeo/forgebucket/internal/events"
|
||||
"github.com/forgeo/forgebucket/internal/models"
|
||||
)
|
||||
|
||||
// TriggerSync creates a Deployment record in "pending" state and fires
|
||||
// deployment.started — the same path as a manually-triggered deployment.
|
||||
// GitOps is just the trigger; actual execution is handled externally (or via CI).
|
||||
func (c *Controller) TriggerSync(cfg models.GitOpsConfig, desiredSHA string) {
|
||||
var env models.Environment
|
||||
if found, _ := c.db.ID(cfg.EnvID).Get(&env); !found {
|
||||
log.Printf("gitops: sync env %d not found", cfg.EnvID)
|
||||
return
|
||||
}
|
||||
|
||||
now := time.Now().UTC()
|
||||
deploy := &models.Deployment{
|
||||
EnvID: cfg.EnvID,
|
||||
RepoID: cfg.RepoID,
|
||||
SHA: desiredSHA,
|
||||
Ref: "refs/heads/" + cfg.Branch,
|
||||
Status: models.DeployStatusPending,
|
||||
TriggeredBy: "gitops",
|
||||
Description: "GitOps auto-sync",
|
||||
StartedAt: &now,
|
||||
}
|
||||
if _, err := c.db.Insert(deploy); err != nil {
|
||||
log.Printf("gitops: create deployment: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
cfg.SyncStatus = "syncing"
|
||||
c.db.ID(cfg.ID).Cols("sync_status").Update(&cfg) //nolint:errcheck
|
||||
|
||||
c.bus.Publish(events.SubjectDeploymentStarted, events.DeploymentEvent{ //nolint:errcheck
|
||||
DeploymentID: deploy.ID,
|
||||
EnvID: env.ID,
|
||||
EnvName: env.Name,
|
||||
RepoID: deploy.RepoID,
|
||||
SHA: deploy.SHA,
|
||||
Ref: deploy.Ref,
|
||||
Status: string(deploy.Status),
|
||||
TriggeredBy: deploy.TriggeredBy,
|
||||
})
|
||||
|
||||
log.Printf("gitops: triggered sync deploy %d for env %d (%s)", deploy.ID, cfg.EnvID, desiredSHA[:7])
|
||||
}
|
||||
|
||||
// handleDeploymentSucceeded is called when any deployment.succeeded event fires.
|
||||
// If the deployment was GitOps-triggered, it marks the config as synced.
|
||||
func (c *Controller) handleDeploymentSucceeded(data []byte) {
|
||||
var evt events.DeploymentEvent
|
||||
if err := json.Unmarshal(data, &evt); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Only act on deployments triggered by gitops.
|
||||
if evt.TriggeredBy != "gitops" {
|
||||
// Still update ActualSHA and resolve drift if this env has a GitOps config —
|
||||
// manual deployments also advance the state.
|
||||
var cfg models.GitOpsConfig
|
||||
if found, _ := c.db.Where("env_id = ?", evt.EnvID).Get(&cfg); found {
|
||||
markSynced(c.db, evt.EnvID, evt.SHA)
|
||||
log.Printf("gitops: env %d synced via manual deploy (%s)", evt.EnvID, sha7(evt.SHA))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
markSynced(c.db, evt.EnvID, evt.SHA)
|
||||
log.Printf("gitops: env %d synced (%s)", evt.EnvID, sha7(evt.SHA))
|
||||
}
|
||||
|
||||
// handleDeploymentFailed is called when deployment.failed fires.
|
||||
// If the deployment was GitOps-triggered, it reverts SyncStatus back to drifted.
|
||||
func (c *Controller) handleDeploymentFailed(data []byte) {
|
||||
var evt events.DeploymentEvent
|
||||
if err := json.Unmarshal(data, &evt); err != nil {
|
||||
return
|
||||
}
|
||||
if evt.TriggeredBy != "gitops" {
|
||||
return
|
||||
}
|
||||
|
||||
var cfg models.GitOpsConfig
|
||||
if found, _ := c.db.Where("env_id = ?", evt.EnvID).Get(&cfg); !found {
|
||||
return
|
||||
}
|
||||
cfg.SyncStatus = "drifted"
|
||||
c.db.ID(cfg.ID).Cols("sync_status").Update(&cfg) //nolint:errcheck
|
||||
log.Printf("gitops: env %d sync failed — reverting to drifted", evt.EnvID)
|
||||
}
|
||||
Reference in New Issue
Block a user