Example #1
0
func (c *Container) start(p *Process) error {
	// save the state
	glog.V(3).Infof("save state id %s, boundle %s", c.Id, c.BundlePath)
	stateDir := filepath.Join(c.ownerPod.sv.StateDir, c.Id)
	_, err := os.Stat(stateDir)
	if err == nil {
		glog.V(1).Infof("Container %s exists\n", c.Id)
		return fmt.Errorf("Container %s exists\n", c.Id)
	}
	err = os.MkdirAll(stateDir, 0644)
	if err != nil {
		glog.V(1).Infof("%s\n", err.Error())
		return err
	}

	state := &specs.State{
		Version:    c.Spec.Version,
		ID:         c.Id,
		Pid:        c.ownerPod.getNsPid(),
		BundlePath: c.BundlePath,
	}
	stateData, err := json.MarshalIndent(state, "", "\t")
	if err != nil {
		glog.V(1).Infof("%s\n", err.Error())
		return err
	}
	stateFile := filepath.Join(stateDir, "state.json")
	err = ioutil.WriteFile(stateFile, stateData, 0644)
	if err != nil {
		glog.V(1).Infof("%s\n", err.Error())
		return err
	}

	glog.V(3).Infof("prepare hypervisor info")
	u := pod.ConvertOCF2UserContainer(c.Spec)
	if !filepath.IsAbs(u.Image) {
		u.Image = filepath.Join(c.BundlePath, u.Image)
	}
	vmRootfs := filepath.Join(hypervisor.BaseDir, c.ownerPod.vm.Id, hypervisor.ShareDirTag, c.Id, "rootfs")
	os.MkdirAll(vmRootfs, 0755)

	// Mount rootfs
	err = utils.Mount(u.Image, vmRootfs)
	if err != nil {
		glog.Errorf("mount %s to %s failed: %s\n", u.Image, vmRootfs, err.Error())
		return err
	}

	// Pre-create dirs necessary for hyperstart before setting rootfs readonly
	// TODO: a better way to support readonly rootfs
	if err = preCreateDirs(u.Image); err != nil {
		return err
	}

	// Mount necessary files and directories from spec
	for _, m := range c.Spec.Mounts {
		if err := mountToRootfs(&m, vmRootfs, ""); err != nil {
			return fmt.Errorf("mounting %q to rootfs %q at %q failed: %v", m.Source, vmRootfs, m.Destination, err)
		}
	}

	// set rootfs readonly
	if c.Spec.Root.Readonly {
		err = utils.SetReadonly(vmRootfs)
		if err != nil {
			glog.Errorf("set rootfs %s readonly failed: %s\n", vmRootfs, err.Error())
			return err
		}
	}

	envs := make(map[string]string)
	for _, env := range u.Envs {
		envs[env.Env] = env.Value
	}

	info := &hypervisor.ContainerInfo{
		Id:     c.Id,
		Rootfs: "rootfs",
		Image:  pod.UserVolume{Source: c.Id},
		Fstype: "dir",
		Cmd:    u.Command,
		Envs:   envs,
	}

	err = c.ownerPod.vm.Attach(p.stdio, c.Id, nil)
	if err != nil {
		glog.V(1).Infof("StartPod fail: fail to set up tty connection.\n")
		return err
	}

	err = execPrestartHooks(c.Spec, state)
	if err != nil {
		glog.V(1).Infof("execute Prestart hooks failed, %s\n", err.Error())
		return err
	}

	err = c.ownerPod.initPodNetwork(c)
	if err != nil {
		glog.Errorf("fail to initialize pod network %v", err)
		return err
	}

	c.ownerPod.podStatus.AddContainer(c.Id, c.ownerPod.podStatus.Id, "", []string{}, types.S_POD_CREATED)
	return c.ownerPod.vm.NewContainer(u, info)
}
Example #2
0
File: runv.go Project: ZJU-SEL/runv
func startVContainer(context *nsContext, root, container string) {
	stateDir := filepath.Join(root, container)

	err := createVSocket(context, root, container)
	if err != nil {
		fmt.Printf("create runv Socket err: %v\n", err)
		return
	}

	sock, ok := context.sockets[container]
	if !ok {
		fmt.Printf("can not find runv Socket, container %v\n", container)
		return
	}

	conn, err := sock.Accept()
	if err != nil {
		fmt.Printf("accept on runv Socket err: %v\n", err)
		return
	}

	// get config from sock
	msg, err := hypervisor.ReadVmMessage(conn.(*net.UnixConn))
	if err != nil || msg.Code != RUNV_STARTCONTAINER {
		fmt.Printf("read runv client data failed: %v\n", err)
		return
	}
	config := &startConfig{}
	err = json.Unmarshal(msg.Message, config)
	if err != nil || config.Root != root || config.Name != container {
		fmt.Printf("parse runv start config failed: %v\n", err)
		return
	}

	// start pure pod
	err = startRunvPod(context, config)
	if err != nil {
		fmt.Printf("Start Pod failed: %s\n", err.Error())
		return
	}
	defer cleanupRunvPod(context, container)

	// save the state
	state := &specs.State{
		Version:    config.LinuxSpec.Spec.Version,
		ID:         container,
		Pid:        -1,
		BundlePath: config.BundlePath,
	}
	stateData, err := json.MarshalIndent(state, "", "\t")
	if err != nil {
		fmt.Printf("%s\n", err.Error())
		return
	}
	stateFile := filepath.Join(stateDir, "state.json")
	err = ioutil.WriteFile(stateFile, stateData, 0644)
	if err != nil {
		fmt.Printf("%s\n", err.Error())
		return
	}

	userContainer := pod.ConvertOCF2UserContainer(&config.LinuxSpec, &config.LinuxRuntimeSpec)
	info, err := prepareInfo(config, userContainer, context.vmId)
	if err != nil {
		fmt.Printf("%s\n", err.Error())
		return
	}

	defer func() {
		rootDir := filepath.Join(hypervisor.BaseDir, context.vmId, hypervisor.ShareDirTag, info.Id, "rootfs")
		utils.Umount(rootDir)
		os.RemoveAll(filepath.Join(hypervisor.BaseDir, context.vmId, hypervisor.ShareDirTag, info.Id))
	}()

	tag, _ := runvAllocAndRespondTag(conn)

	tty := &hypervisor.TtyIO{
		ClientTag: tag,
		Stdin:     conn,
		Stdout:    conn,
		Callback:  make(chan *types.VmResponse, 1),
	}

	context.Lock()
	context.ttyList[tag] = tty
	context.Unlock()

	err = context.vm.Attach(tty, info.Id, nil)
	if err != nil {
		fmt.Printf("StartPod fail: fail to set up tty connection.\n")
		return
	}

	err = execPrestartHooks(&config.LinuxRuntimeSpec.RuntimeSpec, state)
	if err != nil {
		fmt.Printf("execute Prestart hooks failed, %s\n", err.Error())
		return
	}

	context.podStatus.AddContainer(info.Id, context.podId, "", []string{}, types.S_POD_CREATED)
	context.vm.NewContainer(userContainer, info)
	ListenAndHandleRunvRequests(context, info, sock)

	err = execPoststartHooks(&config.LinuxRuntimeSpec.RuntimeSpec, state)
	if err != nil {
		fmt.Printf("execute Poststart hooks failed %s\n", err.Error())
	}

	err = tty.WaitForFinish()
	if err != nil {
		fmt.Printf("get exit code failed %s\n", err.Error())
	}

	err = execPoststopHooks(&config.LinuxRuntimeSpec.RuntimeSpec, state)
	if err != nil {
		fmt.Printf("execute Poststop hooks failed %s\n", err.Error())
		return
	}
}