Skip to content

Commit

Permalink
Merge pull request #9950 from Luap99/unshare-rootless-cni
Browse files Browse the repository at this point in the history
podman unshare: add --rootless-cni to join the ns
  • Loading branch information
openshift-merge-robot authored Apr 12, 2021
2 parents 0d9b1b8 + 0a39ad1 commit 3b03ff7
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 22 deletions.
6 changes: 4 additions & 2 deletions cmd/podman/system/unshare.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ import (
)

var (
unshareOptions = entities.SystemUnshareOptions{}
unshareDescription = "Runs a command in a modified user namespace."
unshareCommand = &cobra.Command{
Use: "unshare [COMMAND [ARG...]]",
Use: "unshare [options] [COMMAND [ARG...]]",
DisableFlagsInUseLine: true,
Short: "Run a command in a modified user namespace",
Long: unshareDescription,
Expand All @@ -33,6 +34,7 @@ func init() {
})
flags := unshareCommand.Flags()
flags.SetInterspersed(false)
flags.BoolVar(&unshareOptions.RootlessCNI, "rootless-cni", false, "Join the rootless network namespace used for CNI networking")
}

func unshare(cmd *cobra.Command, args []string) error {
Expand All @@ -49,5 +51,5 @@ func unshare(cmd *cobra.Command, args []string) error {
args = []string{shell}
}

return registry.ContainerEngine().Unshare(registry.Context(), args)
return registry.ContainerEngine().Unshare(registry.Context(), args, unshareOptions)
}
37 changes: 37 additions & 0 deletions docs/source/markdown/podman-unshare.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@ The unshare session defines two environment variables:
- **CONTAINERS_GRAPHROOT**: the path to the persistent container's data.
- **CONTAINERS_RUNROOT**: the path to the volatile container's data.

## OPTIONS

#### **\-\-help**, **-h**

Print usage statement

#### **\-\-rootless-cni**

Join the rootless network namespace used for CNI networking. It can be used to
connect to a rootless container via IP address (CNI networking). This is otherwise
not possible from the host network namespace.
_Note: Using this option with more than one unshare session can have unexpected results._

## EXAMPLE

```
Expand All @@ -35,6 +48,30 @@ $ podman unshare cat /proc/self/uid_map /proc/self/gid_map
1 10000 65536
0 1000 1
1 10000 65536
$ podman unshare --rootless-cni ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: tap0: <BROADCAST,UP,LOWER_UP> mtu 65520 qdisc fq_codel state UNKNOWN group default qlen 1000
link/ether 36:0e:4a:c7:45:7e brd ff:ff:ff:ff:ff:ff
inet 10.0.2.100/24 brd 10.0.2.255 scope global tap0
valid_lft forever preferred_lft forever
inet6 fe80::340e:4aff:fec7:457e/64 scope link
valid_lft forever preferred_lft forever
3: cni-podman2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 5e:3a:71:d2:b4:3a brd ff:ff:ff:ff:ff:ff
inet 10.89.1.1/24 brd 10.89.1.255 scope global cni-podman2
valid_lft forever preferred_lft forever
inet6 fe80::5c3a:71ff:fed2:b43a/64 scope link
valid_lft forever preferred_lft forever
4: vethd4ba3a2f@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master cni-podman2 state UP group default
link/ether 8a:c9:56:32:17:0c brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::88c9:56ff:fe32:170c/64 scope link
valid_lft forever preferred_lft forever
```


Expand Down
27 changes: 16 additions & 11 deletions libpod/networking_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,13 @@ func (r *Runtime) getPodNetwork(id, name, nsPath string, networks []string, port
return ctrNetwork
}

