@@ -0,0 +1,2890 @@
+#!/usr/bin/env python2.7%0A#%0A# Docker From Scratch Workshop%0A# Level 2 - adding mount namespace%0A#%0A# Goal: separate our mount table from the other processes%0A#       i.e. running:%0A#                rd.py run -i ubuntu /bin/sh%0A#            will:%0A#               fork a new chrooted process in a new mount namespace%0A#%0A%0Afrom __future__ import print_function%0A%0Aimport os%0Aimport tarfile%0Aimport uuid%0A%0Aimport click%0A%0Aimport linux%0A%0A%0Adef _get_image_path(image_name, image_dir, image_suffix='tar'):%0A    return os.path.join(image_dir, os.extsep.join(%5Bimage_name, image_suffix%5D))%0A%0A%0Adef _get_container_path(container_id, container_dir, *subdir_names):%0A    return os.path.join(container_dir, container_id, *subdir_names)%0A%0A%0Adef create_container_root(image_name, image_dir, container_id, container_dir):%0A    image_path = _get_image_path(image_name, image_dir)%0A    container_root = _get_container_path(container_id, container_dir, 'rootfs')%0A%0A    assert os.path.exists(image_path), %22unable to locate image %25s%22 %25 image_name%0A%0A    if not os.path.exists(container_root):%0A        os.makedirs(container_root)%0A%0A    with tarfile.open(image_path) as t:%0A        # Fun fact: tar files may contain *nix devices! *facepalm*%0A        t.extractall(container_root,%0A                     members=%5Bm for m in t.getmembers() if m.type not in (tarfile.CHRTYPE, tarfile.BLKTYPE)%5D)%0A%0A    return container_root%0A%0A%0A@click.group()%0Adef cli():%0A    pass%0A%0A%0Adef contain(command, image_name, image_dir, container_id, container_dir):%0A    new_root = create_container_root(image_name, image_dir, container_id, container_dir)%0A    print('Created a new root fs for our container: %7B%7D'.format(new_root))%0A    # TODO: you probably want to mount stuff here...%0A%0A    os.chroot(new_root)%0A%0A    os.execvp(command%5B0%5D, command)%0A%0A%0A@cli.command()%0A@click.option('--image-name', '-i', help='Image name', default='ubuntu')%0A@click.option('--image-dir', help='Images directory', default='/workshop/images')%0A@click.option('--container-dir', help='Containers directory', default='/workshop/containers')%0A@click.argument('Command', required=True, nargs=-1)%0Adef run(image_name, image_dir, container_dir, command):%0A    container_id = str(uuid.uuid4())%0A    # TODO: time to say goodbye to the old mount namespace, see %22man 2 unshare%22 to get some help%0A    #   HINT 1: there is no os.unshare(), time to use the linux module we made just for you!%0A    #   HINT 2: the linux module include both functions and constants! e.g. linux.CLONE_NEWNS%0A    pid = os.fork()%0A    if pid == 0:%0A        # This is the child, we need to exec the command%0A        contain(command, image_name, image_dir, container_id, container_dir)%0A    else:%0A        # This is the parent, pid contains the PID of the forked process%0A        _, status = os.waitpid(pid, 0)  # wait for the forked child, fetch the exit status%0A        print('%7B%7D exited with status %7B%7D'.format(pid, status))%0A%0A%0Aif __name__ == '__main__':%0A    cli()%0A

add level 2 (mount namespace)