SDSM-for-SDI / experiment-scripts / migrate_from_shell.py
migrate_from_shell.py
Raw
#!/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")