type rootlessCNI struct {
type RootlessCNI struct {
ns ns.NetNS
dir string
lock lockfile.Locker
}

func (r *rootlessCNI) Do(toRun func() error) error {
func (r *RootlessCNI) Do(toRun func() error) error {
err := r.ns.Do(func(_ ns.NetNS) error {
// before we can run the given function
// we have to setup all mounts correctly
Expand Down Expand Up @@ -174,9 +174,14 @@ func (r *rootlessCNI) Do(toRun func() error) error {
return err
}

// cleanup the rootless cni namespace if needed
// Cleanup the rootless cni namespace if needed
// check if we have running containers with the bridge network mode
func (r *rootlessCNI) cleanup(runtime *Runtime) error {
func (r *RootlessCNI) Cleanup(runtime *Runtime) error {
_, err := os.Stat(r.dir)
if os.IsNotExist(err) {
// the directory does not exists no need for cleanup
return nil
}
r.lock.Lock()
defer r.lock.Unlock()
running := func(c *Container) bool {
Expand Down Expand Up @@ -234,10 +239,10 @@ func (r *rootlessCNI) cleanup(runtime *Runtime) error {
return nil
}

// getRootlessCNINetNs returns the rootless cni object. If create is set to true
// GetRootlessCNINetNs returns the rootless cni object. If create is set to true
// the rootless cni namespace will be created if it does not exists already.
func (r *Runtime) getRootlessCNINetNs(new bool) (*rootlessCNI, error) {
var rootlessCNINS *rootlessCNI
func (r *Runtime) GetRootlessCNINetNs(new bool) (*RootlessCNI, error) {
var rootlessCNINS *RootlessCNI
if rootless.IsRootless() {
runDir, err := util.GetRuntimeDir()
if err != nil {
Expand Down Expand Up @@ -421,7 +426,7 @@ func (r *Runtime) getRootlessCNINetNs(new bool) (*rootlessCNI, error) {
os.Setenv("PATH", path)
}

rootlessCNINS = &rootlessCNI{
rootlessCNINS = &RootlessCNI{
ns: ns,
dir: cniDir,
lock: lock,
Expand All @@ -433,7 +438,7 @@ func (r *Runtime) getRootlessCNINetNs(new bool) (*rootlessCNI, error) {
// setUpOCICNIPod will set up the cni networks, on error it will also tear down the cni
// networks. If rootless it will join/create the rootless cni namespace.
func (r *Runtime) setUpOCICNIPod(podNetwork ocicni.PodNetwork) ([]ocicni.NetResult, error) {
rootlessCNINS, err := r.getRootlessCNINetNs(true)
rootlessCNINS, err := r.GetRootlessCNINetNs(true)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -651,7 +656,7 @@ func (r *Runtime) closeNetNS(ctr *Container) error {
// Tear down a container's CNI network configuration and joins the
// rootless net ns as rootless user
func (r *Runtime) teardownOCICNIPod(podNetwork ocicni.PodNetwork) error {
rootlessCNINS, err := r.getRootlessCNINetNs(false)
rootlessCNINS, err := r.GetRootlessCNINetNs(false)
if err != nil {
return err
}
Expand All @@ -665,7 +670,7 @@ func (r *Runtime) teardownOCICNIPod(podNetwork ocicni.PodNetwork) error {
// execute the cni setup in the rootless net ns
err = rootlessCNINS.Do(tearDownPod)
if err == nil {
err = rootlessCNINS.cleanup(r)
err = rootlessCNINS.Cleanup(r)
}
} else {
err = tearDownPod()
Expand Down
2 changes: 1 addition & 1 deletion pkg/domain/entities/engine_container.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ type ContainerEngine interface {
SecretRm(ctx context.Context, nameOrID []string, opts SecretRmOptions) ([]*SecretRmReport, error)
Shutdown(ctx context.Context)
SystemDf(ctx context.Context, options SystemDfOptions) (*SystemDfReport, error)
Unshare(ctx context.Context, args []string) error
Unshare(ctx context.Context, args []string, options SystemUnshareOptions) error
Version(ctx context.Context) (*SystemVersionReport, error)
VolumeCreate(ctx context.Context, opts VolumeCreateOptions) (*IDOrNameResponse, error)
VolumeExists(ctx context.Context, namesOrID string) (*BoolReport, error)
Expand Down
5 changes: 5 additions & 0 deletions pkg/domain/entities/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ type SystemVersionReport struct {
Server *define.Version `json:",omitempty"`
}

// SystemUnshareOptions describes the options for the unshare command
type SystemUnshareOptions struct {
RootlessCNI bool
}

type ComponentVersion struct {
types.Version
}
Expand Down
26 changes: 19 additions & 7 deletions pkg/domain/infra/abi/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,13 +390,25 @@ func unshareEnv(graphroot, runroot string) []string {
fmt.Sprintf("CONTAINERS_RUNROOT=%s", runroot))
}

func (ic *ContainerEngine) Unshare(ctx context.Context, args []string) error {
cmd := exec.Command(args[0], args[1:]...)
cmd.Env = unshareEnv(ic.Libpod.StorageConfig().GraphRoot, ic.Libpod.StorageConfig().RunRoot)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
func (ic *ContainerEngine) Unshare(ctx context.Context, args []string, options entities.SystemUnshareOptions) error {
unshare := func() error {
cmd := exec.Command(args[0], args[1:]...)
cmd.Env = unshareEnv(ic.Libpod.StorageConfig().GraphRoot, ic.Libpod.StorageConfig().RunRoot)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}

if options.RootlessCNI {
rootlesscni, err := ic.Libpod.GetRootlessCNINetNs(true)
if err != nil {
return err
}
defer rootlesscni.Cleanup(ic.Libpod)
return rootlesscni.Do(unshare)
}
return unshare()
}

func (ic ContainerEngine) Version(ctx context.Context) (*entities.SystemVersionReport, error) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/domain/infra/tunnel/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
return system.DiskUsage(ic.ClientCtx, nil)
}

func (ic *ContainerEngine) Unshare(ctx context.Context, args []string) error {
func (ic *ContainerEngine) Unshare(ctx context.Context, args []string, options entities.SystemUnshareOptions) error {
return errors.New("unshare is not supported on remote clients")
}

Expand Down
7 changes: 7 additions & 0 deletions test/e2e/unshare_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,11 @@ var _ = Describe("Podman unshare", func() {
ok, _ := session.GrepString(userNS)
Expect(ok).To(BeFalse())
})

It("podman unshare --rootles-cni", func() {
session := podmanTest.Podman([]string{"unshare", "--rootless-cni", "ip", "addr"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("tap0"))
})
})

0 comments on commit 3b03ff7

Please sign in to comment.