<commit_before>package userdocker

import (
	"io"
	"io/ioutil"
	"os"
	"os/signal"
	"strconv"
	"syscall"
	"time"

	"golang.org/x/net/context"

	"path/filepath"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/engine-api/types"
	composeClient "github.com/docker/libcompose/docker/client"
	"github.com/docker/libcompose/project"
	"github.com/rancher/os/cmd/control"
	"github.com/rancher/os/compose"
	"github.com/rancher/os/config"
	rosDocker "github.com/rancher/os/docker"
	"github.com/rancher/os/util"
)

const (
	DEFAULT_STORAGE_CONTEXT = "console"
	DOCKER_PID_FILE         = "/var/run/docker.pid"
	DOCKER_COMMAND          = "docker-init"
	userDocker              = "user-docker"
)

func Main() {
	cfg := config.LoadConfig()

	execID, resp, err := startDocker(cfg)
	if err != nil {
		log.Fatal(err)
	}

	process, err := getDockerProcess()
	if err != nil {
		log.Fatal(err)
	}

	handleTerm(process)

	// Wait for Docker daemon to exit
	io.Copy(ioutil.Discard, resp.Reader)
	resp.Close()

	client, err := rosDocker.NewSystemClient()
	if err != nil {
		log.Fatal(err)
	}

	state, err := client.ContainerExecInspect(context.Background(), execID)
	if err != nil {
		log.Fatal(err)
	}

	// Proxy exit code
	os.Exit(state.ExitCode)
}

func writeCerts(cfg *config.CloudConfig) error {
	outDir := control.ServerTlsPath
	if err := os.MkdirAll(outDir, 0700); err != nil {
		return err
	}
	caCertPath := filepath.Join(outDir, control.CaCert)
	caKeyPath := filepath.Join(outDir, control.CaKey)
	serverCertPath := filepath.Join(outDir, control.ServerCert)
	serverKeyPath := filepath.Join(outDir, control.ServerKey)
	if cfg.Rancher.Docker.CACert != "" {
		if err := util.WriteFileAtomic(caCertPath, []byte(cfg.Rancher.Docker.CACert), 0400); err != nil {
			return err
		}

		if err := util.WriteFileAtomic(caKeyPath, []byte(cfg.Rancher.Docker.CAKey), 0400); err != nil {
			return err
		}
	}
	if cfg.Rancher.Docker.ServerCert != "" {
		if err := util.WriteFileAtomic(serverCertPath, []byte(cfg.Rancher.Docker.ServerCert), 0400); err != nil {
			return err
		}

		if err := util.WriteFileAtomic(serverKeyPath, []byte(cfg.Rancher.Docker.ServerKey), 0400); err != nil {
			return err
		}
	}
	return nil
}

func startDocker(cfg *config.CloudConfig) (string, types.HijackedResponse, error) {
	storageContext := cfg.Rancher.Docker.StorageContext
	if storageContext == "" {
		storageContext = DEFAULT_STORAGE_CONTEXT
	}

	log.Infof("Starting Docker in context: %s", storageContext)

	p, err := compose.GetProject(cfg, true, false)
	if err != nil {
		return "", types.HijackedResponse{}, err
	}

	pid, err := waitForPid(storageContext, p)
	if err != nil {
		return "", types.HijackedResponse{}, err
	}

	log.Infof("%s PID %d", storageContext, pid)

	client, err := rosDocker.NewSystemClient()
	if err != nil {
		return "", types.HijackedResponse{}, err
	}

	if err := os.Remove(DOCKER_PID_FILE); err != nil && !os.IsNotExist(err) {
		return "", types.HijackedResponse{}, err
	}

	dockerCfg := cfg.Rancher.Docker

	args := dockerCfg.FullArgs()

	log.Debugf("User Docker args: %v", args)

	if dockerCfg.TLS {
		if err := writeCerts(cfg); err != nil {
			return "", types.HijackedResponse{}, err
		}
	}

	cmd := []string{"env"}
	log.Info(dockerCfg.AppendEnv())
	cmd = append(cmd, dockerCfg.AppendEnv()...)
	cmd = append(cmd, DOCKER_COMMAND)
	cmd = append(cmd, args...)
	log.Infof("Running %v", cmd)

	resp, err := client.ContainerExecCreate(context.Background(), types.ExecConfig{
		Container:    storageContext,
		Privileged:   true,
		AttachStderr: true,
		AttachStdout: true,
		Cmd:          cmd,
	})
	if err != nil {
		return "", types.HijackedResponse{}, err
	}

	attachResp, err := client.ContainerExecAttach(context.Background(), resp.ID, types.ExecConfig{
		Detach:       false,
		AttachStderr: true,
		AttachStdout: true,
	})
	if err != nil {
		return "", types.HijackedResponse{}, err
	}

	if err := client.ContainerExecStart(context.Background(), resp.ID, types.ExecStartCheck{
		Detach: false,
	}); err != nil {
		return "", types.HijackedResponse{}, err
	}

	return resp.ID, attachResp, nil
}

func getDockerProcess() (*os.Process, error) {
	pidBytes, err := waitForFile(DOCKER_PID_FILE)
	if err != nil {
		return nil, err
	}
	dockerPid, err := strconv.Atoi(string(pidBytes))
	if err != nil {
		return nil, err
	}
	return os.FindProcess(dockerPid)
}

