Fork me on GitHub
  ▖     
▃▀▄▄▖▄▄▖
 ▀▖     
        


#!/usr/bin/env python3
#
# usage: plash create CONTAINER [ CMD1 [ CMD2 ... ] ]
#
# Creates a new container from a command. If no command is passed, a shell is
# started. The new container is printed to stdout, all other output goes to
# stderr. Note that a new container is only returned if the build command
# returns 0 (success) as exit code.  For most cases use `plash build` for a
# higher level interface.
#
# Parameters may be interpreted as build instruction.
#
# Examples:
#
# $ plash create 7 ./buildscript.sh
# 42
#
# $ sudo plash create 3
# /home/fulano # echo 'hello' > /file
# /home/fulano # exit 0
# 71
#
# $ plash create -f ubuntu -- touch /myfile
# 44

import os
import subprocess
import sys
from os.path import join
from subprocess import DEVNULL, CalledProcessError, Popen
from sys import exit

from plash.utils import (assert_initialized, die, die_with_usage,
                         get_plash_data, handle_build_args, handle_help_flag,
                         mkdtemp, nodepath_or_die)

assert_initialized()
handle_help_flag()
handle_build_args()

plash_tmp = join(get_plash_data(), 'tmp')

try:
    container = sys.argv[1]
    cmd = sys.argv[2:]
except IndexError:
    die_with_usage()

nodepath_or_die(container)

changesdir = mkdtemp()
p = subprocess.Popen(
    [
        'plash-runopts',
        '-c',
        container,
        '-d',
        changesdir,
        '-m',
        '/home',
    ] + (['-m', '/root'] if os.access('/root', os.R_OK) else []) + [
        '-m',
        '/etc/resolv.conf',
        '-m',
        '/sys',
        '-m',
        '/dev',
        '-m',
        '/proc',
        '--',
    ] + cmd,
    stdout=2
)  # redirect stdout to stderr because we are passing the container id through stdout

exit = p.wait()
if exit:
    die("build failed with exit status {}".format(exit), exit=4)

os.execlp('plash-add-layer', 'plash-add-layer', container,
          os.path.join(changesdir, 'data'))