migrate

package
v0.0.0-...-8fc3db6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 12, 2019 License: MIT Imports: 10 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var Command = cli.Command{
	Name:  "migrate",
	Usage: "Migrate running container",
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "src",
			Usage: "Source host where the container is running",
		},
		cli.StringFlag{
			Name:  "dst",
			Usage: "Target host to migrate the container",
		},
		cli.BoolFlag{
			Name:  "pre-dump",
			Usage: "Perform a pre-dump to minimize downtime",
		},
		cli.BoolFlag{
			Name:  "force",
			Usage: "Doesn't fail of validations related to different versions of executable binaries and cpu differences",
		},
		cli.StringFlag{
			Name:  "hook-pre-restore",
			Usage: "Command to run right before restoring process",
		},
		cli.StringFlag{
			Name:  "hook-post-restore",
			Usage: "Command to run right after a successful process restoration",
		},
		cli.StringFlag{
			Name:  "hook-failed-restore",
			Usage: "Command to run right after a failed process restoration",
		},
	},
	Action: func(c *cli.Context) {
		srcUrl := validate.ParseURL(c.String("src"))
		dstUrl := validate.ParseURL(c.String("dst"))

		log.Println("Performing validations")
		src, dst := validate.Validate(srcUrl, dstUrl, c.Bool("force"))

		log.Println("Preparing everything to do a checkpoint")
		containerId := getContainerId(srcUrl.Path)
		var imagesPath string
		var restoreCmd cmd.Cmd
		var migrateStart time.Time
		var downtime time.Duration

		if c.Bool("pre-dump") {

			predumpPath := fmt.Sprintf("%s/images/0", srcUrl.Path)
			prepareDir(src, predumpPath)

			checkpoint(src, containerId, predumpPath, true)

			srcTarFile := fmt.Sprintf("%s/predump.tar.gz", srcUrl.Path)
			prepareTar(src, srcTarFile, predumpPath)

			prepareDir(dst, fmt.Sprintf("%s/images/0", dstUrl.Path))

			log.Println("Copying predump image to dst")
			err := cmd.Scp(src.URL(srcTarFile), dst.URL(fmt.Sprintf("%s/images/0", dstUrl.Path)))
			if err != nil {
				log.Fatal("Error copying predump image files to dst", err)
			}

			dstTarFile := fmt.Sprintf("%s/images/0/predump.tar.gz", dstUrl.Path)
			unpackTar(dst, dstTarFile, fmt.Sprintf("%s/images/0", dstUrl.Path))

			migrateStart = time.Now()

			iptablesBefore, ipErr := getIPTables(src)

			if ipErr != nil {
				log.Fatal("Error capturing iptables rules. ", ipErr)
			}
			imagesPath = fmt.Sprintf("%s/images/1", srcUrl.Path)
			prepareDir(src, fmt.Sprintf("%s/images/1", srcUrl.Path))
			log.Println("Performing the checkpoint")
			_, _, err = src.Run("sudo", "runc", "--id", containerId, "checkpoint", "--image-path", imagesPath, "--prev-images-dir", "../0", "--track-mem", "--tcp-established")
			if err != nil {
				log.Fatal("Error performing checkpoint:", err)
			}

			iptablesAfter, ipErr2 := getIPTables(src)

			if ipErr2 != nil {
				log.Fatal("Error capturing iptables rules. ", ipErr2)
			}

			iptablesRules := iptables.Diff(iptablesAfter, iptablesBefore)

			srcTarFile = fmt.Sprintf("%s/dump.tar.gz", srcUrl.Path)
			prepareTar(src, srcTarFile, imagesPath)
			prepareDir(dst, fmt.Sprintf("%s/images/1", dstUrl.Path))

			log.Println("Copying final dump image to dst")
			err = cmd.Scp(src.URL(srcTarFile), dst.URL(fmt.Sprintf("%s/images/1", dstUrl.Path)))
			if err != nil {
				log.Fatal("Error copying predump image files to dst", err)
			}

			dstTarFile = fmt.Sprintf("%s/images/1/dump.tar.gz", dstUrl.Path)
			unpackTar(dst, dstTarFile, fmt.Sprintf("%s/images/1", dstUrl.Path))

			log.Println("Performing the restore")

			applyErr := applyIPTablesRules(dst, iptablesRules)
			if applyErr != nil {
				log.Fatal("Error applying IPTables rules. ", applyErr)
			}
			TriggerHook(c.String("hook-pre-restore"))

			removeErr := removeIPTablesRules(src, iptablesRules)
			if removeErr != nil {
				log.Fatal("Error removing IPTables rules. ", removeErr)
			}
			configFilePath := fmt.Sprintf("%s/config.json", dstUrl.Path)
			runtimeFilePath := fmt.Sprintf("%s/runtime.json", dstUrl.Path)
			dstImagesPath := fmt.Sprintf("%s/images/1", dstUrl.Path)

			restoreCmd, err = dst.Start("sudo", "runc", "--id", containerId, "restore", "--tcp-established", "--image-path", dstImagesPath, "--config-file", configFilePath, "--runtime-file", runtimeFilePath)
			if err != nil {
				log.Fatal("Error performing restore:", err)
			}
		} else {
			imagesPath = fmt.Sprintf("%s/images", srcUrl.Path)
			prepareDir(src, imagesPath)

			migrateStart = time.Now()
			iptablesBefore, ipErr := getIPTables(src)

			if ipErr != nil {
				log.Fatal("Error capturing iptables rules. ", ipErr)
			}
			checkpoint(src, containerId, imagesPath, false)
			iptablesAfter, ipErr2 := getIPTables(src)

			if ipErr2 != nil {
				log.Fatal("Error capturing iptables rules. ", ipErr2)
			}

			iptablesRules := iptables.Diff(iptablesAfter, iptablesBefore)

			srcTarFile := fmt.Sprintf("%s/dump.tar.gz", srcUrl.Path)
			prepareTar(src, srcTarFile, imagesPath)

			prepareDir(dst, fmt.Sprintf("%s/images", dstUrl.Path))

			log.Println("Copying checkpoint image to dst")
			err := cmd.Scp(src.URL(srcTarFile), dst.URL(fmt.Sprintf("%s/images", dstUrl.Path)))
			if err != nil {
				log.Fatal("Error copying image files to dst", err)
			}

			dstTarFile := fmt.Sprintf("%s/images/dump.tar.gz", dstUrl.Path)
			unpackTar(dst, dstTarFile, fmt.Sprintf("%s/images", dstUrl.Path))

			log.Println("Performing the restore")

			applyErr := applyIPTablesRules(dst, iptablesRules)
			if applyErr != nil {
				log.Fatal("Error applying IPTables rules. ", applyErr)
			}

			TriggerHook(c.String("hook-pre-restore"))

			removeErr := removeIPTablesRules(src, iptablesRules)
			if removeErr != nil {
				log.Fatal("Error removing IPTables rules. ", removeErr)
			}
			configFilePath := fmt.Sprintf("%s/config.json", dstUrl.Path)
			runtimeFilePath := fmt.Sprintf("%s/runtime.json", dstUrl.Path)
			dstImagesPath := fmt.Sprintf("%s/images", dstUrl.Path)
			restoreCmd, err = dst.Start("sudo", "runc", "--id", containerId, "restore", "--tcp-established", "--image-path", dstImagesPath, "--config-file", configFilePath, "--runtime-file", runtimeFilePath)
			if err != nil {
				log.Fatal("Error performing restore:", err)
			}

		}

		var restoreSucceed bool
		var restoreError error
		var wg sync.WaitGroup
		wg.Add(1)

		go func() {
			restoreError = restoreCmd.Wait()
			wg.Done()
		}()

		go func() {
			log.Println("Waiting for container to start...")

			if isRunning(containerId, dst) {
				restoreSucceed = true
				wg.Done()
				return
			}
			ticker := time.NewTicker(200 * time.Millisecond)
			go func() {
				for _ = range ticker.C {
					if isRunning(containerId, dst) {
						restoreSucceed = true
						break
					}

				}
				ticker.Stop()
				wg.Done()
			}()
		}()

		wg.Wait()

		downtime = time.Since(migrateStart)

		if restoreSucceed {
			log.Printf("Restore finished successfully, total downtime: %dms", downtime/time.Millisecond)
			TriggerHook(c.String("hook-post-restore"))
		} else {
			log.Println("Error performing restore:", restoreError)
			TriggerHook(c.String("hook-failed-restore"))
		}

	},
}

Functions

func TriggerHook

func TriggerHook(command string) error

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL