Commit 3eb967f0 by Stéphane Graber

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: 's avatarStéphane Graber <stgraber@ubuntu.com> Acked-by: 's avatarSerge E. Hallyn <serge.hallyn@ubuntu.com>
parent 0ecf64b5
...@@ -66,14 +66,10 @@ subparser_add.add_argument(dest="name", metavar="NAME", nargs="?", ...@@ -66,14 +66,10 @@ subparser_add.add_argument(dest="name", metavar="NAME", nargs="?",
args = parser.parse_args() args = parser.parse_args()
# Some basic checks # Some basic checks
## Check for valid action
if not hasattr(args, "action"): if not hasattr(args, "action"):
parser.error(_("You must specify an 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 ## Don't rename if no alternative name
if not args.name: if not args.name:
args.name = args.device args.name = args.device
...@@ -81,6 +77,11 @@ if not args.name: ...@@ -81,6 +77,11 @@ if not args.name:
## Check that the container is ready ## Check that the container is ready
container = lxc.Container(args.container, args.lxcpath) 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: if not container.running:
parser.error("The container must be running.") parser.error("The container must be running.")
......
...@@ -123,8 +123,7 @@ parser.add_argument("-P", "--lxcpath", dest="lxcpath", metavar="PATH", ...@@ -123,8 +123,7 @@ parser.add_argument("-P", "--lxcpath", dest="lxcpath", metavar="PATH",
default=lxc.default_config_path) default=lxc.default_config_path)
parser.add_argument("--active", action="store_true", parser.add_argument("--active", action="store_true",
help=_("list only active containers " help=_("list only active containers"))
"(same as --running --frozen)"))
parser.add_argument("--frozen", dest="state", action="append_const", parser.add_argument("--frozen", dest="state", action="append_const",
const="FROZEN", help=_("list only frozen containers")) const="FROZEN", help=_("list only frozen containers"))
...@@ -153,7 +152,7 @@ args = parser.parse_args() ...@@ -153,7 +152,7 @@ args = parser.parse_args()
if args.active: if args.active:
if not args.state: if not args.state:
args.state = [] args.state = []
args.state += ["RUNNING", "FROZEN"] args.state += ["RUNNING", "FROZEN", "UNKNOWN"]
# If the output is piped, default to --one # If the output is piped, default to --one
if not sys.stdout.isatty(): if not sys.stdout.isatty():
...@@ -166,25 +165,27 @@ lxcpath = os.environ.get('NESTED', args.lxcpath) ...@@ -166,25 +165,27 @@ lxcpath = os.environ.get('NESTED', args.lxcpath)
args.fancy_format = args.fancy_format.strip().split(",") args.fancy_format = args.fancy_format.strip().split(",")
# Basic checks # Basic checks
## The user needs to be uid 0 ## Check for setns
if not os.geteuid() == 0 and (args.fancy or args.state): SUPPORT_SETNS = os.path.exists("/proc/self/ns")
parser.error(_("You must be root to access advanced container properties. " SUPPORT_SETNS_NET = False
"Try running: sudo %s" SUPPORT_SETNS_PID = False
% (sys.argv[0]))) 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 ## Nesting requires setns to pid and net ns
if args.nesting: if args.nesting:
if not os.path.exists("/proc/self/ns/"): if not SUPPORT_SETNS:
parser.error(_("Showing nested containers requires setns support " parser.error(_("Showing nested containers requires setns support "
"which your kernel doesn't 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 " 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 " 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 # List of containers, stored as dictionaries
containers = [] containers = []
...@@ -203,8 +204,13 @@ for container_name in lxc.list_containers(config_path=lxcpath): ...@@ -203,8 +204,13 @@ for container_name in lxc.list_containers(config_path=lxcpath):
container = lxc.Container(container_name, args.lxcpath) container = lxc.Container(container_name, args.lxcpath)
if container.controllable:
state = container.state
else:
state = 'UNKNOWN'
# Filter by status # Filter by status
if args.state and container.state not in args.state: if args.state and state not in args.state:
continue continue
# Nothing more is needed if we're not printing some fancy output # 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): ...@@ -214,17 +220,30 @@ for container_name in lxc.list_containers(config_path=lxcpath):
# Some extra field we may want # Some extra field we may want
if 'state' in args.fancy_format or args.nesting: 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: if 'pid' in args.fancy_format or args.nesting:
entry['pid'] = "-" entry['pid'] = "-"
if container.init_pid != -1: if state == 'UNKNOWN':
entry['pid'] = state
elif container.init_pid != -1:
entry['pid'] = str(container.init_pid) entry['pid'] = str(container.init_pid)
# Get the IPs # Get the IPs
for family, protocol in {'inet': 'ipv4', 'inet6': 'ipv6'}.items(): for family, protocol in {'inet': 'ipv4', 'inet6': 'ipv6'}.items():
if protocol in args.fancy_format or args.nesting: if protocol in args.fancy_format or args.nesting:
entry[protocol] = "-" 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) ips = container.get_ips(family=family)
if ips: if ips:
entry[protocol] = ", ".join(ips) entry[protocol] = ", ".join(ips)
......
...@@ -118,11 +118,6 @@ if not args.storage_type: ...@@ -118,11 +118,6 @@ if not args.storage_type:
if args.keep_data and args.storage_type == "tmpfs": if args.keep_data and args.storage_type == "tmpfs":
parser.error(_("You can't use -k with the tmpfs storage type.")) 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 # Load the orig container
orig = lxc.Container(args.orig, args.lxcpath) orig = lxc.Container(args.orig, args.lxcpath)
if not orig.defined: if not orig.defined:
......
...@@ -150,9 +150,6 @@ class Container(_lxc.Container): ...@@ -150,9 +150,6 @@ class Container(_lxc.Container):
Creates a new Container instance. Creates a new Container instance.
""" """
if os.geteuid() != 0:
raise Exception("Running as non-root.")
if config_path: if config_path:
_lxc.Container.__init__(self, name, config_path) _lxc.Container.__init__(self, name, config_path)
else: else:
......
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