lxd/container_lxc.go
func (c *containerLXC) Stop(stateful bool) error {
	var ctxMap log.Ctx

	// Check that we're not already stopped
	if !c.IsRunning() {
		return fmt.Errorf("The container is already stopped")
	}

	// Setup a new operation
	op, err := c.createOperation("stop", false, true)
	if err != nil {
		return err
	}

	ctxMap = log.Ctx{
		"project":   c.project,
		"name":      c.name,
		"action":    op.action,
		"created":   c.creationDate,
		"ephemeral": c.ephemeral,
		"used":      c.lastUsedDate,
		"stateful":  stateful}

	logger.Info("Stopping container", ctxMap)

	// Handle stateful stop
	if stateful {
		// Cleanup any existing state
		stateDir := c.StatePath()
		os.RemoveAll(stateDir)

		err := os.MkdirAll(stateDir, 0700)
		if err != nil {
			op.Done(err)
			logger.Error("Failed stopping container", ctxMap)
			return err
		}

		criuMigrationArgs := CriuMigrationArgs{
			cmd:          lxc.MIGRATE_DUMP,
			stateDir:     stateDir,
			function:     "snapshot",
			stop:         true,
			actionScript: false,
			dumpDir:      "",
			preDumpDir:   "",
		}

		// Checkpoint
		err = c.Migrate(&criuMigrationArgs)
		if err != nil {
			op.Done(err)
			logger.Error("Failed stopping container", ctxMap)
			return err
		}

		err = op.Wait()
		if err != nil && c.IsRunning() {
			logger.Error("Failed stopping container", ctxMap)
			return err
		}

		c.stateful = true
		err = c.state.Cluster.ContainerSetStateful(c.id, true)
		if err != nil {
			op.Done(err)
			logger.Error("Failed stopping container", ctxMap)
			return err
		}

		op.Done(nil)
		logger.Info("Stopped container", ctxMap)
		eventSendLifecycle(c.project, "container-stopped",
			fmt.Sprintf("/1.0/containers/%s", c.name), nil)
		return nil
	} else if shared.PathExists(c.StatePath()) {
		os.RemoveAll(c.StatePath())
	}

	// Load the go-lxc struct
	err = c.initLXC(false)
	if err != nil {
		op.Done(err)
		logger.Error("Failed stopping container", ctxMap)
		return err
	}

	// Fork-bomb mitigation, prevent forking from this point on
	if c.state.OS.CGroupPidsController {
		// Attempt to disable forking new processes
		c.CGroupSet("pids.max", "0")
	} else if c.state.OS.CGroupFreezerController {
		// Attempt to freeze the container
		freezer := make(chan bool, 1)
		go func() {
			c.Freeze()
			freezer <- true
		}()

		select {
		case <-freezer:
		case <-time.After(time.Second * 5):
			c.Unfreeze()
		}
	}

	if err := c.c.Stop(); err != nil {
		op.Done(err)
		logger.Error("Failed stopping container", ctxMap)
		return err
	}

	err = op.Wait()
	if err != nil && c.IsRunning() {
		logger.Error("Failed stopping container", ctxMap)
		return err
	}

	logger.Info("Stopped container", ctxMap)
	eventSendLifecycle(c.project, "container-stopped",
		fmt.Sprintf("/1.0/containers/%s", c.name), nil)

	return nil
}
func (c *containerLXC) Stop(stateful bool) error {
	var ctxMap log.Ctx

	// Check that we're not already stopped
	if !c.IsRunning() {
		return fmt.Errorf("The container is already stopped")
	}

	// Setup a new operation
	op, err := c.createOperation("stop", false, true)
	if err != nil {
		return err
	}

	ctxMap = log.Ctx{
		"project":   c.project,
		"name":      c.name,
		"action":    op.action,
		"created":   c.creationDate,
		"ephemeral": c.ephemeral,
		"used":      c.lastUsedDate,
		"stateful":  stateful}

	logger.Info("Stopping container", ctxMap)

	// Handle stateful stop
	if stateful {
		// Cleanup any existing state
		stateDir := c.StatePath()
		os.RemoveAll(stateDir)

		err := os.MkdirAll(stateDir, 0700)
		if err != nil {
			op.Done(err)
			logger.Error("Failed stopping container", ctxMap)
			return err
		}

		criuMigrationArgs := CriuMigrationArgs{
			cmd:          lxc.MIGRATE_DUMP,
			stateDir:     stateDir,
			function:     "snapshot",
			stop:         true,
			actionScript: false,
			dumpDir:      "",
			preDumpDir:   "",
		}

		// Checkpoint
		err = c.Migrate(&criuMigrationArgs)
		if err != nil {
			op.Done(err)
			logger.Error("Failed stopping container", ctxMap)
			return err
		}

		err = op.Wait()
		if err != nil && c.IsRunning() {
			logger.Error("Failed stopping container", ctxMap)
			return err
		}

		c.stateful = true
		err = c.state.Cluster.ContainerSetStateful(c.id, true)
		if err != nil {
			op.Done(err)
			logger.Error("Failed stopping container", ctxMap)
			return err
		}

		op.Done(nil)
		logger.Info("Stopped container", ctxMap)
		eventSendLifecycle(c.project, "container-stopped",
			fmt.Sprintf("/1.0/containers/%s", c.name), nil)
		return nil
	} else if shared.PathExists(c.StatePath()) {
		os.RemoveAll(c.StatePath())
	}

	// Load the go-lxc struct
	err = c.initLXC(false)
	if err != nil {
		op.Done(err)
		logger.Error("Failed stopping container", ctxMap)
		return err
	}

	// Fork-bomb mitigation, prevent forking from this point on
	if c.state.OS.CGroupPidsController {
		// Attempt to disable forking new processes
		c.CGroupSet("pids.max", "0")
	} else if c.state.OS.CGroupFreezerController {
		// Attempt to freeze the container
		freezer := make(chan bool, 1)
		go func() {
			c.Freeze()
			freezer <- true
		}()

		select {
		case <-freezer:
		case <-time.After(time.Second * 5):
			c.Unfreeze()
		}
	}

	if err := c.c.Stop(); err != nil {
		op.Done(err)
		logger.Error("Failed stopping container", ctxMap)
		return err
	}

	err = op.Wait()
	if err != nil && c.IsRunning() {
		logger.Error("Failed stopping container", ctxMap)
		return err
	}

	logger.Info("Stopped container", ctxMap)
	eventSendLifecycle(c.project, "container-stopped",
		fmt.Sprintf("/1.0/containers/%s", c.name), nil)

	return nil
}
func ( c * containerLXC ) Stop ( stateful bool ) error { var ctxMap log . Ctx // Check that we're not already stopped if ! c . IsRunning ( ) { return fmt . Errorf ( " " ) } // Setup a new operation op , err := c . createOperation ( " " , false , true ) if err != nil { return err } ctxMap = log . Ctx { " " : c . project , " " : c . name , " " : op . action , " " : c . creationDate , " " : c . ephemeral , " " : c . lastUsedDate , " " : stateful } logger . Info ( " " , ctxMap ) // Handle stateful stop if stateful { // Cleanup any existing state stateDir := c . StatePath ( ) os . RemoveAll ( stateDir ) err := os . MkdirAll ( stateDir , 0700 ) if err != nil { op . Done ( err ) logger . Error ( " " , ctxMap ) return err } criuMigrationArgs := CriuMigrationArgs { cmd : lxc . MIGRATE_DUMP , stateDir : stateDir , function : " " , stop : true , actionScript : false , dumpDir : " " , preDumpDir : " " , } // Checkpoint err = c . Migrate ( & criuMigrationArgs ) if err != nil { op . Done ( err ) logger . Error ( " " , ctxMap ) return err } err = op . Wait ( ) if err != nil && c . IsRunning ( ) { logger . Error ( " " , ctxMap ) return err } c . stateful = true err = c . state . Cluster . ContainerSetStateful ( c . id , true ) if err != nil { op . Done ( err ) logger . Error ( " " , ctxMap ) return err } op . Done ( nil ) logger . Info ( " " , ctxMap ) eventSendLifecycle ( c . project , " " , fmt . Sprintf ( " " , c . name ) , nil ) return nil } else if shared . PathExists ( c . StatePath ( ) ) { os . RemoveAll ( c . StatePath ( ) ) } // Load the go-lxc struct err = c . initLXC ( false ) if err != nil { op . Done ( err ) logger . Error ( " " , ctxMap ) return err } // Fork-bomb mitigation, prevent forking from this point on if c . state . OS . CGroupPidsController { // Attempt to disable forking new processes c . CGroupSet ( " " , " " ) } else if c . state . OS . CGroupFreezerController { // Attempt to freeze the container freezer := make ( chan bool , 1 ) go func ( ) { c . Freeze ( ) freezer <- true } ( ) select { case <- freezer : case <- time . After ( time . Second * 5 ) : c . Unfreeze ( ) } } if err := c . c . Stop ( ) ; err != nil { op . Done ( err ) logger . Error ( " " , ctxMap ) return err } err = op . Wait ( ) if err != nil && c . IsRunning ( ) { logger . Error ( " " , ctxMap ) return err } logger . Info ( " " , ctxMap ) eventSendLifecycle ( c . project , " " , fmt . Sprintf ( " " , c . name ) , nil ) return nil }
// Stop functions
Stop functions