#!/usr/bin/env python #code taken from https://www.redhat.com/en/blog/container-migration-around-world and partially modified import socket import sys import select import time import os import shutil import subprocess import distutils.util #import rpyc def error(): print("Something did not work. Exiting!") sys.exit(1) def prepare(image_path, parent_path): try: shutil.rmtree(image_path) except: pass try: shutil.rmtree(parent_path) except: pass def pre_dump(base_path, container): old_cwd = os.getcwd() print("old_cwd " + old_cwd) os.chdir(base_path) cmd = 'time -p runc checkpoint --pre-dump --image-path parent' cmd += ' ' + container start = time.time() print ("Starting checkpointing pre-dump at: %f" % (start) ) print(cmd) ret = os.system(cmd) #end = time.time() #print "%s finished after %d second(s) with %d" % (cmd, end - start, ret) os.chdir(old_cwd) if ret != 0: error() def real_dump(precopy, postcopy): old_cwd = os.getcwd() print("old_cwd " + old_cwd) os.chdir(base_path) cmd = 'time -p runc checkpoint --image-path image --leave-running' cmd = 'time -p runc checkpoint --image-path image ' if precopy: cmd += ' --parent-path ../parent' if postcopy: cmd += ' --lazy-pages' cmd += ' --page-server localhost:27' try: os.unlink('/tmp/postcopy-pipe') except: pass os.mkfifo('/tmp/postcopy-pipe') cmd += ' --status-fd /tmp/postcopy-pipe' cmd += ' ' + container start = time.time() print ("Starting checkpointing dump at: %f" % (start)) print (cmd) p = subprocess.Popen(cmd, shell=True) if postcopy: p_pipe = os.open('/tmp/postcopy-pipe', os.O_RDONLY) ret = os.read(p_pipe, 1) if ret == '\0': print ('Ready for lazy page transfer') ret = 0 else: ret = p.wait() end = time.time() print ("%s finished after %.2f second(s) with %d" % (cmd, end - start, ret)) os.chdir(old_cwd) if ret != 0: error() def xfer_pre_dump(parent_path, dest, base_path): sys.stdout.write('PRE-DUMP size: ') sys.stdout.flush() cmd = 'du -hs %s' % parent_path print("cmd: "+ cmd) ret = os.system(cmd) cmd = 'time -p rsync %s --stats %s %s:%s/' % (rsync_opts, parent_path, dest, base_path) print ("Transferring PRE-DUMP to %s" % dest) #start = time.time() print("cmd: " + cmd) ret = os.system(cmd) #end = time.time() #print "PRE-DUMP transfer time %s seconds" % (end - start) if ret != 0: error() def xfer_final(image_path, dest, base_path): sys.stdout.write('DUMP size: ') sys.stdout.flush() cmd = 'du -hs %s' % image_path print("cmd: " + cmd) ret = os.system(cmd) cmd = 'time -p rsync %s --stats %s %s:%s/' % (rsync_opts, image_path, dest, base_path) print ("Transferring DUMP to %s" % dest) #start = time.time() print("cmd: " + cmd) ret = os.system(cmd) #end = time.time() #print "DUMP transfer time %s seconds" % (end - start) if ret != 0: error() def touch(fname): open(fname, 'a').close() # def give_ip(dest): # print "Giving floating IP to " + dest # touch('/tmp/give_up_master_99') # cs = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # cs.connect((dest, 18863)) # cs.send('{ "take_ip" : "/tmp/give_up_master_99" }') # os.system('systemctl stop keepalived') # cs.close() def migrate(container, dest, pre, lazy): base_path = runc_base + container image_path = base_path + "/image" parent_path = base_path + "/parent" prepare(image_path, parent_path) if pre: pre_dump(base_path, container) xfer_pre_dump(parent_path, dest, base_path) real_dump(pre, lazy) # give_ip(dest) xfer_final(image_path, dest, base_path) cs = socket.socket(socket.AF_INET, socket.SOCK_STREAM) cs.connect((dest, 18863)) input = [cs,sys.stdin] cmd = '{ "restore" : { "path" : "' + base_path + '", "name" : "' + container + '" , "image_path" : "' + image_path + '" , "lazy" : "' + str(lazy) + '" } }' print('cmd: ' + cmd) cs.send(cmd) while True: inputready, outputready, exceptready = select.select(input,[],[], 5) if not inputready: break for s in inputready: answer = s.recv(1024) print (answer) print ("Migrate function in migrate_from_shell is returning") return True #def remove_directories(container, pre): # base_path = runc_base + container # old_cwd = os.getcwd() # os.chdir(base_path) # cmd = 'rm -rf ./image' # ret = os.system(cmd) # if ret == 0 and pre: # cmd = 'rm -rf ./parent' # ret = os.system(cmd) # os.chdir(old_cwd) # if ret != 0: # error() if __name__ == '__main__': runc_base = "/runc/containers/" lazy = False pre = False #if len(sys.argv) < 3: # print "Usage: " + sys.argv[0] + " [container id] [destination] [pre-copy] [post-copy]" # sys.exit(1) #from rpyc.utils.server import ThreadedServer #server = ThreadedServer(MigrationTrigger, port=18862) #server.start() container = sys.argv[1] dest = sys.argv[2] if len(sys.argv) > 3: pre = distutils.util.strtobool(sys.argv[3]) if len(sys.argv) > 4: lazy = distutils.util.strtobool(sys.argv[4]) base_path = runc_base + container image_path = base_path + "/image" parent_path = base_path + "/parent" rsync_opts = "-ha" migrate(container, dest, pre, lazy) #remove_directories(container, pre) print ("Exiting migrate_from_shell")