[lxc-devel] [PATCH] lxc-ls: Fix support of --nesting for unpriv

Serge Hallyn serge.hallyn at ubuntu.com
Tue Mar 4 22:23:04 UTC 2014


Quoting Stéphane Graber (stgraber at ubuntu.com):
> This reworks the way lxc-ls works in nesting mode. In the past it'd use
> attach_wait's subprocess function to call itself in the container's
> namespace, carefully only attaching to the namespaces it needed.
> 
> This works great for system containers but not so much as soon as you
> also need to attach to userns. Instead this fix moves all of the
> container listing code into a get_containers function (hence the massive
> diff, sorry), this function is then called recursively.
> 
> For running containers, the function is called through attach_wait
> inside the container's namespace, for stopped container, the function is
> simply called recursively with a base path (container's rootfs) in an
> attempt to find containers that way.
> Communication between the parent lxc-ls and the child lxc-ls is done
> through a temporary fd and serialized state using json (similar to what
> was done using stdout in the previous implementation).
> 
> As get_global_config_item unfortunately caches the values, there's no
> easy way to figure out what the lxcpath should be for a root container
> when running as non-root, so just use @LXCPATH@ for now and have
> python do the parsing itself.
> 
> As a result, the following things now work as expected:
>  - listing nested unprivileged containers (root containers inside unpriv)
>  - listing nested containers when they're not running
>  - filtering containers in nesting mode (only the first level is filtered)
>  - copy with invalid config (used to traceback)
> 
> Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>

One change below,

Acked-by: Serge E. Hallyn <serge.hallyn at ubuntu.com>

...

> +# List of containers, stored as dictionaries
> +def get_containers(fd=None, base="/", root=False):
> +    containers = []
> +
> +    paths = [args.lxcpath]
> +
> +    if not root:
> +        paths.append(get_root_path(base))
> +
> +    # Generate a unique list of valid paths
> +    paths = set([os.path.normpath("%s/%s" % (base, path)) for path in paths])
> +
> +    for path in paths:
> +        if not os.access(path, os.R_OK):
> +            continue
> +
> +        for container_name in lxc.list_containers(config_path=path):
> +            entry = {}
> +            entry['name'] = container_name
> +
> +            # Apply filter
> +            if root and args.filter and \
> +               not re.match(args.filter, container_name):
> +                continue
> +
> +            # Return before grabbing the object (non-root)
> +            if not args.state and not args.fancy and not args.nesting:
> +                containers.append(entry)
> +                continue
> +
> +            try:
> +                container = lxc.Container(container_name, path)
> +            except:
> +                print("Invalid container: %s" % conainer_name, file=sys.stderr)
> +                pass

I think you meant continue here instead of pass?  Otherwise you
will proceed with a bogus 'container'.

> +
> +            if container.controllable:
> +                state = container.state
> +            else:
> +                state = 'UNKNOWN'
> +
> +            # Filter by status
> +            if args.state and state not in args.state:
> +                continue


More information about the lxc-devel mailing list