diff options
-rw-r--r-- | Makefile | 9 | ||||
-rw-r--r-- | OWNERS | 2 | ||||
-rw-r--r-- | cmd/podman/images.go | 2 | ||||
-rw-r--r-- | cmd/podman/info.go | 10 | ||||
-rw-r--r-- | contrib/spec/podman.spec.in | 1 | ||||
-rw-r--r-- | docs/podman-run.1.md | 26 | ||||
-rw-r--r-- | install.md | 1 | ||||
-rw-r--r-- | libpod/container_api.go | 2 | ||||
-rw-r--r-- | libpod/util.go | 73 | ||||
-rw-r--r-- | pkg/adapter/client.go | 50 | ||||
-rw-r--r-- | pkg/adapter/client_config.go | 32 | ||||
-rw-r--r-- | pkg/adapter/runtime.go | 5 | ||||
-rw-r--r-- | pkg/spec/spec.go | 8 | ||||
-rw-r--r-- | test/e2e/images_test.go | 13 |
14 files changed, 142 insertions, 92 deletions
@@ -259,14 +259,17 @@ changelog: ## Generate changelog $(shell cat $(TMPFILE) >> changelog.txt) $(shell rm $(TMPFILE)) -install: .gopathok install.bin install.man install.cni install.systemd ## Install binaries to system locations +install: .gopathok install.bin install.remote install.man install.cni install.systemd ## Install binaries to system locations + +install.remote: + install ${SELINUXOPT} -d -m 755 $(BINDIR) + install ${SELINUXOPT} -m 755 bin/podman-remote $(BINDIR)/podman-remote + test -z "${SELINUXOPT}" || chcon --verbose --reference=$(BINDIR)/podman bin/podman-remote install.bin: install ${SELINUXOPT} -d -m 755 $(BINDIR) install ${SELINUXOPT} -m 755 bin/podman $(BINDIR)/podman - install ${SELINUXOPT} -m 755 bin/podman-remote $(BINDIR)/podman-remote test -z "${SELINUXOPT}" || chcon --verbose --reference=$(BINDIR)/podman bin/podman - test -z "${SELINUXOPT}" || chcon --verbose --reference=$(BINDIR)/podman bin/podman-remote install.man: docs install ${SELINUXOPT} -d -m 755 $(MANDIR)/man1 @@ -7,6 +7,7 @@ approvers: - umohnani8 - giuseppe - vrothberg + - jwhonce reviewers: - mheon - baude @@ -16,3 +17,4 @@ reviewers: - umohnani8 - giuseppe - vrothberg + - jwhonce diff --git a/cmd/podman/images.go b/cmd/podman/images.go index 1c46571c3..3f755efc1 100644 --- a/cmd/podman/images.go +++ b/cmd/podman/images.go @@ -362,7 +362,7 @@ func CreateFilterFuncs(ctx context.Context, r *adapter.LocalRuntime, filters []s var filterFuncs []imagefilters.ResultFilter for _, filter := range filters { splitFilter := strings.Split(filter, "=") - if len(splitFilter) != 2 { + if len(splitFilter) < 2 { return nil, errors.Errorf("invalid filter syntax %s", filter) } switch splitFilter[0] { diff --git a/cmd/podman/info.go b/cmd/podman/info.go index a6fce7fcb..823303354 100644 --- a/cmd/podman/info.go +++ b/cmd/podman/info.go @@ -10,6 +10,7 @@ import ( "github.com/containers/libpod/pkg/adapter" "github.com/containers/libpod/version" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -60,7 +61,16 @@ func infoCmd(c *cliconfig.InfoValues) error { if err != nil { return errors.Wrapf(err, "error getting info") } + if runtime.Remote { + endpoint, err := runtime.RemoteEndpoint() + if err != nil { + logrus.Errorf("Failed to obtain server connection: %s", err.Error()) + } else { + remoteClientInfo["Connection"] = endpoint.Connection + remoteClientInfo["Connection Type"] = endpoint.Type.String() + } + remoteClientInfo["RemoteAPI Version"] = version.RemoteAPIVersion remoteClientInfo["Podman Version"] = version.Version remoteClientInfo["OS Arch"] = fmt.Sprintf("%s/%s", rt.GOOS, rt.GOARCH) diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in index 228f65b50..985dbbc74 100644 --- a/contrib/spec/podman.spec.in +++ b/contrib/spec/podman.spec.in @@ -387,6 +387,7 @@ popd install -dp %{buildroot}%{_unitdir} PODMAN_VERSION=%{version} %{__make} PREFIX=%{buildroot}%{_prefix} ETCDIR=%{buildroot}%{_sysconfdir} \ install.bin \ + install.remote \ install.man \ install.cni \ install.systemd \ diff --git a/docs/podman-run.1.md b/docs/podman-run.1.md index 1840e0f0b..210ed4f8a 100644 --- a/docs/podman-run.1.md +++ b/docs/podman-run.1.md @@ -291,16 +291,16 @@ The initialization time needed for a container to bootstrap. The value can be ex The maximum time allowed to complete the healthcheck before an interval is considered failed. Like start-period, the value can be expressed in a time format such as `1m22s`. The default value is `30s`. +**--help** + +Print usage statement + **--hostname**="" Container host name Sets the container host name that is available inside the container. -**--help** - -Print usage statement - **--http-proxy**=*true*|*false* By default proxy environment variables are passed into the container if set @@ -769,25 +769,11 @@ This option is incompatible with --gidmap, --uidmap, --subuid and --subgid Set the UTS mode for the container -`host`: use the host's UTS namespace inside the container. -`ns`: specify the user namespace to use. +- `host`: use the host's UTS namespace inside the container. +- `ns`: specify the user namespace to use. **NOTE**: the host mode gives the container access to changing the host's hostname and is therefore considered insecure. -**--userns**="" - -Set the user namespace mode for the container. The use of userns is disabled by default. - - **host**: use the host user namespace and enable all privileged options (e.g., `pid=host` or `--privileged`). - **ns**: specify the user namespace to use. - -**--uts**=*host* - -Set the UTS mode for the container - **host**: use the host's UTS namespace inside the container. - **ns**: specify the user namespace to use. - Note: the host mode gives the container access to changing the host's hostname and is therefore considered insecure. - **--volume**, **-v**[=*[HOST-DIR:CONTAINER-DIR[:OPTIONS]]*] Create a bind mount. If you specify, ` -v /HOST-DIR:/CONTAINER-DIR`, podman diff --git a/install.md b/install.md index a278cb4ba..ae74acdf8 100644 --- a/install.md +++ b/install.md @@ -91,7 +91,6 @@ Fedora, CentOS, RHEL, and related distributions: sudo yum install -y \ atomic-registries \ btrfs-progs-devel \ - conmon \ containernetworking-cni \ device-mapper-devel \ git \ diff --git a/libpod/container_api.go b/libpod/container_api.go index 06a31da11..eff5bfe5f 100644 --- a/libpod/container_api.go +++ b/libpod/container_api.go @@ -289,8 +289,8 @@ func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir chWait := make(chan error) go func() { chWait <- execCmd.Wait() + close(chWait) }() - defer close(chWait) pidFile := c.execPidPath(sessionID) // 60 second seems a reasonable time to wait diff --git a/libpod/util.go b/libpod/util.go index 7e2dff21a..3a15f9e39 100644 --- a/libpod/util.go +++ b/libpod/util.go @@ -90,11 +90,7 @@ func MountExists(specMounts []spec.Mount, dest string) bool { // WaitForFile waits until a file has been created or the given timeout has occurred func WaitForFile(path string, chWait chan error, timeout time.Duration) (bool, error) { - done := make(chan struct{}) - chControl := make(chan struct{}) - var inotifyEvents chan fsnotify.Event - var timer chan struct{} watcher, err := fsnotify.NewWatcher() if err == nil { if err := watcher.Add(filepath.Dir(path)); err == nil { @@ -102,51 +98,36 @@ func WaitForFile(path string, chWait chan error, timeout time.Duration) (bool, e } defer watcher.Close() } - if inotifyEvents == nil { - // If for any reason we fail to create the inotify - // watcher, fallback to polling the file - timer = make(chan struct{}) - go func() { - select { - case <-chControl: - close(timer) - return - default: - time.Sleep(25 * time.Millisecond) - timer <- struct{}{} - } - }() - } - go func() { - for { - select { - case <-chControl: - return - case <-timer: - _, err := os.Stat(path) - if err == nil { - close(done) - return - } - case <-inotifyEvents: - _, err := os.Stat(path) - if err == nil { - close(done) - return - } + timeoutChan := time.After(timeout) + + for { + select { + case e := <-chWait: + return true, e + case <-inotifyEvents: + _, err := os.Stat(path) + if err == nil { + return false, nil + } + if !os.IsNotExist(err) { + return false, errors.Wrapf(err, "checking file %s", path) + } + case <-time.After(25 * time.Millisecond): + // Check periodically for the file existence. It is needed + // if the inotify watcher could not have been created. It is + // also useful when using inotify as if for any reasons we missed + // a notification, we won't hang the process. + _, err := os.Stat(path) + if err == nil { + return false, nil + } + if !os.IsNotExist(err) { + return false, errors.Wrapf(err, "checking file %s", path) } + case <-timeoutChan: + return false, errors.Wrapf(ErrInternal, "timed out waiting for file %s", path) } - }() - - select { - case e := <-chWait: - return true, e - case <-done: - return false, nil - case <-time.After(timeout): - close(chControl) - return false, errors.Wrapf(ErrInternal, "timed out waiting for file %s", path) } } diff --git a/pkg/adapter/client.go b/pkg/adapter/client.go index f672a92a6..01914834f 100644 --- a/pkg/adapter/client.go +++ b/pkg/adapter/client.go @@ -10,44 +10,56 @@ import ( "github.com/varlink/go/varlink" ) -type VarlinkConnectionInfo struct { - RemoteUserName string - RemoteHost string - VarlinkAddress string -} - -// Connect provides a varlink connection -func (r RemoteRuntime) Connect() (*varlink.Connection, error) { - var ( - err error - connection *varlink.Connection - ) +var remoteEndpoint *Endpoint - logLevel := r.cmd.LogLevel +func (r RemoteRuntime) RemoteEndpoint() (remoteEndpoint *Endpoint, err error) { + if remoteEndpoint == nil { + remoteEndpoint = &Endpoint{Unknown, ""} + } else { + return remoteEndpoint, nil + } // I'm leaving this here for now as a document of the birdge format. It can be removed later once the bridge // function is more flushed out. - //bridge := `ssh -T root@192.168.122.1 "/usr/bin/varlink -A '/usr/bin/podman varlink \$VARLINK_ADDRESS' bridge"` + // bridge := `ssh -T root@192.168.122.1 "/usr/bin/varlink -A '/usr/bin/podman varlink \$VARLINK_ADDRESS' bridge"` if len(r.cmd.RemoteHost) > 0 { // The user has provided a remote host endpoint if len(r.cmd.RemoteUserName) < 1 { return nil, errors.New("you must provide a username when providing a remote host name") } - bridge := fmt.Sprintf(`ssh -T %s@%s /usr/bin/varlink -A \'/usr/bin/podman --log-level=%s varlink \\\$VARLINK_ADDRESS\' bridge`, r.cmd.RemoteUserName, r.cmd.RemoteHost, logLevel) - connection, err = varlink.NewBridge(bridge) + remoteEndpoint.Type = BridgeConnection + remoteEndpoint.Connection = fmt.Sprintf( + `ssh -T %s@%s /usr/bin/varlink -A \'/usr/bin/podman --log-level=%s varlink \\\$VARLINK_ADDRESS\' bridge`, + r.cmd.RemoteUserName, r.cmd.RemoteHost, r.cmd.LogLevel) + } else if bridge := os.Getenv("PODMAN_VARLINK_BRIDGE"); bridge != "" { - connection, err = varlink.NewBridge(bridge) + remoteEndpoint.Type = BridgeConnection + remoteEndpoint.Connection = bridge } else { address := os.Getenv("PODMAN_VARLINK_ADDRESS") if address == "" { address = DefaultAddress } - connection, err = varlink.NewConnection(address) + remoteEndpoint.Type = DirectConnection + remoteEndpoint.Connection = address } + return +} + +// Connect provides a varlink connection +func (r RemoteRuntime) Connect() (*varlink.Connection, error) { + ep, err := r.RemoteEndpoint() if err != nil { return nil, err } - return connection, nil + + switch ep.Type { + case DirectConnection: + return varlink.NewConnection(ep.Connection) + case BridgeConnection: + return varlink.NewBridge(ep.Connection) + } + return nil, errors.New(fmt.Sprintf("Unable to determine type of varlink connection: %s", ep.Connection)) } // RefreshConnection is used to replace the current r.Conn after things like diff --git a/pkg/adapter/client_config.go b/pkg/adapter/client_config.go index d165ef1cc..3559b16e3 100644 --- a/pkg/adapter/client_config.go +++ b/pkg/adapter/client_config.go @@ -2,3 +2,35 @@ package adapter // DefaultAddress is the default address of the varlink socket const DefaultAddress = "unix:/run/podman/io.podman" + +// EndpointType declares the type of server connection +type EndpointType int + +// Enum of connection types +const ( + Unknown = iota - 1 // Unknown connection type + BridgeConnection // BridgeConnection proxy connection via ssh + DirectConnection // DirectConnection socket connection to server +) + +// String prints ASCII string for EndpointType +func (e EndpointType) String() string { + // declare an array of strings + // ... operator counts how many + // items in the array (7) + names := [...]string{ + "BridgeConnection", + "DirectConnection", + } + + if e < BridgeConnection || e > DirectConnection { + return "Unknown" + } + return names[e] +} + +// Endpoint type and connection string to use +type Endpoint struct { + Type EndpointType + Connection string +} diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go index 21613c425..37ee1b737 100644 --- a/pkg/adapter/runtime.go +++ b/pkg/adapter/runtime.go @@ -398,3 +398,8 @@ func (r *LocalRuntime) GetPodsByStatus(statuses []string) ([]*libpod.Pod, error) func (r *LocalRuntime) GetVersion() (libpod.Version, error) { return libpod.GetVersion() } + +// RemoteEndpoint resolve interface requirement +func (r *LocalRuntime) RemoteEndpoint() (*Endpoint, error) { + return nil, errors.New("RemoteEndpoint() not implemented for local connection") +} diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go index c2c5e0900..0d953ff6f 100644 --- a/pkg/spec/spec.go +++ b/pkg/spec/spec.go @@ -268,7 +268,9 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM // SECURITY OPTS g.SetProcessNoNewPrivileges(config.NoNewPrivs) - g.SetProcessApparmorProfile(config.ApparmorProfile) + if !config.Privileged { + g.SetProcessApparmorProfile(config.ApparmorProfile) + } blockAccessToKernelFilesystems(config, &g) @@ -355,6 +357,10 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM if addedResources && !cgroup2 { return nil, errors.New("invalid configuration, cannot set resources with rootless containers not using cgroups v2 unified mode") } + if !cgroup2 { + // Force the resources block to be empty instead of having default values. + configSpec.Linux.Resources = &spec.LinuxResources{} + } } // Make sure that the bind mounts keep options like nosuid, noexec, nodev. diff --git a/test/e2e/images_test.go b/test/e2e/images_test.go index bec6e304b..23455163b 100644 --- a/test/e2e/images_test.go +++ b/test/e2e/images_test.go @@ -298,4 +298,17 @@ ENV foo=bar Expect(session2.ExitCode()).To(Equal(0)) Expect(len(session2.OutputToStringArray())).To(Equal(6)) }) + + It("podman images filter by label", func() { + SkipIfRemote() + dockerfile := `FROM docker.io/library/alpine:latest +LABEL version="1.0" +LABEL "com.example.vendor"="Example Vendor" +` + podmanTest.BuildImage(dockerfile, "test", "true") + session := podmanTest.Podman([]string{"images", "-f", "label=version=1.0"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(len(session.OutputToStringArray())).To(Equal(2)) + }) }) |