Complete Push command feature
- Implement backend flag parsing logic to deploy image to a specific domain - Introduce `ImageID` field in `PushPayload` struct - Improve error handling in `PostPush` method with `sendJsonError` - Add response verification and domain availability check in `push.go` - Wait & check url availability in final step of push command
- commit
- dbdc5cd8afe1302911cc0ebda154f1d1f986019b
- author
- bnema · · 2023-11-01 08:37 UTC
- parent
- 0113c40
- signature
- unsigned
6 files · +153 -57
M internal/cli/cmd/push.go +48 -5
| @@ -1,9 +1,13 @@ | |||
| 1 | 1 | package cmd | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | + | "crypto/tls" | |
| 4 | 5 | "fmt" | |
| 6 | + | "net/http" | |
| 5 | 7 | "os" | |
| 6 | 8 | "regexp" | |
| 9 | + | "strings" | |
| 10 | + | "time" | |
| 7 | 11 | ||
| 8 | 12 | "github.com/bnema/gordon/internal/cli" | |
| 9 | 13 | "github.com/bnema/gordon/internal/cli/handler" | |
| @@ -82,12 +86,51 @@ func NewPushCommand(a *cli.App) *cobra.Command { | |||
| 82 | 86 | // Stop the progress bar | |
| 83 | 87 | bar.Finish() | |
| 84 | 88 | ||
| 85 | - | if resp.StatusCode != 200 { | |
| 86 | - | fmt.Println("Unexpected status code:", resp.StatusCode) | |
| 87 | - | return | |
| 88 | - | } | |
| 89 | + | // Check the response | |
| 90 | + | targetDomain := string(resp.Body) | |
| 91 | + | targetDomain = strings.TrimSpace(targetDomain) // Remove leading and trailing whitespace | |
| 92 | + | targetDomain = strings.Trim(targetDomain, "\"") // Remove leading and trailing quotes | |
| 93 | + | ||
| 94 | + | // Notify user | |
| 95 | + | fmt.Println("Wait while Traefik is setting up the domain and certificate...") | |
| 96 | + | progressIndicator := "" | |
| 97 | + | // Check URL availability | |
| 98 | + | for { | |
| 99 | + | client := &http.Client{ | |
| 100 | + | Timeout: time.Second * 20, | |
| 101 | + | Transport: &http.Transport{ | |
| 102 | + | TLSClientConfig: &tls.Config{InsecureSkipVerify: false}, // set false to ensure certificate is validated | |
| 103 | + | }, | |
| 104 | + | } | |
| 105 | + | ||
| 106 | + | // Making GET request to the target domain | |
| 107 | + | resp, err := client.Get(targetDomain) | |
| 108 | + | if err != nil { | |
| 109 | + | // we do nothing here, we just wait for the domain to be available | |
| 110 | + | ||
| 111 | + | } else { | |
| 112 | + | fmt.Println("Domain is available at:", targetDomain) | |
| 113 | + | break | |
| 114 | + | } | |
| 89 | 115 | ||
| 90 | - | fmt.Println(resp.Body) | |
| 116 | + | // Close the response body, if non-nil | |
| 117 | + | if resp != nil { | |
| 118 | + | resp.Body.Close() | |
| 119 | + | } | |
| 120 | + | ||
| 121 | + | // Update and print the progress indicator | |
| 122 | + | progressIndicator += "." | |
| 123 | + | ||
| 124 | + | // Limit the progress indicator to 5 dots | |
| 125 | + | if len(progressIndicator) > 5 { | |
| 126 | + | progressIndicator = "" | |
| 127 | + | } | |
| 128 | + | ||
| 129 | + | fmt.Printf("\r%s", progressIndicator) | |
| 130 | + | ||
| 131 | + | // Wait for 1 secondsbefore next check | |
| 132 | + | time.Sleep(time.Second) | |
| 133 | + | } | |
| 91 | 134 | }, | |
| 92 | 135 | } | |
| 93 | 136 | ||
| @@ -1,9 +1,13 @@ | |||||
| 1 | package cmd | 1 | package cmd | ||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | + | "crypto/tls" | |||
| 4 | "fmt" | 5 | "fmt" | ||
| 6 | + | "net/http" | |||
| 5 | "os" | 7 | "os" | ||
| 6 | "regexp" | 8 | "regexp" | ||
| 9 | + | "strings" | |||
| 10 | + | "time" | |||
| 7 | 11 | ||||
| 8 | "github.com/bnema/gordon/internal/cli" | 12 | "github.com/bnema/gordon/internal/cli" | ||
| 9 | "github.com/bnema/gordon/internal/cli/handler" | 13 | "github.com/bnema/gordon/internal/cli/handler" | ||
| @@ -82,12 +86,51 @@ func NewPushCommand(a *cli.App) *cobra.Command { | |||||
| 82 | // Stop the progress bar | 86 | // Stop the progress bar | ||
| 83 | bar.Finish() | 87 | bar.Finish() | ||
| 84 | 88 | ||||
| 85 | - | if resp.StatusCode != 200 { | 89 | + | // Check the response |
| 86 | - | fmt.Println("Unexpected status code:", resp.StatusCode) | 90 | + | targetDomain := string(resp.Body) |
| 87 | - | return | 91 | + | targetDomain = strings.TrimSpace(targetDomain) // Remove leading and trailing whitespace |
| 88 | - | } | 92 | + | targetDomain = strings.Trim(targetDomain, "\"") // Remove leading and trailing quotes |
| 93 | + | ||||
| 94 | + | // Notify user | |||
| 95 | + | fmt.Println("Wait while Traefik is setting up the domain and certificate...") | |||
| 96 | + | progressIndicator := "" | |||
| 97 | + | // Check URL availability | |||
| 98 | + | for { | |||
| 99 | + | client := &http.Client{ | |||
| 100 | + | Timeout: time.Second * 20, | |||
| 101 | + | Transport: &http.Transport{ | |||
| 102 | + | TLSClientConfig: &tls.Config{InsecureSkipVerify: false}, // set false to ensure certificate is validated | |||
| 103 | + | }, | |||
| 104 | + | } | |||
| 105 | + | ||||
| 106 | + | // Making GET request to the target domain | |||
| 107 | + | resp, err := client.Get(targetDomain) | |||
| 108 | + | if err != nil { | |||
| 109 | + | // we do nothing here, we just wait for the domain to be available | |||
| 110 | + | ||||
| 111 | + | } else { | |||
| 112 | + | fmt.Println("Domain is available at:", targetDomain) | |||
| 113 | + | break | |||
| 114 | + | } | |||
| 89 | 115 | ||||
| 90 | - | fmt.Println(resp.Body) | 116 | + | // Close the response body, if non-nil |
| 117 | + | if resp != nil { | |||
| 118 | + | resp.Body.Close() | |||
| 119 | + | } | |||
| 120 | + | ||||
| 121 | + | // Update and print the progress indicator | |||
| 122 | + | progressIndicator += "." | |||
| 123 | + | ||||
| 124 | + | // Limit the progress indicator to 5 dots | |||
| 125 | + | if len(progressIndicator) > 5 { | |||
| 126 | + | progressIndicator = "" | |||
| 127 | + | } | |||
| 128 | + | ||||
| 129 | + | fmt.Printf("\r%s", progressIndicator) | |||
| 130 | + | ||||
| 131 | + | // Wait for 1 secondsbefore next check | |||
| 132 | + | time.Sleep(time.Second) | |||
| 133 | + | } | |||
| 91 | }, | 134 | }, | ||
| 92 | } | 135 | } | ||
| 93 | 136 | ||||
M internal/common/payload.go +1 -0
| @@ -73,5 +73,6 @@ type PushPayload struct { | |||
| 73 | 73 | Ports string `json:"ports"` | |
| 74 | 74 | TargetDomain string `json:"targetdomain"` | |
| 75 | 75 | ImageName string `json:"imagename"` | |
| 76 | + | ImageID string `json:"imageid"` | |
| 76 | 77 | Data io.ReadCloser | |
| 77 | 78 | } | |
| @@ -73,5 +73,6 @@ type PushPayload struct { | |||||
| 73 | Ports string `json:"ports"` | 73 | Ports string `json:"ports"` | ||
| 74 | TargetDomain string `json:"targetdomain"` | 74 | TargetDomain string `json:"targetdomain"` | ||
| 75 | ImageName string `json:"imagename"` | 75 | ImageName string `json:"imagename"` | ||
| 76 | + | ImageID string `json:"imageid"` | |||
| 76 | Data io.ReadCloser | 77 | Data io.ReadCloser | ||
| 77 | } | 78 | } | ||
M internal/httpserve/handler/clientendpoins.go +34 -17
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | 9 | ||
| 10 | 10 | "github.com/bnema/gordon/internal/common" | |
| 11 | 11 | "github.com/bnema/gordon/internal/server" | |
| 12 | + | "github.com/bnema/gordon/internal/templating/cmdparams" | |
| 12 | 13 | "github.com/bnema/gordon/pkg/docker" | |
| 13 | 14 | "github.com/bnema/gordon/pkg/store" | |
| 14 | 15 | "github.com/labstack/echo/v4" | |
| @@ -85,19 +86,19 @@ func PostPush(c echo.Context, a *server.App) error { | |||
| 85 | 86 | // Save the image tar in the storage | |
| 86 | 87 | imageFilePath, err := store.SaveImageToStorage(&a.Config, imageFileName, imageReader) | |
| 87 | 88 | if err != nil { | |
| 88 | - | return err | |
| 89 | + | return sendJsonError(c, err) | |
| 89 | 90 | } | |
| 90 | 91 | ||
| 91 | 92 | // Import the tar in docker | |
| 92 | 93 | err = docker.ImportImageToEngine(imageFilePath) | |
| 93 | 94 | if err != nil { | |
| 94 | - | return err | |
| 95 | + | return sendJsonError(c, err) | |
| 95 | 96 | } | |
| 96 | 97 | ||
| 97 | 98 | // Remove the image from the storage | |
| 98 | 99 | err = store.RemoveFromStorage() | |
| 99 | 100 | if err != nil { | |
| 100 | - | return err | |
| 101 | + | return sendJsonError(c, err) | |
| 101 | 102 | } | |
| 102 | 103 | ||
| 103 | 104 | // append localhost to the image name since it's a manually imported image and not from a registry | |
| @@ -106,23 +107,39 @@ func PostPush(c echo.Context, a *server.App) error { | |||
| 106 | 107 | // Get the image ID | |
| 107 | 108 | imageID, err := docker.GetImageID(payload.ImageName) | |
| 108 | 109 | if err != nil { | |
| 109 | - | return err | |
| 110 | + | return sendJsonError(c, err) | |
| 110 | 111 | } | |
| 111 | 112 | ||
| 112 | - | // Print the imageID short version | |
| 113 | - | fmt.Println("Image ID:", imageID[:12]) | |
| 113 | + | // Update the payload with the image ID | |
| 114 | + | payload.ImageID = imageID | |
| 114 | 115 | ||
| 115 | - | // // Create the container with traefik labels | |
| 116 | - | // err = addTraefikLabels(payload) | |
| 117 | - | // if err != nil { | |
| 118 | - | // return err | |
| 119 | - | // } | |
| 116 | + | // Create the container using cmdparams.FromPayloadStructToCmdParams | |
| 117 | + | params, err := cmdparams.FromPayloadStructToCmdParams(payload, a) | |
| 118 | + | if err != nil { | |
| 119 | + | return sendJsonError(c, err) | |
| 120 | + | } | |
| 120 | 121 | ||
| 121 | - | // // Start the container | |
| 122 | - | // err = docker.StartContainer(imageID) | |
| 123 | - | // if err != nil { | |
| 124 | - | // return err | |
| 125 | - | // } | |
| 122 | + | // Create the container | |
| 123 | + | containerID, err := docker.CreateContainer(params) | |
| 124 | + | if err != nil { | |
| 125 | + | return sendJsonError(c, err) | |
| 126 | + | } | |
| 127 | + | ||
| 128 | + | // Start the container | |
| 129 | + | err = docker.StartContainer(containerID) | |
| 130 | + | if err != nil { | |
| 131 | + | return sendJsonError(c, err) | |
| 132 | + | } | |
| 126 | 133 | ||
| 127 | - | return c.JSON(http.StatusOK, "Image pushed successfully") | |
| 134 | + | // Remove the container if it fails to start | |
| 135 | + | defer func() { | |
| 136 | + | if err != nil { | |
| 137 | + | docker.RemoveContainer(containerID) | |
| 138 | + | c.JSON(http.StatusInternalServerError, sendJsonError(c, err)) | |
| 139 | + | return | |
| 140 | + | } | |
| 141 | + | }() | |
| 142 | + | ||
| 143 | + | // If we arrive here, send back payload.TargetDomain so the client can test it | |
| 144 | + | return c.JSON(http.StatusOK, payload.TargetDomain) | |
| 128 | 145 | } | |
| @@ -9,6 +9,7 @@ import ( | |||||
| 9 | 9 | ||||
| 10 | "github.com/bnema/gordon/internal/common" | 10 | "github.com/bnema/gordon/internal/common" | ||
| 11 | "github.com/bnema/gordon/internal/server" | 11 | "github.com/bnema/gordon/internal/server" | ||
| 12 | + | "github.com/bnema/gordon/internal/templating/cmdparams" | |||
| 12 | "github.com/bnema/gordon/pkg/docker" | 13 | "github.com/bnema/gordon/pkg/docker" | ||
| 13 | "github.com/bnema/gordon/pkg/store" | 14 | "github.com/bnema/gordon/pkg/store" | ||
| 14 | "github.com/labstack/echo/v4" | 15 | "github.com/labstack/echo/v4" | ||
| @@ -85,19 +86,19 @@ func PostPush(c echo.Context, a *server.App) error { | |||||
| 85 | // Save the image tar in the storage | 86 | // Save the image tar in the storage | ||
| 86 | imageFilePath, err := store.SaveImageToStorage(&a.Config, imageFileName, imageReader) | 87 | imageFilePath, err := store.SaveImageToStorage(&a.Config, imageFileName, imageReader) | ||
| 87 | if err != nil { | 88 | if err != nil { | ||
| 88 | - | return err | 89 | + | return sendJsonError(c, err) |
| 89 | } | 90 | } | ||
| 90 | 91 | ||||
| 91 | // Import the tar in docker | 92 | // Import the tar in docker | ||
| 92 | err = docker.ImportImageToEngine(imageFilePath) | 93 | err = docker.ImportImageToEngine(imageFilePath) | ||
| 93 | if err != nil { | 94 | if err != nil { | ||
| 94 | - | return err | 95 | + | return sendJsonError(c, err) |
| 95 | } | 96 | } | ||
| 96 | 97 | ||||
| 97 | // Remove the image from the storage | 98 | // Remove the image from the storage | ||
| 98 | err = store.RemoveFromStorage() | 99 | err = store.RemoveFromStorage() | ||
| 99 | if err != nil { | 100 | if err != nil { | ||
| 100 | - | return err | 101 | + | return sendJsonError(c, err) |
| 101 | } | 102 | } | ||
| 102 | 103 | ||||
| 103 | // append localhost to the image name since it's a manually imported image and not from a registry | 104 | // append localhost to the image name since it's a manually imported image and not from a registry | ||
| @@ -106,23 +107,39 @@ func PostPush(c echo.Context, a *server.App) error { | |||||
| 106 | // Get the image ID | 107 | // Get the image ID | ||
| 107 | imageID, err := docker.GetImageID(payload.ImageName) | 108 | imageID, err := docker.GetImageID(payload.ImageName) | ||
| 108 | if err != nil { | 109 | if err != nil { | ||
| 109 | - | return err | 110 | + | return sendJsonError(c, err) |
| 110 | } | 111 | } | ||
| 111 | 112 | ||||
| 112 | - | // Print the imageID short version | 113 | + | // Update the payload with the image ID |
| 113 | - | fmt.Println("Image ID:", imageID[:12]) | 114 | + | payload.ImageID = imageID |
| 114 | 115 | ||||
| 115 | - | // // Create the container with traefik labels | 116 | + | // Create the container using cmdparams.FromPayloadStructToCmdParams |
| 116 | - | // err = addTraefikLabels(payload) | 117 | + | params, err := cmdparams.FromPayloadStructToCmdParams(payload, a) |
| 117 | - | // if err != nil { | 118 | + | if err != nil { |
| 118 | - | // return err | 119 | + | return sendJsonError(c, err) |
| 119 | - | // } | 120 | + | } |
| 120 | 121 | ||||
| 121 | - | // // Start the container | 122 | + | // Create the container |
| 122 | - | // err = docker.StartContainer(imageID) | 123 | + | containerID, err := docker.CreateContainer(params) |
| 123 | - | // if err != nil { | 124 | + | if err != nil { |
| 124 | - | // return err | 125 | + | return sendJsonError(c, err) |
| 125 | - | // } | 126 | + | } |
| 127 | + | ||||
| 128 | + | // Start the container | |||
| 129 | + | err = docker.StartContainer(containerID) | |||
| 130 | + | if err != nil { | |||
| 131 | + | return sendJsonError(c, err) | |||
| 132 | + | } | |||
| 126 | 133 | ||||
| 127 | - | return c.JSON(http.StatusOK, "Image pushed successfully") | 134 | + | // Remove the container if it fails to start |
| 135 | + | defer func() { | |||
| 136 | + | if err != nil { | |||
| 137 | + | docker.RemoveContainer(containerID) | |||
| 138 | + | c.JSON(http.StatusInternalServerError, sendJsonError(c, err)) | |||
| 139 | + | return | |||
| 140 | + | } | |||
| 141 | + | }() | |||
| 142 | + | ||||
| 143 | + | // If we arrive here, send back payload.TargetDomain so the client can test it | |||
| 144 | + | return c.JSON(http.StatusOK, payload.TargetDomain) | |||
| 128 | } | 145 | } | ||
M internal/httpserve/handler/senderror.go +4 -0
| @@ -15,3 +15,7 @@ func sendError(c echo.Context, err error) error { | |||
| 15 | 15 | } | |
| 16 | 16 | return c.HTML(http.StatusInternalServerError, sanitizedHTML) | |
| 17 | 17 | } | |
| 18 | + | ||
| 19 | + | func sendJsonError(c echo.Context, err error) error { | |
| 20 | + | return c.JSON(http.StatusInternalServerError, err.Error()) | |
| 21 | + | } | |
| @@ -15,3 +15,7 @@ func sendError(c echo.Context, err error) error { | |||||
| 15 | } | 15 | } | ||
| 16 | return c.HTML(http.StatusInternalServerError, sanitizedHTML) | 16 | return c.HTML(http.StatusInternalServerError, sanitizedHTML) | ||
| 17 | } | 17 | } | ||
| 18 | + | ||||
| 19 | + | func sendJsonError(c echo.Context, err error) error { | |||
| 20 | + | return c.JSON(http.StatusInternalServerError, err.Error()) | |||
| 21 | + | } | |||
D internal/templating/cmdparams/_fromcli.go +0 -35
| @@ -1,35 +0,0 @@ | |||
| 1 | - | package cmdparams | |
| 2 | - | ||
| 3 | - | import ( | |
| 4 | - | "io" | |
| 5 | - | ||
| 6 | - | "github.com/bnema/gordon/internal/common" | |
| 7 | - | "github.com/bnema/gordon/pkg/docker" | |
| 8 | - | ) | |
| 9 | - | ||
| 10 | - | type PushPayload struct { | |
| 11 | - | Ports string `json:"ports"` | |
| 12 | - | TargetDomain string `json:"targetdomain"` | |
| 13 | - | ImageName string `json:"imagename"` | |
| 14 | - | Data io.ReadCloser | |
| 15 | - | } | |
| 16 | - | ||
| 17 | - | // FromYAMLStructToCmdParams converts a YAMLContainerParams struct to a ContainerCommandParams struct | |
| 18 | - | func FromPayloadStructToCmdParams(ppl *common.PushPayload) (docker.ContainerCommandParams, error) { | |
| 19 | - | ||
| 20 | - | params := docker.ContainerCommandParams{ | |
| 21 | - | IsSSL: ppl.IsSSL, | |
| 22 | - | ContainerName: ppl.ContainerName, | |
| 23 | - | ServiceName: ppl.ServiceName, | |
| 24 | - | Domain: ppl.Domain, | |
| 25 | - | ImageName: ppl.ImageName, | |
| 26 | - | ImageID: ppl.ImageID, | |
| 27 | - | Restart: ppl.Restart, | |
| 28 | - | Volumes: ppl.Volumes, | |
| 29 | - | Environment: ppl.Environment, | |
| 30 | - | Network: ppl.Network, | |
| 31 | - | PortMappings: ppl.PortMappings, | |
| 32 | - | } | |
| 33 | - | ||
| 34 | - | return params, nil | |
| 35 | - | } | |
| @@ -1,35 +0,0 @@ | |||||
| 1 | - | package cmdparams | |||
| 2 | - | ||||
| 3 | - | import ( | |||
| 4 | - | "io" | |||
| 5 | - | ||||
| 6 | - | "github.com/bnema/gordon/internal/common" | |||
| 7 | - | "github.com/bnema/gordon/pkg/docker" | |||
| 8 | - | ) | |||
| 9 | - | ||||
| 10 | - | type PushPayload struct { | |||
| 11 | - | Ports string `json:"ports"` | |||
| 12 | - | TargetDomain string `json:"targetdomain"` | |||
| 13 | - | ImageName string `json:"imagename"` | |||
| 14 | - | Data io.ReadCloser | |||
| 15 | - | } | |||
| 16 | - | ||||
| 17 | - | // FromYAMLStructToCmdParams converts a YAMLContainerParams struct to a ContainerCommandParams struct | |||
| 18 | - | func FromPayloadStructToCmdParams(ppl *common.PushPayload) (docker.ContainerCommandParams, error) { | |||
| 19 | - | ||||
| 20 | - | params := docker.ContainerCommandParams{ | |||
| 21 | - | IsSSL: ppl.IsSSL, | |||
| 22 | - | ContainerName: ppl.ContainerName, | |||
| 23 | - | ServiceName: ppl.ServiceName, | |||
| 24 | - | Domain: ppl.Domain, | |||
| 25 | - | ImageName: ppl.ImageName, | |||
| 26 | - | ImageID: ppl.ImageID, | |||
| 27 | - | Restart: ppl.Restart, | |||
| 28 | - | Volumes: ppl.Volumes, | |||
| 29 | - | Environment: ppl.Environment, | |||
| 30 | - | Network: ppl.Network, | |||
| 31 | - | PortMappings: ppl.PortMappings, | |||
| 32 | - | } | |||
| 33 | - | ||||
| 34 | - | return params, nil | |||
| 35 | - | } | |||
A internal/templating/cmdparams/fromcli.go +66 -0
| @@ -0,0 +1,66 @@ | |||
| 1 | + | package cmdparams | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "fmt" | |
| 5 | + | "net/url" | |
| 6 | + | "strings" | |
| 7 | + | ||
| 8 | + | "github.com/bnema/gordon/internal/common" | |
| 9 | + | "github.com/bnema/gordon/internal/server" | |
| 10 | + | "github.com/bnema/gordon/pkg/docker" | |
| 11 | + | ) | |
| 12 | + | ||
| 13 | + | // FromYAMLStructToCmdParams converts a YAMLContainerParams struct to a ContainerCommandParams struct | |
| 14 | + | func FromPayloadStructToCmdParams(ppl *common.PushPayload, a *server.App) (docker.ContainerCommandParams, error) { | |
| 15 | + | ||
| 16 | + | imageID, err := docker.GetImageID(ppl.ImageName) | |
| 17 | + | if err != nil { | |
| 18 | + | return docker.ContainerCommandParams{}, err | |
| 19 | + | } | |
| 20 | + | ||
| 21 | + | // volume empty for now | |
| 22 | + | volumeSlice := ParseVolumeSlice("") | |
| 23 | + | ||
| 24 | + | environmentSlice := ParseEnvironmentSlice("") | |
| 25 | + | ||
| 26 | + | portMappings, err := ParsePortMappingsSlice(ppl.Ports) | |
| 27 | + | if err != nil { | |
| 28 | + | return docker.ContainerCommandParams{}, err | |
| 29 | + | } | |
| 30 | + | ||
| 31 | + | // from ppl.TargetDomain, (eg. "https://test.example.com") get container_name (eg. "test"), get container_subdomain (eg. "test"), get container_domain (eg. "example.com") and get container_protocol (eg. "https") | |
| 32 | + | // Parse TargetDomain to get the various components | |
| 33 | + | parsedURL, err := url.Parse(ppl.TargetDomain) | |
| 34 | + | if err != nil { | |
| 35 | + | return docker.ContainerCommandParams{}, err | |
| 36 | + | } | |
| 37 | + | ||
| 38 | + | // Extract the subdomain and domain from the host | |
| 39 | + | hostParts := strings.Split(parsedURL.Host, ".") | |
| 40 | + | if len(hostParts) < 2 { | |
| 41 | + | return docker.ContainerCommandParams{}, fmt.Errorf("invalid domain: %s", parsedURL.Host) | |
| 42 | + | } | |
| 43 | + | ||
| 44 | + | // Protocol (http/https), Container name, Container subdomain, and Container domain | |
| 45 | + | protocol := parsedURL.Scheme | |
| 46 | + | containerSubdomain := hostParts[0] | |
| 47 | + | containerDomain := strings.Join(hostParts[1:], ".") | |
| 48 | + | ||
| 49 | + | params := docker.ContainerCommandParams{ | |
| 50 | + | IsSSL: protocol == "https", | |
| 51 | + | ContainerName: containerSubdomain, | |
| 52 | + | ServiceName: containerSubdomain, | |
| 53 | + | Domain: containerDomain, | |
| 54 | + | ImageName: ppl.ImageName, | |
| 55 | + | ImageID: imageID, | |
| 56 | + | Restart: "always", | |
| 57 | + | Volumes: volumeSlice, | |
| 58 | + | Environment: environmentSlice, | |
| 59 | + | Network: a.Config.ContainerEngine.Network, | |
| 60 | + | PortMappings: portMappings, | |
| 61 | + | } | |
| 62 | + | ||
| 63 | + | CreateTraefikLabels(¶ms) | |
| 64 | + | ||
| 65 | + | return params, nil | |
| 66 | + | } | |
| @@ -0,0 +1,66 @@ | |||||
| 1 | + | package cmdparams | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "fmt" | |||
| 5 | + | "net/url" | |||
| 6 | + | "strings" | |||
| 7 | + | ||||
| 8 | + | "github.com/bnema/gordon/internal/common" | |||
| 9 | + | "github.com/bnema/gordon/internal/server" | |||
| 10 | + | "github.com/bnema/gordon/pkg/docker" | |||
| 11 | + | ) | |||
| 12 | + | ||||
| 13 | + | // FromYAMLStructToCmdParams converts a YAMLContainerParams struct to a ContainerCommandParams struct | |||
| 14 | + | func FromPayloadStructToCmdParams(ppl *common.PushPayload, a *server.App) (docker.ContainerCommandParams, error) { | |||
| 15 | + | ||||
| 16 | + | imageID, err := docker.GetImageID(ppl.ImageName) | |||
| 17 | + | if err != nil { | |||
| 18 | + | return docker.ContainerCommandParams{}, err | |||
| 19 | + | } | |||
| 20 | + | ||||
| 21 | + | // volume empty for now | |||
| 22 | + | volumeSlice := ParseVolumeSlice("") | |||
| 23 | + | ||||
| 24 | + | environmentSlice := ParseEnvironmentSlice("") | |||
| 25 | + | ||||
| 26 | + | portMappings, err := ParsePortMappingsSlice(ppl.Ports) | |||
| 27 | + | if err != nil { | |||
| 28 | + | return docker.ContainerCommandParams{}, err | |||
| 29 | + | } | |||
| 30 | + | ||||
| 31 | + | // from ppl.TargetDomain, (eg. "https://test.example.com") get container_name (eg. "test"), get container_subdomain (eg. "test"), get container_domain (eg. "example.com") and get container_protocol (eg. "https") | |||
| 32 | + | // Parse TargetDomain to get the various components | |||
| 33 | + | parsedURL, err := url.Parse(ppl.TargetDomain) | |||
| 34 | + | if err != nil { | |||
| 35 | + | return docker.ContainerCommandParams{}, err | |||
| 36 | + | } | |||
| 37 | + | ||||
| 38 | + | // Extract the subdomain and domain from the host | |||
| 39 | + | hostParts := strings.Split(parsedURL.Host, ".") | |||
| 40 | + | if len(hostParts) < 2 { | |||
| 41 | + | return docker.ContainerCommandParams{}, fmt.Errorf("invalid domain: %s", parsedURL.Host) | |||
| 42 | + | } | |||
| 43 | + | ||||
| 44 | + | // Protocol (http/https), Container name, Container subdomain, and Container domain | |||
| 45 | + | protocol := parsedURL.Scheme | |||
| 46 | + | containerSubdomain := hostParts[0] | |||
| 47 | + | containerDomain := strings.Join(hostParts[1:], ".") | |||
| 48 | + | ||||
| 49 | + | params := docker.ContainerCommandParams{ | |||
| 50 | + | IsSSL: protocol == "https", | |||
| 51 | + | ContainerName: containerSubdomain, | |||
| 52 | + | ServiceName: containerSubdomain, | |||
| 53 | + | Domain: containerDomain, | |||
| 54 | + | ImageName: ppl.ImageName, | |||
| 55 | + | ImageID: imageID, | |||
| 56 | + | Restart: "always", | |||
| 57 | + | Volumes: volumeSlice, | |||
| 58 | + | Environment: environmentSlice, | |||
| 59 | + | Network: a.Config.ContainerEngine.Network, | |||
| 60 | + | PortMappings: portMappings, | |||
| 61 | + | } | |||
| 62 | + | ||||
| 63 | + | CreateTraefikLabels(¶ms) | |||
| 64 | + | ||||
| 65 | + | return params, nil | |||
| 66 | + | } | |||