Commit 337dbc6f authored by Kirill Smelkov's avatar Kirill Smelkov

slapns - playground for SlapOS + Namespaces

parents
# slapns | pythonic package setup
from setuptools import setup, find_packages
# read file content
def readfile(path):
with open(path, 'r') as f:
return f.read()
setup(
name = 'slapns',
version = '0.0.0.dev1',
description = 'SlapOS vs Namespaces playground',
url = 'https://lab.nexedi.com/kirr/slapns',
license = 'GPLv3+ with wide exception for Open-Source',
author = 'Nexedians',
author_email= 'kirr@nexedi.com',
keywords = 'SlapOS user-namespaces',
packages = find_packages(),
install_requires = ['python-unshare'],
entry_points= {'console_scripts': [
'slapns = slapns:main',
]
},
classifiers = [_.strip() for _ in """\
Development Status :: 3 - Alpha
Intended Audience :: Developers
Programming Language :: Python :: 2
Programming Language :: Python :: 3\
""".splitlines()]
)
#!/usr/bin/env python
# Copyright (C) 2018 Nexedi SA and Contributors.
# Kirill Smelkov <kirr@nexedi.com>
#
# This program is free software: you can Use, Study, Modify and Redistribute
# it under the terms of the GNU General Public License version 3, or (at your
# option) any later version, as published by the Free Software Foundation.
#
# You can also Link and Combine this program with other software covered by
# the terms of any of the Free Software licenses or any of the Open Source
# Initiative approved licenses and Convey the resulting work. Corresponding
# source of such a combination shall include the source code for all other
# software used.
#
# This program is distributed WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options.
"""Slapns is a playground for SlapOS + Namespaces"""
from unshare import unshare, CLONE_NEWUSER, CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWNET
from os.path import abspath
import os, sys, ctypes, errno
MS_RDONLY = 1 << 0
MS_BIND = 1 << 12
# from https://stackoverflow.com/questions/1667257/how-do-i-mount-a-filesystem-using-python
# XXX better use pylibmount from util-linux directly
def mount(source, target, fs, flags=0, options=None):
ret = ctypes.CDLL('libc.so.6', use_errno=True).mount(source, target, fs, flags, options)
if ret < 0:
errno = ctypes.get_errno()
raise RuntimeError("Error mounting {} ({}) on {} with options '{}': {}".
format(source, fs, target, options, os.strerror(errno)))
# bind does `mount --bind source target ...`
def bind(source, target, flags=0, options=''):
return mount(source, target, None, flags | MS_BIND, options)
# writefile writes data to file @path.
def writefile(path, data):
with open(path, "wb") as f:
f.write(data)
# mkdir_p makes sure a directory exists at path.
def mkdir_p(path, mode=0777):
try:
os.makedirs(path, mode)
except OSError as exc:
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise
# usage: slapns <slappart>
# create new container inside <slappart> directory + run it.
def main():
slappart = sys.argv[1]
# create directories inside container
dirv = ["/proc", "/sys", "/tmp", "/bin", "/sbin", "/lib", "/lib64",
"/usr/bin", "/usr/lib"]
for _ in dirv:
mkdir_p(slappart + _)
# find out my uid/gid
uid = os.getuid()
gid = os.getgid()
# unshare from parent namespace (unshare -Umpn)
unshare(CLONE_NEWUSER | CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWNET)
# make us a root (UID=0) inside it (unshare -r)
writefile("/proc/self/setgroups", "deny")
writefile("/proc/self/uid_map", "0 %d 1" % uid)
writefile("/proc/self/gid_map", "0 %d 1" % gid)
# mount new tmpfs
mount("none", slappart + "/tmp", "tmpfs")
# read-only bind mount bin, lib, ... from SR
# FIXME stub: here we bind from base system for now
bind("/bin", slappart + "/bin", MS_RDONLY)
bind("/sbin", slappart + "/sbin", MS_RDONLY)
bind("/lib", slappart + "/lib", MS_RDONLY)
bind("/lib64", slappart + "/lib64", MS_RDONLY)
bind("/usr/bin", slappart + "/usr/bin", MS_RDONLY)
bind("/usr/lib", slappart + "/usr/lib", MS_RDONLY)
# XXX sysfs and proc are somehow special - mount succeeds only after fork
pid = os.fork()
if pid != 0:
# parent
_, st = os.waitpid(pid, 0)
sys.exit(st >> 8) # st = (exit << 8) | signal
# child
mount("none", slappart + "/proc", "proc")
mount("none", slappart + "/sys", "sysfs")
# TODO setup networking
# chroot to container
slappart = abspath(slappart)
os.chdir(slappart)
os.chroot(slappart)
# FIXME stub: -> $SHELL
os.execv("/bin/bash", ["bash"])
if __name__ == '__main__':
main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment