Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: fix for temporary errors #201

Merged
merged 2 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all 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 .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
type=ref,event=branch
type=ref,event=tag
type=ref,event=pr
type=semver,pattern={{major}},enable=${{ github.event_name == 'push' && contains(github.ref, 'refs/tags/') }}
type=semver,pattern=v{{major}},enable=${{ github.event_name == 'push' && contains(github.ref, 'refs/tags/') }}
images: |
ghcr.io/cresta/atlantis-drift-detection
- name: Build and push
Expand Down
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ runs:
using: 'docker'
# TODO: Figure out a way to auto update this. It's very useful for speeding up the action to not have it build the
# container each run
image: 'docker://ghcr.io/cresta/atlantis-drift-detection:v0.0.11'
image: 'docker://ghcr.io/cresta/atlantis-drift-detection:v1'
13 changes: 9 additions & 4 deletions cmd/atlantis-drift-detection/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ package main
import (
"context"
"fmt"
"net/http"
"os"
"time"

"github.com/cresta/atlantis-drift-detection/internal/atlantis"
"github.com/cresta/atlantis-drift-detection/internal/drifter"
"github.com/cresta/atlantis-drift-detection/internal/notification"
Expand All @@ -11,9 +15,6 @@ import (
"github.com/cresta/gogit"
"github.com/cresta/gogithub"
"github.com/joho/godotenv"
"net/http"
"os"
"time"

// Empty import allows pinning to version atlantis uses
_ "github.com/nlopes/slack"
Expand Down Expand Up @@ -100,7 +101,11 @@ func main() {
logger.Info("setting up slack webhook notification")
notif.Notifications = append(notif.Notifications, slackClient)
}
ghClient, err := gogithub.NewGQLClient(ctx, logger, nil)
var existingConfig *gogithub.NewGQLClientConfig
if os.Getenv("GITHUB_TOKEN") != "" {
existingConfig = &gogithub.NewGQLClientConfig{Token: os.Getenv("GITHUB_TOKEN")}
}
ghClient, err := gogithub.NewGQLClient(ctx, logger, existingConfig)
if err != nil {
logger.Panic("failed to create github client", zap.Error(err))
}
Expand Down
20 changes: 17 additions & 3 deletions internal/atlantis/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import (
"context"
"encoding/json"
"fmt"
"github.com/runatlantis/atlantis/server/controllers"
"github.com/runatlantis/atlantis/server/events/command"
"io"
"net/http"
"strings"

"github.com/runatlantis/atlantis/server/controllers"
"github.com/runatlantis/atlantis/server/events/command"
)

type Client struct {
Expand Down Expand Up @@ -65,6 +66,10 @@ type TemporaryError interface {
error
}

type errorResponse struct {
Error string `json:"error"`
}

func (p *possiblyTemporaryError) Temporary() bool {
return true
}
Expand Down Expand Up @@ -107,11 +112,20 @@ func (c *Client) PlanSummary(ctx context.Context, req *PlanSummaryRequest) (*Pla
if err := resp.Body.Close(); err != nil {
return nil, fmt.Errorf("unable to close response body: %w", err)
}
if resp.StatusCode == http.StatusUnauthorized {
var errResp errorResponse
if err := json.NewDecoder(&fullBody).Decode(&errResp); err != nil {
return nil, fmt.Errorf("unauthorized request to %s: %w", destination, err)
}
return nil, fmt.Errorf("unauthorized request to %s: %s", destination, errResp.Error)
}

var bodyResult command.Result
if err := json.NewDecoder(&fullBody).Decode(&bodyResult); err != nil {
retErr := fmt.Errorf("error decoding plan response(code:%d)(status:%s)(body:%s): %w", resp.StatusCode, resp.Status, fullBody.String(), err)
if resp.StatusCode == http.StatusServiceUnavailable {
if resp.StatusCode == http.StatusServiceUnavailable || resp.StatusCode == http.StatusInternalServerError {
// This is a bit of a hack, but atlantis sometimes returns errors we can't fully process. These could be
// because the workspace won't apply, or because the service is just overloaded. We cannot tell.
return nil, &possiblyTemporaryError{retErr}
}
return nil, retErr
Expand Down
9 changes: 9 additions & 0 deletions internal/notification/multi.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ type Multi struct {
Notifications []Notification
}

func (m *Multi) TemporaryError(ctx context.Context, dir string, workspace string, err error) error {
for _, n := range m.Notifications {
if err := n.TemporaryError(ctx, dir, workspace, err); err != nil {
return err
}
}
return nil
}

func (m *Multi) ExtraWorkspaceInRemote(ctx context.Context, dir string, workspace string) error {
for _, n := range m.Notifications {
if err := n.ExtraWorkspaceInRemote(ctx, dir, workspace); err != nil {
Expand Down
2 changes: 2 additions & 0 deletions internal/notification/notification.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ type Notification interface {
ExtraWorkspaceInRemote(ctx context.Context, dir string, workspace string) error
MissingWorkspaceInRemote(ctx context.Context, dir string, workspace string) error
PlanDrift(ctx context.Context, dir string, workspace string) error
// TemporaryError is called when an error occurs but we can't really tell what it means
TemporaryError(ctx context.Context, dir string, workspace string, err error) error
}
4 changes: 4 additions & 0 deletions internal/notification/slackwebhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ type SlackWebhook struct {
HTTPClient *http.Client
}

func (s *SlackWebhook) TemporaryError(ctx context.Context, dir string, workspace string, err error) error {
return s.sendSlackMessage(ctx, fmt.Sprintf("Unknown error in remote\nDirectory: %s\nWorkspace: %s\nError: %s", dir, workspace, err.Error()))
}

func NewSlackWebhook(webhookURL string, HTTPClient *http.Client) *SlackWebhook {
if webhookURL == "" {
return nil
Expand Down
12 changes: 9 additions & 3 deletions internal/notification/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ package notification

import (
"context"
"github.com/cresta/gogithub"
"sync"

"github.com/cresta/gogithub"
)

func NewWorkflow(ghClient gogithub.GitHub, owner string, repo string, id string, ref string) *Workflow {
Expand All @@ -30,11 +31,16 @@ type Workflow struct {
directoriesDone map[string]struct{}
}

func (w *Workflow) ExtraWorkspaceInRemote(ctx context.Context, dir string, workspace string) error {
func (w *Workflow) TemporaryError(_ context.Context, _ string, _ string, _ error) error {
// Ignored
return nil
}

func (w *Workflow) ExtraWorkspaceInRemote(_ context.Context, _ string, _ string) error {
return nil
}

func (w *Workflow) MissingWorkspaceInRemote(ctx context.Context, dir string, workspace string) error {
func (w *Workflow) MissingWorkspaceInRemote(_ context.Context, _ string, _ string) error {
return nil
}

Expand Down
6 changes: 6 additions & 0 deletions internal/notification/zap.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@ package notification

import (
"context"

"go.uber.org/zap"
)

type Zap struct {
Logger *zap.Logger
}

func (I *Zap) TemporaryError(_ context.Context, dir string, workspace string, err error) error {
I.Logger.Error("Unknown error in remote", zap.String("dir", dir), zap.String("workspace", workspace), zap.Error(err))
return nil
}

func (I *Zap) PlanDrift(_ context.Context, dir string, workspace string) error {
I.Logger.Info("Plan has drifted", zap.String("dir", dir), zap.String("workspace", workspace))
return nil
Expand Down
Loading