Refactor: Improve Docker client and container/image handling
- Simplify Docker client initialization and management - Update container/image structs and processing - Refactor OAuth and main.go configurations - Improve error handling and code organization
- commit
- 97319bf26bb8910bbeb2c4099b346dc51f018db0
- author
- bamen · · 2024-08-27 05:37 UTC
- parent
- 5e4df08
- signature
- unsigned
6 files · +53 -53
M cmd/cli/main.go +6 -7
| @@ -3,7 +3,6 @@ package main | |||
| 3 | 3 | import ( | |
| 4 | 4 | "fmt" | |
| 5 | 5 | "log" | |
| 6 | - | "os" | |
| 7 | 6 | "regexp" | |
| 8 | 7 | ||
| 9 | 8 | "github.com/bnema/gordon/internal/cli" | |
| @@ -17,13 +16,13 @@ import ( | |||
| 17 | 16 | ) | |
| 18 | 17 | ||
| 19 | 18 | var ( | |
| 20 | - | build string | |
| 21 | - | commit string | |
| 22 | - | date string | |
| 19 | + | build string | |
| 20 | + | commit string | |
| 21 | + | date string | |
| 22 | + | rootCmd = &cobra.Command{Use: "gordon"} | |
| 23 | + | proxyURL = "https://gordon-proxy.bamen.dev" | |
| 23 | 24 | ) | |
| 24 | 25 | ||
| 25 | - | var rootCmd = &cobra.Command{Use: "gordon"} | |
| 26 | - | ||
| 27 | 26 | func InitializeCommands(client *cli.App, server *server.App) { | |
| 28 | 27 | rootCmd.AddCommand(cmd.NewRootCommand(client)) | |
| 29 | 28 | rootCmd.AddCommand(cmd.NewServeCommand(server)) | |
| @@ -44,7 +43,7 @@ func main() { | |||
| 44 | 43 | BuildVersion: build, | |
| 45 | 44 | BuildCommit: commit, | |
| 46 | 45 | BuildDate: date, | |
| 47 | - | ProxyURL: os.Getenv("PROXY_URL"), | |
| 46 | + | ProxyURL: proxyURL, | |
| 48 | 47 | } | |
| 49 | 48 | ||
| 50 | 49 | a, err := cli.NewClientApp(buildInfo) | |
| @@ -3,7 +3,6 @@ package main | |||||
| 3 | import ( | 3 | import ( | ||
| 4 | "fmt" | 4 | "fmt" | ||
| 5 | "log" | 5 | "log" | ||
| 6 | - | "os" | |||
| 7 | "regexp" | 6 | "regexp" | ||
| 8 | 7 | ||||
| 9 | "github.com/bnema/gordon/internal/cli" | 8 | "github.com/bnema/gordon/internal/cli" | ||
| @@ -17,13 +16,13 @@ import ( | |||||
| 17 | ) | 16 | ) | ||
| 18 | 17 | ||||
| 19 | var ( | 18 | var ( | ||
| 20 | - | build string | 19 | + | build string |
| 21 | - | commit string | 20 | + | commit string |
| 22 | - | date string | 21 | + | date string |
| 22 | + | rootCmd = &cobra.Command{Use: "gordon"} | |||
| 23 | + | proxyURL = "https://gordon-proxy.bamen.dev" | |||
| 23 | ) | 24 | ) | ||
| 24 | 25 | ||||
| 25 | - | var rootCmd = &cobra.Command{Use: "gordon"} | |||
| 26 | - | ||||
| 27 | func InitializeCommands(client *cli.App, server *server.App) { | 26 | func InitializeCommands(client *cli.App, server *server.App) { | ||
| 28 | rootCmd.AddCommand(cmd.NewRootCommand(client)) | 27 | rootCmd.AddCommand(cmd.NewRootCommand(client)) | ||
| 29 | rootCmd.AddCommand(cmd.NewServeCommand(server)) | 28 | rootCmd.AddCommand(cmd.NewServeCommand(server)) | ||
| @@ -44,7 +43,7 @@ func main() { | |||||
| 44 | BuildVersion: build, | 43 | BuildVersion: build, | ||
| 45 | BuildCommit: commit, | 44 | BuildCommit: commit, | ||
| 46 | BuildDate: date, | 45 | BuildDate: date, | ||
| 47 | - | ProxyURL: os.Getenv("PROXY_URL"), | 46 | + | ProxyURL: proxyURL, |
| 48 | } | 47 | } | ||
| 49 | 48 | ||||
| 50 | a, err := cli.NewClientApp(buildInfo) | 49 | a, err := cli.NewClientApp(buildInfo) | ||
M internal/common/initdockerclient.go +2 -3
| @@ -7,10 +7,9 @@ import ( | |||
| 7 | 7 | ) | |
| 8 | 8 | ||
| 9 | 9 | func DockerInit(cc *ContainerEngineConfig) { | |
| 10 | - | dockerClient := docker.DockerClient{} | |
| 11 | - | err := dockerClient.InitializeClient(NewDockerConfig(cc)) | |
| 10 | + | err := docker.InitializeClient(NewDockerConfig(cc)) | |
| 12 | 11 | if err != nil { | |
| 13 | - | log.Printf("Error: %s", err) | |
| 12 | + | log.Printf("Error initializing Docker client: %s", err) | |
| 14 | 13 | } | |
| 15 | 14 | } | |
| 16 | 15 | ||
| @@ -7,10 +7,9 @@ import ( | |||||
| 7 | ) | 7 | ) | ||
| 8 | 8 | ||||
| 9 | func DockerInit(cc *ContainerEngineConfig) { | 9 | func DockerInit(cc *ContainerEngineConfig) { | ||
| 10 | - | dockerClient := docker.DockerClient{} | 10 | + | err := docker.InitializeClient(NewDockerConfig(cc)) |
| 11 | - | err := dockerClient.InitializeClient(NewDockerConfig(cc)) | |||
| 12 | if err != nil { | 11 | if err != nil { | ||
| 13 | - | log.Printf("Error: %s", err) | 12 | + | log.Printf("Error initializing Docker client: %s", err) |
| 14 | } | 13 | } | ||
| 15 | } | 14 | } | ||
| 16 | 15 | ||||
M internal/httpserve/handler/containers.go +23 -19
| @@ -50,11 +50,13 @@ func safelyInteractWithIDMap(op MapOperation, key string, value ...string) (stri | |||
| 50 | 50 | } | |
| 51 | 51 | ||
| 52 | 52 | type HumanReadableContainerImage struct { | |
| 53 | - | *types.ImageInspect | |
| 54 | - | Name string | |
| 55 | - | ShortID string | |
| 56 | - | CreatedStr string | |
| 57 | - | SizeStr string | |
| 53 | + | ID string | |
| 54 | + | Name string | |
| 55 | + | ShortID string | |
| 56 | + | CreatedStr string | |
| 57 | + | SizeStr string | |
| 58 | + | RepoDigests []string | |
| 59 | + | RepoTags []string | |
| 58 | 60 | } | |
| 59 | 61 | ||
| 60 | 62 | type HumanReadableContainer struct { | |
| @@ -98,27 +100,29 @@ func ImageManagerComponent(c echo.Context, a *server.App) error { | |||
| 98 | 100 | if err != nil { | |
| 99 | 101 | return sendError(c, err) | |
| 100 | 102 | } | |
| 103 | + | ||
| 101 | 104 | var humanReadableImages []HumanReadableContainerImage | |
| 102 | 105 | ||
| 103 | - | for _, image := range images { | |
| 104 | - | // We need to shorten the ID because it breaks the HTML | |
| 105 | - | ShortID := image.ID[7:19] | |
| 106 | - | // And we store both the ShortID and the full ID in a map so we can retrieve the full ID later | |
| 107 | - | safelyInteractWithIDMap(Update, ShortID, image.ID) | |
| 108 | - | createdTime := time.Unix(image.Created, 0) | |
| 106 | + | for _, img := range images { | |
| 107 | + | shortID := img.ID[7:19] | |
| 108 | + | safelyInteractWithIDMap(Update, shortID, img.ID) | |
| 109 | + | createdTime := time.Unix(img.Created, 0) | |
| 109 | 110 | createdStr := humanize.TimeAgo(createdTime) | |
| 110 | - | sizeStr := humanize.BytesToReadableSize(image.Size) | |
| 111 | - | for _, repoTag := range image.RepoTags { | |
| 111 | + | sizeStr := humanize.BytesToReadableSize(img.Size) | |
| 112 | + | ||
| 113 | + | for _, repoTag := range img.RepoTags { | |
| 112 | 114 | humanReadableImages = append(humanReadableImages, HumanReadableContainerImage{ | |
| 113 | - | ImageInspect: &types.ImageInspect{ | |
| 114 | - | ID: ShortID, // Set the ID to the ShortID | |
| 115 | - | }, | |
| 116 | - | CreatedStr: createdStr, | |
| 117 | - | SizeStr: sizeStr, | |
| 118 | - | Name: repoTag, | |
| 115 | + | ID: img.ID, | |
| 116 | + | ShortID: shortID, | |
| 117 | + | CreatedStr: createdStr, | |
| 118 | + | SizeStr: sizeStr, | |
| 119 | + | Name: repoTag, | |
| 120 | + | RepoDigests: img.RepoDigests, | |
| 121 | + | RepoTags: img.RepoTags, | |
| 119 | 122 | }) | |
| 120 | 123 | } | |
| 121 | 124 | } | |
| 125 | + | ||
| 122 | 126 | data := map[string]interface{}{ | |
| 123 | 127 | "Images": humanReadableImages, | |
| 124 | 128 | } | |
| @@ -50,11 +50,13 @@ func safelyInteractWithIDMap(op MapOperation, key string, value ...string) (stri | |||||
| 50 | } | 50 | } | ||
| 51 | 51 | ||||
| 52 | type HumanReadableContainerImage struct { | 52 | type HumanReadableContainerImage struct { | ||
| 53 | - | *types.ImageInspect | 53 | + | ID string |
| 54 | - | Name string | 54 | + | Name string |
| 55 | - | ShortID string | 55 | + | ShortID string |
| 56 | - | CreatedStr string | 56 | + | CreatedStr string |
| 57 | - | SizeStr string | 57 | + | SizeStr string |
| 58 | + | RepoDigests []string | |||
| 59 | + | RepoTags []string | |||
| 58 | } | 60 | } | ||
| 59 | 61 | ||||
| 60 | type HumanReadableContainer struct { | 62 | type HumanReadableContainer struct { | ||
| @@ -98,27 +100,29 @@ func ImageManagerComponent(c echo.Context, a *server.App) error { | |||||
| 98 | if err != nil { | 100 | if err != nil { | ||
| 99 | return sendError(c, err) | 101 | return sendError(c, err) | ||
| 100 | } | 102 | } | ||
| 103 | + | ||||
| 101 | var humanReadableImages []HumanReadableContainerImage | 104 | var humanReadableImages []HumanReadableContainerImage | ||
| 102 | 105 | ||||
| 103 | - | for _, image := range images { | 106 | + | for _, img := range images { |
| 104 | - | // We need to shorten the ID because it breaks the HTML | 107 | + | shortID := img.ID[7:19] |
| 105 | - | ShortID := image.ID[7:19] | 108 | + | safelyInteractWithIDMap(Update, shortID, img.ID) |
| 106 | - | // And we store both the ShortID and the full ID in a map so we can retrieve the full ID later | 109 | + | createdTime := time.Unix(img.Created, 0) |
| 107 | - | safelyInteractWithIDMap(Update, ShortID, image.ID) | |||
| 108 | - | createdTime := time.Unix(image.Created, 0) | |||
| 109 | createdStr := humanize.TimeAgo(createdTime) | 110 | createdStr := humanize.TimeAgo(createdTime) | ||
| 110 | - | sizeStr := humanize.BytesToReadableSize(image.Size) | 111 | + | sizeStr := humanize.BytesToReadableSize(img.Size) |
| 111 | - | for _, repoTag := range image.RepoTags { | 112 | + | |
| 113 | + | for _, repoTag := range img.RepoTags { | |||
| 112 | humanReadableImages = append(humanReadableImages, HumanReadableContainerImage{ | 114 | humanReadableImages = append(humanReadableImages, HumanReadableContainerImage{ | ||
| 113 | - | ImageInspect: &types.ImageInspect{ | 115 | + | ID: img.ID, |
| 114 | - | ID: ShortID, // Set the ID to the ShortID | 116 | + | ShortID: shortID, |
| 115 | - | }, | 117 | + | CreatedStr: createdStr, |
| 116 | - | CreatedStr: createdStr, | 118 | + | SizeStr: sizeStr, |
| 117 | - | SizeStr: sizeStr, | 119 | + | Name: repoTag, |
| 118 | - | Name: repoTag, | 120 | + | RepoDigests: img.RepoDigests, |
| 121 | + | RepoTags: img.RepoTags, | |||
| 119 | }) | 122 | }) | ||
| 120 | } | 123 | } | ||
| 121 | } | 124 | } | ||
| 125 | + | ||||
| 122 | data := map[string]interface{}{ | 126 | data := map[string]interface{}{ | ||
| 123 | "Images": humanReadableImages, | 127 | "Images": humanReadableImages, | ||
| 124 | } | 128 | } | ||
M internal/httpserve/handler/oauth.go +1 -2
| @@ -6,7 +6,6 @@ import ( | |||
| 6 | 6 | "fmt" | |
| 7 | 7 | "io" | |
| 8 | 8 | "net/http" | |
| 9 | - | "os" | |
| 10 | 9 | "time" | |
| 11 | 10 | ||
| 12 | 11 | "github.com/bnema/gordon/internal/db" | |
| @@ -115,7 +114,7 @@ func StartOAuthGithub(c echo.Context, a *server.App) error { | |||
| 115 | 114 | ||
| 116 | 115 | // initiateGithubOAuthFlow starts a new GitHub OAuth flow | |
| 117 | 116 | func initiateGithubOAuthFlow(c echo.Context, a *server.App) error { | |
| 118 | - | clientID := os.Getenv("GITHUB_APP_ID") | |
| 117 | + | clientID := "" // IDK why it needs that even empty, but it does | |
| 119 | 118 | redirectDomain := a.GenerateOauthCallbackURL() | |
| 120 | 119 | encodedState := base64.StdEncoding.EncodeToString([]byte("redirectDomain:" + redirectDomain)) | |
| 121 | 120 | ||
| @@ -6,7 +6,6 @@ import ( | |||||
| 6 | "fmt" | 6 | "fmt" | ||
| 7 | "io" | 7 | "io" | ||
| 8 | "net/http" | 8 | "net/http" | ||
| 9 | - | "os" | |||
| 10 | "time" | 9 | "time" | ||
| 11 | 10 | ||||
| 12 | "github.com/bnema/gordon/internal/db" | 11 | "github.com/bnema/gordon/internal/db" | ||
| @@ -115,7 +114,7 @@ func StartOAuthGithub(c echo.Context, a *server.App) error { | |||||
| 115 | 114 | ||||
| 116 | // initiateGithubOAuthFlow starts a new GitHub OAuth flow | 115 | // initiateGithubOAuthFlow starts a new GitHub OAuth flow | ||
| 117 | func initiateGithubOAuthFlow(c echo.Context, a *server.App) error { | 116 | func initiateGithubOAuthFlow(c echo.Context, a *server.App) error { | ||
| 118 | - | clientID := os.Getenv("GITHUB_APP_ID") | 117 | + | clientID := "" // IDK why it needs that even empty, but it does |
| 119 | redirectDomain := a.GenerateOauthCallbackURL() | 118 | redirectDomain := a.GenerateOauthCallbackURL() | ||
| 120 | encodedState := base64.StdEncoding.EncodeToString([]byte("redirectDomain:" + redirectDomain)) | 119 | encodedState := base64.StdEncoding.EncodeToString([]byte("redirectDomain:" + redirectDomain)) | ||
| 121 | 120 | ||||
M internal/templating/models/html/fragments/imagelist.gohtml +3 -3
| @@ -1,6 +1,6 @@ | |||
| 1 | 1 | <div class="flex flex-col p-4"> | |
| 2 | 2 | <!-- Upload button aligned right of Images --> | |
| 3 | - | <div class="flex justify-between items-center mb-1"> | |
| 3 | + | <div class="flex justify-between items-center mb-1"> | |
| 4 | 4 | <h1 class="text-lg md:text-xl font-bold text-gordonmascot-hblue">Images</h1> | |
| 5 | 5 | <button | |
| 6 | 6 | class="py-1 px-2 bg-blue-500 hover:bg-blue-700 text-white font-bold rounded" | |
| @@ -24,14 +24,14 @@ | |||
| 24 | 24 | }} | |
| 25 | 25 | <tr id="img-{{.ID}}" hx-ext="response-targets" class=" hover:bg-slate-100"> | |
| 26 | 26 | <td> | |
| 27 | - | <span title="{{.ImageSummary.ID}}">{{.Name}}</span> | |
| 27 | + | <span title="{{.ID}}">{{.Name}}</span> | |
| 28 | 28 | </td> | |
| 29 | 29 | <td> | |
| 30 | 30 | <span title="Image creation date">{{.CreatedStr}}</span> | |
| 31 | 31 | </td> | |
| 32 | 32 | <td>{{.SizeStr}}</td> | |
| 33 | 33 | <td align="right"> | |
| 34 | - | ||
| 34 | + | ||
| 35 | 35 | <button | |
| 36 | 36 | id="add-button-img-{{.ID}}" | |
| 37 | 37 | hx-get="/htmx/create-container/{{.ID}}" | |
| @@ -1,6 +1,6 @@ | |||||
| 1 | <div class="flex flex-col p-4"> | 1 | <div class="flex flex-col p-4"> | ||
| 2 | <!-- Upload button aligned right of Images --> | 2 | <!-- Upload button aligned right of Images --> | ||
| 3 | - | <div class="flex justify-between items-center mb-1"> | 3 | + | <div class="flex justify-between items-center mb-1"> |
| 4 | <h1 class="text-lg md:text-xl font-bold text-gordonmascot-hblue">Images</h1> | 4 | <h1 class="text-lg md:text-xl font-bold text-gordonmascot-hblue">Images</h1> | ||
| 5 | <button | 5 | <button | ||
| 6 | class="py-1 px-2 bg-blue-500 hover:bg-blue-700 text-white font-bold rounded" | 6 | class="py-1 px-2 bg-blue-500 hover:bg-blue-700 text-white font-bold rounded" | ||
| @@ -24,14 +24,14 @@ | |||||
| 24 | }} | 24 | }} | ||
| 25 | <tr id="img-{{.ID}}" hx-ext="response-targets" class=" hover:bg-slate-100"> | 25 | <tr id="img-{{.ID}}" hx-ext="response-targets" class=" hover:bg-slate-100"> | ||
| 26 | <td> | 26 | <td> | ||
| 27 | - | <span title="{{.ImageSummary.ID}}">{{.Name}}</span> | 27 | + | <span title="{{.ID}}">{{.Name}}</span> |
| 28 | </td> | 28 | </td> | ||
| 29 | <td> | 29 | <td> | ||
| 30 | <span title="Image creation date">{{.CreatedStr}}</span> | 30 | <span title="Image creation date">{{.CreatedStr}}</span> | ||
| 31 | </td> | 31 | </td> | ||
| 32 | <td>{{.SizeStr}}</td> | 32 | <td>{{.SizeStr}}</td> | ||
| 33 | <td align="right"> | 33 | <td align="right"> | ||
| 34 | - | 34 | + | ||
| 35 | <button | 35 | <button | ||
| 36 | id="add-button-img-{{.ID}}" | 36 | id="add-button-img-{{.ID}}" | ||
| 37 | hx-get="/htmx/create-container/{{.ID}}" | 37 | hx-get="/htmx/create-container/{{.ID}}" | ||
M pkg/docker/client.go +18 -19
| @@ -2,23 +2,18 @@ package docker | |||
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "context" | |
| 5 | - | "crypto/tls" | |
| 6 | 5 | "fmt" | |
| 7 | 6 | "os" | |
| 8 | 7 | "time" | |
| 9 | 8 | ||
| 9 | + | "github.com/docker/docker/api/types" | |
| 10 | 10 | "github.com/docker/docker/api/types/container" | |
| 11 | 11 | "github.com/docker/docker/client" | |
| 12 | 12 | ) | |
| 13 | 13 | ||
| 14 | - | type ContainerEngineClient interface { | |
| 15 | - | InitializeClient(*Config) error | |
| 16 | - | // Add other methods that both Docker and Podman should implement | |
| 17 | - | } | |
| 18 | 14 | type Config struct { | |
| 19 | 15 | Sock string | |
| 20 | 16 | PodmanEnable bool | |
| 21 | - | TLSConfig *tls.Config | |
| 22 | 17 | } | |
| 23 | 18 | ||
| 24 | 19 | var ( | |
| @@ -26,21 +21,15 @@ var ( | |||
| 26 | 21 | currentConfig *Config | |
| 27 | 22 | ) | |
| 28 | 23 | ||
| 29 | - | // DockerClient implements the ContainerEngineClient interface for Docker | |
| 30 | - | type DockerClient struct{} | |
| 31 | - | ||
| 32 | - | func (d *DockerClient) InitializeClient(config *Config) error { | |
| 33 | - | // Validate if the Sock field is not empty | |
| 24 | + | func InitializeClient(config *Config) error { | |
| 34 | 25 | if config.Sock == "" { | |
| 35 | 26 | return fmt.Errorf("sock field in Config is empty") | |
| 36 | 27 | } | |
| 37 | 28 | ||
| 38 | - | // Check if the socket file exists if not return an error | |
| 39 | 29 | if _, err := os.Stat(config.Sock); os.IsNotExist(err) { | |
| 40 | 30 | return err | |
| 41 | 31 | } | |
| 42 | 32 | ||
| 43 | - | // Initialize Docker client | |
| 44 | 33 | cli, err := client.NewClientWithOpts( | |
| 45 | 34 | client.WithAPIVersionNegotiation(), | |
| 46 | 35 | client.WithHost("unix://"+config.Sock), | |
| @@ -53,19 +42,16 @@ func (d *DockerClient) InitializeClient(config *Config) error { | |||
| 53 | 42 | return nil | |
| 54 | 43 | } | |
| 55 | 44 | ||
| 56 | - | // CheckIfInitialized checks if the Docker client is initialized | |
| 57 | 45 | func CheckIfInitialized() error { | |
| 58 | - | // Check if there is a socket file | |
| 59 | 46 | if currentConfig == nil || currentConfig.Sock == "" { | |
| 60 | 47 | return fmt.Errorf("docker client is not initialized or configuration is missing") | |
| 61 | 48 | } | |
| 62 | 49 | ||
| 63 | - | socketPath := currentConfig.Sock // Use the package-level variable | |
| 50 | + | socketPath := currentConfig.Sock | |
| 64 | 51 | if _, err := os.Stat(socketPath); os.IsNotExist(err) { | |
| 65 | 52 | return fmt.Errorf("sock file does not exist: %s", socketPath) | |
| 66 | 53 | } | |
| 67 | 54 | ||
| 68 | - | // Then we check if the dockerCli is nil | |
| 69 | 55 | if dockerCli == nil { | |
| 70 | 56 | return fmt.Errorf("docker client is not initialized") | |
| 71 | 57 | } | |
| @@ -73,10 +59,23 @@ func CheckIfInitialized() error { | |||
| 73 | 59 | ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) | |
| 74 | 60 | defer cancel() | |
| 75 | 61 | ||
| 76 | - | // More stringent check: try to list containers | |
| 77 | - | _, err := dockerCli.ContainerList(ctx, container.ListOptions{}) | |
| 62 | + | containers, err := dockerCli.ContainerList(ctx, container.ListOptions{}) | |
| 78 | 63 | if err != nil { | |
| 79 | 64 | return fmt.Errorf("cannot connect to Docker daemon: %s", err) | |
| 80 | 65 | } | |
| 66 | + | fmt.Printf("Found %d containers\n", len(containers)) | |
| 81 | 67 | return nil | |
| 82 | 68 | } | |
| 69 | + | ||
| 70 | + | func ListContainers(ctx context.Context) ([]types.Container, error) { | |
| 71 | + | if dockerCli == nil { | |
| 72 | + | return nil, fmt.Errorf("Docker client is not initialized") | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | containers, err := dockerCli.ContainerList(ctx, container.ListOptions{}) | |
| 76 | + | if err != nil { | |
| 77 | + | return nil, fmt.Errorf("error listing containers: %w", err) | |
| 78 | + | } | |
| 79 | + | ||
| 80 | + | return containers, nil | |
| 81 | + | } | |
| @@ -2,23 +2,18 @@ package docker | |||||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | "context" | 4 | "context" | ||
| 5 | - | "crypto/tls" | |||
| 6 | "fmt" | 5 | "fmt" | ||
| 7 | "os" | 6 | "os" | ||
| 8 | "time" | 7 | "time" | ||
| 9 | 8 | ||||
| 9 | + | "github.com/docker/docker/api/types" | |||
| 10 | "github.com/docker/docker/api/types/container" | 10 | "github.com/docker/docker/api/types/container" | ||
| 11 | "github.com/docker/docker/client" | 11 | "github.com/docker/docker/client" | ||
| 12 | ) | 12 | ) | ||
| 13 | 13 | ||||
| 14 | - | type ContainerEngineClient interface { | |||
| 15 | - | InitializeClient(*Config) error | |||
| 16 | - | // Add other methods that both Docker and Podman should implement | |||
| 17 | - | } | |||
| 18 | type Config struct { | 14 | type Config struct { | ||
| 19 | Sock string | 15 | Sock string | ||
| 20 | PodmanEnable bool | 16 | PodmanEnable bool | ||
| 21 | - | TLSConfig *tls.Config | |||
| 22 | } | 17 | } | ||
| 23 | 18 | ||||
| 24 | var ( | 19 | var ( | ||
| @@ -26,21 +21,15 @@ var ( | |||||
| 26 | currentConfig *Config | 21 | currentConfig *Config | ||
| 27 | ) | 22 | ) | ||
| 28 | 23 | ||||
| 29 | - | // DockerClient implements the ContainerEngineClient interface for Docker | 24 | + | func InitializeClient(config *Config) error { |
| 30 | - | type DockerClient struct{} | |||
| 31 | - | ||||
| 32 | - | func (d *DockerClient) InitializeClient(config *Config) error { | |||
| 33 | - | // Validate if the Sock field is not empty | |||
| 34 | if config.Sock == "" { | 25 | if config.Sock == "" { | ||
| 35 | return fmt.Errorf("sock field in Config is empty") | 26 | return fmt.Errorf("sock field in Config is empty") | ||
| 36 | } | 27 | } | ||
| 37 | 28 | ||||
| 38 | - | // Check if the socket file exists if not return an error | |||
| 39 | if _, err := os.Stat(config.Sock); os.IsNotExist(err) { | 29 | if _, err := os.Stat(config.Sock); os.IsNotExist(err) { | ||
| 40 | return err | 30 | return err | ||
| 41 | } | 31 | } | ||
| 42 | 32 | ||||
| 43 | - | // Initialize Docker client | |||
| 44 | cli, err := client.NewClientWithOpts( | 33 | cli, err := client.NewClientWithOpts( | ||
| 45 | client.WithAPIVersionNegotiation(), | 34 | client.WithAPIVersionNegotiation(), | ||
| 46 | client.WithHost("unix://"+config.Sock), | 35 | client.WithHost("unix://"+config.Sock), | ||
| @@ -53,19 +42,16 @@ func (d *DockerClient) InitializeClient(config *Config) error { | |||||
| 53 | return nil | 42 | return nil | ||
| 54 | } | 43 | } | ||
| 55 | 44 | ||||
| 56 | - | // CheckIfInitialized checks if the Docker client is initialized | |||
| 57 | func CheckIfInitialized() error { | 45 | func CheckIfInitialized() error { | ||
| 58 | - | // Check if there is a socket file | |||
| 59 | if currentConfig == nil || currentConfig.Sock == "" { | 46 | if currentConfig == nil || currentConfig.Sock == "" { | ||
| 60 | return fmt.Errorf("docker client is not initialized or configuration is missing") | 47 | return fmt.Errorf("docker client is not initialized or configuration is missing") | ||
| 61 | } | 48 | } | ||
| 62 | 49 | ||||
| 63 | - | socketPath := currentConfig.Sock // Use the package-level variable | 50 | + | socketPath := currentConfig.Sock |
| 64 | if _, err := os.Stat(socketPath); os.IsNotExist(err) { | 51 | if _, err := os.Stat(socketPath); os.IsNotExist(err) { | ||
| 65 | return fmt.Errorf("sock file does not exist: %s", socketPath) | 52 | return fmt.Errorf("sock file does not exist: %s", socketPath) | ||
| 66 | } | 53 | } | ||
| 67 | 54 | ||||
| 68 | - | // Then we check if the dockerCli is nil | |||
| 69 | if dockerCli == nil { | 55 | if dockerCli == nil { | ||
| 70 | return fmt.Errorf("docker client is not initialized") | 56 | return fmt.Errorf("docker client is not initialized") | ||
| 71 | } | 57 | } | ||
| @@ -73,10 +59,23 @@ func CheckIfInitialized() error { | |||||
| 73 | ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) | 59 | ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) | ||
| 74 | defer cancel() | 60 | defer cancel() | ||
| 75 | 61 | ||||
| 76 | - | // More stringent check: try to list containers | 62 | + | containers, err := dockerCli.ContainerList(ctx, container.ListOptions{}) |
| 77 | - | _, err := dockerCli.ContainerList(ctx, container.ListOptions{}) | |||
| 78 | if err != nil { | 63 | if err != nil { | ||
| 79 | return fmt.Errorf("cannot connect to Docker daemon: %s", err) | 64 | return fmt.Errorf("cannot connect to Docker daemon: %s", err) | ||
| 80 | } | 65 | } | ||
| 66 | + | fmt.Printf("Found %d containers\n", len(containers)) | |||
| 81 | return nil | 67 | return nil | ||
| 82 | } | 68 | } | ||
| 69 | + | ||||
| 70 | + | func ListContainers(ctx context.Context) ([]types.Container, error) { | |||
| 71 | + | if dockerCli == nil { | |||
| 72 | + | return nil, fmt.Errorf("Docker client is not initialized") | |||
| 73 | + | } | |||
| 74 | + | ||||
| 75 | + | containers, err := dockerCli.ContainerList(ctx, container.ListOptions{}) | |||
| 76 | + | if err != nil { | |||
| 77 | + | return nil, fmt.Errorf("error listing containers: %w", err) | |||
| 78 | + | } | |||
| 79 | + | ||||
| 80 | + | return containers, nil | |||
| 81 | + | } | |||