Beispiel #1
0
func (p *process) startContainer(wr io.Writer) error {
	var startBarier = make(chan struct{})
	go p.collectOutput(startBarier, wr)
	if err := p.client.ContainerStart(p.ctx, p.containerID, ""); err != nil {
		p.cancellation()
		return err
	}
	isolate.NotifyAboutStart(wr)
	close(startBarier)
	return nil
}
Beispiel #2
0
// Spawn spawns a new process
func (b *Box) Spawn(ctx context.Context, config isolate.SpawnConfig, output io.Writer) (proc isolate.Process, err error) {
	spoolPath := b.spoolPath
	if val, ok := config.Opts["spool"]; ok {
		spoolPath = fmt.Sprintf("%s", val)
	}
	workDir := filepath.Join(spoolPath, config.Name)

	var execPath = config.Executable
	if !filepath.IsAbs(config.Executable) {
		execPath = filepath.Join(workDir, config.Executable)
	}

	packedEnv := make([]string, 0, len(config.Env))
	for k, v := range config.Env {
		packedEnv = append(packedEnv, k+"="+v)
	}

	packedArgs := make([]string, 1, len(config.Args)*2+1)
	packedArgs[0] = filepath.Base(config.Executable)
	for k, v := range config.Args {
		packedArgs = append(packedArgs, k, v)
	}

	defer apexctx.GetLogger(ctx).WithFields(
		log.Fields{"name": config.Name, "executable": config.Executable,
			"workDir": workDir, "execPath": execPath}).Trace("processBox.Spawn").Stop(&err)

	// Update statistics
	start := time.Now()
	spawningQueueSize.Inc(1)
	if spawningQueueSize.Count() > 10 {
		spawningQueueSize.Dec(1)
		return nil, syscall.EAGAIN
	}
	err = b.spawnSm.Acquire(ctx)
	spawningQueueSize.Dec(1)
	if err != nil {
		return nil, isolate.ErrSpawningCancelled
	}
	defer b.spawnSm.Release()
	// NOTE: once process was put to the map
	// its waiter responsibility to Wait for it.

	// NOTE: No defer here
	b.mu.Lock()
	if isolate.IsCancelled(ctx) {
		b.mu.Unlock()
		return nil, isolate.ErrSpawningCancelled
	}

	newProcStart := time.Now()
	pr, err := newProcess(ctx, execPath, packedArgs, packedEnv, workDir, output)
	newProcStarted := time.Now()
	// Update has lock, so move it out from Hot spot
	defer procsNewTimer.Update(newProcStarted.Sub(newProcStart))
	if err != nil {
		b.mu.Unlock()
		procsErroredCounter.Inc(1)
		return nil, err
	}
	b.children[pr.cmd.Process.Pid] = pr.cmd
	b.mu.Unlock()

	totalSpawnTimer.UpdateSince(start)
	isolate.NotifyAboutStart(output)
	procsCreatedCounter.Inc(1)
	return pr, err
}
Beispiel #3
0
// Spawn spawns new Porto container
func (b *Box) Spawn(ctx context.Context, config isolate.SpawnConfig, output io.Writer) (isolate.Process, error) {
	profile := portoProfile{
		Profile: config.Opts,
	}
	start := time.Now()

	spawningQueueSize.Inc(1)
	if spawningQueueSize.Count() > 10 {
		spawningQueueSize.Dec(1)
		return nil, syscall.EAGAIN
	}

	ei := execInfo{
		portoProfile: profile,
		name:         config.Name,
		executable:   config.Executable,
		ulimits:      b.config.DefaultUlimits,
		args:         config.Args,
		env:          config.Env,
	}

	ID := b.appGenLabel(config.Name) + "_" + uuid.New()
	cfg := containerConfig{
		Root:           filepath.Join(b.config.Containers, ID),
		ID:             b.addRootNamespacePrefix(ID),
		Layer:          b.appLayerName(config.Name),
		CleanupEnabled: b.config.CleanupEnabled,
		SetImgURI:      b.config.SetImgURI,
		VolumeBackend:  b.config.VolumeBackend,
	}

	portoConn, err := portoConnect()
	if err != nil {
		return nil, err
	}
	defer portoConn.Close()

	err = b.spawnSM.Acquire(ctx)
	spawningQueueSize.Dec(1)
	if err != nil {
		return nil, isolate.ErrSpawningCancelled
	}
	defer b.spawnSM.Release()

	apexctx.GetLogger(ctx).WithFields(log.Fields{"name": config.Name, "layer": cfg.Layer, "root": cfg.Root, "id": cfg.ID}).Info("Create container")

	containersCreatedCounter.Inc(1)
	pr, err := newContainer(ctx, portoConn, cfg, ei)
	if err != nil {
		containersErroredCounter.Inc(1)
		return nil, err
	}

	b.muContainers.Lock()
	b.containers[pr.containerID] = pr
	b.muContainers.Unlock()

	if err = pr.start(portoConn, output); err != nil {
		containersErroredCounter.Inc(1)
		pr.Cleanup(portoConn)
		return nil, err
	}
	isolate.NotifyAboutStart(output)
	totalSpawnTimer.UpdateSince(start)
	return pr, nil
}