Fix: improve Docker startup and compose validation#78
Fix: improve Docker startup and compose validation#78austin047 wants to merge 4 commits intoflatrun:mainfrom
Conversation
Code Review SummaryThis PR improves the robustness of the Flatrun Agent by ensuring Docker is reachable at startup and adding schema validation for Docker Compose files using the CLI. 🚀 Key Improvements
💡 Minor Suggestions
|
| @@ -42,6 +43,15 @@ func main() { | |||
| log.Fatalf("Failed to load config from %s: %v", resolvedConfigPath, err) | |||
| } | |||
There was a problem hiding this comment.
Using exec.Command("docker", "info") relies on the docker CLI being installed in the PATH. Since you've added the moby/moby client dependency, it is more efficient and reliable to check connectivity using the library's Ping() or Info() methods instead of spawning a shell process.
| } | |
| func ensureDockerReachable(socket string) { | |
| ctx := context.Background() | |
| cli, err := client.NewClientWithOpts(client.WithHost(socket), client.WithAPIVersionNegotiation()) | |
| if err != nil { | |
| log.Fatalf("Failed to create Docker client: %v", err) | |
| } | |
| defer cli.Close() | |
| if _, err := cli.Ping(ctx); err != nil { | |
| log.Fatalf("Docker is not reachable: %v", err) | |
| } | |
| } |
| return nil | ||
| } | ||
|
|
||
| func validateComposeWithCLI(content string) error { |
There was a problem hiding this comment.
Closing the file before deleting it is safer on some operating systems (like Windows). Also, consider using defer os.Remove(tmp.Name()) immediately after creation to ensure cleanup even if subsequent steps fail.
| func validateComposeWithCLI(content string) error { | |
| tmp, err := os.CreateTemp("", "compose-*.yml") | |
| if err != nil { | |
| log.Printf("Warning: skipping CLI validation, failed to create temp file: %v", err) | |
| return nil | |
| } | |
| defer os.Remove(tmp.Name()) | |
| defer tmp.Close() |
| log.Fatalf("Failed to load config from %s: %v", resolvedConfigPath, err) | ||
| } | ||
|
|
||
| os.Setenv("DOCKER_HOST", cfg.DockerSocket) |
There was a problem hiding this comment.
Setting DOCKER_HOST globally via os.Setenv can cause side effects if other parts of the application or third-party libraries expect a different environment. Since you've already added the Moby client, it is better to pass the socket explicitly to constructors rather than relying on global environment variables.
| os.Setenv("DOCKER_HOST", cfg.DockerSocket) | |
| ensureDockerReachable(cfg.DockerSocket) |
pkg/config/config.go
Outdated
| } | ||
| if cfg.DockerSocket == "" { | ||
| cfg.DockerSocket = "unix:///var/run/docker.sock" | ||
| apiClient, err := client.New(client.FromEnv) |
There was a problem hiding this comment.
Creating a new client just to detect the default host is slightly heavy. Note that client.FromEnv will look at the DOCKER_HOST environment variable first. Ensure this fallback logic matches the expected behavior if the agent is running inside a container.
| apiClient, err := client.New(client.FromEnv) | |
| cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) | |
| if err == nil { | |
| cfg.DockerSocket = cli.DaemonHost() | |
| cli.Close() | |
| } else { | |
| cfg.DockerSocket = "unix:///var/run/docker.sock" | |
| } |
config.exampledeployments_path to ./deployment