detached 65f28f2

Fix deployment errors not being returned properly

commit
65f28f212de6573224d4b2603319cefc565c699c
author
bamen · · 2024-09-27 08:13 UTC
parent
6f8e085
signature
unsigned
5 files · +69 -32
M buildpush-dev.sh +2 -2
@@ -20,8 +20,8 @@ mkdir -p $DIST_DIR
2020
2121 # Build Go binaries for multiple platforms with CGO_ENABLED=0
2222 echo "Building Go binaries..."
23-CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o $DIST_DIR/gordon-linux-amd64 ./cmd/cli
24-CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o $DIST_DIR/gordon-linux-arm64 ./cmd/cli
23+CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o $DIST_DIR/gordon-linux-amd64 ./main.go
24+CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o $DIST_DIR/gordon-linux-arm64 ./main.go
2525
2626 # Clean up any dangling images before building
2727 echo "Cleaning up dangling images..."
@@ -20,8 +20,8 @@ mkdir -p $DIST_DIR
20 20
21 # Build Go binaries for multiple platforms with CGO_ENABLED=021 # Build Go binaries for multiple platforms with CGO_ENABLED=0
22 echo "Building Go binaries..."22 echo "Building Go binaries..."
23-CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o $DIST_DIR/gordon-linux-amd64 ./cmd/cli23+CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o $DIST_DIR/gordon-linux-amd64 ./main.go
24-CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o $DIST_DIR/gordon-linux-arm64 ./cmd/cli24+CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o $DIST_DIR/gordon-linux-arm64 ./main.go
25 25
26 # Clean up any dangling images before building26 # Clean up any dangling images before building
27 echo "Cleaning up dangling images..."27 echo "Cleaning up dangling images..."
M internal/cli/cmd/deploy.go +12 -13
@@ -136,27 +136,26 @@ func deployImage(a *cli.App, reader io.Reader, imageName, port, targetDomain str
136136
137137 resp, err := handler.SendHTTPRequest(a, &reqPayload, "POST", "/deploy")
138138 if err != nil {
139- return &common.DeploymentError{
140- StatusCode: 0,
141- Message: fmt.Sprintf("error sending HTTP request: %v", err),
139+ if deployErr, ok := err.(*common.DeploymentError); ok {
140+ log.Error("Deployment failed",
141+ "status_code", deployErr.StatusCode,
142+ "message", deployErr.Message,
143+ )
144+ } else {
145+ log.Error("Error sending HTTP request", "error", err)
142146 }
147+ return nil // Return nil to prevent double-logging
143148 }
144149
145150 var deployResponse common.DeployResponse
146151 if err := json.Unmarshal(resp.Body, &deployResponse); err != nil {
147- return &common.DeploymentError{
148- StatusCode: resp.StatusCode,
149- Message: fmt.Sprintf("error parsing response: %v", err),
150- RawResponse: string(resp.Body),
151- }
152+ log.Error("Error parsing response", "error", err)
153+ return nil
152154 }
153155
154156 if !deployResponse.Success {
155- return &common.DeploymentError{
156- StatusCode: resp.StatusCode,
157- Message: deployResponse.Message,
158- RawResponse: string(resp.Body),
159- }
157+ log.Error("Deployment failed", "message", deployResponse.Message)
158+ return nil
160159 }
161160
162161 log.Info("Application deployed", "domain", deployResponse.Domain)
@@ -136,27 +136,26 @@ func deployImage(a *cli.App, reader io.Reader, imageName, port, targetDomain str
136 136
137 resp, err := handler.SendHTTPRequest(a, &reqPayload, "POST", "/deploy")137 resp, err := handler.SendHTTPRequest(a, &reqPayload, "POST", "/deploy")
138 if err != nil {138 if err != nil {
139- return &common.DeploymentError{139+ if deployErr, ok := err.(*common.DeploymentError); ok {
140- StatusCode: 0,140+ log.Error("Deployment failed",
141- Message: fmt.Sprintf("error sending HTTP request: %v", err),141+ "status_code", deployErr.StatusCode,
142+ "message", deployErr.Message,
143+ )
144+ } else {
145+ log.Error("Error sending HTTP request", "error", err)
142 }146 }
147+ return nil // Return nil to prevent double-logging
143 }148 }
144 149
145 var deployResponse common.DeployResponse150 var deployResponse common.DeployResponse
146 if err := json.Unmarshal(resp.Body, &deployResponse); err != nil {151 if err := json.Unmarshal(resp.Body, &deployResponse); err != nil {
147- return &common.DeploymentError{152+ log.Error("Error parsing response", "error", err)
148- StatusCode: resp.StatusCode,153+ return nil
149- Message: fmt.Sprintf("error parsing response: %v", err),
150- RawResponse: string(resp.Body),
151- }
152 }154 }
153 155
154 if !deployResponse.Success {156 if !deployResponse.Success {
155- return &common.DeploymentError{157+ log.Error("Deployment failed", "message", deployResponse.Message)
156- StatusCode: resp.StatusCode,158+ return nil
157- Message: deployResponse.Message,
158- RawResponse: string(resp.Body),
159- }
160 }159 }
161 160
162 log.Info("Application deployed", "domain", deployResponse.Domain)161 log.Info("Application deployed", "domain", deployResponse.Domain)
M internal/cli/handler/http.go +14 -4
@@ -66,7 +66,10 @@ func SendHTTPRequest(a *cli.App, rp *common.RequestPayload, method string, endpo
6666 }
6767
6868 if resp.StatusCode != http.StatusOK {
69- var errorResp map[string]interface{}
69+ var errorResp struct {
70+ Success bool `json:"success"`
71+ Message string `json:"message"`
72+ }
7073 if err := json.Unmarshal(body, &errorResp); err == nil {
7174 if resp.StatusCode == http.StatusUnauthorized && !reauthenticated {
7275 fmt.Println("Token is invalid or expired. Initiating re-authentication...")
@@ -78,10 +81,17 @@ func SendHTTPRequest(a *cli.App, rp *common.RequestPayload, method string, endpo
7881 reauthenticated = true
7982 continue
8083 }
81- errorMsg := fmt.Sprintf("Request failed: status=%d, error=%v", resp.StatusCode, errorResp["error"])
82- return nil, fmt.Errorf(errorMsg)
84+ return nil, &common.DeploymentError{
85+ StatusCode: resp.StatusCode,
86+ Message: errorResp.Message,
87+ RawResponse: string(body),
88+ }
89+ }
90+ return nil, &common.DeploymentError{
91+ StatusCode: resp.StatusCode,
92+ Message: "Unexpected error occurred",
93+ RawResponse: string(body),
8394 }
84- return nil, fmt.Errorf("request failed with status %d: %s", resp.StatusCode, string(body))
8595 }
8696
8797 return &Response{Http: resp, Body: body, StatusCode: resp.StatusCode}, nil
@@ -66,7 +66,10 @@ func SendHTTPRequest(a *cli.App, rp *common.RequestPayload, method string, endpo
66 }66 }
67 67
68 if resp.StatusCode != http.StatusOK {68 if resp.StatusCode != http.StatusOK {
69- var errorResp map[string]interface{}69+ var errorResp struct {
70+ Success bool `json:"success"`
71+ Message string `json:"message"`
72+ }
70 if err := json.Unmarshal(body, &errorResp); err == nil {73 if err := json.Unmarshal(body, &errorResp); err == nil {
71 if resp.StatusCode == http.StatusUnauthorized && !reauthenticated {74 if resp.StatusCode == http.StatusUnauthorized && !reauthenticated {
72 fmt.Println("Token is invalid or expired. Initiating re-authentication...")75 fmt.Println("Token is invalid or expired. Initiating re-authentication...")
@@ -78,10 +81,17 @@ func SendHTTPRequest(a *cli.App, rp *common.RequestPayload, method string, endpo
78 reauthenticated = true81 reauthenticated = true
79 continue82 continue
80 }83 }
81- errorMsg := fmt.Sprintf("Request failed: status=%d, error=%v", resp.StatusCode, errorResp["error"])84+ return nil, &common.DeploymentError{
82- return nil, fmt.Errorf(errorMsg)85+ StatusCode: resp.StatusCode,
86+ Message: errorResp.Message,
87+ RawResponse: string(body),
88+ }
89+ }
90+ return nil, &common.DeploymentError{
91+ StatusCode: resp.StatusCode,
92+ Message: "Unexpected error occurred",
93+ RawResponse: string(body),
83 }94 }
84- return nil, fmt.Errorf("request failed with status %d: %s", resp.StatusCode, string(body))
85 }95 }
86 96
87 return &Response{Http: resp, Body: body, StatusCode: resp.StatusCode}, nil97 return &Response{Http: resp, Body: body, StatusCode: resp.StatusCode}, nil
M internal/common/payload.go +5 -4
@@ -17,9 +17,10 @@ type Payload interface {
1717 }
1818
1919 type DeployResponse struct {
20- Success bool `json:"success"`
21- Message string `json:"message"`
22- Domain string `json:"domain,omitempty"`
20+ Success bool `json:"success"`
21+ Message string `json:"message"`
22+ Domain string `json:"domain,omitempty"`
23+ ContainerID string `json:"container_id,omitempty"`
2324 }
2425
2526 type PushResponse struct {
@@ -29,7 +30,7 @@ type PushResponse struct {
2930 }
3031
3132 type DeploymentError struct {
32- StatusCode int `json:"status_code"`
33+ StatusCode int `json:"status"`
3334 Message string `json:"message"`
3435 RawResponse string `json:"raw_response"`
3536 }
@@ -17,9 +17,10 @@ type Payload interface {
17 }17 }
18 18
19 type DeployResponse struct {19 type DeployResponse struct {
20- Success bool `json:"success"`20+ Success bool `json:"success"`
21- Message string `json:"message"`21+ Message string `json:"message"`
22- Domain string `json:"domain,omitempty"`22+ Domain string `json:"domain,omitempty"`
23+ ContainerID string `json:"container_id,omitempty"`
23 }24 }
24 25
25 type PushResponse struct {26 type PushResponse struct {
@@ -29,7 +30,7 @@ type PushResponse struct {
29 }30 }
30 31
31 type DeploymentError struct {32 type DeploymentError struct {
32- StatusCode int `json:"status_code"`33+ StatusCode int `json:"status"`
33 Message string `json:"message"`34 Message string `json:"message"`
34 RawResponse string `json:"raw_response"`35 RawResponse string `json:"raw_response"`
35 }36 }
M internal/httpserve/handler/cli-endpoints.go +36 -9
@@ -6,12 +6,14 @@ import (
66 "fmt"
77 "net/http"
88 "regexp"
9+ "strings"
910
1011 "github.com/bnema/gordon/internal/common"
1112 "github.com/bnema/gordon/internal/server"
1213 "github.com/bnema/gordon/internal/templating/cmdparams"
1314 "github.com/bnema/gordon/pkg/docker"
1415 "github.com/bnema/gordon/pkg/store"
16+ "github.com/charmbracelet/log"
1517 "github.com/labstack/echo/v4"
1618 )
1719
@@ -25,6 +27,8 @@ type PushResponse = common.PushResponse
2527
2628 // sendJSONResponse is a helper function to send JSON responses
2729 func sendJSONResponse(c echo.Context, statusCode int, response interface{}) error {
30+ // Debug
31+ log.Debug("Sending JSON response", "statusCode", statusCode, "response", response)
2832 return c.JSON(statusCode, response)
2933 }
3034
@@ -166,37 +170,60 @@ func generateCreateContainerURL(a *server.App, shortID string) string {
166170
167171 // PostDeploy handles the container deployment request
168172 func PostDeploy(c echo.Context, a *server.App) error {
173+ // Debug
174+ log.Info("Starting deployment process", "handler", "PostDeploy", "requestID", c.Response().Header().Get(echo.HeaderXRequestID))
175+
169176 payload, err := validateAndPrepareDeployPayload(c)
170177 if err != nil {
178+ // Debug
179+ log.Error("Failed to validate and prepare payload", "error", err)
171180 return sendJSONResponse(c, http.StatusBadRequest, DeployResponse{
172181 Success: false,
173- Message: err.Error(),
182+ Message: fmt.Sprintf("Invalid payload: %v", err),
174183 })
175184 }
185+ // Debug
186+ log.Info("Payload validated and prepared", "payload", payload)
176187
177- _, err = saveAndImportDeployImage(c, a, payload)
188+ imagePath, err := saveAndImportDeployImage(c, a, payload)
178189 if err != nil {
190+ // Debug
191+ log.Error("Failed to save and import image", "error", err)
179192 return sendJSONResponse(c, http.StatusInternalServerError, DeployResponse{
180193 Success: false,
181- Message: err.Error(),
194+ Message: fmt.Sprintf("Failed to save or import image: %v", err),
182195 })
183196 }
197+ // Debug
198+ log.Info("Image saved and imported successfully", "imagePath", imagePath)
184199
185- _, err = createAndStartContainer(a, payload)
200+ containerID, err := createAndStartContainer(a, payload)
186201 if err != nil {
202+ if strings.Contains(err.Error(), "is already in use") {
203+ log.Warn("Container already exists", "error", err)
204+ return sendJSONResponse(c, http.StatusConflict, DeployResponse{
205+ Success: false,
206+ Message: fmt.Sprintf("Container with name '%s' already exists. Please remove it first or use a different name.", payload.ImageName),
207+ })
208+ }
209+ log.Error("Failed to create or start container", "error", err)
187210 return sendJSONResponse(c, http.StatusInternalServerError, DeployResponse{
188211 Success: false,
189- Message: err.Error(),
212+ Message: fmt.Sprintf("Failed to create or start container: %v", err),
190213 })
191214 }
215+ // Debug
216+ log.Info("Container created and started successfully", "containerID", containerID)
192217
193218 response := DeployResponse{
194- Success: true,
195- Message: "Deployment successful",
196- Domain: payload.TargetDomain,
219+ Success: true,
220+ Message: "Deployment successful",
221+ Domain: payload.TargetDomain,
222+ ContainerID: containerID,
197223 }
198224
199- logResponse(response)
225+ // Debug
226+ log.Info("Deployment completed successfully", "response", response)
200227
201228 return sendJSONResponse(c, http.StatusOK, response)
202229 }
@@ -6,12 +6,14 @@ import (
6 "fmt"6 "fmt"
7 "net/http"7 "net/http"
8 "regexp"8 "regexp"
9+ "strings"
9 10
10 "github.com/bnema/gordon/internal/common"11 "github.com/bnema/gordon/internal/common"
11 "github.com/bnema/gordon/internal/server"12 "github.com/bnema/gordon/internal/server"
12 "github.com/bnema/gordon/internal/templating/cmdparams"13 "github.com/bnema/gordon/internal/templating/cmdparams"
13 "github.com/bnema/gordon/pkg/docker"14 "github.com/bnema/gordon/pkg/docker"
14 "github.com/bnema/gordon/pkg/store"15 "github.com/bnema/gordon/pkg/store"
16+ "github.com/charmbracelet/log"
15 "github.com/labstack/echo/v4"17 "github.com/labstack/echo/v4"
16 )18 )
17 19
@@ -25,6 +27,8 @@ type PushResponse = common.PushResponse
25 27
26 // sendJSONResponse is a helper function to send JSON responses28 // sendJSONResponse is a helper function to send JSON responses
27 func sendJSONResponse(c echo.Context, statusCode int, response interface{}) error {29 func sendJSONResponse(c echo.Context, statusCode int, response interface{}) error {
30+ // Debug
31+ log.Debug("Sending JSON response", "statusCode", statusCode, "response", response)
28 return c.JSON(statusCode, response)32 return c.JSON(statusCode, response)
29 }33 }
30 34
@@ -166,37 +170,60 @@ func generateCreateContainerURL(a *server.App, shortID string) string {
166 170
167 // PostDeploy handles the container deployment request171 // PostDeploy handles the container deployment request
168 func PostDeploy(c echo.Context, a *server.App) error {172 func PostDeploy(c echo.Context, a *server.App) error {
173+ // Debug
174+ log.Info("Starting deployment process", "handler", "PostDeploy", "requestID", c.Response().Header().Get(echo.HeaderXRequestID))
175+
169 payload, err := validateAndPrepareDeployPayload(c)176 payload, err := validateAndPrepareDeployPayload(c)
170 if err != nil {177 if err != nil {
178+ // Debug
179+ log.Error("Failed to validate and prepare payload", "error", err)
171 return sendJSONResponse(c, http.StatusBadRequest, DeployResponse{180 return sendJSONResponse(c, http.StatusBadRequest, DeployResponse{
172 Success: false,181 Success: false,
173- Message: err.Error(),182+ Message: fmt.Sprintf("Invalid payload: %v", err),
174 })183 })
175 }184 }
185+ // Debug
186+ log.Info("Payload validated and prepared", "payload", payload)
176 187
177- _, err = saveAndImportDeployImage(c, a, payload)188+ imagePath, err := saveAndImportDeployImage(c, a, payload)
178 if err != nil {189 if err != nil {
190+ // Debug
191+ log.Error("Failed to save and import image", "error", err)
179 return sendJSONResponse(c, http.StatusInternalServerError, DeployResponse{192 return sendJSONResponse(c, http.StatusInternalServerError, DeployResponse{
180 Success: false,193 Success: false,
181- Message: err.Error(),194+ Message: fmt.Sprintf("Failed to save or import image: %v", err),
182 })195 })
183 }196 }
197+ // Debug
198+ log.Info("Image saved and imported successfully", "imagePath", imagePath)
184 199
185- _, err = createAndStartContainer(a, payload)200+ containerID, err := createAndStartContainer(a, payload)
186 if err != nil {201 if err != nil {
202+ if strings.Contains(err.Error(), "is already in use") {
203+ log.Warn("Container already exists", "error", err)
204+ return sendJSONResponse(c, http.StatusConflict, DeployResponse{
205+ Success: false,
206+ Message: fmt.Sprintf("Container with name '%s' already exists. Please remove it first or use a different name.", payload.ImageName),
207+ })
208+ }
209+ log.Error("Failed to create or start container", "error", err)
187 return sendJSONResponse(c, http.StatusInternalServerError, DeployResponse{210 return sendJSONResponse(c, http.StatusInternalServerError, DeployResponse{
188 Success: false,211 Success: false,
189- Message: err.Error(),212+ Message: fmt.Sprintf("Failed to create or start container: %v", err),
190 })213 })
191 }214 }
215+ // Debug
216+ log.Info("Container created and started successfully", "containerID", containerID)
192 217
193 response := DeployResponse{218 response := DeployResponse{
194- Success: true,219+ Success: true,
195- Message: "Deployment successful",220+ Message: "Deployment successful",
196- Domain: payload.TargetDomain,221+ Domain: payload.TargetDomain,
222+ ContainerID: containerID,
197 }223 }
198 224
199- logResponse(response)225+ // Debug
226+ log.Info("Deployment completed successfully", "response", response)
200 227
201 return sendJSONResponse(c, http.StatusOK, response)228 return sendJSONResponse(c, http.StatusOK, response)
202 }229 }

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close