func()

in machine.go [492:584]


func (m *Machine) startVMM(ctx context.Context) error {
	m.logger.Printf("Called startVMM(), setting up a VMM on %s", m.Cfg.SocketPath)
	startCmd := m.cmd.Start

	m.logger.Debugf("Starting %v", m.cmd.Args)

	var err error
	if m.Cfg.NetNS != "" && m.Cfg.JailerCfg == nil {
		// If the VM needs to be started in a netns but no jailer netns was configured,
		// start the vmm child process in the netns directly here.
		err = ns.WithNetNSPath(m.Cfg.NetNS, func(_ ns.NetNS) error {
			return startCmd()
		})
	} else {
		// Else, just start the process normally as it's either not in a netns or will
		// be placed in one by the jailer process instead.
		err = startCmd()
	}

	if err != nil {
		m.logger.Errorf("Failed to start VMM: %s", err)

		m.fatalErr = err
		close(m.exitCh)

		return err
	}
	m.logger.Debugf("VMM started socket path is %s", m.Cfg.SocketPath)

	m.cleanupFuncs = append(m.cleanupFuncs,
		func() error {
			if err := os.Remove(m.Cfg.SocketPath); !os.IsNotExist(err) {
				return err
			}
			return nil
		},
	)

	errCh := make(chan error)
	go func() {
		waitErr := m.cmd.Wait()
		if waitErr != nil {
			m.logger.Warnf("firecracker exited: %s", waitErr.Error())
		} else {
			m.logger.Printf("firecracker exited: status=0")
		}

		cleanupErr := m.doCleanup()
		if cleanupErr != nil {
			m.logger.Errorf("failed to cleanup after VM exit: %v", cleanupErr)
		}

		errCh <- multierror.Append(waitErr, cleanupErr).ErrorOrNil()

		// Notify subscribers that there will be no more values.
		// When err is nil, two reads are performed (waitForSocket and close exitCh goroutine),
		// second one never ends as it tries to read from empty channel.
		close(errCh)
	}()

	m.setupSignals()

	// Wait for firecracker to initialize:
	err = m.waitForSocket(time.Duration(m.client.firecrackerInitTimeout)*time.Second, errCh)
	if err != nil {
		err = errors.Wrapf(err, "Firecracker did not create API socket %s", m.Cfg.SocketPath)
		m.fatalErr = err
		close(m.exitCh)

		return err
	}

	// This goroutine is used to kill the process by context cancelletion,
	// but doesn't tell anyone about that.
	go func() {
		<-ctx.Done()
		err := m.stopVMM()
		if err != nil {
			m.logger.WithError(err).Errorf("failed to stop vm %q", m.Cfg.VMID)
		}
	}()

	// This goroutine is used to tell clients that the process is stopped
	// (gracefully or not).
	go func() {
		m.fatalErr = <-errCh
		m.logger.Debugf("closing the exitCh %v", m.fatalErr)
		close(m.exitCh)
	}()

	m.logger.Debugf("returning from startVMM()")
	return nil
}