func handleTerm(process *os.Process) {
	term := make(chan os.Signal)
	signal.Notify(term, syscall.SIGTERM)<commit_msg>Remove second exec start in User Docker<commit_after>package userdocker

import (
	"io"
	"io/ioutil"
	"os"
	"os/signal"
	"strconv"
	"syscall"
	"time"

	"golang.org/x/net/context"

	"path/filepath"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/engine-api/types"
	composeClient "github.com/docker/libcompose/docker/client"
	"github.com/docker/libcompose/project"
	"github.com/rancher/os/cmd/control"
	"github.com/rancher/os/compose"
	"github.com/rancher/os/config"
	rosDocker "github.com/rancher/os/docker"
	"github.com/rancher/os/util"
)

const (
	DEFAULT_STORAGE_CONTEXT = "console"
	DOCKER_PID_FILE         = "/var/run/docker.pid"
	DOCKER_COMMAND          = "docker-init"
	userDocker              = "user-docker"
)

func Main() {
	cfg := config.LoadConfig()

	execID, resp, err := startDocker(cfg)
	if err != nil {
		log.Fatal(err)
	}

	process, err := getDockerProcess()
	if err != nil {
		log.Fatal(err)
	}

	handleTerm(process)

	// Wait for Docker daemon to exit
	io.Copy(ioutil.Discard, resp.Reader)
	resp.Close()

	client, err := rosDocker.NewSystemClient()
	if err != nil {
		log.Fatal(err)
	}

	state, err := client.ContainerExecInspect(context.Background(), execID)
	if err != nil {
		log.Fatal(err)
	}

	// Proxy exit code
	os.Exit(state.ExitCode)
}

func writeCerts(cfg *config.CloudConfig) error {
	outDir := control.ServerTlsPath
	if err := os.MkdirAll(outDir, 0700); err != nil {
		return err
	}
	caCertPath := filepath.Join(outDir, control.CaCert)
	caKeyPath := filepath.Join(outDir, control.CaKey)
	serverCertPath := filepath.Join(outDir, control.ServerCert)
	serverKeyPath := filepath.Join(outDir, control.ServerKey)
	if cfg.Rancher.Docker.CACert != "" {
		if err := util.WriteFileAtomic(caCertPath, []byte(cfg.Rancher.Docker.CACert), 0400); err != nil {
			return err
		}

		if err := util.WriteFileAtomic(caKeyPath, []byte(cfg.Rancher.Docker.CAKey), 0400); err != nil {
			return err
		}
	}
	if cfg.Rancher.Docker.ServerCert != "" {
		if err := util.WriteFileAtomic(serverCertPath, []byte(cfg.Rancher.Docker.ServerCert), 0400); err != nil {
			return err
		}

		if err := util.WriteFileAtomic(serverKeyPath, []byte(cfg.Rancher.Docker.ServerKey), 0400); err != nil {
			return err
		}
	}
	return nil
}

func startDocker(cfg *config.CloudConfig) (string, types.HijackedResponse, error) {
	storageContext := cfg.Rancher.Docker.StorageContext
	if storageContext == "" {
		storageContext = DEFAULT_STORAGE_CONTEXT
	}

	log.Infof("Starting Docker in context: %s", storageContext)

	p, err := compose.GetProject(cfg, true, false)
	if err != nil {
		return "", types.HijackedResponse{}, err
	}

	pid, err := waitForPid(storageContext, p)
	if err != nil {
		return "", types.HijackedResponse{}, err
	}

	log.Infof("%s PID %d", storageContext, pid)

	client, err := rosDocker.NewSystemClient()
	if err != nil {
		return "", types.HijackedResponse{}, err
	}

	if err := os.Remove(DOCKER_PID_FILE); err != nil && !os.IsNotExist(err) {
		return "", types.HijackedResponse{}, err
	}

	dockerCfg := cfg.Rancher.Docker

	args := dockerCfg.FullArgs()

	log.Debugf("User Docker args: %v", args)

	if dockerCfg.TLS {
		if err := writeCerts(cfg); err != nil {
			return "", types.HijackedResponse{}, err
		}
	}

	cmd := []string{"env"}
	log.Info(dockerCfg.AppendEnv())
	cmd = append(cmd, dockerCfg.AppendEnv()...)
	cmd = append(cmd, DOCKER_COMMAND)
	cmd = append(cmd, args...)
	log.Infof("Running %v", cmd)

	resp, err := client.ContainerExecCreate(context.Background(), types.ExecConfig{
		Container:    storageContext,
		Privileged:   true,
		AttachStderr: true,
		AttachStdout: true,
		Cmd:          cmd,
	})
	if err != nil {
		return "", types.HijackedResponse{}, err
	}

	attachResp, err := client.ContainerExecAttach(context.Background(), resp.ID, types.ExecConfig{
		Detach:       false,
		AttachStderr: true,
		AttachStdout: true,
	})
	if err != nil {
		return "", types.HijackedResponse{}, err
	}

	return resp.ID, attachResp, nil
}

func getDockerProcess() (*os.Process, error) {
	pidBytes, err := waitForFile(DOCKER_PID_FILE)
	if err != nil {
		return nil, err
	}
	dockerPid, err := strconv.Atoi(string(pidBytes))
	if err != nil {
		return nil, err
	}
	return os.FindProcess(dockerPid)
}

func handleTerm(process *os.Process) {
	term := make(chan os.Signal)
	signal.Notify(term, syscall.SIGTERM)
{'fraction_non_alphanumeric': 0.14995442114858706, 'fraction_numerical': 0.004557885141294439, 'mean_word_length': 4.009703196347032, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1320330', 'n_tokens_mistral': 3493, 'n_tokens_neox': 3251, 'n_words': 653}