From: Stéphane Graber Date: Wed, 11 Dec 2013 19:46:34 +0000 (-0500) Subject: python3: Support unpriv containers X-Git-Tag: lxc-1.0.0.beta1~26 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3eb967f09640c6e789a4790edd9c0d0019b075e6;p=thirdparty%2Flxc.git python3: Support unpriv containers This removes any existing uid check in the python3 binding and tools, replacing those by .controllable where appropriate. Extra checks are also added to make lxc-ls work as a user, returning as much information as can possibly be retrieved. Signed-off-by: Stéphane Graber Acked-by: Serge E. Hallyn --- diff --git a/src/lxc/lxc-device b/src/lxc/lxc-device index 9d24248ec..78be6ab87 100644 --- a/src/lxc/lxc-device +++ b/src/lxc/lxc-device @@ -66,14 +66,10 @@ subparser_add.add_argument(dest="name", metavar="NAME", nargs="?", args = parser.parse_args() # Some basic checks +## Check for valid action if not hasattr(args, "action"): parser.error(_("You must specify an action.")) -## The user needs to be uid 0 -if not os.geteuid() == 0: - parser.error(_("You must be root to run this script. Try running: sudo %s" - % (sys.argv[0]))) - ## Don't rename if no alternative name if not args.name: args.name = args.device @@ -81,6 +77,11 @@ if not args.name: ## Check that the container is ready container = lxc.Container(args.container, args.lxcpath) +## Check that we have control over the container +if not container.controllable: + parser.error("Insufficent privileges to control: %s" % container.name) + +## Check that the container is running if not container.running: parser.error("The container must be running.") diff --git a/src/lxc/lxc-ls b/src/lxc/lxc-ls index 26c968459..b058bd028 100755 --- a/src/lxc/lxc-ls +++ b/src/lxc/lxc-ls @@ -123,8 +123,7 @@ parser.add_argument("-P", "--lxcpath", dest="lxcpath", metavar="PATH", default=lxc.default_config_path) parser.add_argument("--active", action="store_true", - help=_("list only active containers " - "(same as --running --frozen)")) + help=_("list only active containers")) parser.add_argument("--frozen", dest="state", action="append_const", const="FROZEN", help=_("list only frozen containers")) @@ -153,7 +152,7 @@ args = parser.parse_args() if args.active: if not args.state: args.state = [] - args.state += ["RUNNING", "FROZEN"] + args.state += ["RUNNING", "FROZEN", "UNKNOWN"] # If the output is piped, default to --one if not sys.stdout.isatty(): @@ -166,25 +165,27 @@ lxcpath = os.environ.get('NESTED', args.lxcpath) args.fancy_format = args.fancy_format.strip().split(",") # Basic checks -## The user needs to be uid 0 -if not os.geteuid() == 0 and (args.fancy or args.state): - parser.error(_("You must be root to access advanced container properties. " - "Try running: sudo %s" - % (sys.argv[0]))) +## Check for setns +SUPPORT_SETNS = os.path.exists("/proc/self/ns") +SUPPORT_SETNS_NET = False +SUPPORT_SETNS_PID = False +if SUPPORT_SETNS: + SUPPORT_SETNS_NET = os.path.exists("/proc/self/ns/net") + SUPPORT_SETNS_PID = os.path.exists("/proc/self/ns/pid") ## Nesting requires setns to pid and net ns if args.nesting: - if not os.path.exists("/proc/self/ns/"): + if not SUPPORT_SETNS: parser.error(_("Showing nested containers requires setns support " "which your kernel doesn't support.")) - if not "pid" in os.listdir("/proc/self/ns/"): + if not SUPPORT_SETNS_NET: parser.error(_("Showing nested containers requires setns to the " - "PID namespace which your kernel doesn't support.")) + "network namespace which your kernel doesn't support.")) - if not "net" in os.listdir("/proc/self/ns/"): + if not SUPPORT_SETNS_PID: parser.error(_("Showing nested containers requires setns to the " - "network namespace which your kernel doesn't support.")) + "PID namespace which your kernel doesn't support.")) # List of containers, stored as dictionaries containers = [] @@ -203,8 +204,13 @@ for container_name in lxc.list_containers(config_path=lxcpath): container = lxc.Container(container_name, args.lxcpath) + if container.controllable: + state = container.state + else: + state = 'UNKNOWN' + # Filter by status - if args.state and container.state not in args.state: + if args.state and state not in args.state: continue # Nothing more is needed if we're not printing some fancy output @@ -214,17 +220,30 @@ for container_name in lxc.list_containers(config_path=lxcpath): # Some extra field we may want if 'state' in args.fancy_format or args.nesting: - entry['state'] = container.state + entry['state'] = state if 'pid' in args.fancy_format or args.nesting: entry['pid'] = "-" - if container.init_pid != -1: + if state == 'UNKNOWN': + entry['pid'] = state + elif container.init_pid != -1: entry['pid'] = str(container.init_pid) # Get the IPs for family, protocol in {'inet': 'ipv4', 'inet6': 'ipv6'}.items(): if protocol in args.fancy_format or args.nesting: entry[protocol] = "-" + + if state == 'UNKNOWN': + entry[protocol] = state + continue + + # FIXME: We should get get_ips working as non-root + if container.running and (not SUPPORT_SETNS_NET \ + or os.geteuid() != 0): + entry[protocol] = 'UNKNOWN' + continue + ips = container.get_ips(family=family) if ips: entry[protocol] = ", ".join(ips) diff --git a/src/lxc/lxc-start-ephemeral.in b/src/lxc/lxc-start-ephemeral.in index 0f0c398b5..118b1b5f7 100644 --- a/src/lxc/lxc-start-ephemeral.in +++ b/src/lxc/lxc-start-ephemeral.in @@ -118,11 +118,6 @@ if not args.storage_type: if args.keep_data and args.storage_type == "tmpfs": parser.error(_("You can't use -k with the tmpfs storage type.")) -## The user needs to be uid 0 -if not os.geteuid() == 0: - parser.error(_("You must be root to run this script. Try running: sudo %s" - % (sys.argv[0]))) - # Load the orig container orig = lxc.Container(args.orig, args.lxcpath) if not orig.defined: diff --git a/src/python-lxc/lxc/__init__.py b/src/python-lxc/lxc/__init__.py index c3d840c45..e70878111 100644 --- a/src/python-lxc/lxc/__init__.py +++ b/src/python-lxc/lxc/__init__.py @@ -150,9 +150,6 @@ class Container(_lxc.Container): Creates a new Container instance. """ - if os.geteuid() != 0: - raise Exception("Running as non-root.") - if config_path: _lxc.Container.__init__(self, name, config_path) else: