From 287bec0d65f2cf2cc2af60dc272f85517f7322c7 Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Fri, 16 Feb 2024 23:32:17 +0530 Subject: [PATCH 01/34] fixed docker start command bug Signed-off-by: Yaxhveer --- pkg/clients/clients.go | 2 +- pkg/clients/docker/docker_client.go | 24 +++++++------ pkg/graph/serve.go | 12 ++++--- pkg/hooks/launch.go | 53 ++++++++++++++++++++++++---- pkg/hooks/loader.go | 17 +++++---- pkg/hooks/util.go | 30 ++++++++++++++++ pkg/service/mockrecord/mockrecord.go | 2 +- pkg/service/mocktest/mocktest.go | 6 ++-- pkg/service/record/record.go | 12 ++++--- pkg/service/test/test.go | 16 ++++++--- utils/utils.go | 4 +++ 11 files changed, 135 insertions(+), 43 deletions(-) diff --git a/pkg/clients/clients.go b/pkg/clients/clients.go index 4475400ea..13105665d 100755 --- a/pkg/clients/clients.go +++ b/pkg/clients/clients.go @@ -10,7 +10,7 @@ type InternalDockerClient interface { ExtractNetworksForContainer(containerName string) (map[string]*network.EndpointSettings, error) ConnectContainerToNetworks(containerName string, settings map[string]*network.EndpointSettings) error ConnectContainerToNetworksByNames(containerName string, networkName []string) error - StopAndRemoveDockerContainer() error + StopDockerContainer(removeContainer bool) error GetContainerID() string SetContainerID(containerID string) NetworkExists(network string) (bool, error) diff --git a/pkg/clients/docker/docker_client.go b/pkg/clients/docker/docker_client.go index d3c3eacb3..e5a38e58e 100755 --- a/pkg/clients/docker/docker_client.go +++ b/pkg/clients/docker/docker_client.go @@ -140,7 +140,7 @@ func (idc *internalDockerClient) ConnectContainerToNetworksByNames(containerName } // Stop and Remove the docker container -func (idc *internalDockerClient) StopAndRemoveDockerContainer() error { +func (idc *internalDockerClient) StopDockerContainer(removeContainer bool) error { dockerClient := idc containerID := idc.containerID @@ -156,17 +156,21 @@ func (idc *internalDockerClient) StopAndRemoveDockerContainer() error { } } - removeOptions := types.ContainerRemoveOptions{ - RemoveVolumes: true, - Force: true, - } + idc.logger.Debug("Docker Container stopped successfully.") - err = dockerClient.ContainerRemove(context.Background(), containerID, removeOptions) - if err != nil { - return fmt.Errorf("failed to remove the docker container: %w", err) - } + if removeContainer { + removeOptions := types.ContainerRemoveOptions{ + RemoveVolumes: true, + Force: true, + } - idc.logger.Debug("Docker Container stopped and removed successfully.") + err = dockerClient.ContainerRemove(context.Background(), containerID, removeOptions) + if err != nil { + return fmt.Errorf("failed to remove the docker container: %w", err) + } + + idc.logger.Debug("Docker Container removed successfully.") + } return nil } diff --git a/pkg/graph/serve.go b/pkg/graph/serve.go index 02676d62d..364b711ae 100644 --- a/pkg/graph/serve.go +++ b/pkg/graph/serve.go @@ -7,6 +7,7 @@ import ( "os" "os/signal" "strconv" + "strings" "sync" "syscall" "time" @@ -49,6 +50,9 @@ func (g *graph) Serve(path string, proxyPort uint32, mongopassword, testReportPa port = defaultPort } + // Remove the container on program exit + removeContainer := !strings.Contains(appCmd, "docker start") + // Listen for the interrupt signal stopper := make(chan os.Signal, 1) signal.Notify(stopper, syscall.SIGINT, syscall.SIGTERM) @@ -91,7 +95,7 @@ func (g *graph) Serve(path string, proxyPort uint32, mongopassword, testReportPa select { case <-stopper: - loadedHooks.Stop(true) + loadedHooks.Stop(true, removeContainer) return default: // start the proxy @@ -166,7 +170,7 @@ func (g *graph) Serve(path string, proxyPort uint32, mongopassword, testReportPa abortStopHooksForcefully := false select { case <-stopper: - loadedHooks.Stop(true) + loadedHooks.Stop(true, removeContainer) ps.StopProxyServer() return default: @@ -187,7 +191,7 @@ func (g *graph) Serve(path string, proxyPort uint32, mongopassword, testReportPa if !abortStopHooksForcefully { abortStopHooksInterrupt <- true // stop listening for the eBPF events - loadedHooks.Stop(true) + loadedHooks.Stop(true, removeContainer) ps.StopProxyServer() exitCmd <- true //stop listening for proxy server @@ -200,7 +204,7 @@ func (g *graph) Serve(path string, proxyPort uint32, mongopassword, testReportPa select { case <-stopper: abortStopHooksForcefully = true - loadedHooks.Stop(false) + loadedHooks.Stop(false, removeContainer) ps.StopProxyServer() return case <-abortStopHooksInterrupt: diff --git a/pkg/hooks/launch.go b/pkg/hooks/launch.go index 199cdd224..0dde2c73d 100755 --- a/pkg/hooks/launch.go +++ b/pkg/hooks/launch.go @@ -202,6 +202,42 @@ func (h *Hook) LaunchUserApplication(appCmd, appContainer, appNetwork string, De } h.logger.Debug("", zap.Any("appContainer", appContainer), zap.Any("appNetwork", appNetwork), zap.Any("appCmd", appCmd)) + } else if cmd == "docker-start" { + var err error + + // extracting container name from app command + pattern := `start\s+(\w+)` + + re := regexp.MustCompile(pattern) + matches := re.FindStringSubmatch(appCmd) + if len(matches) < 2 { + h.logger.Error("container name not found in command") + } + + containerID := matches[1] + + cont, net, err := GetContainerInfo(containerID, appNetwork) + + h.logger.Info("", zap.String("Parsed container name", cont)) + h.logger.Info("", zap.String("Parsed docker network", net)) + + if err != nil { + h.logger.Error("failed to parse container and network name from given docker command", zap.Error(err), zap.Any("AppCmd", appCmd)) + return err + } + + if len(appContainer) != 0 && appContainer != cont { + h.logger.Warn(fmt.Sprintf("given app container:(%v) is different from parsed app container:(%v)", appContainer, cont)) + } + + appContainer = cont + + //injecting appNetwork to keploy. + err = h.injectNetworkToKeploy(appNetwork) + if err != nil { + h.logger.Error(fmt.Sprintf("failed to inject network:%v to the keploy container", appNetwork)) + return err + } } else if cmd == "docker" { var err error cont, net, err := parseDockerCommand(appCmd) @@ -279,9 +315,11 @@ func (h *Hook) processDockerEnv(appCmd, appContainer, appNetwork string, buildDe defer h.Recover(pkg.GenerateRandomID()) err := h.runApp(appCmd, true) - h.logger.Debug("Application stopped with the error", zap.Error(err)) - if !stopApplicationErrors { - appErrCh <- err + if err != nil { + h.logger.Debug("Application stopped with the error", zap.Error(err)) + if !stopApplicationErrors { + appErrCh <- err + } } }() } @@ -305,6 +343,7 @@ func (h *Hook) processDockerEnv(appCmd, appContainer, appNetwork string, buildDe eventFilter := filters.NewArgs() eventFilter.Add("type", "container") eventFilter.Add("event", "create") + eventFilter.Add("event", "start") messages, errs := dockerClient.Events(context.Background(), types.EventsOptions{ Filters: eventFilter, @@ -338,7 +377,7 @@ func (h *Hook) processDockerEnv(appCmd, appContainer, appNetwork string, buildDe case <-logTicker.C: h.logger.Info("still waiting for the container to start.", zap.String("containerName", appContainer)) case e := <-messages: - if e.Type == events.ContainerEventType && e.Action == "create" { + if e.Type == events.ContainerEventType && (e.Action == "create" || e.Action == "start") { // Set Docker Container ID h.idc.SetContainerID(e.ID) @@ -546,9 +585,9 @@ func (h *Hook) runApp(appCmd string, isUnitTestIntegration bool) error { } h.logger.Error("userApplication failed to run with the following error. Please check application logs", zap.Error(err)) return ErrCommandError - } else { - return ErrUnExpected - } + } + + return nil } // injectNetworkToKeploy attaches the given network to the keploy container and also sends the keploy container ip of the new network interface to the kernel space diff --git a/pkg/hooks/loader.go b/pkg/hooks/loader.go index ef205bbc3..296bae555 100755 --- a/pkg/hooks/loader.go +++ b/pkg/hooks/loader.go @@ -421,19 +421,19 @@ func (h *Hook) findAndCollectChildProcesses(parentPID string, pids *[]int) { } // StopUserApplication stops the user application -func (h *Hook) StopUserApplication() { +func (h *Hook) StopUserApplication(removeContainer bool) { h.logger.Info("keploy has initiated the shutdown of the user application.") h.SetUserAppTerminateInitiated(true) if h.userAppCmd != nil && h.userAppCmd.Process != nil { h.logger.Debug("the process state for the user process", zap.String("state", h.userAppCmd.ProcessState.String()), zap.Any("processState", h.userAppCmd.ProcessState)) - if h.userAppCmd.ProcessState != nil && h.userAppCmd.ProcessState.Exited() { + if h.userAppCmd.ProcessState != nil && h.userAppCmd.ProcessState.Exited() && !strings.Contains(h.userAppCmd.String(), "docker start") { return } // Stop Docker Container and Remove it if Keploy ran using docker. containerID := h.idc.GetContainerID() if len(containerID) != 0 { - err := h.idc.StopAndRemoveDockerContainer() + err := h.idc.StopDockerContainer(removeContainer) if err != nil { h.logger.Error(fmt.Sprintf("Failed to stop/remove the docker container %s. Please stop and remove the application container manually.", containerID), zap.Error(err)) } @@ -450,9 +450,9 @@ func (h *Hook) Recover(id int) { stackTrace := debug.Stack() h.logger.Debug("Recover from panic in go routine", zap.Any("current routine id", id), zap.Any("main routine id", h.mainRoutineId), zap.Any("stack trace", string(stackTrace))) - h.Stop(true) + h.Stop(true, true) // stop the user application cmd - h.StopUserApplication() + h.StopUserApplication(true) if id != h.mainRoutineId { log.Panic(r) os.Exit(1) @@ -475,11 +475,10 @@ func deleteFileIfExists(filename string, logger *zap.Logger) error { return nil } -func (h *Hook) Stop(forceStop bool) { - - if !forceStop && !h.IsUserAppTerminateInitiated() { +func (h *Hook) Stop(forceStop bool, removeContainer bool) { + if !forceStop && !h.IsUserAppTerminateInitiated() { h.logger.Info("Received signal to exit keploy program..") - h.StopUserApplication() + h.StopUserApplication(removeContainer) } else { h.logger.Info("Exiting keploy program gracefully.") } diff --git a/pkg/hooks/util.go b/pkg/hooks/util.go index b1a0b2b49..af8a4e8ae 100644 --- a/pkg/hooks/util.go +++ b/pkg/hooks/util.go @@ -1,9 +1,13 @@ package hooks import ( + "context" "encoding/binary" "errors" + "fmt" "net" + + "github.com/docker/docker/client" ) const mockTable string = "mock" @@ -27,3 +31,29 @@ func ConvertIPToUint32(ipStr string) (uint32, error) { return 0, errors.New("failed to parse IP address") } } + +// GetContainerInfo returns the containerName and networkName from containerId +func GetContainerInfo(containerID string, networkName string) (string, string, error) { + + dockerClient, err := client.NewClientWithOpts(client.FromEnv) + if err != nil { + return "", "", err + } + + containerInfo, err := dockerClient.ContainerInspect(context.Background(), containerID) + if err != nil { + return "", "", err + } + + containerName := containerInfo.Name[1:] + + // Extract network as given by the user + networkInfo := "" + for networkInfo, _ = range containerInfo.NetworkSettings.Networks { + if networkInfo == networkName { + return containerName, networkName, nil + } + } + + return "", "", fmt.Errorf("network not found") +} diff --git a/pkg/service/mockrecord/mockrecord.go b/pkg/service/mockrecord/mockrecord.go index e22346712..27f95d697 100644 --- a/pkg/service/mockrecord/mockrecord.go +++ b/pkg/service/mockrecord/mockrecord.go @@ -81,6 +81,6 @@ func (s *mockRecorder) MockRecord(path string, proxyPort uint32, pid uint32, moc } // Shutdown other resources - loadedHooks.Stop(true) + loadedHooks.Stop(true, true) ps.StopProxyServer() } diff --git a/pkg/service/mocktest/mocktest.go b/pkg/service/mocktest/mocktest.go index 3529c0d33..10a8de4c3 100644 --- a/pkg/service/mocktest/mocktest.go +++ b/pkg/service/mocktest/mocktest.go @@ -71,7 +71,7 @@ func (s *mockTester) MockTest(path string, proxyPort, pid uint32, mockName strin tcsMocks, err := ys.ReadTcsMocks(&models.TestCase{}, "") if err != nil { - loadedHooks.Stop(true) + loadedHooks.Stop(true, true) ps.StopProxyServer() return } @@ -92,7 +92,7 @@ func (s *mockTester) MockTest(path string, proxyPort, pid uint32, mockName strin configMocks, err := ys.ReadConfigMocks("") if err != nil { - loadedHooks.Stop(true) + loadedHooks.Stop(true, true) ps.StopProxyServer() return } @@ -134,6 +134,6 @@ func (s *mockTester) MockTest(path string, proxyPort, pid uint32, mockName strin tele.MockTestRun(usedMocks) } // Shutdown other resources - loadedHooks.Stop(true) + loadedHooks.Stop(true, true) ps.StopProxyServer() } diff --git a/pkg/service/record/record.go b/pkg/service/record/record.go index 2bdc926ae..6a2beabbc 100755 --- a/pkg/service/record/record.go +++ b/pkg/service/record/record.go @@ -4,6 +4,7 @@ import ( "context" "os" "os/signal" + "strings" "syscall" "time" @@ -49,6 +50,9 @@ func (r *recorder) CaptureTraffic(path string, proxyPort uint32, appCmd, appCont stopper := make(chan os.Signal, 1) signal.Notify(stopper, os.Interrupt, os.Kill, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGKILL) + // Remove the container on program exit + removeContainer := !strings.Contains(appCmd, "docker start") + models.SetMode(models.MODE_RECORD) tele.Ping(false) @@ -81,7 +85,7 @@ func (r *recorder) CaptureTraffic(path string, proxyPort uint32, appCmd, appCont select { case <-stopper: - loadedHooks.Stop(true) + loadedHooks.Stop(true, removeContainer) return default: // start the BootProxy @@ -106,7 +110,7 @@ func (r *recorder) CaptureTraffic(path string, proxyPort uint32, appCmd, appCont select { case <-stopper: - loadedHooks.Stop(true) + loadedHooks.Stop(true, removeContainer) ps.StopProxyServer() return default: @@ -142,7 +146,7 @@ func (r *recorder) CaptureTraffic(path string, proxyPort uint32, appCmd, appCont if !abortStopHooksForcefully { abortStopHooksInterrupt <- true // stop listening for the eBPF events - loadedHooks.Stop(!stopApplication) + loadedHooks.Stop(!stopApplication, removeContainer) //stop listening for proxy server ps.StopProxyServer() exitCmd <- true @@ -155,7 +159,7 @@ func (r *recorder) CaptureTraffic(path string, proxyPort uint32, appCmd, appCont select { case <-stopper: abortStopHooksForcefully = true - loadedHooks.Stop(false) + loadedHooks.Stop(false, removeContainer) if testsTotal != 0 { tele.RecordedTestSuite(dirName, testsTotal, mocksTotal) } diff --git a/pkg/service/test/test.go b/pkg/service/test/test.go index eecd230e0..ab850b946 100755 --- a/pkg/service/test/test.go +++ b/pkg/service/test/test.go @@ -124,6 +124,10 @@ func (t *tester) InitialiseTest(cfg *TestConfig) (TestEnvironmentSetup, error) { stopper := make(chan os.Signal, 1) signal.Notify(stopper, os.Interrupt, os.Kill, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGKILL) + + // Remove the container on program exit + removeContainer := !strings.Contains(cfg.AppCmd, "docker start") + models.SetMode(models.MODE_TEST) returnVal.TestReportFS = cfg.TestReport @@ -148,7 +152,7 @@ func (t *tester) InitialiseTest(cfg *TestConfig) (TestEnvironmentSetup, error) { select { case <-stopper: - returnVal.LoadedHooks.Stop(true) + returnVal.LoadedHooks.Stop(true, removeContainer) return returnVal, errors.New("Keploy was interupted by stopper") default: // start the proxy @@ -181,7 +185,7 @@ func (t *tester) InitialiseTest(cfg *TestConfig) (TestEnvironmentSetup, error) { select { case <-stopper: returnVal.AbortStopHooksForcefully = true - returnVal.LoadedHooks.Stop(false) + returnVal.LoadedHooks.Stop(false, removeContainer) //Call the telemetry events. if resultForTele[0] != 0 || resultForTele[1] != 0 { cfg.Tele.Testrun(resultForTele[0], resultForTele[1]) @@ -332,10 +336,14 @@ func (t *tester) Test(path string, testReportPath string, generateTestReport boo } } + + // Remove the container on program exit + removeContainer := !strings.Contains(appCmd, "docker start") + if !initialisedValues.AbortStopHooksForcefully { initialisedValues.AbortStopHooksInterrupt <- true // stop listening for the eBPF events - initialisedValues.LoadedHooks.Stop(true) + initialisedValues.LoadedHooks.Stop(true, removeContainer) //stop listening for proxy server initialisedValues.ProxySet.StopProxyServer() return true @@ -663,7 +671,7 @@ func (t *tester) RunTestSet(testSet, path, testReportPath string, generateTestRe } else { // stop the user application if !isApplicationStopped && !serveTest { - initialisedValues.LoadedHooks.StopUserApplication() + initialisedValues.LoadedHooks.StopUserApplication(true) } } }() diff --git a/utils/utils.go b/utils/utils.go index ab2ecbef7..b4400f394 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -179,6 +179,8 @@ func IsDockerRelatedCmd(cmd string) (bool, string) { "sudo docker-compose ", "docker compose ", "sudo docker compose ", + "docker start", + "sudo docker start", "docker ", "sudo docker ", } @@ -187,6 +189,8 @@ func IsDockerRelatedCmd(cmd string) (bool, string) { if strings.HasPrefix(strings.ToLower(cmd), pattern) { if strings.Contains(pattern, "compose") { return true, "docker-compose" + } else if strings.Contains(pattern, "start") { + return true, "docker-start" } return true, "docker" } From 9349a798b28ded2cfed72ed9e93965caa249571d Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Sat, 17 Feb 2024 02:01:06 +0530 Subject: [PATCH 02/34] changes Signed-off-by: Yaxhveer --- pkg/hooks/launch.go | 6 +++++- pkg/hooks/util.go | 3 +-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/pkg/hooks/launch.go b/pkg/hooks/launch.go index 0dde2c73d..3d33d3ed9 100755 --- a/pkg/hooks/launch.go +++ b/pkg/hooks/launch.go @@ -230,7 +230,11 @@ func (h *Hook) LaunchUserApplication(appCmd, appContainer, appNetwork string, De h.logger.Warn(fmt.Sprintf("given app container:(%v) is different from parsed app container:(%v)", appContainer, cont)) } - appContainer = cont + if len(appNetwork) != 0 && appNetwork != net { + h.logger.Warn(fmt.Sprintf("given docker network:(%v) is different from parsed docker network:(%v)", appNetwork, net)) + } + + appContainer, appNetwork = cont, net //injecting appNetwork to keploy. err = h.injectNetworkToKeploy(appNetwork) diff --git a/pkg/hooks/util.go b/pkg/hooks/util.go index af8a4e8ae..8efdab0a7 100644 --- a/pkg/hooks/util.go +++ b/pkg/hooks/util.go @@ -4,7 +4,6 @@ import ( "context" "encoding/binary" "errors" - "fmt" "net" "github.com/docker/docker/client" @@ -55,5 +54,5 @@ func GetContainerInfo(containerID string, networkName string) (string, string, e } } - return "", "", fmt.Errorf("network not found") + return containerName, networkInfo, nil } From c2379e870962709be067df804a91ece1664d5b35 Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Sat, 17 Feb 2024 11:57:47 +0530 Subject: [PATCH 03/34] changes Signed-off-by: Yaxhveer --- pkg/hooks/loader.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/hooks/loader.go b/pkg/hooks/loader.go index 296bae555..8bf7434fb 100755 --- a/pkg/hooks/loader.go +++ b/pkg/hooks/loader.go @@ -426,7 +426,7 @@ func (h *Hook) StopUserApplication(removeContainer bool) { h.SetUserAppTerminateInitiated(true) if h.userAppCmd != nil && h.userAppCmd.Process != nil { h.logger.Debug("the process state for the user process", zap.String("state", h.userAppCmd.ProcessState.String()), zap.Any("processState", h.userAppCmd.ProcessState)) - if h.userAppCmd.ProcessState != nil && h.userAppCmd.ProcessState.Exited() && !strings.Contains(h.userAppCmd.String(), "docker start") { + if h.userAppCmd.ProcessState != nil && h.userAppCmd.ProcessState.Exited() && !strings.Contains(h.userAppCmd.String(), "docker") { return } From 5f50192e3cff11548486c74f9c8363025e357996 Mon Sep 17 00:00:00 2001 From: Ahmed Lotfy <76037906+AhmedLotfy02@users.noreply.github.com> Date: Sat, 17 Feb 2024 09:07:57 +0200 Subject: [PATCH 04/34] [fix]: update permission to keploy directory if it exists (#1585) Signed-off-by: Yaxhveer --- cmd/test.go | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/cmd/test.go b/cmd/test.go index 07c7c7896..e79459e94 100755 --- a/cmd/test.go +++ b/cmd/test.go @@ -397,17 +397,17 @@ func (t *Test) GetCmd() *cobra.Command { if generateTestReport { testReportPath = path + "/testReports" - + testReportPath, err = pkg.GetNextTestReportDir(testReportPath, models.TestRunTemplateName) - t.logger.Info("", zap.Any("keploy testReport path", testReportPath)) - if err != nil { - t.logger.Error("failed to get the next test report directory", zap.Error(err)) - return err - } + t.logger.Info("", zap.Any("keploy testReport path", testReportPath)) + if err != nil { + t.logger.Error("failed to get the next test report directory", zap.Error(err)) + return err + } } else { t.logger.Info("Test Reports are not being generated since generateTestReport flag is set false") } - + var hasContainerName bool if isDockerCmd { if strings.Contains(appCmd, "--name") { @@ -449,11 +449,14 @@ func (t *Test) GetCmd() *cobra.Command { PassthroughHosts: passThroughHosts, }, enableTele) - cmd := exec.Command("sudo", "chmod", "-R", "777", path) - err = cmd.Run() - if err != nil { - t.logger.Error("failed to set the permission of keploy directory", zap.Error(err)) - return err + fileExist := utils.CheckFileExists(path) + if fileExist { + cmd := exec.Command("sudo", "chmod", "-R", "777", path) + err = cmd.Run() + if err != nil { + t.logger.Error("failed to run command", zap.Error(err)) + return err + } } } @@ -511,4 +514,4 @@ func (t *Test) GetCmd() *cobra.Command { testCmd.SilenceErrors = true return testCmd -} \ No newline at end of file +} From e2af67e08c494a1ddbd4de746b5ad0fefafa7e19 Mon Sep 17 00:00:00 2001 From: naoki kuroda <68233204+nnnkkk7@users.noreply.github.com> Date: Sat, 17 Feb 2024 16:18:58 +0900 Subject: [PATCH 05/34] chore: replace deprecated io/ioutil package (#1350) Signed-off-by: Yaxhveer --- pkg/clients/docker/docker_client.go | 18 +++++++++--------- pkg/platform/telemetry/utils.go | 3 +-- .../integrations/httpparser/httpparser.go | 3 +-- pkg/proxy/proxy.go | 3 +-- utils/utils.go | 4 ++-- 5 files changed, 14 insertions(+), 17 deletions(-) diff --git a/pkg/clients/docker/docker_client.go b/pkg/clients/docker/docker_client.go index e5a38e58e..903306043 100755 --- a/pkg/clients/docker/docker_client.go +++ b/pkg/clients/docker/docker_client.go @@ -3,7 +3,7 @@ package docker import ( "context" "fmt" - "io/ioutil" + "os" "path/filepath" "time" @@ -220,7 +220,7 @@ type Compose struct { // CheckBindMounts returns information about whether bind mounts if they are being used contain relative file names or not func (idc *internalDockerClient) CheckBindMounts(filePath string) bool { - data, err := ioutil.ReadFile(filePath) + data, err := os.ReadFile(filePath) if err != nil { idc.logger.Error("error reading file", zap.Any("filePath", filePath), zap.Error(err)) return false @@ -265,7 +265,7 @@ func (idc *internalDockerClient) CheckBindMounts(filePath string) bool { // CheckNetworkInfo returns information about network name and also about whether the network is external or not in a docker-compose file. func (idc *internalDockerClient) CheckNetworkInfo(filePath string) (bool, bool, string) { - data, err := ioutil.ReadFile(filePath) + data, err := os.ReadFile(filePath) if err != nil { idc.logger.Error("error reading file", zap.Any("filePath", filePath), zap.Error(err)) return false, false, "" @@ -370,7 +370,7 @@ func (idc *internalDockerClient) GetHostWorkingDirectory() (string, error) { // ReplaceRelativePaths replaces relative paths in bind mounts with absolute paths func (idc *internalDockerClient) ReplaceRelativePaths(dockerComposefilePath, newComposeFile string) error { - data, err := ioutil.ReadFile(dockerComposefilePath) + data, err := os.ReadFile(dockerComposefilePath) if err != nil { return err } @@ -430,7 +430,7 @@ func (idc *internalDockerClient) ReplaceRelativePaths(dockerComposefilePath, new } newFilePath := filepath.Join(filepath.Dir(dockerComposefilePath), newComposeFile) - err = ioutil.WriteFile(newFilePath, newData, 0644) + err = os.WriteFile(newFilePath, newData, 0644) if err != nil { return err } @@ -440,7 +440,7 @@ func (idc *internalDockerClient) ReplaceRelativePaths(dockerComposefilePath, new // MakeNetworkExternal makes the existing network of the user docker compose file external and save it to a new file func (idc *internalDockerClient) MakeNetworkExternal(dockerComposefilePath, newComposeFile string) error { - data, err := ioutil.ReadFile(dockerComposefilePath) + data, err := os.ReadFile(dockerComposefilePath) if err != nil { return err } @@ -497,7 +497,7 @@ func (idc *internalDockerClient) MakeNetworkExternal(dockerComposefilePath, newC } newFilePath := filepath.Join(filepath.Dir(dockerComposefilePath), newComposeFile) - err = ioutil.WriteFile(newFilePath, newData, 0644) + err = os.WriteFile(newFilePath, newData, 0644) if err != nil { return err } @@ -508,7 +508,7 @@ func (idc *internalDockerClient) MakeNetworkExternal(dockerComposefilePath, newC // AddNetworkToCompose adds the keploy-network network to the new docker compose file and copy rest of the contents from // existing user docker compose file func (idc *internalDockerClient) AddNetworkToCompose(dockerComposefilePath, newComposeFile string) error { - data, err := ioutil.ReadFile(dockerComposefilePath) + data, err := os.ReadFile(dockerComposefilePath) if err != nil { return err } @@ -583,7 +583,7 @@ func (idc *internalDockerClient) AddNetworkToCompose(dockerComposefilePath, newC } newFilePath := filepath.Join(filepath.Dir(dockerComposefilePath), newComposeFile) - err = ioutil.WriteFile(newFilePath, newData, 0644) + err = os.WriteFile(newFilePath, newData, 0644) if err != nil { return err } diff --git a/pkg/platform/telemetry/utils.go b/pkg/platform/telemetry/utils.go index f94592eee..a1022fdbe 100644 --- a/pkg/platform/telemetry/utils.go +++ b/pkg/platform/telemetry/utils.go @@ -4,7 +4,6 @@ import ( "encoding/json" "errors" "io" - "io/ioutil" "net/http" "go.keploy.io/server/pkg/models" @@ -31,7 +30,7 @@ func unmarshalResp(resp *http.Response, log *zap.Logger) (id string, err error) }(resp.Body) var res map[string]string - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { log.Debug("failed to read response from telemetry server", zap.String("url", "https://telemetry.keploy.io/analytics"), zap.Error(err)) return diff --git a/pkg/proxy/integrations/httpparser/httpparser.go b/pkg/proxy/integrations/httpparser/httpparser.go index acc53e31c..e640c8311 100755 --- a/pkg/proxy/integrations/httpparser/httpparser.go +++ b/pkg/proxy/integrations/httpparser/httpparser.go @@ -8,7 +8,6 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "net" "net/http" "net/url" @@ -470,7 +469,7 @@ func decodeOutgoingHttp(requestBuffer []byte, clientConn, destConn net.Conn, h * return } - reqBody, err := ioutil.ReadAll(req.Body) + reqBody, err := io.ReadAll(req.Body) if err != nil { logger.Error("failed to read from request body", zap.Any("metadata", getReqMeta(req)), zap.Error(err)) return diff --git a/pkg/proxy/proxy.go b/pkg/proxy/proxy.go index 90ae2408f..1313f8c89 100755 --- a/pkg/proxy/proxy.go +++ b/pkg/proxy/proxy.go @@ -10,7 +10,6 @@ import ( "embed" "fmt" "io" - "io/ioutil" "log" "net" "os" @@ -158,7 +157,7 @@ func isJavaInstalled() bool { // to extract ca certificate to temp func ExtractCertToTemp() (string, error) { - tempFile, err := ioutil.TempFile("", "ca.crt") + tempFile, err := os.CreateTemp("", "ca.crt") if err != nil { return "", err } diff --git a/utils/utils.go b/utils/utils.go index b4400f394..4e2e48376 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -5,7 +5,7 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" + "io" "net" "net/http" "os" @@ -118,7 +118,7 @@ func attachLogFileToSentry(logFilePath string) { } defer file.Close() - content, _ := ioutil.ReadAll(file) + content, _ := io.ReadAll(file) sentry.ConfigureScope(func(scope *sentry.Scope) { scope.SetExtra("logfile", string(content)) From 7294389b2f637bf2abc561b620471ad617574c99 Mon Sep 17 00:00:00 2001 From: Ahmed Lotfy <76037906+AhmedLotfy02@users.noreply.github.com> Date: Mon, 19 Feb 2024 15:42:05 +0200 Subject: [PATCH 06/34] [refactor]: hide complete test summary in case of app not running (#1590) Signed-off-by: Yaxhveer --- pkg/service/test/test.go | 57 ++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/pkg/service/test/test.go b/pkg/service/test/test.go index ab850b946..f1bbcddf6 100755 --- a/pkg/service/test/test.go +++ b/pkg/service/test/test.go @@ -304,35 +304,36 @@ func (t *tester) Test(path string, testReportPath string, generateTestReport boo }) - pp.Printf("\n <=========================================> \n COMPLETE TESTRUN SUMMARY. \n\tTotal tests: %s\n"+"\tTotal test passed: %s\n"+"\tTotal test failed: %s\n", totalTests, totalTestPassed, totalTestFailed) - - pp.Printf("\n\tTest Suite Name\t\tTotal Test\tPassed\t\tFailed\t\n") - for _, testSuiteName := range testSuiteNames { - pp.Printf("\n\t%s\t\t%s\t\t%s\t\t%s", testSuiteName, completeTestReport[testSuiteName].total, completeTestReport[testSuiteName].passed, completeTestReport[testSuiteName].failed) - } - - pp.Printf("\n<=========================================> \n\n") - - t.logger.Info("test run completed", zap.Bool("passed overall", result)) - // log the overall code coverage for the test run of go binaries - if options.WithCoverage { - t.logger.Info("there is a opportunity to get the coverage here") - // logs the coverage using covdata - coverCmd := exec.Command("go", "tool", "covdata", "percent", "-i="+os.Getenv("GOCOVERDIR")) - output, err := coverCmd.Output() - if err != nil { - t.logger.Error("failed to get the coverage of the go binary", zap.Error(err), zap.Any("cmd", coverCmd.String())) - } - t.logger.Sugar().Infoln("\n", models.HighlightPassingString(string(output))) + if totalTests > 0 { + pp.Printf("\n <=========================================> \n COMPLETE TESTRUN SUMMARY. \n\tTotal tests: %s\n"+"\tTotal test passed: %s\n"+"\tTotal test failed: %s\n", totalTests, totalTestPassed, totalTestFailed) + + pp.Printf("\n\tTest Suite Name\t\tTotal Test\tPassed\t\tFailed\t\n") + for _, testSuiteName := range testSuiteNames { + pp.Printf("\n\t%s\t\t%s\t\t%s\t\t%s", testSuiteName, completeTestReport[testSuiteName].total, completeTestReport[testSuiteName].passed, completeTestReport[testSuiteName].failed) + } + + pp.Printf("\n<=========================================> \n\n") + t.logger.Info("test run completed", zap.Bool("passed overall", result)) + // log the overall code coverage for the test run of go binaries + if options.WithCoverage { + t.logger.Info("there is a opportunity to get the coverage here") + // logs the coverage using covdata + coverCmd := exec.Command("go", "tool", "covdata", "percent", "-i="+os.Getenv("GOCOVERDIR")) + output, err := coverCmd.Output() + if err != nil { + t.logger.Error("failed to get the coverage of the go binary", zap.Error(err), zap.Any("cmd", coverCmd.String())) + } + t.logger.Sugar().Infoln("\n", models.HighlightPassingString(string(output))) - // merges the coverage files into a single txt file which can be merged with the go-test coverage - generateCovTxtCmd := exec.Command("go", "tool", "covdata", "textfmt", "-i="+os.Getenv("GOCOVERDIR"), "-o="+os.Getenv("GOCOVERDIR")+"/total-coverage.txt") - output, err = generateCovTxtCmd.Output() - if err != nil { - t.logger.Error("failed to get the coverage of the go binary", zap.Error(err), zap.Any("cmd", coverCmd.String())) - } - if len(output) > 0 { - t.logger.Sugar().Infoln("\n", models.HighlightFailingString(string(output))) + // merges the coverage files into a single txt file which can be merged with the go-test coverage + generateCovTxtCmd := exec.Command("go", "tool", "covdata", "textfmt", "-i="+os.Getenv("GOCOVERDIR"), "-o="+os.Getenv("GOCOVERDIR")+"/total-coverage.txt") + output, err = generateCovTxtCmd.Output() + if err != nil { + t.logger.Error("failed to get the coverage of the go binary", zap.Error(err), zap.Any("cmd", coverCmd.String())) + } + if len(output) > 0 { + t.logger.Sugar().Infoln("\n", models.HighlightFailingString(string(output))) + } } } From a83483913b928633535c846be83abc6661462e77 Mon Sep 17 00:00:00 2001 From: Yashveer <101015836+Yaxhveer@users.noreply.github.com> Date: Mon, 19 Feb 2024 23:24:56 +0530 Subject: [PATCH 07/34] Dummy commit Signed-off-by: Yaxhveer --- pkg/hooks/launch.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/hooks/launch.go b/pkg/hooks/launch.go index 3d33d3ed9..01796cd53 100755 --- a/pkg/hooks/launch.go +++ b/pkg/hooks/launch.go @@ -300,7 +300,7 @@ func (h *Hook) LaunchUserApplication(appCmd, appContainer, appNetwork string, De } func (h *Hook) processDockerEnv(appCmd, appContainer, appNetwork string, buildDelay time.Duration) error { - // to notify the kernel hooks that the user application is related to Docker. + // to notify the kernel hooks that the user application is related to Docker. key := 0 value := true h.objects.DockerCmdMap.Update(uint32(key), &value, ebpf.UpdateAny) From 215d3cf1f0f641c9b608e6ac80bad981059dcb4e Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Tue, 20 Feb 2024 20:17:17 +0530 Subject: [PATCH 08/34] code refactored Signed-off-by: Yaxhveer --- pkg/hooks/util.go | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/pkg/hooks/util.go b/pkg/hooks/util.go index 8efdab0a7..087116d4f 100644 --- a/pkg/hooks/util.go +++ b/pkg/hooks/util.go @@ -1,12 +1,9 @@ package hooks import ( - "context" "encoding/binary" "errors" "net" - - "github.com/docker/docker/client" ) const mockTable string = "mock" @@ -29,30 +26,4 @@ func ConvertIPToUint32(ipStr string) (uint32, error) { } else { return 0, errors.New("failed to parse IP address") } -} - -// GetContainerInfo returns the containerName and networkName from containerId -func GetContainerInfo(containerID string, networkName string) (string, string, error) { - - dockerClient, err := client.NewClientWithOpts(client.FromEnv) - if err != nil { - return "", "", err - } - - containerInfo, err := dockerClient.ContainerInspect(context.Background(), containerID) - if err != nil { - return "", "", err - } - - containerName := containerInfo.Name[1:] - - // Extract network as given by the user - networkInfo := "" - for networkInfo, _ = range containerInfo.NetworkSettings.Networks { - if networkInfo == networkName { - return containerName, networkName, nil - } - } - - return containerName, networkInfo, nil -} +} \ No newline at end of file From 4466e0a69fb3c6679ed17db0d46e33a58e8d842c Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Tue, 20 Feb 2024 20:18:01 +0530 Subject: [PATCH 09/34] code refactored Signed-off-by: Yaxhveer --- pkg/hooks/launch.go | 79 ++++++++++++--------------------------------- 1 file changed, 21 insertions(+), 58 deletions(-) diff --git a/pkg/hooks/launch.go b/pkg/hooks/launch.go index 01796cd53..9a852e831 100755 --- a/pkg/hooks/launch.go +++ b/pkg/hooks/launch.go @@ -202,72 +202,35 @@ func (h *Hook) LaunchUserApplication(appCmd, appContainer, appNetwork string, De } h.logger.Debug("", zap.Any("appContainer", appContainer), zap.Any("appNetwork", appNetwork), zap.Any("appCmd", appCmd)) - } else if cmd == "docker-start" { + } else if cmd == "docker" || cmd == "docker-start"{ var err error - // extracting container name from app command - pattern := `start\s+(\w+)` + if cmd == "docker" { + cont, net, err := parseDockerCommand(appCmd) + h.logger.Debug("", zap.String("Parsed container name", cont)) + h.logger.Debug("", zap.String("Parsed docker network", net)) - re := regexp.MustCompile(pattern) - matches := re.FindStringSubmatch(appCmd) - if len(matches) < 2 { - h.logger.Error("container name not found in command") - } - - containerID := matches[1] - - cont, net, err := GetContainerInfo(containerID, appNetwork) - - h.logger.Info("", zap.String("Parsed container name", cont)) - h.logger.Info("", zap.String("Parsed docker network", net)) - - if err != nil { - h.logger.Error("failed to parse container and network name from given docker command", zap.Error(err), zap.Any("AppCmd", appCmd)) - return err - } - - if len(appContainer) != 0 && appContainer != cont { - h.logger.Warn(fmt.Sprintf("given app container:(%v) is different from parsed app container:(%v)", appContainer, cont)) - } - - if len(appNetwork) != 0 && appNetwork != net { - h.logger.Warn(fmt.Sprintf("given docker network:(%v) is different from parsed docker network:(%v)", appNetwork, net)) - } - - appContainer, appNetwork = cont, net - - //injecting appNetwork to keploy. - err = h.injectNetworkToKeploy(appNetwork) - if err != nil { - h.logger.Error(fmt.Sprintf("failed to inject network:%v to the keploy container", appNetwork)) - return err - } - } else if cmd == "docker" { - var err error - cont, net, err := parseDockerCommand(appCmd) - h.logger.Debug("", zap.String("Parsed container name", cont)) - h.logger.Debug("", zap.String("Parsed docker network", net)) + if err != nil { + h.logger.Error("failed to parse container name from given docker command", zap.Error(err), zap.Any("AppCmd", appCmd)) + return err + } - if err != nil { - h.logger.Error("failed to parse container name from given docker command", zap.Error(err), zap.Any("AppCmd", appCmd)) - return err - } + if err != nil { + h.logger.Error("failed to parse network name from given docker command", zap.Error(err), zap.Any("AppCmd", appCmd)) + return err + } - if err != nil { - h.logger.Error("failed to parse network name from given docker command", zap.Error(err), zap.Any("AppCmd", appCmd)) - return err - } + if len(appContainer) != 0 && appContainer != cont { + h.logger.Warn(fmt.Sprintf("given app container:(%v) is different from parsed app container:(%v)", appContainer, cont)) + } - if len(appContainer) != 0 && appContainer != cont { - h.logger.Warn(fmt.Sprintf("given app container:(%v) is different from parsed app container:(%v)", appContainer, cont)) - } + if len(appNetwork) != 0 && appNetwork != net { + h.logger.Warn(fmt.Sprintf("given docker network:(%v) is different from parsed docker network:(%v)", appNetwork, net)) + } - if len(appNetwork) != 0 && appNetwork != net { - h.logger.Warn(fmt.Sprintf("given docker network:(%v) is different from parsed docker network:(%v)", appNetwork, net)) + appContainer, appNetwork = cont, net } - - appContainer, appNetwork = cont, net - + //injecting appNetwork to keploy. err = h.injectNetworkToKeploy(appNetwork) if err != nil { From 40516aa9ff6eabcc6eac512073002318b8c166aa Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Thu, 22 Feb 2024 11:17:48 +0530 Subject: [PATCH 10/34] updated the changes Signed-off-by: Yaxhveer --- pkg/clients/clients.go | 2 +- pkg/clients/docker/docker_client.go | 4 ++-- pkg/graph/serve.go | 11 ++++------- pkg/hooks/loader.go | 15 ++++++++------- pkg/service/mockrecord/mockrecord.go | 2 +- pkg/service/mocktest/mocktest.go | 6 +++--- pkg/service/record/record.go | 11 ++++------- pkg/service/test/test.go | 16 ++++------------ 8 files changed, 27 insertions(+), 40 deletions(-) diff --git a/pkg/clients/clients.go b/pkg/clients/clients.go index 13105665d..5d6123a13 100755 --- a/pkg/clients/clients.go +++ b/pkg/clients/clients.go @@ -10,7 +10,7 @@ type InternalDockerClient interface { ExtractNetworksForContainer(containerName string) (map[string]*network.EndpointSettings, error) ConnectContainerToNetworks(containerName string, settings map[string]*network.EndpointSettings) error ConnectContainerToNetworksByNames(containerName string, networkName []string) error - StopDockerContainer(removeContainer bool) error + StopAndRemoveDockerContainer(skipRemove bool) error GetContainerID() string SetContainerID(containerID string) NetworkExists(network string) (bool, error) diff --git a/pkg/clients/docker/docker_client.go b/pkg/clients/docker/docker_client.go index 903306043..09e9cde55 100755 --- a/pkg/clients/docker/docker_client.go +++ b/pkg/clients/docker/docker_client.go @@ -140,7 +140,7 @@ func (idc *internalDockerClient) ConnectContainerToNetworksByNames(containerName } // Stop and Remove the docker container -func (idc *internalDockerClient) StopDockerContainer(removeContainer bool) error { +func (idc *internalDockerClient) StopAndRemoveDockerContainer(skipRemove bool) error { dockerClient := idc containerID := idc.containerID @@ -158,7 +158,7 @@ func (idc *internalDockerClient) StopDockerContainer(removeContainer bool) error idc.logger.Debug("Docker Container stopped successfully.") - if removeContainer { + if !skipRemove { removeOptions := types.ContainerRemoveOptions{ RemoveVolumes: true, Force: true, diff --git a/pkg/graph/serve.go b/pkg/graph/serve.go index 364b711ae..8ec3c7ded 100644 --- a/pkg/graph/serve.go +++ b/pkg/graph/serve.go @@ -7,7 +7,6 @@ import ( "os" "os/signal" "strconv" - "strings" "sync" "syscall" "time" @@ -50,8 +49,6 @@ func (g *graph) Serve(path string, proxyPort uint32, mongopassword, testReportPa port = defaultPort } - // Remove the container on program exit - removeContainer := !strings.Contains(appCmd, "docker start") // Listen for the interrupt signal stopper := make(chan os.Signal, 1) @@ -95,7 +92,7 @@ func (g *graph) Serve(path string, proxyPort uint32, mongopassword, testReportPa select { case <-stopper: - loadedHooks.Stop(true, removeContainer) + loadedHooks.Stop(true) return default: // start the proxy @@ -170,7 +167,7 @@ func (g *graph) Serve(path string, proxyPort uint32, mongopassword, testReportPa abortStopHooksForcefully := false select { case <-stopper: - loadedHooks.Stop(true, removeContainer) + loadedHooks.Stop(true) ps.StopProxyServer() return default: @@ -191,7 +188,7 @@ func (g *graph) Serve(path string, proxyPort uint32, mongopassword, testReportPa if !abortStopHooksForcefully { abortStopHooksInterrupt <- true // stop listening for the eBPF events - loadedHooks.Stop(true, removeContainer) + loadedHooks.Stop(true) ps.StopProxyServer() exitCmd <- true //stop listening for proxy server @@ -204,7 +201,7 @@ func (g *graph) Serve(path string, proxyPort uint32, mongopassword, testReportPa select { case <-stopper: abortStopHooksForcefully = true - loadedHooks.Stop(false, removeContainer) + loadedHooks.Stop(false) ps.StopProxyServer() return case <-abortStopHooksInterrupt: diff --git a/pkg/hooks/loader.go b/pkg/hooks/loader.go index 8bf7434fb..7f0443a63 100755 --- a/pkg/hooks/loader.go +++ b/pkg/hooks/loader.go @@ -421,7 +421,7 @@ func (h *Hook) findAndCollectChildProcesses(parentPID string, pids *[]int) { } // StopUserApplication stops the user application -func (h *Hook) StopUserApplication(removeContainer bool) { +func (h *Hook) StopUserApplication() { h.logger.Info("keploy has initiated the shutdown of the user application.") h.SetUserAppTerminateInitiated(true) if h.userAppCmd != nil && h.userAppCmd.Process != nil { @@ -433,7 +433,8 @@ func (h *Hook) StopUserApplication(removeContainer bool) { // Stop Docker Container and Remove it if Keploy ran using docker. containerID := h.idc.GetContainerID() if len(containerID) != 0 { - err := h.idc.StopDockerContainer(removeContainer) + skipRemove := strings.Contains(h.userAppCmd.String(), "docker start") + err := h.idc.StopAndRemoveDockerContainer(skipRemove) if err != nil { h.logger.Error(fmt.Sprintf("Failed to stop/remove the docker container %s. Please stop and remove the application container manually.", containerID), zap.Error(err)) } @@ -450,9 +451,9 @@ func (h *Hook) Recover(id int) { stackTrace := debug.Stack() h.logger.Debug("Recover from panic in go routine", zap.Any("current routine id", id), zap.Any("main routine id", h.mainRoutineId), zap.Any("stack trace", string(stackTrace))) - h.Stop(true, true) + h.Stop(true) // stop the user application cmd - h.StopUserApplication(true) + h.StopUserApplication() if id != h.mainRoutineId { log.Panic(r) os.Exit(1) @@ -475,10 +476,10 @@ func deleteFileIfExists(filename string, logger *zap.Logger) error { return nil } -func (h *Hook) Stop(forceStop bool, removeContainer bool) { - if !forceStop && !h.IsUserAppTerminateInitiated() { +func (h *Hook) Stop(forceStop bool) { + if !forceStop && !h.IsUserAppTerminateInitiated() { h.logger.Info("Received signal to exit keploy program..") - h.StopUserApplication(removeContainer) + h.StopUserApplication() } else { h.logger.Info("Exiting keploy program gracefully.") } diff --git a/pkg/service/mockrecord/mockrecord.go b/pkg/service/mockrecord/mockrecord.go index 27f95d697..e22346712 100644 --- a/pkg/service/mockrecord/mockrecord.go +++ b/pkg/service/mockrecord/mockrecord.go @@ -81,6 +81,6 @@ func (s *mockRecorder) MockRecord(path string, proxyPort uint32, pid uint32, moc } // Shutdown other resources - loadedHooks.Stop(true, true) + loadedHooks.Stop(true) ps.StopProxyServer() } diff --git a/pkg/service/mocktest/mocktest.go b/pkg/service/mocktest/mocktest.go index 10a8de4c3..3529c0d33 100644 --- a/pkg/service/mocktest/mocktest.go +++ b/pkg/service/mocktest/mocktest.go @@ -71,7 +71,7 @@ func (s *mockTester) MockTest(path string, proxyPort, pid uint32, mockName strin tcsMocks, err := ys.ReadTcsMocks(&models.TestCase{}, "") if err != nil { - loadedHooks.Stop(true, true) + loadedHooks.Stop(true) ps.StopProxyServer() return } @@ -92,7 +92,7 @@ func (s *mockTester) MockTest(path string, proxyPort, pid uint32, mockName strin configMocks, err := ys.ReadConfigMocks("") if err != nil { - loadedHooks.Stop(true, true) + loadedHooks.Stop(true) ps.StopProxyServer() return } @@ -134,6 +134,6 @@ func (s *mockTester) MockTest(path string, proxyPort, pid uint32, mockName strin tele.MockTestRun(usedMocks) } // Shutdown other resources - loadedHooks.Stop(true, true) + loadedHooks.Stop(true) ps.StopProxyServer() } diff --git a/pkg/service/record/record.go b/pkg/service/record/record.go index 6a2beabbc..74a16f5fb 100755 --- a/pkg/service/record/record.go +++ b/pkg/service/record/record.go @@ -4,7 +4,6 @@ import ( "context" "os" "os/signal" - "strings" "syscall" "time" @@ -50,8 +49,6 @@ func (r *recorder) CaptureTraffic(path string, proxyPort uint32, appCmd, appCont stopper := make(chan os.Signal, 1) signal.Notify(stopper, os.Interrupt, os.Kill, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGKILL) - // Remove the container on program exit - removeContainer := !strings.Contains(appCmd, "docker start") models.SetMode(models.MODE_RECORD) tele.Ping(false) @@ -85,7 +82,7 @@ func (r *recorder) CaptureTraffic(path string, proxyPort uint32, appCmd, appCont select { case <-stopper: - loadedHooks.Stop(true, removeContainer) + loadedHooks.Stop(true) return default: // start the BootProxy @@ -110,7 +107,7 @@ func (r *recorder) CaptureTraffic(path string, proxyPort uint32, appCmd, appCont select { case <-stopper: - loadedHooks.Stop(true, removeContainer) + loadedHooks.Stop(true) ps.StopProxyServer() return default: @@ -146,7 +143,7 @@ func (r *recorder) CaptureTraffic(path string, proxyPort uint32, appCmd, appCont if !abortStopHooksForcefully { abortStopHooksInterrupt <- true // stop listening for the eBPF events - loadedHooks.Stop(!stopApplication, removeContainer) + loadedHooks.Stop(!stopApplication) //stop listening for proxy server ps.StopProxyServer() exitCmd <- true @@ -159,7 +156,7 @@ func (r *recorder) CaptureTraffic(path string, proxyPort uint32, appCmd, appCont select { case <-stopper: abortStopHooksForcefully = true - loadedHooks.Stop(false, removeContainer) + loadedHooks.Stop(false) if testsTotal != 0 { tele.RecordedTestSuite(dirName, testsTotal, mocksTotal) } diff --git a/pkg/service/test/test.go b/pkg/service/test/test.go index f1bbcddf6..b5dec6d06 100755 --- a/pkg/service/test/test.go +++ b/pkg/service/test/test.go @@ -124,10 +124,6 @@ func (t *tester) InitialiseTest(cfg *TestConfig) (TestEnvironmentSetup, error) { stopper := make(chan os.Signal, 1) signal.Notify(stopper, os.Interrupt, os.Kill, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGKILL) - - // Remove the container on program exit - removeContainer := !strings.Contains(cfg.AppCmd, "docker start") - models.SetMode(models.MODE_TEST) returnVal.TestReportFS = cfg.TestReport @@ -152,7 +148,7 @@ func (t *tester) InitialiseTest(cfg *TestConfig) (TestEnvironmentSetup, error) { select { case <-stopper: - returnVal.LoadedHooks.Stop(true, removeContainer) + returnVal.LoadedHooks.Stop(true) return returnVal, errors.New("Keploy was interupted by stopper") default: // start the proxy @@ -185,7 +181,7 @@ func (t *tester) InitialiseTest(cfg *TestConfig) (TestEnvironmentSetup, error) { select { case <-stopper: returnVal.AbortStopHooksForcefully = true - returnVal.LoadedHooks.Stop(false, removeContainer) + returnVal.LoadedHooks.Stop(false) //Call the telemetry events. if resultForTele[0] != 0 || resultForTele[1] != 0 { cfg.Tele.Testrun(resultForTele[0], resultForTele[1]) @@ -337,14 +333,10 @@ func (t *tester) Test(path string, testReportPath string, generateTestReport boo } } - - // Remove the container on program exit - removeContainer := !strings.Contains(appCmd, "docker start") - if !initialisedValues.AbortStopHooksForcefully { initialisedValues.AbortStopHooksInterrupt <- true // stop listening for the eBPF events - initialisedValues.LoadedHooks.Stop(true, removeContainer) + initialisedValues.LoadedHooks.Stop(true) //stop listening for proxy server initialisedValues.ProxySet.StopProxyServer() return true @@ -672,7 +664,7 @@ func (t *tester) RunTestSet(testSet, path, testReportPath string, generateTestRe } else { // stop the user application if !isApplicationStopped && !serveTest { - initialisedValues.LoadedHooks.StopUserApplication(true) + initialisedValues.LoadedHooks.StopUserApplication() } } }() From f3ddde915cc7b16d794631a427bf68e7b92e7274 Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Thu, 22 Feb 2024 19:40:00 +0530 Subject: [PATCH 11/34] dummy commit Signed-off-by: Yaxhveer --- pkg/hooks/util.go | 2 +- pkg/service/record/record.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/hooks/util.go b/pkg/hooks/util.go index 087116d4f..b1a0b2b49 100644 --- a/pkg/hooks/util.go +++ b/pkg/hooks/util.go @@ -26,4 +26,4 @@ func ConvertIPToUint32(ipStr string) (uint32, error) { } else { return 0, errors.New("failed to parse IP address") } -} \ No newline at end of file +} diff --git a/pkg/service/record/record.go b/pkg/service/record/record.go index 74a16f5fb..2bdc926ae 100755 --- a/pkg/service/record/record.go +++ b/pkg/service/record/record.go @@ -49,7 +49,6 @@ func (r *recorder) CaptureTraffic(path string, proxyPort uint32, appCmd, appCont stopper := make(chan os.Signal, 1) signal.Notify(stopper, os.Interrupt, os.Kill, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGKILL) - models.SetMode(models.MODE_RECORD) tele.Ping(false) From 24bf9b66e963fb4cc18fb1cce904c7332eba8288 Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Thu, 22 Feb 2024 19:54:52 +0530 Subject: [PATCH 12/34] dummy commit Signed-off-by: Yaxhveer --- pkg/graph/serve.go | 1 - pkg/hooks/launch.go | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/graph/serve.go b/pkg/graph/serve.go index b94e00ba3..cd1ef13a6 100644 --- a/pkg/graph/serve.go +++ b/pkg/graph/serve.go @@ -49,7 +49,6 @@ func (g *graph) Serve(path string, proxyPort uint32, mongopassword, testReportPa port = defaultPort } - // Listen for the interrupt signal stopper := make(chan os.Signal, 1) signal.Notify(stopper, syscall.SIGINT, syscall.SIGTERM) diff --git a/pkg/hooks/launch.go b/pkg/hooks/launch.go index 1b12310c2..a861a0c37 100755 --- a/pkg/hooks/launch.go +++ b/pkg/hooks/launch.go @@ -202,7 +202,7 @@ func (h *Hook) LaunchUserApplication(appCmd, appContainer, appNetwork string, De } h.logger.Debug("", zap.Any("appContainer", appContainer), zap.Any("appNetwork", appNetwork), zap.Any("appCmd", appCmd)) - } else if cmd == "docker" || cmd == "docker-start"{ + } else if (cmd == "docker" || cmd == "docker-start"){ var err error if cmd == "docker" { From 5df13512d015a03baf21433a35d0910e7ae25cc8 Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Thu, 22 Feb 2024 19:57:41 +0530 Subject: [PATCH 13/34] changes Signed-off-by: Yaxhveer --- pkg/hooks/launch.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/hooks/launch.go b/pkg/hooks/launch.go index a861a0c37..f5790fb57 100755 --- a/pkg/hooks/launch.go +++ b/pkg/hooks/launch.go @@ -202,7 +202,7 @@ func (h *Hook) LaunchUserApplication(appCmd, appContainer, appNetwork string, De } h.logger.Debug("", zap.Any("appContainer", appContainer), zap.Any("appNetwork", appNetwork), zap.Any("appCmd", appCmd)) - } else if (cmd == "docker" || cmd == "docker-start"){ + } else if cmd == "docker" || cmd == "docker-start" { var err error if cmd == "docker" { From cc4e01f69db940854a1efc7073730a006085988c Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Thu, 22 Feb 2024 20:00:40 +0530 Subject: [PATCH 14/34] dummy commit Signed-off-by: Yaxhveer --- pkg/hooks/launch.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/hooks/launch.go b/pkg/hooks/launch.go index f5790fb57..ad02c6b4a 100755 --- a/pkg/hooks/launch.go +++ b/pkg/hooks/launch.go @@ -230,7 +230,7 @@ func (h *Hook) LaunchUserApplication(appCmd, appContainer, appNetwork string, De appContainer, appNetwork = cont, net } - + //injecting appNetwork to keploy. err = h.injectNetworkToKeploy(appNetwork) if err != nil { From cc61b0089e8d975d2c17d22675ac799ed5f3813d Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Thu, 22 Feb 2024 20:03:51 +0530 Subject: [PATCH 15/34] linter issue fixed Signed-off-by: Yaxhveer --- pkg/hooks/launch.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/hooks/launch.go b/pkg/hooks/launch.go index ad02c6b4a..6f134433f 100755 --- a/pkg/hooks/launch.go +++ b/pkg/hooks/launch.go @@ -266,7 +266,7 @@ func (h *Hook) LaunchUserApplication(appCmd, appContainer, appNetwork string, De } func (h *Hook) processDockerEnv(appCmd, appContainer, appNetwork string, buildDelay time.Duration) error { - // to notify the kernel hooks that the user application is related to Docker. + // to notify the kernel hooks that the user application is related to Docker. key := 0 value := true h.objects.DockerCmdMap.Update(uint32(key), &value, ebpf.UpdateAny) @@ -555,7 +555,7 @@ func (h *Hook) runApp(appCmd string, isUnitTestIntegration bool) error { } h.logger.Error("userApplication failed to run with the following error. Please check application logs", zap.Error(err)) return ErrCommandError - } + } return nil } From 6db5e695594be1888cae91acce7a711dd4a18729 Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Sat, 24 Feb 2024 15:22:29 +0530 Subject: [PATCH 16/34] updated changes Signed-off-by: Yaxhveer --- pkg/hooks/loader.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pkg/hooks/loader.go b/pkg/hooks/loader.go index 603db92f2..aa925bcee 100755 --- a/pkg/hooks/loader.go +++ b/pkg/hooks/loader.go @@ -533,14 +533,17 @@ func (h *Hook) StopUserApplication() { h.SetUserAppTerminateInitiated(true) if h.userAppCmd != nil && h.userAppCmd.Process != nil { h.logger.Debug("the process state for the user process", zap.String("state", h.userAppCmd.ProcessState.String()), zap.Any("processState", h.userAppCmd.ProcessState)) - if h.userAppCmd.ProcessState != nil && h.userAppCmd.ProcessState.Exited() && !strings.Contains(h.userAppCmd.String(), "docker") { + + // passing userAppCmd without /usr/bin/sh -c + dockerCmdBool, dockerCmd := utils.IsDockerRelatedCmd(h.userAppCmd.String()[15:]) + if h.userAppCmd.ProcessState != nil && h.userAppCmd.ProcessState.Exited() && !dockerCmdBool { return } // Stop Docker Container and Remove it if Keploy ran using docker. containerID := h.idc.GetContainerID() if len(containerID) != 0 { - skipRemove := strings.Contains(h.userAppCmd.String(), "docker start") + skipRemove := dockerCmd == "docker-start" err := h.idc.StopAndRemoveDockerContainer(skipRemove) if err != nil { h.logger.Error(fmt.Sprintf("Failed to stop/remove the docker container %s. Please stop and remove the application container manually.", containerID), zap.Error(err)) From bdc268adc17b44a6e00c7df0099e3df607d9abf6 Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Mon, 4 Mar 2024 14:21:02 +0530 Subject: [PATCH 17/34] refactored Signed-off-by: Yaxhveer --- pkg/hooks/launch.go | 13 ++++++------- pkg/hooks/loader.go | 9 +++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pkg/hooks/launch.go b/pkg/hooks/launch.go index 6f134433f..faf29fd9a 100755 --- a/pkg/hooks/launch.go +++ b/pkg/hooks/launch.go @@ -285,11 +285,10 @@ func (h *Hook) processDockerEnv(appCmd, appContainer, appNetwork string, buildDe defer h.Recover(pkg.GenerateRandomID()) err := h.runApp(appCmd, true) - if err != nil { - h.logger.Debug("Application stopped with the error", zap.Error(err)) - if !stopApplicationErrors { - appErrCh <- err - } + log.Println(err) + h.logger.Debug("Application stopped with the error", zap.Error(err)) + if !stopApplicationErrors { + appErrCh <- err } }() } @@ -555,9 +554,9 @@ func (h *Hook) runApp(appCmd string, isUnitTestIntegration bool) error { } h.logger.Error("userApplication failed to run with the following error. Please check application logs", zap.Error(err)) return ErrCommandError + } else { + return ErrUnExpected } - - return nil } // injectNetworkToKeploy attaches the given network to the keploy container and also sends the keploy container ip of the new network interface to the kernel space diff --git a/pkg/hooks/loader.go b/pkg/hooks/loader.go index aa925bcee..5c971d71f 100755 --- a/pkg/hooks/loader.go +++ b/pkg/hooks/loader.go @@ -533,17 +533,17 @@ func (h *Hook) StopUserApplication() { h.SetUserAppTerminateInitiated(true) if h.userAppCmd != nil && h.userAppCmd.Process != nil { h.logger.Debug("the process state for the user process", zap.String("state", h.userAppCmd.ProcessState.String()), zap.Any("processState", h.userAppCmd.ProcessState)) - - // passing userAppCmd without /usr/bin/sh -c - dockerCmdBool, dockerCmd := utils.IsDockerRelatedCmd(h.userAppCmd.String()[15:]) - if h.userAppCmd.ProcessState != nil && h.userAppCmd.ProcessState.Exited() && !dockerCmdBool { + if h.userAppCmd.ProcessState != nil && h.userAppCmd.ProcessState.Exited() { return } // Stop Docker Container and Remove it if Keploy ran using docker. containerID := h.idc.GetContainerID() if len(containerID) != 0 { + // passing userAppCmd without /usr/bin/sh -c + _, dockerCmd := utils.IsDockerRelatedCmd(h.userAppCmd.String()[15:]) skipRemove := dockerCmd == "docker-start" + err := h.idc.StopAndRemoveDockerContainer(skipRemove) if err != nil { h.logger.Error(fmt.Sprintf("Failed to stop/remove the docker container %s. Please stop and remove the application container manually.", containerID), zap.Error(err)) @@ -587,6 +587,7 @@ func deleteFileIfExists(filename string, logger *zap.Logger) error { } func (h *Hook) Stop(forceStop bool) { + if !forceStop && !h.IsUserAppTerminateInitiated() { h.logger.Info("Received signal to exit keploy program..") h.StopUserApplication() From 8f53727f8030c537781b69f52a329141c0abace6 Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Mon, 4 Mar 2024 14:23:18 +0530 Subject: [PATCH 18/34] refactored Signed-off-by: Yaxhveer --- pkg/hooks/launch.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/hooks/launch.go b/pkg/hooks/launch.go index faf29fd9a..721bcc379 100755 --- a/pkg/hooks/launch.go +++ b/pkg/hooks/launch.go @@ -285,7 +285,6 @@ func (h *Hook) processDockerEnv(appCmd, appContainer, appNetwork string, buildDe defer h.Recover(pkg.GenerateRandomID()) err := h.runApp(appCmd, true) - log.Println(err) h.logger.Debug("Application stopped with the error", zap.Error(err)) if !stopApplicationErrors { appErrCh <- err From 632245fa6b5cad996c32f25583a6424d5eef610a Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Wed, 3 Apr 2024 22:25:37 +0530 Subject: [PATCH 19/34] Merge branch 'main' of https://github.com/Yaxhveer/keploy into docker-start-cmd Signed-off-by: Yaxhveer --- pkg/core/app/docker/docker.go | 255 +++++++++++++--------------------- 1 file changed, 93 insertions(+), 162 deletions(-) diff --git a/pkg/core/app/docker/docker.go b/pkg/core/app/docker/docker.go index 8b077e1d1..dee5da59d 100755 --- a/pkg/core/app/docker/docker.go +++ b/pkg/core/app/docker/docker.go @@ -1,86 +1,82 @@ +// Package docker provides functionality for working with Docker containers. package docker import ( "context" "fmt" - "os" "path/filepath" "time" nativeDockerClient "github.com/docker/docker/client" + "go.keploy.io/server/v2/utils" "go.uber.org/zap" "gopkg.in/yaml.v3" "github.com/docker/docker/api/types/network" - "go.keploy.io/server/pkg/clients" - "github.com/docker/docker/api/types" dockerContainerPkg "github.com/docker/docker/api/types/container" ) const ( - kDefaultTimeoutForDockerQuery = 1 * time.Minute + defaultTimeoutForDockerQuery = 1 * time.Minute ) -type internalDockerClient struct { +type Impl struct { nativeDockerClient.APIClient timeoutForDockerQuery time.Duration logger *zap.Logger containerID string } -func NewInternalDockerClient(logger *zap.Logger) (clients.InternalDockerClient, error) { +func New(logger *zap.Logger) (Client, error) { dockerClient, err := nativeDockerClient.NewClientWithOpts(nativeDockerClient.FromEnv, nativeDockerClient.WithAPIVersionNegotiation()) if err != nil { return nil, err } - return &internalDockerClient{ + return &Impl{ APIClient: dockerClient, - timeoutForDockerQuery: kDefaultTimeoutForDockerQuery, + timeoutForDockerQuery: defaultTimeoutForDockerQuery, logger: logger, }, nil } -// Getter function for containerID -func (idc *internalDockerClient) GetContainerID() string { +// GetContainerID is a Getter function for containerID +func (idc *Impl) GetContainerID() string { return idc.containerID } -// Setter function for containerID -func (idc *internalDockerClient) SetContainerID(containerID string) { +// SetContainerID is a Setter function for containerID +func (idc *Impl) SetContainerID(containerID string) { idc.containerID = containerID } // ExtractNetworksForContainer returns the list of all the networks that the container is a part of. // Note that if a user did not explicitly attach the container to a network, the Docker daemon attaches it // to a network called "bridge". -func (idc *internalDockerClient) ExtractNetworksForContainer(containerName string) (map[string]*network.EndpointSettings, error) { +func (idc *Impl) ExtractNetworksForContainer(containerName string) (map[string]*network.EndpointSettings, error) { ctx, cancel := context.WithTimeout(context.Background(), idc.timeoutForDockerQuery) defer cancel() containerJSON, err := idc.ContainerInspect(ctx, containerName) if err != nil { - idc.logger.Error("Could not inspect container via the Docker API", zap.Error(err), - zap.Any("container_name", containerName)) + utils.LogError(idc.logger, err, "couldn't inspect container via the Docker API", zap.String("containerName", containerName)) return nil, err } if settings := containerJSON.NetworkSettings; settings != nil { return settings.Networks, nil - } else { - // Docker attaches the container to "bridge" network by default. - // If the network list is empty, the docker daemon is possibly misbehaving, - // or the container is in a bad state. - idc.logger.Error("The network list for the given container is empty. This is unexpected.", - zap.Any("container_name", containerName)) - return nil, fmt.Errorf("the container is not attached to any network") } + // Docker attaches the container to "bridge" network by default. + // If the network list is empty, the docker daemon is possibly misbehaving, + // or the container is in a bad state. + utils.LogError(idc.logger, nil, "The network list for the given container is empty. This is unexpected.", zap.String("containerName", containerName)) + return nil, fmt.Errorf("the container is not attached to any network") } -func (idc *internalDockerClient) ConnectContainerToNetworks(containerName string, settings map[string]*network.EndpointSettings) error { +func (idc *Impl) ConnectContainerToNetworks(containerName string, settings map[string]*network.EndpointSettings) error { if settings == nil { return fmt.Errorf("provided network settings is empty") } @@ -109,7 +105,7 @@ func (idc *internalDockerClient) ConnectContainerToNetworks(containerName string return nil } -func (idc *internalDockerClient) ConnectContainerToNetworksByNames(containerName string, networkNames []string) error { +func (idc *Impl) AttachNetwork(containerName string, networkNames []string) error { if len(networkNames) == 0 { return fmt.Errorf("provided network names list is empty") } @@ -139,8 +135,8 @@ func (idc *internalDockerClient) ConnectContainerToNetworksByNames(containerName return nil } -// Stop and Remove the docker container -func (idc *internalDockerClient) StopAndRemoveDockerContainer() error { +// StopAndRemoveDockerContainer will Stop and Remove the docker container +func (idc *Impl) StopAndRemoveDockerContainer() error { dockerClient := idc containerID := idc.containerID @@ -172,7 +168,7 @@ func (idc *internalDockerClient) StopAndRemoveDockerContainer() error { } // NetworkExists checks if the given network exists locally or not -func (idc *internalDockerClient) NetworkExists(networkName string) (bool, error) { +func (idc *Impl) NetworkExists(networkName string) (bool, error) { ctx, cancel := context.WithTimeout(context.Background(), idc.timeoutForDockerQuery) defer cancel() @@ -192,8 +188,8 @@ func (idc *internalDockerClient) NetworkExists(networkName string) (bool, error) return false, nil } -// CreateCustomNetwork creates a custom docker network of type bridge. -func (idc *internalDockerClient) CreateCustomNetwork(networkName string) error { +// CreateNetwork creates a custom docker network of type bridge. +func (idc *Impl) CreateNetwork(networkName string) error { ctx, cancel := context.WithTimeout(context.Background(), idc.timeoutForDockerQuery) defer cancel() @@ -214,21 +210,38 @@ type Compose struct { Secrets yaml.Node `yaml:"secrets,omitempty"` } -// CheckBindMounts returns information about whether bind mounts if they are being used contain relative file names or not -func (idc *internalDockerClient) CheckBindMounts(filePath string) bool { +func (idc *Impl) ReadComposeFile(filePath string) (*Compose, error) { data, err := os.ReadFile(filePath) if err != nil { - idc.logger.Error("error reading file", zap.Any("filePath", filePath), zap.Error(err)) - return false + return nil, err } var compose Compose err = yaml.Unmarshal(data, &compose) if err != nil { - idc.logger.Error("error unmarshalling YAML into compose struct", zap.Error(err)) - return false + return nil, err + } + + return &compose, nil +} + +func (idc *Impl) WriteComposeFile(compose *Compose, path string) error { + data, err := yaml.Marshal(compose) + if err != nil { + return err } + // write data to file + + err = os.WriteFile(path, data, 0644) + if err != nil { + return err + } + return nil +} + +// HasRelativePath returns information about whether bind mounts if they are being used contain relative file names or not +func (idc *Impl) HasRelativePath(compose *Compose) bool { if compose.Services.Content == nil { return false } @@ -259,26 +272,13 @@ func (idc *internalDockerClient) CheckBindMounts(filePath string) bool { } -// CheckNetworkInfo returns information about network name and also about whether the network is external or not in a docker-compose file. -func (idc *internalDockerClient) CheckNetworkInfo(filePath string) (bool, bool, string) { - data, err := os.ReadFile(filePath) - if err != nil { - idc.logger.Error("error reading file", zap.Any("filePath", filePath), zap.Error(err)) - return false, false, "" - } - - var compose Compose - err = yaml.Unmarshal(data, &compose) - if err != nil { - idc.logger.Error("error unmarshalling YAML into compose struct", zap.Error(err)) - return false, false, "" - } - +// GetNetworkInfo CheckNetworkInfo returns information about network name and also about whether the network is external or not in a docker-compose file. +func (idc *Impl) GetNetworkInfo(compose *Compose) *NetworkInfo { if compose.Networks.Content == nil { - return false, false, "" + return nil } - var defaultNetworkName string + var defaultNetwork string for i := 0; i < len(compose.Networks.Content); i += 2 { if i+1 >= len(compose.Networks.Content) { @@ -287,8 +287,8 @@ func (idc *internalDockerClient) CheckNetworkInfo(filePath string) (bool, bool, networkKeyNode := compose.Networks.Content[i] networkValueNode := compose.Networks.Content[i+1] - if defaultNetworkName == "" { - defaultNetworkName = networkKeyNode.Value + if defaultNetwork == "" { + defaultNetwork = networkKeyNode.Value } isExternal := false @@ -323,34 +323,35 @@ func (idc *internalDockerClient) CheckNetworkInfo(filePath string) (bool, bool, } if isExternal { + n := &NetworkInfo{External: true, Name: networkKeyNode.Value} if externalName != "" { - return true, true, externalName + n.Name = externalName } - return true, true, networkKeyNode.Value + return n } } - if defaultNetworkName != "" { - return true, false, defaultNetworkName + if defaultNetwork != "" { + return &NetworkInfo{External: false, Name: defaultNetwork} } - return false, false, "" + return nil } -// Inspect Keploy docker container to get bind mount for current directory -func (idc *internalDockerClient) GetHostWorkingDirectory() (string, error) { +// GetHostWorkingDirectory Inspects Keploy docker container to get bind mount for current directory +func (idc *Impl) GetHostWorkingDirectory() (string, error) { ctx, cancel := context.WithTimeout(context.Background(), idc.timeoutForDockerQuery) defer cancel() curDir, err := os.Getwd() if err != nil { - idc.logger.Error("failed to get current working directory", zap.Error(err)) + utils.LogError(idc.logger, err, "failed to get current working directory") return "", err } container, err := idc.ContainerInspect(ctx, "keploy-v2") if err != nil { - idc.logger.Error("error inspecting keploy-v2 container", zap.Error(err)) + utils.LogError(idc.logger, err, "error inspecting keploy-v2 container") return "", err } containerMounts := container.Mounts @@ -364,34 +365,23 @@ func (idc *internalDockerClient) GetHostWorkingDirectory() (string, error) { return "", fmt.Errorf(fmt.Sprintf("could not find mount for %s in keploy-v2 container", curDir)) } -// ReplaceRelativePaths replaces relative paths in bind mounts with absolute paths -func (idc *internalDockerClient) ReplaceRelativePaths(dockerComposefilePath, newComposeFile string) error { - data, err := os.ReadFile(dockerComposefilePath) - if err != nil { - return err - } - - var compose Compose - err = yaml.Unmarshal(data, &compose) - if err != nil { - return err - } - +// ForceAbsolutePath replaces relative paths in bind mounts with absolute paths +func (idc *Impl) ForceAbsolutePath(c *Compose, basePath string) error { hostWorkingDirectory, err := idc.GetHostWorkingDirectory() if err != nil { return err } - dockerComposeContext, err := filepath.Abs(filepath.Join(hostWorkingDirectory, dockerComposefilePath)) + dockerComposeContext, err := filepath.Abs(filepath.Join(hostWorkingDirectory, basePath)) if err != nil { - idc.logger.Error("error getting absolute path for docker compose file", zap.Error(err)) + utils.LogError(idc.logger, err, "error getting absolute path for docker compose file") return err } dockerComposeContext = filepath.Dir(dockerComposeContext) idc.logger.Debug("docker compose file location in host filesystem", zap.Any("dockerComposeContext", dockerComposeContext)) // Loop through all services in compose file - for _, service := range compose.Services.Content { + for _, service := range c.Services.Content { for i, item := range service.Content { @@ -419,42 +409,19 @@ func (idc *internalDockerClient) ReplaceRelativePaths(dockerComposefilePath, new } } } - - newData, err := yaml.Marshal(&compose) - if err != nil { - return err - } - - newFilePath := filepath.Join(filepath.Dir(dockerComposefilePath), newComposeFile) - err = os.WriteFile(newFilePath, newData, 0644) - if err != nil { - return err - } - return nil } // MakeNetworkExternal makes the existing network of the user docker compose file external and save it to a new file -func (idc *internalDockerClient) MakeNetworkExternal(dockerComposefilePath, newComposeFile string) error { - data, err := os.ReadFile(dockerComposefilePath) - if err != nil { - return err - } - - var compose Compose - err = yaml.Unmarshal(data, &compose) - if err != nil { - return err - } - +func (idc *Impl) MakeNetworkExternal(c *Compose) error { // Iterate over all networks and check the 'external' flag. - if compose.Networks.Content != nil { - for i := 0; i < len(compose.Networks.Content); i += 2 { - if i+1 >= len(compose.Networks.Content) { + if c.Networks.Content != nil { + for i := 0; i < len(c.Networks.Content); i += 2 { + if i+1 >= len(c.Networks.Content) { break } // networkKeyNode := compose.Networks.Content[i] - networkValueNode := compose.Networks.Content[i+1] + networkValueNode := c.Networks.Content[i+1] // If it's a shorthand notation or null value, initialize it as an empty mapping node if (networkValueNode.Kind == yaml.ScalarNode && networkValueNode.Value == "") || networkValueNode.Tag == "!!null" { @@ -486,45 +453,25 @@ func (idc *internalDockerClient) MakeNetworkExternal(dockerComposefilePath, newC } } } - - newData, err := yaml.Marshal(&compose) - if err != nil { - return err - } - - newFilePath := filepath.Join(filepath.Dir(dockerComposefilePath), newComposeFile) - err = os.WriteFile(newFilePath, newData, 0644) - if err != nil { - return err - } - return nil } -// AddNetworkToCompose adds the keploy-network network to the new docker compose file and copy rest of the contents from +// SetKeployNetwork adds the keploy-network network to the new docker compose file and copy rest of the contents from // existing user docker compose file -func (idc *internalDockerClient) AddNetworkToCompose(dockerComposefilePath, newComposeFile string) error { - data, err := os.ReadFile(dockerComposefilePath) - if err != nil { - return err - } - - var compose Compose - err = yaml.Unmarshal(data, &compose) - if err != nil { - return err - } - +func (idc *Impl) SetKeployNetwork(c *Compose) (*NetworkInfo, error) { // Ensure that the top-level networks mapping exists. - if compose.Networks.Content == nil { - compose.Networks.Kind = yaml.MappingNode - compose.Networks.Content = make([]*yaml.Node, 0) + if c.Networks.Content == nil { + c.Networks.Kind = yaml.MappingNode + c.Networks.Content = make([]*yaml.Node, 0) + } + networkInfo := &NetworkInfo{ + Name: "keploy-network", + External: true, } - // Check if "keploy-network" already exists exists := false - for i := 0; i < len(compose.Networks.Content); i += 2 { - if compose.Networks.Content[i].Value == "keploy-network" { + for i := 0; i < len(c.Networks.Content); i += 2 { + if c.Networks.Content[i].Value == "keploy-network" { exists = true break } @@ -532,20 +479,17 @@ func (idc *internalDockerClient) AddNetworkToCompose(dockerComposefilePath, newC if !exists { // Add the keploy-network with external: true - compose.Networks.Content = append(compose.Networks.Content, + c.Networks.Content = append(c.Networks.Content, &yaml.Node{Kind: yaml.ScalarNode, Value: "keploy-network"}, - &yaml.Node{ - Kind: yaml.MappingNode, - Content: []*yaml.Node{ - {Kind: yaml.ScalarNode, Value: "external"}, - {Kind: yaml.ScalarNode, Value: "true"}, - }, - }, + &yaml.Node{Kind: yaml.MappingNode, Content: []*yaml.Node{ + {Kind: yaml.ScalarNode, Value: "external"}, + {Kind: yaml.ScalarNode, Value: "true"}, + }}, ) } // Add or modify network for each service - for _, service := range compose.Services.Content { + for _, service := range c.Services.Content { networksFound := false for _, item := range service.Content { if item.Value == "networks" { @@ -572,18 +516,5 @@ func (idc *internalDockerClient) AddNetworkToCompose(dockerComposefilePath, newC } } } - - newData, err := yaml.Marshal(&compose) - if err != nil { - return err - } - - newFilePath := filepath.Join(filepath.Dir(dockerComposefilePath), newComposeFile) - err = os.WriteFile(newFilePath, newData, 0644) - if err != nil { - return err - } - - idc.logger.Debug("successfully created kdocker-compose.yaml file") - return nil -} + return networkInfo, nil +} \ No newline at end of file From b2e5e03cf3f7c5ea131091eafaa06186b700de73 Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Thu, 4 Apr 2024 00:45:41 +0530 Subject: [PATCH 20/34] updated branch Signed-off-by: Yaxhveer --- pkg/core/app/app.go | 51 ++++++++++++++++++++++------------ pkg/core/app/docker/docker.go | 22 ++++++++++++++- pkg/core/app/docker/service.go | 2 ++ pkg/core/app/util.go | 14 ++++++++++ pkg/core/core.go | 2 +- pkg/service/replay/replay.go | 2 +- utils/docker.go | 2 +- utils/utils.go | 18 ++++++++---- 8 files changed, 87 insertions(+), 26 deletions(-) diff --git a/pkg/core/app/app.go b/pkg/core/app/app.go index d31ce0dcf..21ed147fd 100644 --- a/pkg/core/app/app.go +++ b/pkg/core/app/app.go @@ -66,8 +66,13 @@ func (a *App) Setup(_ context.Context) error { return err } a.docker = d + + if a.kind == utils.DockerStart && !isAttachMode(a.cmd) { + return fmt.Errorf("docker start require --attach/-a or --interactive/-i flag") + } + switch a.kind { - case utils.Docker: + case utils.DockerRun, utils.DockerStart: err := a.SetupDocker() if err != nil { return err @@ -93,21 +98,33 @@ func (a *App) ContainerIPv4Addr() string { func (a *App) SetupDocker() error { var err error - cont, net, err := parseDockerCmd(a.cmd) - if err != nil { - utils.LogError(a.logger, err, "failed to parse container name from given docker command", zap.String("cmd", a.cmd)) - return err - } - if a.container == "" { - a.container = cont - } else if a.container != cont { - a.logger.Warn(fmt.Sprintf("given app container:(%v) is different from parsed app container:(%v)", a.container, cont)) - } - if a.containerNetwork == "" { - a.containerNetwork = net - } else if a.containerNetwork != net { - a.logger.Warn(fmt.Sprintf("given docker network:(%v) is different from parsed docker network:(%v)", a.containerNetwork, net)) + if a.kind == utils.DockerRun { + cont, net, err := parseDockerCmd(a.cmd) + + if err != nil { + utils.LogError(a.logger, err, "failed to parse container name from given docker command", zap.String("cmd", a.cmd)) + return err + } + if a.container == "" { + a.container = cont + } else if a.container != cont { + a.logger.Warn(fmt.Sprintf("given app container:(%v) is different from parsed app container:(%v)", a.container, cont)) + } + + if a.containerNetwork == "" { + a.containerNetwork = net + } else if a.containerNetwork != net { + a.logger.Warn(fmt.Sprintf("given docker network:(%v) is different from parsed docker network:(%v)", a.containerNetwork, net)) + } + } else { + running, err := a.docker.IsContainerRunning(a.container) + if err != nil { + return err + } + if running { + return fmt.Errorf("docker container is already in running state.") + } } //injecting appNetwork to keploy. @@ -414,7 +431,7 @@ func (a *App) runDocker(ctx context.Context) models.AppError { func (a *App) Run(ctx context.Context, inodeChan chan uint64) models.AppError { a.inodeChan = inodeChan - if a.kind == utils.DockerCompose || a.kind == utils.Docker { + if a.kind == utils.DockerCompose || a.kind == utils.DockerRun || a.kind == utils.DockerStart { return a.runDocker(ctx) } return a.run(ctx) @@ -425,7 +442,7 @@ func (a *App) run(ctx context.Context) models.AppError { userCmd := a.cmd username := os.Getenv("SUDO_USER") - if utils.FindDockerCmd(a.cmd) == utils.Docker { + if utils.FindDockerCmd(a.cmd) == utils.DockerRun { userCmd = utils.EnsureRmBeforeName(userCmd) } diff --git a/pkg/core/app/docker/docker.go b/pkg/core/app/docker/docker.go index dee5da59d..d89f16aed 100755 --- a/pkg/core/app/docker/docker.go +++ b/pkg/core/app/docker/docker.go @@ -517,4 +517,24 @@ func (idc *Impl) SetKeployNetwork(c *Compose) (*NetworkInfo, error) { } } return networkInfo, nil -} \ No newline at end of file +} + +// IsContainerRunning check if the container is already running or not, required for docker start command. +func (idc *Impl) IsContainerRunning(containerName string) (bool, error) { + + ctx, cancel := context.WithTimeout(context.Background(), idc.timeoutForDockerQuery) + defer cancel() + + containerJSON, err := idc.ContainerInspect(ctx, containerName) + if err != nil { + if nativeDockerClient.IsErrNotFound(err) { + return false, nil + } + return false, fmt.Errorf("error retrieving container info: %v", err) + } + + if containerJSON.State.Running { + return true, nil + } + return false, nil +} diff --git a/pkg/core/app/docker/service.go b/pkg/core/app/docker/service.go index c61dc1b31..8306f0816 100644 --- a/pkg/core/app/docker/service.go +++ b/pkg/core/app/docker/service.go @@ -25,6 +25,8 @@ type Client interface { SetKeployNetwork(c *Compose) (*NetworkInfo, error) ReadComposeFile(filePath string) (*Compose, error) WriteComposeFile(compose *Compose, path string) error + + IsContainerRunning(containerName string) (bool, error) } type NetworkInfo struct { diff --git a/pkg/core/app/util.go b/pkg/core/app/util.go index 4b568fc1d..d354f4ee8 100644 --- a/pkg/core/app/util.go +++ b/pkg/core/app/util.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "regexp" + "slices" "strconv" "strings" "syscall" @@ -85,3 +86,16 @@ func getInode(pid int) (uint64, error) { } return i, nil } + +func isAttachMode(command string) bool { + args := strings.Fields(command) + flags := []string{"-a", "--attach", "-i", "--interactive"} + + for _, arg := range args { + if slices.Contains(flags, arg) { + return true + } + } + + return false +} \ No newline at end of file diff --git a/pkg/core/core.go b/pkg/core/core.go index 6294cbf87..fe9fa83df 100644 --- a/pkg/core/core.go +++ b/pkg/core/core.go @@ -80,7 +80,7 @@ func (c *Core) Hook(ctx context.Context, id uint64, opts models.HookOptions) err isDocker := false appKind := a.Kind(ctx) //check if the app is docker/docker-compose or native - if appKind == utils.Docker || appKind == utils.DockerCompose { + if appKind == utils.DockerRun || appKind == utils.DockerStart ||appKind == utils.DockerCompose { isDocker = true } diff --git a/pkg/service/replay/replay.go b/pkg/service/replay/replay.go index dee076e56..f84f53367 100644 --- a/pkg/service/replay/replay.go +++ b/pkg/service/replay/replay.go @@ -548,7 +548,7 @@ func (r *replayer) SimulateRequest(ctx context.Context, appID uint64, tc *models case models.HTTP: r.logger.Debug("Before simulating the request", zap.Any("Test case", tc)) cmdType := utils.FindDockerCmd(r.config.Command) - if cmdType == utils.Docker || cmdType == utils.DockerCompose { + if cmdType == utils.DockerRun || cmdType == utils.DockerStart || cmdType == utils.DockerCompose { var err error userIP, err := r.instrumentation.GetAppIP(ctx, appID) diff --git a/utils/docker.go b/utils/docker.go index 353b1416f..442bc7f4c 100644 --- a/utils/docker.go +++ b/utils/docker.go @@ -68,7 +68,7 @@ func StartInDocker(ctx context.Context, logger *zap.Logger, conf *config.Config) // If it does, then we would run the docker version of keploy and // pass the command and control to it. cmdType := FindDockerCmd(conf.Command) - if conf.InDocker || !(cmdType == Docker || cmdType == DockerCompose) { + if conf.InDocker || !(cmdType == DockerRun || cmdType == DockerStart || cmdType == DockerCompose) { return nil } // pass the all the commands and args to the docker version of Keploy diff --git a/utils/utils.go b/utils/utils.go index 86df8dc79..7bb8a2a55 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -352,7 +352,8 @@ func FindDockerCmd(cmd string) CmdType { cmdLower := strings.TrimSpace(strings.ToLower(cmd)) // Define patterns for Docker and Docker Compose - dockerPatterns := []string{"docker", "sudo docker"} + dockerRunPatterns := []string{"docker run", "sudo docker run"} + dockerStartPatterns := []string{"docker start", "sudo docker start"} dockerComposePatterns := []string{"docker-compose", "sudo docker-compose", "docker compose", "sudo docker compose"} // Check for Docker Compose command patterns and file extensions @@ -361,10 +362,16 @@ func FindDockerCmd(cmd string) CmdType { return DockerCompose } } - // Check for Docker command patterns - for _, pattern := range dockerPatterns { + // Check for Docker start command patterns + for _, pattern := range dockerStartPatterns { if strings.HasPrefix(cmdLower, pattern) { - return Docker + return DockerStart + } + } + // Check for Docker run command patterns + for _, pattern := range dockerRunPatterns { + if strings.HasPrefix(cmdLower, pattern) { + return DockerRun } } return Native @@ -374,7 +381,8 @@ type CmdType string // CmdType constants const ( - Docker CmdType = "docker" + DockerRun CmdType = "docker-run" + DockerStart CmdType = "docker-start" DockerCompose CmdType = "docker-compose" Native CmdType = "native" ) From 1213a7df26366b2245cbfa16c5fdeea0293188fb Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Thu, 4 Apr 2024 00:50:34 +0530 Subject: [PATCH 21/34] fixed linter issue Signed-off-by: Yaxhveer --- pkg/core/app/app.go | 2 +- pkg/core/app/docker/docker.go | 20 ++++++++++---------- pkg/core/app/util.go | 2 +- pkg/core/core.go | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pkg/core/app/app.go b/pkg/core/app/app.go index 21ed147fd..9da064e85 100644 --- a/pkg/core/app/app.go +++ b/pkg/core/app/app.go @@ -123,7 +123,7 @@ func (a *App) SetupDocker() error { return err } if running { - return fmt.Errorf("docker container is already in running state.") + return fmt.Errorf("docker container is already in running state") } } diff --git a/pkg/core/app/docker/docker.go b/pkg/core/app/docker/docker.go index d89f16aed..c444c5b9a 100755 --- a/pkg/core/app/docker/docker.go +++ b/pkg/core/app/docker/docker.go @@ -526,15 +526,15 @@ func (idc *Impl) IsContainerRunning(containerName string) (bool, error) { defer cancel() containerJSON, err := idc.ContainerInspect(ctx, containerName) - if err != nil { - if nativeDockerClient.IsErrNotFound(err) { - return false, nil - } - return false, fmt.Errorf("error retrieving container info: %v", err) - } - - if containerJSON.State.Running { - return true, nil - } + if err != nil { + if nativeDockerClient.IsErrNotFound(err) { + return false, nil + } + return false, fmt.Errorf("error retrieving container info: %v", err) + } + + if containerJSON.State.Running { + return true, nil + } return false, nil } diff --git a/pkg/core/app/util.go b/pkg/core/app/util.go index d354f4ee8..fab55eaf1 100644 --- a/pkg/core/app/util.go +++ b/pkg/core/app/util.go @@ -98,4 +98,4 @@ func isAttachMode(command string) bool { } return false -} \ No newline at end of file +} diff --git a/pkg/core/core.go b/pkg/core/core.go index fe9fa83df..caa263528 100644 --- a/pkg/core/core.go +++ b/pkg/core/core.go @@ -80,7 +80,7 @@ func (c *Core) Hook(ctx context.Context, id uint64, opts models.HookOptions) err isDocker := false appKind := a.Kind(ctx) //check if the app is docker/docker-compose or native - if appKind == utils.DockerRun || appKind == utils.DockerStart ||appKind == utils.DockerCompose { + if appKind == utils.DockerRun || appKind == utils.DockerStart || appKind == utils.DockerCompose { isDocker = true } From cae36dfd7e9b2b85c0ed02677621a95a57c86497 Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Fri, 5 Apr 2024 20:27:49 +0530 Subject: [PATCH 22/34] fixing linter issue Signed-off-by: Yaxhveer --- pkg/service/replay/replay.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/service/replay/replay.go b/pkg/service/replay/replay.go index 0d60f9814..e04bc7d13 100644 --- a/pkg/service/replay/replay.go +++ b/pkg/service/replay/replay.go @@ -575,7 +575,6 @@ func (r *Replayer) GetTestSetStatus(ctx context.Context, testRunID string, testS return status, nil } - func (r *Replayer) compareResp(tc *models.TestCase, actualResponse *models.HTTPResp, testSetID string) (bool, *models.Result) { noiseConfig := r.config.Test.GlobalNoise.Global From 02c575c6b75440a3771819c6a964a960bc4a6a31 Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Mon, 15 Apr 2024 18:23:42 +0530 Subject: [PATCH 23/34] Merge branch 'main' into docker-start-cmd Signed-off-by: Yaxhveer --- pkg/core/app/app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/core/app/app.go b/pkg/core/app/app.go index df71ab179..734fec7e3 100644 --- a/pkg/core/app/app.go +++ b/pkg/core/app/app.go @@ -69,7 +69,7 @@ func (a *App) Setup(_ context.Context) error { } a.docker = d - if (a.kind == utils.Docker || a.kind == utils.DockerCompose) && IsDetachMode(a.cmd) { + if (a.kind == utils.DockerRun || a.kind == utils.DockerCompose) && IsDetachMode(a.cmd) { return fmt.Errorf("detach mode is not allowed in Keploy command") } From 9c3f37a4a371186845ed138b3a994d6d8a8cc9a3 Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Mon, 15 Apr 2024 18:33:51 +0530 Subject: [PATCH 24/34] updated changes Signed-off-by: Yaxhveer --- pkg/core/app/app.go | 14 ++++++-------- pkg/core/app/util.go | 29 +++++++++++++++-------------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/pkg/core/app/app.go b/pkg/core/app/app.go index 734fec7e3..3c7cb5cfc 100644 --- a/pkg/core/app/app.go +++ b/pkg/core/app/app.go @@ -69,13 +69,11 @@ func (a *App) Setup(_ context.Context) error { } a.docker = d - if (a.kind == utils.DockerRun || a.kind == utils.DockerCompose) && IsDetachMode(a.cmd) { - return fmt.Errorf("detach mode is not allowed in Keploy command") - } - - - if a.kind == utils.DockerStart && !isAttachMode(a.cmd) { - return fmt.Errorf("docker start require --attach/-a or --interactive/-i flag") + if a.kind == utils.DockerStart || a.kind == utils.DockerRun || a.kind == utils.DockerCompose { + err = IsDetachMode(a.cmd, a.kind) + if err != nil { + return err + } } switch a.kind { @@ -124,7 +122,7 @@ func (a *App) SetupDocker() error { } else if a.containerNetwork != net { a.logger.Warn(fmt.Sprintf("given docker network:(%v) is different from parsed docker network:(%v)", a.containerNetwork, net)) } - } else { + } else if a.kind == utils.DockerStart { running, err := a.docker.IsContainerRunning(a.container) if err != nil { return err diff --git a/pkg/core/app/util.go b/pkg/core/app/util.go index 82c68bab3..a6a767f4f 100644 --- a/pkg/core/app/util.go +++ b/pkg/core/app/util.go @@ -9,6 +9,8 @@ import ( "strconv" "strings" "syscall" + + "go.keploy.io/server/v2/utils" ) func findComposeFile() string { @@ -87,26 +89,25 @@ func getInode(pid int) (uint64, error) { return i, nil } -func IsDetachMode(command string) bool { +func IsDetachMode(command string, kind utils.CmdType) error { args := strings.Fields(command) - for _, arg := range args { - if arg == "-d" || arg == "--detach" { - return true - } - } - return false -} + if kind == utils.DockerStart { + flags := []string{"-a", "--attach", "-i", "--interactive"} -func isAttachMode(command string) bool { - args := strings.Fields(command) - flags := []string{"-a", "--attach", "-i", "--interactive"} + for _, arg := range args { + if slices.Contains(flags, arg) { + return fmt.Errorf("docker start require --attach/-a or --interactive/-i flag") + } + } + return nil + } for _, arg := range args { - if slices.Contains(flags, arg) { - return true + if arg == "-d" || arg == "--detach" { + return fmt.Errorf("detach mode is not allowed in Keploy command") } } - return false + return nil } From cd2dc5dd04b43c31a3fb3f227981cfa6bf6dc07d Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Sat, 20 Apr 2024 22:47:04 +0530 Subject: [PATCH 25/34] refactored changes Signed-off-by: Yaxhveer --- pkg/core/app/app.go | 16 +++++++++------- pkg/core/app/docker/docker.go | 5 +---- pkg/core/app/util.go | 13 ++++++++----- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/pkg/core/app/app.go b/pkg/core/app/app.go index 3c7cb5cfc..fd7c1f781 100644 --- a/pkg/core/app/app.go +++ b/pkg/core/app/app.go @@ -69,11 +69,9 @@ func (a *App) Setup(_ context.Context) error { } a.docker = d - if a.kind == utils.DockerStart || a.kind == utils.DockerRun || a.kind == utils.DockerCompose { - err = IsDetachMode(a.cmd, a.kind) - if err != nil { - return err - } + if (a.kind == utils.DockerStart || a.kind == utils.DockerRun || a.kind == utils.DockerCompose) && isDetachMode(a.logger, a.cmd, a.kind) { + + return fmt.Errorf("application could not be started in detached mode") } switch a.kind { @@ -104,7 +102,8 @@ func (a *App) ContainerIPv4Addr() string { func (a *App) SetupDocker() error { var err error - if a.kind == utils.DockerRun { + switch a.kind { + case utils.DockerRun: cont, net, err := ParseDockerCmd(a.cmd) if err != nil { @@ -122,7 +121,10 @@ func (a *App) SetupDocker() error { } else if a.containerNetwork != net { a.logger.Warn(fmt.Sprintf("given docker network:(%v) is different from parsed docker network:(%v)", a.containerNetwork, net)) } - } else if a.kind == utils.DockerStart { + case utils.DockerStart: + if a.container == "" || a.containerNetwork == "" { + return fmt.Errorf("container name or network name is not being specified.") + } running, err := a.docker.IsContainerRunning(a.container) if err != nil { return err diff --git a/pkg/core/app/docker/docker.go b/pkg/core/app/docker/docker.go index 0160063c8..714a7bcec 100755 --- a/pkg/core/app/docker/docker.go +++ b/pkg/core/app/docker/docker.go @@ -527,10 +527,7 @@ func (idc *Impl) IsContainerRunning(containerName string) (bool, error) { containerJSON, err := idc.ContainerInspect(ctx, containerName) if err != nil { - if nativeDockerClient.IsErrNotFound(err) { - return false, nil - } - return false, fmt.Errorf("error retrieving container info: %v", err) + return false, err } if containerJSON.State.Running { diff --git a/pkg/core/app/util.go b/pkg/core/app/util.go index a6a767f4f..a679ce4c1 100644 --- a/pkg/core/app/util.go +++ b/pkg/core/app/util.go @@ -11,6 +11,7 @@ import ( "syscall" "go.keploy.io/server/v2/utils" + "go.uber.org/zap" ) func findComposeFile() string { @@ -89,7 +90,7 @@ func getInode(pid int) (uint64, error) { return i, nil } -func IsDetachMode(command string, kind utils.CmdType) error { +func isDetachMode(logger *zap.Logger, command string, kind utils.CmdType) bool { args := strings.Fields(command) if kind == utils.DockerStart { @@ -97,17 +98,19 @@ func IsDetachMode(command string, kind utils.CmdType) error { for _, arg := range args { if slices.Contains(flags, arg) { - return fmt.Errorf("docker start require --attach/-a or --interactive/-i flag") + return false } } - return nil + utils.LogError(logger, fmt.Errorf("docker start require --attach/-a or --interactive/-i flag"), "failed to start command") + return true } for _, arg := range args { if arg == "-d" || arg == "--detach" { - return fmt.Errorf("detach mode is not allowed in Keploy command") + utils.LogError(logger, fmt.Errorf("detach mode is not allowed in Keploy command"), "failed to start command") + return true } } - return nil + return false } From 0bc13845f75a6094c15269881dcc485bcd193398 Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Sat, 20 Apr 2024 22:54:22 +0530 Subject: [PATCH 26/34] fixed linter issue Signed-off-by: Yaxhveer --- pkg/core/app/app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/core/app/app.go b/pkg/core/app/app.go index fd7c1f781..03f927835 100644 --- a/pkg/core/app/app.go +++ b/pkg/core/app/app.go @@ -70,7 +70,7 @@ func (a *App) Setup(_ context.Context) error { a.docker = d if (a.kind == utils.DockerStart || a.kind == utils.DockerRun || a.kind == utils.DockerCompose) && isDetachMode(a.logger, a.cmd, a.kind) { - + return fmt.Errorf("application could not be started in detached mode") } From 4be8be6d7adce4006f9021cc76f8e2548986122e Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Sat, 20 Apr 2024 22:58:07 +0530 Subject: [PATCH 27/34] fixed linter issue Signed-off-by: Yaxhveer --- pkg/core/app/app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/core/app/app.go b/pkg/core/app/app.go index 03f927835..d60be400e 100644 --- a/pkg/core/app/app.go +++ b/pkg/core/app/app.go @@ -123,7 +123,7 @@ func (a *App) SetupDocker() error { } case utils.DockerStart: if a.container == "" || a.containerNetwork == "" { - return fmt.Errorf("container name or network name is not being specified.") + return fmt.Errorf("container name or network name is not being specified") } running, err := a.docker.IsContainerRunning(a.container) if err != nil { From bc07952019a4883dd81d10070112a112d44b5399 Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Sun, 21 Apr 2024 18:37:03 +0530 Subject: [PATCH 28/34] added parse command for docker start Signed-off-by: Yaxhveer --- pkg/core/app/app.go | 38 +++++++++++++++++--------------------- pkg/core/app/util.go | 23 +++++++++++++++++++++-- 2 files changed, 38 insertions(+), 23 deletions(-) diff --git a/pkg/core/app/app.go b/pkg/core/app/app.go index d60be400e..21d9b0592 100644 --- a/pkg/core/app/app.go +++ b/pkg/core/app/app.go @@ -102,29 +102,25 @@ func (a *App) ContainerIPv4Addr() string { func (a *App) SetupDocker() error { var err error - switch a.kind { - case utils.DockerRun: - cont, net, err := ParseDockerCmd(a.cmd) + cont, net, err := ParseDockerCmd(a.cmd, a.kind, a.docker) - if err != nil { - utils.LogError(a.logger, err, "failed to parse container name from given docker command", zap.String("cmd", a.cmd)) - return err - } - if a.container == "" { - a.container = cont - } else if a.container != cont { - a.logger.Warn(fmt.Sprintf("given app container:(%v) is different from parsed app container:(%v)", a.container, cont)) - } + if err != nil { + utils.LogError(a.logger, err, "failed to parse container name from given docker command", zap.String("cmd", a.cmd)) + return err + } + if a.container == "" { + a.container = cont + } else if a.container != cont { + a.logger.Warn(fmt.Sprintf("given app container:(%v) is different from parsed app container:(%v)", a.container, cont)) + } - if a.containerNetwork == "" { - a.containerNetwork = net - } else if a.containerNetwork != net { - a.logger.Warn(fmt.Sprintf("given docker network:(%v) is different from parsed docker network:(%v)", a.containerNetwork, net)) - } - case utils.DockerStart: - if a.container == "" || a.containerNetwork == "" { - return fmt.Errorf("container name or network name is not being specified") - } + if a.containerNetwork == "" { + a.containerNetwork = net + } else if a.containerNetwork != net { + a.logger.Warn(fmt.Sprintf("given docker network:(%v) is different from parsed docker network:(%v)", a.containerNetwork, net)) + } + + if a.kind == utils.DockerStart { running, err := a.docker.IsContainerRunning(a.container) if err != nil { return err diff --git a/pkg/core/app/util.go b/pkg/core/app/util.go index a679ce4c1..acc8d9eb0 100644 --- a/pkg/core/app/util.go +++ b/pkg/core/app/util.go @@ -10,6 +10,7 @@ import ( "strings" "syscall" + "go.keploy.io/server/v2/pkg/core/app/docker" "go.keploy.io/server/v2/utils" "go.uber.org/zap" ) @@ -51,9 +52,17 @@ func modifyDockerComposeCommand(appCmd, newComposeFile string) string { return fmt.Sprintf("%s -f %s", appCmd, newComposeFile) } -func ParseDockerCmd(cmd string) (string, string, error) { +func ParseDockerCmd(cmd string, kind utils.CmdType, idc docker.Client) (string, string, error) { + // Regular expression patterns - containerNamePattern := `--name\s+([^\s]+)` + var containerNamePattern string + switch kind { + case utils.DockerStart: + containerNamePattern = `start\s+(?:-[^\s]+\s+)*([^\s]*)` + default: + containerNamePattern = `--name\s+([^\s]+)` + } + networkNamePattern := `(--network|--net)\s+([^\s]+)` // Extract container name @@ -64,6 +73,16 @@ func ParseDockerCmd(cmd string) (string, string, error) { } containerName := containerNameMatches[1] + if kind == utils.DockerStart { + networks, err := idc.ExtractNetworksForContainer(containerName) + if err != nil { + return containerName, "", err + } + for i, _ := range networks { + return containerName, i, nil + } + } + // Extract network name networkNameRegex := regexp.MustCompile(networkNamePattern) networkNameMatches := networkNameRegex.FindStringSubmatch(cmd) From 7856a931a662f182a48bbf9d8272211b09bfb859 Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Sun, 21 Apr 2024 18:44:55 +0530 Subject: [PATCH 29/34] fixed linter issue Signed-off-by: Yaxhveer --- pkg/core/app/util.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/core/app/util.go b/pkg/core/app/util.go index acc8d9eb0..27cd64da7 100644 --- a/pkg/core/app/util.go +++ b/pkg/core/app/util.go @@ -78,7 +78,7 @@ func ParseDockerCmd(cmd string, kind utils.CmdType, idc docker.Client) (string, if err != nil { return containerName, "", err } - for i, _ := range networks { + for i := range networks { return containerName, i, nil } } From c6899ee149082d9732a3cac7a761c7d2d3e77e72 Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Tue, 21 May 2024 11:35:03 +0530 Subject: [PATCH 30/34] updated the changes Signed-off-by: Yaxhveer --- pkg/service/record/record.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/service/record/record.go b/pkg/service/record/record.go index 2dd247cc7..b95ceb3ae 100755 --- a/pkg/service/record/record.go +++ b/pkg/service/record/record.go @@ -349,7 +349,7 @@ func (r *Recorder) ReRecord(ctx context.Context, appID uint64) error { } cmdType := utils.FindDockerCmd(r.config.Command) - if cmdType == utils.Docker || cmdType == utils.DockerCompose { + if cmdType == utils.DockerRun || cmdType == utils.DockerStart || cmdType == utils.DockerCompose { host = r.config.ContainerName } @@ -360,7 +360,7 @@ func (r *Recorder) ReRecord(ctx context.Context, appID uint64) error { allTestCasesRecorded := true for _, tc := range tcs { - if cmdType == utils.Docker || cmdType == utils.DockerCompose { + if cmdType == utils.DockerRun || cmdType == utils.DockerStart || cmdType == utils.DockerCompose { userIP, err := r.instrumentation.GetContainerIP(ctx, appID) if err != nil { From fb2d240988d5c9c0881b061ef9c37238398ee243 Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Tue, 21 May 2024 11:59:26 +0530 Subject: [PATCH 31/34] added IsDockerKind function Signed-off-by: Yaxhveer --- pkg/core/app/app.go | 5 ++--- pkg/core/app/util.go | 1 + pkg/core/core.go | 2 +- pkg/service/record/record.go | 4 ++-- pkg/service/replay/replay.go | 4 ++-- utils/docker.go | 2 +- utils/utils.go | 4 ++++ 7 files changed, 13 insertions(+), 9 deletions(-) diff --git a/pkg/core/app/app.go b/pkg/core/app/app.go index 0e49adb8f..233d8bfe5 100644 --- a/pkg/core/app/app.go +++ b/pkg/core/app/app.go @@ -69,8 +69,7 @@ func (a *App) Setup(_ context.Context) error { } a.docker = d - if (a.kind == utils.DockerStart || a.kind == utils.DockerRun || a.kind == utils.DockerCompose) && isDetachMode(a.logger, a.cmd, a.kind) { - + if utils.IsDockerKind(a.kind) && isDetachMode(a.logger, a.cmd, a.kind) { return fmt.Errorf("application could not be started in detached mode") } @@ -433,7 +432,7 @@ func (a *App) runDocker(ctx context.Context) models.AppError { func (a *App) Run(ctx context.Context, inodeChan chan uint64) models.AppError { a.inodeChan = inodeChan - if a.kind == utils.DockerCompose || a.kind == utils.DockerRun || a.kind == utils.DockerStart { + if utils.IsDockerKind(a.kind) { return a.runDocker(ctx) } return a.run(ctx) diff --git a/pkg/core/app/util.go b/pkg/core/app/util.go index 27cd64da7..637283968 100644 --- a/pkg/core/app/util.go +++ b/pkg/core/app/util.go @@ -81,6 +81,7 @@ func ParseDockerCmd(cmd string, kind utils.CmdType, idc docker.Client) (string, for i := range networks { return containerName, i, nil } + return containerName, "", fmt.Errorf("failed to parse network name") } // Extract network name diff --git a/pkg/core/core.go b/pkg/core/core.go index 6bc2df590..6e6134e56 100644 --- a/pkg/core/core.go +++ b/pkg/core/core.go @@ -79,7 +79,7 @@ func (c *Core) Hook(ctx context.Context, id uint64, opts models.HookOptions) err isDocker := false appKind := a.Kind(ctx) //check if the app is docker/docker-compose or native - if appKind == utils.DockerRun || appKind == utils.DockerStart || appKind == utils.DockerCompose { + if utils.IsDockerKind(appKind) { isDocker = true } diff --git a/pkg/service/record/record.go b/pkg/service/record/record.go index b95ceb3ae..558660a35 100755 --- a/pkg/service/record/record.go +++ b/pkg/service/record/record.go @@ -349,7 +349,7 @@ func (r *Recorder) ReRecord(ctx context.Context, appID uint64) error { } cmdType := utils.FindDockerCmd(r.config.Command) - if cmdType == utils.DockerRun || cmdType == utils.DockerStart || cmdType == utils.DockerCompose { + if utils.IsDockerKind(cmdType) { host = r.config.ContainerName } @@ -360,7 +360,7 @@ func (r *Recorder) ReRecord(ctx context.Context, appID uint64) error { allTestCasesRecorded := true for _, tc := range tcs { - if cmdType == utils.DockerRun || cmdType == utils.DockerStart || cmdType == utils.DockerCompose { + if utils.IsDockerKind(cmdType) { userIP, err := r.instrumentation.GetContainerIP(ctx, appID) if err != nil { diff --git a/pkg/service/replay/replay.go b/pkg/service/replay/replay.go index 165468868..9c6fb12a7 100644 --- a/pkg/service/replay/replay.go +++ b/pkg/service/replay/replay.go @@ -339,7 +339,7 @@ func (r *Replayer) RunTestSet(ctx context.Context, testSetID string, testRunID s cmdType := utils.FindDockerCmd(r.config.Command) var userIP string - if cmdType == utils.DockerRun || cmdType == utils.DockerStart || cmdType == utils.DockerCompose { + if utils.IsDockerKind(cmdType) { userIP, err = r.instrumentation.GetContainerIP(ctx, appID) if err != nil { return models.TestSetStatusFailed, err @@ -413,7 +413,7 @@ func (r *Replayer) RunTestSet(ctx context.Context, testSetID string, testRunID s started := time.Now().UTC() - if cmdType == utils.DockerRun || cmdType == utils.DockerStart || cmdType == utils.DockerCompose { + if utils.IsDockerKind(cmdType) { testCase.HTTPReq.URL, err = utils.ReplaceHostToIP(testCase.HTTPReq.URL, userIP) if err != nil { diff --git a/utils/docker.go b/utils/docker.go index 442bc7f4c..a04a02734 100644 --- a/utils/docker.go +++ b/utils/docker.go @@ -68,7 +68,7 @@ func StartInDocker(ctx context.Context, logger *zap.Logger, conf *config.Config) // If it does, then we would run the docker version of keploy and // pass the command and control to it. cmdType := FindDockerCmd(conf.Command) - if conf.InDocker || !(cmdType == DockerRun || cmdType == DockerStart || cmdType == DockerCompose) { + if conf.InDocker || !(IsDockerKind(cmdType)) { return nil } // pass the all the commands and args to the docker version of Keploy diff --git a/utils/utils.go b/utils/utils.go index 1ac3ecc6d..a30a32b01 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -720,3 +720,7 @@ func EnsureRmBeforeName(cmd string) string { return strings.Join(parts, " ") } + +func IsDockerKind(kind CmdType) bool { + return (kind == DockerRun || kind == DockerStart || kind == DockerCompose) +} From 7c37c68aa177d0b478e71229a042a42b6752a8e6 Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Tue, 21 May 2024 12:10:22 +0530 Subject: [PATCH 32/34] updated commandtype Signed-off-by: Yaxhveer --- pkg/service/replay/replay.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/service/replay/replay.go b/pkg/service/replay/replay.go index 9c6fb12a7..0531ea9ac 100644 --- a/pkg/service/replay/replay.go +++ b/pkg/service/replay/replay.go @@ -337,7 +337,7 @@ func (r *Replayer) RunTestSet(ctx context.Context, testSetID string, testRunID s return models.TestSetStatusUserAbort, context.Canceled } - cmdType := utils.FindDockerCmd(r.config.Command) + cmdType := utils.CmdType(r.config.CommandType) var userIP string if utils.IsDockerKind(cmdType) { userIP, err = r.instrumentation.GetContainerIP(ctx, appID) From 98d4c430045fe0a02d9d9dee5412ec89e81ec12d Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Tue, 21 May 2024 12:38:28 +0530 Subject: [PATCH 33/34] updated commandtype Signed-off-by: Yaxhveer --- pkg/service/record/record.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/service/record/record.go b/pkg/service/record/record.go index 558660a35..1154bbeb1 100755 --- a/pkg/service/record/record.go +++ b/pkg/service/record/record.go @@ -348,7 +348,7 @@ func (r *Recorder) ReRecord(ctx context.Context, appID uint64) error { return nil } - cmdType := utils.FindDockerCmd(r.config.Command) + cmdType := utils.CmdType(r.config.CommandType) if utils.IsDockerKind(cmdType) { host = r.config.ContainerName } From 358cefa8cd03768a6d446e3913947527cae1bd10 Mon Sep 17 00:00:00 2001 From: Yaxhveer Date: Tue, 21 May 2024 14:36:57 +0530 Subject: [PATCH 34/34] corrected parse container Signed-off-by: Yaxhveer --- pkg/core/app/app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/core/app/app.go b/pkg/core/app/app.go index 233d8bfe5..60ccfb9fc 100644 --- a/pkg/core/app/app.go +++ b/pkg/core/app/app.go @@ -120,7 +120,7 @@ func (a *App) SetupDocker() error { } if a.kind == utils.DockerStart { - running, err := a.docker.IsContainerRunning(a.container) + running, err := a.docker.IsContainerRunning(cont) if err != nil { return err }