func (i *Inspector) FinishMonitoring() { cmdResponse, err := ipc.SendContainerCmd(&messages.StopMonitor{}) utils.WarnOn(err) _ = cmdResponse log.Debugf("'stop' response => '%v'\n", cmdResponse) log.Info("docker-slim: waiting for the container finish its work...") //for now there's only one event ("done") //getEvt() should timeout in two minutes (todo: pick a good timeout) evt, err := ipc.GetContainerEvt() utils.WarnOn(err) _ = evt log.Debugf("docker-slim: sensor event => '%v'\n", evt) }
func (i *Inspector) ShutdownContainer() error { i.shutdownContainerChannels() if i.ShowContainerLogs { var outData bytes.Buffer outw := bufio.NewWriter(&outData) var errData bytes.Buffer errw := bufio.NewWriter(&errData) log.Debug("docker-slim: getting container logs => ", i.ContainerID) logsOptions := dockerapi.LogsOptions{ Container: i.ContainerID, OutputStream: outw, ErrorStream: errw, Stdout: true, Stderr: true, } err := i.ApiClient.Logs(logsOptions) if err != nil { log.Infof("docker-slim: error getting container logs => %v - %v\n", i.ContainerID, err) } else { outw.Flush() errw.Flush() fmt.Println("docker-slim: container stdout:") outData.WriteTo(os.Stdout) fmt.Println("docker-slim: container stderr:") errData.WriteTo(os.Stdout) } } err := i.ApiClient.StopContainer(i.ContainerID, 9) utils.WarnOn(err) removeOption := dockerapi.RemoveContainerOptions{ ID: i.ContainerID, RemoveVolumes: true, Force: true, } err = i.ApiClient.RemoveContainer(removeOption) return nil }
func OnProfile(doDebug bool, statePath string, clientConfig *config.DockerClient, imageRef string, doHttpProbe bool, httpProbeCmds []config.HttpProbeCmd, doShowContainerLogs bool, overrides *config.ContainerOverrides, volumeMounts map[string]config.VolumeMount, excludePaths map[string]bool, includePaths map[string]bool, continueAfter *config.ContinueAfter) { fmt.Printf("docker-slim: [profile] image=%v\n", imageRef) doRmFileArtifacts := false client := dockerclient.New(clientConfig) imageInspector, err := image.NewInspector(client, imageRef) utils.FailOn(err) log.Info("docker-slim: inspecting 'fat' image metadata...") err = imageInspector.Inspect() utils.FailOn(err) localVolumePath, artifactLocation := utils.PrepareSlimDirs(statePath, imageInspector.ImageInfo.ID) imageInspector.ArtifactLocation = artifactLocation log.Infof("docker-slim: [%v] 'fat' image size => %v (%v)\n", imageInspector.ImageInfo.ID, imageInspector.ImageInfo.VirtualSize, humanize.Bytes(uint64(imageInspector.ImageInfo.VirtualSize))) log.Info("docker-slim: processing 'fat' image info...") err = imageInspector.ProcessCollectedData() utils.FailOn(err) containerInspector, err := container.NewInspector(client, imageInspector, localVolumePath, overrides, doShowContainerLogs, volumeMounts, excludePaths, includePaths, doDebug) utils.FailOn(err) log.Info("docker-slim: starting instrumented 'fat' container...") err = containerInspector.RunContainer() utils.FailOn(err) log.Info("docker-slim: watching container monitor...") if "probe" == continueAfter.Mode { doHttpProbe = true } if doHttpProbe { probe, err := http.NewCustomProbe(containerInspector, httpProbeCmds) utils.FailOn(err) probe.Start() continueAfter.ContinueChan = probe.DoneChan() } switch continueAfter.Mode { case "enter": fmt.Println("docker-slim: press <enter> when you are done using the container...") creader := bufio.NewReader(os.Stdin) _, _, _ = creader.ReadLine() case "signal": fmt.Println("docker-slim: send SIGUSR1 when you are done using the container...") <-continueAfter.ContinueChan fmt.Println("docker-slim: got SIGUSR1...") case "timeout": fmt.Printf("docker-slim: waiting for the target container (%v seconds)...\n", int(continueAfter.Timeout)) <-time.After(time.Second * continueAfter.Timeout) fmt.Printf("docker-slim: done waiting for the target container...") case "probe": fmt.Println("docker-slim: waiting for the HTTP probe to finish...") <-continueAfter.ContinueChan fmt.Println("docker-slim: HTTP probe is done...") default: utils.Fail("unknown continue-after mode") } containerInspector.FinishMonitoring() log.Info("docker-slim: shutting down 'fat' container...") err = containerInspector.ShutdownContainer() utils.WarnOn(err) log.Info("docker-slim: processing instrumented 'fat' container info...") err = containerInspector.ProcessCollectedData() utils.FailOn(err) if doRmFileArtifacts { log.Info("docker-slim: removing temporary artifacts...") err = utils.RemoveArtifacts(artifactLocation) //TODO: remove only the "files" subdirectory utils.WarnOn(err) } fmt.Println("docker-slim: [profile] done.") }
func New(config *config.DockerClient) *docker.Client { var client *docker.Client var err error newTLSClient := func(host string, certPath string, verify bool) (*docker.Client, error) { var ca []byte cert, err := ioutil.ReadFile(filepath.Join(certPath, "cert.pem")) if err != nil { return nil, err } key, err := ioutil.ReadFile(filepath.Join(certPath, "key.pem")) if err != nil { return nil, err } if verify { var err error ca, err = ioutil.ReadFile(filepath.Join(certPath, "ca.pem")) if err != nil { return nil, err } } return docker.NewVersionedTLSClientFromBytes(host, cert, key, ca, "") } switch { case config.Host != "" && config.UseTLS && config.VerifyTLS && config.TLSCertPath != "": client, err = newTLSClient(config.Host, config.TLSCertPath, true) utils.FailOn(err) log.Debug("docker-slim: new Docker client (TLS,verify) [1]") case config.Host != "" && config.UseTLS && !config.VerifyTLS && config.TLSCertPath != "": client, err = newTLSClient(config.Host, config.TLSCertPath, false) utils.FailOn(err) log.Debug("docker-slim: new Docker client (TLS,no verify) [2]") case config.Host != "" && !config.UseTLS: client, err = docker.NewClient(config.Host) utils.FailOn(err) log.Debug("docker-slim: new Docker client [3]") case config.Host == "" && !config.VerifyTLS && config.Env["DOCKER_TLS_VERIFY"] == "1" && config.Env["DOCKER_CERT_PATH"] != "" && config.Env["DOCKER_HOST"] != "": client, err = newTLSClient(config.Env["DOCKER_HOST"], config.Env["DOCKER_CERT_PATH"], false) utils.FailOn(err) log.Debug("docker-slim: new Docker client (TLS,no verify) [4]") case config.Env["DOCKER_HOST"] != "": client, err = docker.NewClientFromEnv() utils.FailOn(err) log.Debug("docker-slim: new Docker client (env) [5]") case config.Host == "" && config.Env["DOCKER_HOST"] == "": config.Host = "unix:///var/run/docker.sock" client, err = docker.NewClient(config.Host) utils.FailOn(err) log.Debug("docker-slim: new Docker client (default) [6]") default: utils.Fail("no config for Docker client") } if config.Env["DOCKER_HOST"] == "" { if err := os.Setenv("DOCKER_HOST", config.Host); err != nil { utils.WarnOn(err) } log.Debug("docker-slim: configured DOCKER_HOST env var") } return client }
func main() { flag.Parse() if enableDebug { log.SetLevel(log.DebugLevel) } log.Infof("sensor: args => %#v\n", os.Args) dirName, err := os.Getwd() utils.WarnOn(err) log.Debugf("sensor: cwd => %#v\n", dirName) initSignalHandlers() defer func() { log.Debug("defered cleanup on shutdown...") cleanupOnShutdown() }() log.Debug("sensor: setting up channels...") doneChan = make(chan struct{}) err = ipc.InitChannels() utils.FailOn(err) cmdChan, err := ipc.RunCmdServer(doneChan) utils.FailOn(err) monDoneChan := make(chan bool, 1) monDoneAckChan := make(chan bool) pidsChan := make(chan []int, 1) ptmonStartChan := make(chan int, 1) log.Info("sensor: waiting for commands...") doneRunning: for { select { case cmd := <-cmdChan: log.Debug("\nsensor: command => ", cmd) switch data := cmd.(type) { case *messages.StartMonitor: if data == nil { log.Info("sensor: 'start' command - no data...") break } log.Debugf("sensor: 'start' command (%#v) - starting monitor...\n", data) monitor(monDoneChan, monDoneAckChan, pidsChan, ptmonStartChan, data, dirName) //target app started by ptmon... (long story :-)) //TODO: need to get the target app pid to pemon, so it can filter process events log.Debugf("sensor: target app started => %v %#v\n", data.AppName, data.AppArgs) time.Sleep(3 * time.Second) case *messages.StopMonitor: log.Debug("sensor: 'stop' command - stopping monitor...") break doneRunning default: log.Debug("sensor: ignoring unknown command => ", cmd) } case <-time.After(time.Second * 5): log.Debug(".") } } monDoneChan <- true log.Info("sensor: waiting for monitor to finish...") <-monDoneAckChan ipc.TryPublishEvt(3, "monitor.finish.completed") log.Info("sensor: done!") }