Skip to content

Commit

Permalink
feat/handle-webhook-notifications (#33)
Browse files Browse the repository at this point in the history
* feat: start implementing webhook WIP

* feat: start implementing web server which will receive webhooks

* feat: WIP implement webhook handler

* feat: make cmd start server instead of webhook

* improvement(webhook): webhook is now handled by the server

* chore: catch webhook init error

* chore: update default server port

* feat: rename annotations methods

* chore: use log instead of logs

* chore(webhook): add some logs just to see where's it crashing

* chore: update log method

* chore: add sshUrls listing

* feat: handle webhook annotation in state machine

* fix: change condition values

---------

Co-authored-by: Alan <alanl@padok.fr>
  • Loading branch information
spoukke and Alan-pad authored Feb 9, 2023
1 parent b6e4e29 commit a206236
Show file tree
Hide file tree
Showing 17 changed files with 348 additions and 55 deletions.
4 changes: 2 additions & 2 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ package cmd
import (
"github.com/padok-team/burrito/cmd/controllers"
"github.com/padok-team/burrito/cmd/runner"
"github.com/padok-team/burrito/cmd/webhook"
"github.com/padok-team/burrito/cmd/server"
"github.com/padok-team/burrito/internal/burrito"

"github.com/spf13/cobra"
Expand All @@ -27,6 +27,6 @@ func buildBurritoCmd(app *burrito.App) *cobra.Command {

cmd.AddCommand(controllers.BuildControllersCmd(app))
cmd.AddCommand(runner.BuildRunnerCmd(app))
cmd.AddCommand(webhook.BuildWebhookCmd(app))
cmd.AddCommand(server.BuildServerCmd(app))
return cmd
}
15 changes: 15 additions & 0 deletions cmd/server/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package server

import (
"github.com/padok-team/burrito/internal/burrito"
"github.com/spf13/cobra"
)

func BuildServerCmd(app *burrito.App) *cobra.Command {
cmd := &cobra.Command{
Use: "server",
Short: "cmd to use burrito's server",
}
cmd.AddCommand(buildServerStartCmd(app))
return cmd
}
21 changes: 21 additions & 0 deletions cmd/server/start.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package server

import (
"github.com/padok-team/burrito/internal/burrito"
"github.com/spf13/cobra"
)

func buildServerStartCmd(app *burrito.App) *cobra.Command {
cmd := &cobra.Command{
Use: "start",
Short: "Start burrito's server",
RunE: func(cmd *cobra.Command, args []string) error {
app.StartServer()
return nil
},
}

cmd.Flags().StringVar(&app.Config.Server.Port, "port", "8080", "port the server listens on")

return cmd
}
18 changes: 0 additions & 18 deletions cmd/webhook/start.go

This file was deleted.

15 changes: 0 additions & 15 deletions cmd/webhook/webhook.go

This file was deleted.

3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/padok-team/burrito
go 1.19

require (
github.com/go-playground/webhooks/v6 v6.0.1
github.com/onsi/ginkgo/v2 v2.6.0
github.com/onsi/gomega v1.24.1
k8s.io/apimachinery v0.26.0
Expand Down Expand Up @@ -56,7 +57,7 @@ require (
github.com/hashicorp/hc-install v0.4.0
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/terraform-exec v0.17.3
github.com/imdario/mergo v0.3.13
github.com/imdario/mergo v0.3.13 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,12 @@ github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXym
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-playground/webhooks/v6 v6.0.1 h1:ssqgU7vZ+xK+/Uwx4zkf5tfmzOHnLBpzSp5bJ4cX3rg=
github.com/go-playground/webhooks/v6 v6.0.1/go.mod h1:GCocmfMtpJdkEOM1uG9p2nXzg1kY5X/LtvQgtPHUaaA=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogits/go-gogs-client v0.0.0-20200905025246-8bb8a50cb355/go.mod h1:cY2AIrMgHm6oOHmR7jY+9TtjzSjQ3iG7tURJG3Y6XH0=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
Expand Down
4 changes: 2 additions & 2 deletions internal/annotations/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const (
ForceApply string = "notifications.terraform.padok.cloud/force-apply"
)

func AddAnnotations(ctx context.Context, c client.Client, obj configv1alpha1.TerraformLayer, annotations map[string]string) error {
func Add(ctx context.Context, c client.Client, obj configv1alpha1.TerraformLayer, annotations map[string]string) error {
patch := client.MergeFrom(obj.DeepCopy())
currentAnnotations := obj.GetAnnotations()
for k, v := range annotations {
Expand All @@ -32,7 +32,7 @@ func AddAnnotations(ctx context.Context, c client.Client, obj configv1alpha1.Ter
return c.Patch(ctx, &obj, patch)
}

func RemoveAnnotation(ctx context.Context, c client.Client, obj configv1alpha1.TerraformLayer, annotation string) error {
func Remove(ctx context.Context, c client.Client, obj configv1alpha1.TerraformLayer, annotation string) error {
patch := client.MergeFrom(obj.DeepCopy())
annotations := obj.GetAnnotations()
delete(annotations, annotation)
Expand Down
8 changes: 4 additions & 4 deletions internal/burrito/burrito.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@ import (
"github.com/padok-team/burrito/internal/burrito/config"
"github.com/padok-team/burrito/internal/controllers"
"github.com/padok-team/burrito/internal/runner"
"github.com/padok-team/burrito/internal/webhook"
"github.com/padok-team/burrito/internal/server"
)

type App struct {
Config *config.Config

Runner Runner
Controllers Controllers
Webhook Webhook
Server Server

Out io.Writer
Err io.Writer
}

type Webhook interface {
type Server interface {
Exec()
}

Expand All @@ -39,7 +39,7 @@ func New() (*App, error) {
Config: c,
Runner: runner.New(c),
Controllers: controllers.New(c),
Webhook: webhook.New(c),
Server: server.New(c),
Out: os.Stdout,
Err: os.Stderr,
}
Expand Down
18 changes: 16 additions & 2 deletions internal/burrito/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,21 @@ type Config struct {
Controller ControllerConfig `yaml:"controller"`
Webhook WebhookConfig `yaml:"webhook"`
Redis Redis `yaml:"redis"`
Server Server `yaml:"server"`
}

type WebhookConfig struct {
RepositoryProvider string `yaml:"provider"`
Secret string `yaml:"secret"`
Github WebhookGithubConfig `yaml:"github"`
Gitlab WebhookGitlabConfig `yaml:"gitlab"`
Namespace string `yaml:"namespace"`
}

type WebhookGithubConfig struct {
Secret string `yaml:"secret"`
}

type WebhookGitlabConfig struct {
Secret string `yaml:"secret"`
}

type ControllerConfig struct {
Expand Down Expand Up @@ -62,6 +72,10 @@ type Redis struct {
Database int `yaml:"database"`
}

type Server struct {
Port string `yaml:"port"`
}

func (c *Config) Load(flags *pflag.FlagSet) error {
v := viper.New()

Expand Down
5 changes: 5 additions & 0 deletions internal/burrito/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package burrito

func (app *App) StartServer() {
app.Server.Exec()
}
5 changes: 0 additions & 5 deletions internal/burrito/webhook.go

This file was deleted.

33 changes: 33 additions & 0 deletions internal/controllers/terraformlayer/conditions.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,39 @@ func (r *Reconciler) IsPlanArtifactUpToDate(t *configv1alpha1.TerraformLayer) (m
return condition, false
}

func (r *Reconciler) IsLastCommitPlanned(t *configv1alpha1.TerraformLayer) (metav1.Condition, bool) {
condition := metav1.Condition{
Type: "IsLastCommitPlanned",
ObservedGeneration: t.GetObjectMeta().GetGeneration(),
Status: metav1.ConditionUnknown,
LastTransitionTime: metav1.NewTime(time.Now()),
}
lastPlannedCommit, ok := t.Annotations[annotations.LastPlanCommit]
if !ok {
condition.Reason = "NoPlanHasRunYet"
condition.Message = "No plan has run on this layer yet"
condition.Status = metav1.ConditionTrue
return condition, true
}
lastBranchCommit, ok := t.Annotations[annotations.LastBranchCommit]
if !ok {
condition.Reason = "NoCommitReceived"
condition.Message = "No commit has been received from webhook"
condition.Status = metav1.ConditionTrue
return condition, true
}
if lastPlannedCommit == lastBranchCommit {
condition.Reason = "LastCommitPlanned"
condition.Message = "The last commit has already been planned"
condition.Status = metav1.ConditionTrue
return condition, false
}
condition.Reason = "LastCommitNotPlanned"
condition.Message = "The last received commit has not been planned yet"
condition.Status = metav1.ConditionFalse
return condition, true
}

func (r *Reconciler) IsApplyUpToDate(t *configv1alpha1.TerraformLayer) (metav1.Condition, bool) {
condition := metav1.Condition{
Type: "IsApplyUpToDate",
Expand Down
7 changes: 4 additions & 3 deletions internal/controllers/terraformlayer/states.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,17 @@ func (r *Reconciler) GetState(ctx context.Context, l *configv1alpha1.TerraformLa
log := log.FromContext(ctx)
c1, isPlanArtifactUpToDate := r.IsPlanArtifactUpToDate(l)
c2, isApplyUpToDate := r.IsApplyUpToDate(l)
c3, isLastCommitPlanned := r.IsLastCommitPlanned(l)
// c3, hasFailed := HasFailed(r)
conditions := []metav1.Condition{c1, c2}
conditions := []metav1.Condition{c1, c2, c3}
switch {
case isPlanArtifactUpToDate && isApplyUpToDate:
log.Info("Layer is up to date, waiting for a new drift detection cycle")
return &IdleState{}, conditions
case isPlanArtifactUpToDate && !isApplyUpToDate:
case isPlanArtifactUpToDate && !isApplyUpToDate && !isLastCommitPlanned:
log.Info("Layer needs to be applied, acquiring lock and creating a new runner")
return &ApplyNeededState{}, conditions
case !isPlanArtifactUpToDate:
case !isPlanArtifactUpToDate || !isLastCommitPlanned:
log.Info("Layer needs to be planned, acquiring lock and creating a new runner")
return &PlanNeededState{}, conditions
default:
Expand Down
2 changes: 1 addition & 1 deletion internal/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func (r *Runner) Exec() {
number++
ann[annotations.Failure] = strconv.Itoa(number)
}
err = annotations.AddAnnotations(context.TODO(), r.client, *r.layer, ann)
err = annotations.Add(context.TODO(), r.client, *r.layer, ann)
if err != nil {
log.Printf("Could not update layer annotations: %s", err)
}
Expand Down
48 changes: 48 additions & 0 deletions internal/server/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package server

import (
"errors"
"fmt"
"log"
"net/http"
"os"

"github.com/padok-team/burrito/internal/burrito/config"
"github.com/padok-team/burrito/internal/webhook"
)

type Server struct {
config *config.Config
Webhook *webhook.Webhook
}

func New(c *config.Config) *Server {
webhook := webhook.New(c)
err := webhook.Init()
if err != nil {
log.Printf("error initializing webhook: %s", err)
}
return &Server{
config: c,
Webhook: webhook,
}
}

func (s *Server) Exec() {
http.HandleFunc("/healthz", handleHealthz)
http.HandleFunc("/webhook", s.Webhook.GetHttpHandler())

err := http.ListenAndServe(fmt.Sprintf(":%s", s.config.Server.Port), nil)
if errors.Is(err, http.ErrServerClosed) {
log.Println("server is closed")
}
if err != nil {
log.Printf("error starting server, exiting: %s", err)
os.Exit(1)
}
}

func handleHealthz(w http.ResponseWriter, r *http.Request) {
// The HTTP server is always healthy.
// TODO: check it can get terraformlayers and/or repositories
}
Loading

0 comments on commit a206236

Please sign in to comment.