summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/create.go2
-rw-r--r--cmd/podman/inspect.go7
-rw-r--r--cmd/podman/main.go1
-rw-r--r--cmd/podman/pull.go20
-rw-r--r--cmd/podman/push.go18
-rw-r--r--cmd/podman/search.go290
-rw-r--r--completions/bash/podman14
-rw-r--r--docs/podman-build.1.md3
-rw-r--r--docs/podman-inspect.1.md10
-rw-r--r--docs/podman-login.1.md3
-rw-r--r--docs/podman-pull.1.md7
-rw-r--r--docs/podman-push.1.md7
-rw-r--r--docs/podman-search.1.md115
-rw-r--r--docs/podman-stop.1.md4
-rw-r--r--docs/tutorials/podman_tutorial.md42
-rw-r--r--libpod/common/common.go28
-rw-r--r--libpod/container_api.go9
-rw-r--r--libpod/oci.go1
-rw-r--r--package_specs/podman.spec464
-rw-r--r--pkg/inspect/inspect.go6
-rw-r--r--pkg/util/utils.go46
-rwxr-xr-xtest/demos.sh93
-rw-r--r--test/e2e/create_test.go2
-rw-r--r--test/e2e/inspect_test.go5
-rw-r--r--test/podman_search.bats43
-rw-r--r--transfer.md2
-rw-r--r--vendor.conf2
-rw-r--r--vendor/github.com/containers/image/directory/directory_dest.go2
-rw-r--r--vendor/github.com/containers/image/docker/docker_client.go190
-rw-r--r--vendor/github.com/containers/image/docker/docker_image_dest.go8
-rw-r--r--vendor/github.com/containers/image/image/oci.go10
-rw-r--r--vendor/github.com/containers/image/ostree/ostree_dest.go10
-rw-r--r--vendor/github.com/containers/image/tarball/tarball_reference.go2
33 files changed, 1329 insertions, 137 deletions
diff --git a/cmd/podman/create.go b/cmd/podman/create.go
index ac6bc2969..b3aa42b8a 100644
--- a/cmd/podman/create.go
+++ b/cmd/podman/create.go
@@ -527,7 +527,7 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime, imageName string,
}
// STOP SIGNAL
- stopSignal := syscall.SIGINT
+ stopSignal := syscall.SIGTERM
signalString := data.Config.StopSignal
if c.IsSet("stop-signal") {
signalString = c.String("stop-signal")
diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go
index 2e70eaa0a..ba7b17ed7 100644
--- a/cmd/podman/inspect.go
+++ b/cmd/podman/inspect.go
@@ -2,6 +2,7 @@ package main
import (
"encoding/json"
+
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/projectatomic/libpod/cmd/podman/formats"
@@ -163,8 +164,8 @@ func getCtrInspectInfo(ctr *libpod.Container, ctrInspectData *inspect.ContainerI
}
data := &inspect.ContainerData{
- CtrInspectData: ctrInspectData,
- HostConfig: &inspect.HostConfig{
+ ctrInspectData,
+ &inspect.HostConfig{
ConsoleSize: spec.Process.ConsoleSize,
OomScoreAdj: spec.Process.OOMScoreAdj,
CPUShares: shares,
@@ -210,7 +211,7 @@ func getCtrInspectInfo(ctr *libpod.Container, ctrInspectData *inspect.ContainerI
Ulimits: createArtifact.Resources.Ulimit,
SecurityOpt: createArtifact.SecurityOpts,
},
- Config: &inspect.CtrConfig{
+ &inspect.CtrConfig{
Hostname: spec.Hostname,
User: spec.Process.User,
Env: spec.Process.Env,
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index bda8ff517..f18615760 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -64,6 +64,7 @@ func main() {
rmiCommand,
runCommand,
saveCommand,
+ searchCommand,
startCommand,
statsCommand,
stopCommand,
diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go
index 5726b20f1..c19e6715b 100644
--- a/cmd/podman/pull.go
+++ b/cmd/podman/pull.go
@@ -1,16 +1,14 @@
package main
import (
- "fmt"
"io"
"os"
- "golang.org/x/crypto/ssh/terminal"
-
"github.com/containers/image/types"
"github.com/pkg/errors"
"github.com/projectatomic/libpod/libpod"
"github.com/projectatomic/libpod/libpod/common"
+ "github.com/projectatomic/libpod/pkg/util"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
@@ -80,19 +78,11 @@ func pullCmd(c *cli.Context) error {
image := args[0]
var registryCreds *types.DockerAuthConfig
- if c.String("creds") != "" {
- creds, err := common.ParseRegistryCreds(c.String("creds"))
+
+ if c.IsSet("creds") {
+ creds, err := util.ParseRegistryCreds(c.String("creds"))
if err != nil {
- if err == common.ErrNoPassword {
- fmt.Print("Password: ")
- password, err := terminal.ReadPassword(0)
- if err != nil {
- return errors.Wrapf(err, "could not read password from terminal")
- }
- creds.Password = string(password)
- } else {
- return err
- }
+ return err
}
registryCreds = creds
}
diff --git a/cmd/podman/push.go b/cmd/podman/push.go
index 69d6e6629..2f0d73ffa 100644
--- a/cmd/podman/push.go
+++ b/cmd/podman/push.go
@@ -13,8 +13,8 @@ import (
"github.com/pkg/errors"
"github.com/projectatomic/libpod/libpod"
"github.com/projectatomic/libpod/libpod/common"
+ "github.com/projectatomic/libpod/pkg/util"
"github.com/urfave/cli"
- "golang.org/x/crypto/ssh/terminal"
)
var (
@@ -97,25 +97,15 @@ func pushCmd(c *cli.Context) error {
}
}
- registryCredsString := c.String("creds")
certPath := c.String("cert-dir")
skipVerify := !c.BoolT("tls-verify")
removeSignatures := c.Bool("remove-signatures")
signBy := c.String("sign-by")
- if registryCredsString != "" {
- creds, err := common.ParseRegistryCreds(registryCredsString)
+ if c.IsSet("creds") {
+ creds, err := util.ParseRegistryCreds(c.String("creds"))
if err != nil {
- if err == common.ErrNoPassword {
- fmt.Print("Password: ")
- password, err := terminal.ReadPassword(0)
- if err != nil {
- return errors.Wrapf(err, "could not read password from terminal")
- }
- creds.Password = string(password)
- } else {
- return err
- }
+ return err
}
registryCreds = creds
}
diff --git a/cmd/podman/search.go b/cmd/podman/search.go
new file mode 100644
index 000000000..01eaa6729
--- /dev/null
+++ b/cmd/podman/search.go
@@ -0,0 +1,290 @@
+package main
+
+import (
+ "context"
+ "reflect"
+ "strconv"
+ "strings"
+
+ "github.com/containers/image/docker"
+ "github.com/pkg/errors"
+ "github.com/projectatomic/libpod/cmd/podman/formats"
+ "github.com/projectatomic/libpod/libpod"
+ "github.com/projectatomic/libpod/libpod/common"
+ "github.com/sirupsen/logrus"
+ "github.com/urfave/cli"
+)
+
+const (
+ descriptionTruncLength = 44
+ maxQueries = 25
+)
+
+var (
+ searchFlags = []cli.Flag{
+ cli.StringSliceFlag{
+ Name: "filter, f",
+ Usage: "filter output based on conditions provided (default [])",
+ },
+ cli.StringFlag{
+ Name: "format",
+ Usage: "change the output format to a Go template",
+ },
+ cli.IntFlag{
+ Name: "limit",
+ Usage: "limit the number of results",
+ },
+ cli.BoolFlag{
+ Name: "no-trunc",
+ Usage: "do not truncate the output",
+ },
+ cli.StringSliceFlag{
+ Name: "registry",
+ Usage: "specific registry to search",
+ },
+ }
+ searchDescription = `
+ Search registries for a given image. Can search all the default registries or a specific registry.
+ Can limit the number of results, and filter the output based on certain conditions.`
+ searchCommand = cli.Command{
+ Name: "search",
+ Usage: "search registry for image",
+ Description: searchDescription,
+ Flags: searchFlags,
+ Action: searchCmd,
+ ArgsUsage: "TERM",
+ }
+)
+
+type searchParams struct {
+ Index string
+ Name string
+ Description string
+ Stars int
+ Official string
+ Automated string
+}
+
+type searchOpts struct {
+ filter []string
+ limit int
+ noTrunc bool
+ format string
+}
+
+type searchFilterParams struct {
+ stars int
+ isAutomated *bool
+ isOfficial *bool
+}
+
+func searchCmd(c *cli.Context) error {
+ args := c.Args()
+ if len(args) > 1 {
+ return errors.Errorf("too many arguments. Requires exactly 1")
+ }
+ if len(args) == 0 {
+ return errors.Errorf("no argument given, requires exactly 1 argument")
+ }
+ term := args[0]
+
+ if err := validateFlags(c, searchFlags); err != nil {
+ return err
+ }
+
+ runtime, err := getRuntime(c)
+ if err != nil {
+ return errors.Wrapf(err, "could not get runtime")
+ }
+ defer runtime.Shutdown(false)
+
+ format := genSearchFormat(c.String("format"))
+ opts := searchOpts{
+ format: format,
+ noTrunc: c.Bool("no-trunc"),
+ limit: c.Int("limit"),
+ filter: c.StringSlice("filter"),
+ }
+
+ var registries []string
+ if len(c.StringSlice("registry")) > 0 {
+ registries = c.StringSlice("registry")
+ } else {
+ registries, err = libpod.GetRegistries()
+ if err != nil {
+ return errors.Wrapf(err, "error getting registries to search")
+ }
+ }
+
+ filter, err := parseSearchFilter(&opts)
+ if err != nil {
+ return err
+ }
+
+ return generateSearchOutput(term, registries, opts, *filter)
+}
+
+func genSearchFormat(format string) string {
+ if format != "" {
+ // "\t" from the command line is not being recognized as a tab
+ // replacing the string "\t" to a tab character if the user passes in "\t"
+ return strings.Replace(format, `\t`, "\t", -1)
+ }
+ return "table {{.Index}}\t{{.Name}}\t{{.Description}}\t{{.Stars}}\t{{.Official}}\t{{.Automated}}\t"
+}
+
+func searchToGeneric(params []searchParams) (genericParams []interface{}) {
+ for _, v := range params {
+ genericParams = append(genericParams, interface{}(v))
+ }
+ return genericParams
+}
+
+func (s *searchParams) headerMap() map[string]string {
+ v := reflect.Indirect(reflect.ValueOf(s))
+ values := make(map[string]string, v.NumField())
+
+ for i := 0; i < v.NumField(); i++ {
+ key := v.Type().Field(i).Name
+ value := key
+ values[key] = strings.ToUpper(splitCamelCase(value))
+ }
+ return values
+}
+
+func getSearchOutput(term string, registries []string, opts searchOpts, filter searchFilterParams) ([]searchParams, error) {
+ sc := common.GetSystemContext("", "", false)
+ // Max number of queries by default is 25
+ limit := maxQueries
+ if opts.limit != 0 {
+ limit = opts.limit
+ }
+
+ var paramsArr []searchParams
+ for _, reg := range registries {
+ results, err := docker.SearchRegistry(context.TODO(), sc, reg, term, limit)
+ if err != nil {
+ logrus.Errorf("error searching registry %q: %v", reg, err)
+ continue
+ }
+ index := reg
+ arr := strings.Split(reg, ".")
+ if len(arr) > 2 {
+ index = strings.Join(arr[len(arr)-2:], ".")
+ }
+
+ // limit is the number of results to output
+ // if the total number of results is less than the limit, output all
+ // if the limit has been set by the user, output those number of queries
+ limit := maxQueries
+ if len(results) < limit {
+ limit = len(results)
+ }
+ if opts.limit != 0 && opts.limit < len(results) {
+ limit = opts.limit
+ }
+
+ for i := 0; i < limit; i++ {
+ if len(opts.filter) > 0 {
+ // Check whether query matches filters
+ if !(matchesAutomatedFilter(filter, results[i]) && matchesOfficialFilter(filter, results[i]) && matchesStarFilter(filter, results[i])) {
+ continue
+ }
+ }
+ official := ""
+ if results[i].IsOfficial {
+ official = "[OK]"
+ }
+ automated := ""
+ if results[i].IsAutomated {
+ automated = "[OK]"
+ }
+ description := strings.Replace(results[i].Description, "\n", " ", -1)
+ if len(description) > 44 && !opts.noTrunc {
+ description = description[:descriptionTruncLength] + "..."
+ }
+ name := index + "/" + results[i].Name
+ if index == "docker.io" && !strings.Contains(results[i].Name, "/") {
+ name = index + "/library/" + results[i].Name
+ }
+ params := searchParams{
+ Index: index,
+ Name: name,
+ Description: description,
+ Official: official,
+ Automated: automated,
+ Stars: results[i].StarCount,
+ }
+ paramsArr = append(paramsArr, params)
+ }
+ }
+ return paramsArr, nil
+}
+
+func generateSearchOutput(term string, registries []string, opts searchOpts, filter searchFilterParams) error {
+ searchOutput, err := getSearchOutput(term, registries, opts, filter)
+ if err != nil {
+ return err
+ }
+ if len(searchOutput) == 0 {
+ return nil
+ }
+ out := formats.StdoutTemplateArray{Output: searchToGeneric(searchOutput), Template: opts.format, Fields: searchOutput[0].headerMap()}
+ return formats.Writer(out).Out()
+}
+
+func parseSearchFilter(opts *searchOpts) (*searchFilterParams, error) {
+ filterParams := &searchFilterParams{}
+ ptrTrue := true
+ ptrFalse := false
+ for _, filter := range opts.filter {
+ arr := strings.Split(filter, "=")
+ switch arr[0] {
+ case "stars":
+ if len(arr) < 2 {
+ return nil, errors.Errorf("invalid `stars` filter %q, should be stars=<value>", filter)
+ }
+ stars, err := strconv.Atoi(arr[1])
+ if err != nil {
+ return nil, errors.Wrapf(err, "incorrect value type for stars filter")
+ }
+ filterParams.stars = stars
+ break
+ case "is-automated":
+ if len(arr) == 2 && arr[1] == "false" {
+ filterParams.isAutomated = &ptrFalse
+ } else {
+ filterParams.isAutomated = &ptrTrue
+ }
+ break
+ case "is-official":
+ if len(arr) == 2 && arr[1] == "false" {
+ filterParams.isOfficial = &ptrFalse
+ } else {
+ filterParams.isOfficial = &ptrTrue
+ }
+ break
+ default:
+ return nil, errors.Errorf("invalid filter type %q", filter)
+ }
+ }
+ return filterParams, nil
+}
+
+func matchesStarFilter(filter searchFilterParams, result docker.SearchResult) bool {
+ return result.StarCount >= filter.stars
+}
+
+func matchesAutomatedFilter(filter searchFilterParams, result docker.SearchResult) bool {
+ if filter.isAutomated != nil {
+ return result.IsAutomated == *filter.isAutomated
+ }
+ return true
+}
+
+func matchesOfficialFilter(filter searchFilterParams, result docker.SearchResult) bool {
+ if filter.isOfficial != nil {
+ return result.IsOfficial == *filter.isOfficial
+ }
+ return true
+}
diff --git a/completions/bash/podman b/completions/bash/podman
index 0087c56b9..b1033df1c 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -954,6 +954,19 @@ _podman_pull() {
_complete_ "$options_with_args" "$boolean_options"
}
+_podman_search() {
+ local options_with_args="
+ --filter -f
+ --format
+ --limit
+ --registry
+ "
+ local boolean_options="
+ --no-trunc
+ "
+ _complete_ "$options_with_args" "$boolean_options"
+}
+
_podman_unmount() {
_podman_umount $@
}
@@ -1589,6 +1602,7 @@ _podman_podman() {
rmi
run
save
+ search
start
stats
stop
diff --git a/docs/podman-build.1.md b/docs/podman-build.1.md
index 61c8d8aaa..d4e9af175 100644
--- a/docs/podman-build.1.md
+++ b/docs/podman-build.1.md
@@ -38,7 +38,8 @@ resulting image's configuration.
**--cert-dir** *path*
-Use certificates at *path* (*.crt, *.cert, *.key) to connect to the registry
+Use certificates at *path* (*.crt, *.cert, *.key) to connect to the registry.
+Default certificates directory is _/etc/containers/certs.d_.
**--creds** *creds*
diff --git a/docs/podman-inspect.1.md b/docs/podman-inspect.1.md
index 5b8a344d7..e40dfa29f 100644
--- a/docs/podman-inspect.1.md
+++ b/docs/podman-inspect.1.md
@@ -79,6 +79,16 @@ Display the total file size if the type is a container
}
```
+```
+# podman inspect a04 --format "{{.ImageName}}"
+fedora
+```
+
+```
+$ sudo podman inspect a04 --format "{{.GraphDriver.Name}}"
+overlay
+```
+
## SEE ALSO
podman(1)
diff --git a/docs/podman-login.1.md b/docs/podman-login.1.md
index fcf32870a..b22a02553 100644
--- a/docs/podman-login.1.md
+++ b/docs/podman-login.1.md
@@ -38,7 +38,8 @@ Username for registry
Path of the authentication file. Default is ${XDG_\RUNTIME\_DIR}/containers/auth.json
**--cert-dir**
-Pathname of a directory containing TLS certificates and keys used to connect to the registry
+Pathname of a directory containing TLS certificates and keys used to connect to the registry.
+Default certificates directory is _/etc/containers/certs.d_.
**--tls-verify**
Require HTTPS and verify certificates when contacting registries (default: true)
diff --git a/docs/podman-pull.1.md b/docs/podman-pull.1.md
index b1212ee6b..1a1611fd0 100644
--- a/docs/podman-pull.1.md
+++ b/docs/podman-pull.1.md
@@ -61,11 +61,14 @@ If the authorization state is not found there, $HOME/.docker/config.json is chec
**--cert-dir**
-Pathname of a directory containing TLS certificates and keys
+Pathname of a directory containing TLS certificates and keys.
+Default certificates directory is _/etc/containers/certs.d_.
**--creds**
-Credentials (USERNAME:PASSWORD) to use for authenticating to a registry
+The [username[:password]] to use to authenticate with the registry if required.
+If one or both values are not supplied, a command line prompt will appear and the
+value can be entered. The password is entered without echo.
**--quiet, -q**
diff --git a/docs/podman-push.1.md b/docs/podman-push.1.md
index 63c75ea36..964758da6 100644
--- a/docs/podman-push.1.md
+++ b/docs/podman-push.1.md
@@ -53,11 +53,14 @@ If the authorization state is not found there, $HOME/.docker/config.json is chec
**--creds="CREDENTIALS"**
-Credentials (USERNAME:PASSWORD) to use for authenticating to a registry
+The [username[:password]] to use to authenticate with the registry if required.
+If one or both values are not supplied, a command line prompt will appear and the
+value can be entered. The password is entered without echo.
**cert-dir="PATHNAME"**
-Pathname of a directory containing TLS certificates and keys
+Pathname of a directory containing TLS certificates and keys.
+Default certificates directory is _/etc/containers/certs.d_.
**--compress**
diff --git a/docs/podman-search.1.md b/docs/podman-search.1.md
new file mode 100644
index 000000000..668748d3f
--- /dev/null
+++ b/docs/podman-search.1.md
@@ -0,0 +1,115 @@
+% podman(1) podman-search - Tool to search registries for an image
+% Urvashi Mohnani
+# podman-search "1" "January 2018" "podman"
+
+## NAME
+podman search - Search a registry for an image
+
+## SYNOPSIS
+**podman search**
+**TERM**
+[**--filter**|**-f**]
+[**--format**]
+[**--limit**]
+[**--no-trunc**]
+[**--registry**]
+[**--help**|**-h**]
+
+## DESCRIPTION
+**podman search** searches a registry or a list of registries for a matching image.
+The user can specify which registry to search by setting the **--registry** flag, default
+is the default registries set in the config file - **/etc/containers/registries.conf**.
+The number of results can be limited using the **--limit** flag. If more than one registry
+is being searched, the limit will be applied to each registry. The output can be filtered
+using the **--filter** flag.
+
+**podman [GLOBAL OPTIONS]**
+
+**podman search [GLOBAL OPTIONS]**
+
+**podman search [OPTIONS] TERM**
+
+## OPTIONS
+
+**--filter, -f**
+Filter output based on conditions provided (default [])
+
+Supported filters are:
+- stars (int - number of stars the image has)
+- is-automated (boolean - true | false) - is the image automated or not
+- is-official (boolean - true | false) - is the image official or not
+
+**--format**
+Change the output format to a Go template
+
+Valid placeholders for the Go template are listed below:
+
+| **Placeholder** | **Description** |
+| --------------- | ---------------------------- |
+| .Index | Registry |
+| .Name | Image name |
+| .Descriptions | Image description |
+| .Stars | Star count of image |
+| .Official | "[OK]" if image is official |
+| .Automated | "[OK]" if image is automated |
+
+**--limit**
+Limit the number of results
+Note: The results from each registry will be limited to this value.
+Example if limit is 10 and two registries are being searched, the total
+number of results will be 20, 10 from each (if there are at least 10 matches in each).
+The order of the search results is the order in which the API endpoint returns the results.
+
+**--no-trunc**
+Do not truncate the output
+
+**--registry**
+Specific registry to search (only the given registry will be searched, not the default registries)
+
+## EXAMPLES
+
+```
+# podman search --limit 3 rhel
+INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED
+docker.io docker.io/richxsl/rhel7 RHEL 7 image with minimal installation 9
+docker.io docker.io/bluedata/rhel7 RHEL-7.x base container images 1
+docker.io docker.io/gidikern/rhel-oracle-jre RHEL7 with jre8u60 5 [OK]
+redhat.com redhat.com/rhel This platform image provides a minimal runti... 0
+redhat.com redhat.com/rhel6 This platform image provides a minimal runti... 0
+redhat.com redhat.com/rhel6.5 This platform image provides a minimal runti... 0
+```
+
+```
+# podman search alpine
+INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED
+docker.io docker.io/library/alpine A minimal Docker image based on Alpine Linux... 3009 [OK]
+docker.io docker.io/mhart/alpine-node Minimal Node.js built on Alpine Linux 332
+docker.io docker.io/anapsix/alpine-java Oracle Java 8 (and 7) with GLIBC 2.23 over A... 272 [OK]
+docker.io docker.io/tenstartups/alpine Alpine linux base docker image with useful p... 5 [OK]
+```
+
+```
+# podman search --registry registry.fedoraproject.org fedora
+INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED
+fedoraproject.org fedoraproject.org/fedora 0
+fedoraproject.org fedoraproject.org/fedora-minimal 0
+```
+
+```
+# podman search --filter=is-official alpine
+INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED
+docker.io docker.io/library/alpine A minimal Docker image based on Alpine Linux... 3009 [OK]
+```
+
+```
+# podman search --registry registry.fedoraproject.org --format "table {{.Index}} {{.Name}}" fedora
+INDEX NAME
+fedoraproject.org fedoraproject.org/fedora
+fedoraproject.org fedoraproject.org/fedora-minimal
+```
+
+## SEE ALSO
+podman(1), crio(8), crio.conf(5)
+
+## HISTORY
+January 2018, Originally compiled by Urvashi Mohnani <umohnani@redhat.com>
diff --git a/docs/podman-stop.1.md b/docs/podman-stop.1.md
index f4372be5f..58cb2c39c 100644
--- a/docs/podman-stop.1.md
+++ b/docs/podman-stop.1.md
@@ -11,7 +11,9 @@ podman stop - Stop one or more containers
## DESCRIPTION
Stops one or more containers. You may use container IDs or names as input. The **--timeout** switch
allows you to specify the number of seconds to wait before forcibly stopping the container after the stop command
-is issued to the container. The default is 10 seconds.
+is issued to the container. The default is 10 seconds. By default, containers are stopped with SIGTERM
+and then SIGKILL after the timeout. The SIGTERM default can be overridden by the image used to create the
+container and also via command line when creating the container.
## OPTIONS
diff --git a/docs/tutorials/podman_tutorial.md b/docs/tutorials/podman_tutorial.md
index 8402dd74b..5e174ac6b 100644
--- a/docs/tutorials/podman_tutorial.md
+++ b/docs/tutorials/podman_tutorial.md
@@ -12,7 +12,7 @@ for Podman until an RPM becomes available.
### Installing build and runtime dependencies
```
-# sudo dnf install -y git runc libassuan-devel golang golang-github-cpuguy83-go-md2man glibc-static \
+$ sudo dnf install -y git runc libassuan-devel golang golang-github-cpuguy83-go-md2man glibc-static \
gpgme-devel glib2-devel device-mapper-devel libseccomp-devel \
atomic-registries iptables skopeo-containers containernetworking-cni \
conmon
@@ -22,7 +22,7 @@ for Podman until an RPM becomes available.
# git clone https://github.com/projectatomic/libpod/ ~/src/github.com/projectatomic/libpod
# cd !$
# make
-# sudo make install PREFIX=/usr
+$ sudo make install PREFIX=/usr
```
You now have a working podman environment. Jump to [Familiarizing yourself with Podman](Familiarizing yourself with Podman)
@@ -38,8 +38,8 @@ tutorial. For this tutorial, the Ubuntu **artful-server-cloudimg** image was use
#### Installing base packages
```
-# sudo apt-get update
-# sudo apt-get install libdevmapper-dev libglib2.0-dev libgpgme11-dev golang libseccomp-dev \
+$ sudo apt-get update
+$ sudo apt-get install libdevmapper-dev libglib2.0-dev libgpgme11-dev golang libseccomp-dev \
go-md2man libprotobuf-dev libprotobuf-c0-dev libseccomp-dev
```
#### Building and installing conmon
@@ -48,28 +48,28 @@ tutorial. For this tutorial, the Ubuntu **artful-server-cloudimg** image was use
# cd ~/src/github.com/kubernetes-incubator/cri-o
# mkdir bin
# make conmon
-# sudo install -D -m 755 bin/conmon /usr/libexec/crio/conmon
+$ sudo install -D -m 755 bin/conmon /usr/libexec/crio/conmon
```
#### Adding required configuration files
```
-# sudo mkdir -p /etc/containers
-# sudo curl https://raw.githubusercontent.com/projectatomic/registries/master/registries.fedora -o /etc/containers/registries.conf
-# sudo curl https://raw.githubusercontent.com/projectatomic/skopeo/master/default-policy.json -o /etc/containers/policy.json
+$ sudo mkdir -p /etc/containers
+$ sudo curl https://raw.githubusercontent.com/projectatomic/registries/master/registries.fedora -o /etc/containers/registries.conf
+$ sudo curl https://raw.githubusercontent.com/projectatomic/skopeo/master/default-policy.json -o /etc/containers/policy.json
```
#### Installing CNI plugins
```
# git clone https://github.com/containernetworking/plugins.git ~/src/github.com/containernetworking/plugins
# cd ~/src/github.com/containernetworking/plugins
# ./build.sh
-# sudo mkdir -p /usr/libexec/cni
-# sudo cp bin/* /usr/libexec/cni
+$ sudo mkdir -p /usr/libexec/cni
+$ sudo cp bin/* /usr/libexec/cni
```
#### Installing runc
```
# git clone https://github.com/opencontainers/runc.git ~/src/github.com/opencontainers/runc
# cd ~/src/github.com/opencontainers/runc
# GOPATH=~/ make static BUILDTAGS="seccomp selinux"
-# sudo cp runc /usr/bin/runc
+$ sudo cp runc /usr/bin/runc
```
### Building and installing Podman
@@ -77,7 +77,7 @@ tutorial. For this tutorial, the Ubuntu **artful-server-cloudimg** image was use
# git clone https://github.com/projectatomic/libpod/ ~/src/github.com/projectatomic/libpod
# cd ~/src/github.com/projectatomic/libpod
# make
-# sudo make install PREFIX=/usr
+$ sudo make install PREFIX=/usr
```
## Familiarizing yourself with Podman
@@ -86,7 +86,7 @@ tutorial. For this tutorial, the Ubuntu **artful-server-cloudimg** image was use
This sample container will run a very basic httpd server that serves only its index
page.
```
-# sudo podman run -dt -e HTTPD_VAR_RUN=/var/run/httpd -e HTTPD_MAIN_CONF_D_PATH=/etc/httpd/conf.d \
+$ sudo podman run -dt -e HTTPD_VAR_RUN=/var/run/httpd -e HTTPD_MAIN_CONF_D_PATH=/etc/httpd/conf.d \
-e HTTPD_MAIN_CONF_PATH=/etc/httpd/conf \
-e HTTPD_CONTAINER_SCRIPTS_PATH=/usr/share/container-scripts/httpd/ \
registry.fedoraproject.org/f26/httpd /usr/bin/run-httpd
@@ -97,7 +97,7 @@ will print the container ID after it has run.
### Listing running containers
The Podman *ps* command is used to list creating and running containers.
```
-# sudo podman ps
+$ sudo podman ps
```
Note: If you add *-a* to the *ps* command, Podman will show all containers.
@@ -109,8 +109,8 @@ install *iproute* in the container. Notice here that we use the switch **--late
created container. You could also use the container's ID listed during *podman ps* in the previous step or
when you ran the container.
```
-# sudo podman exec --latest -t dnf -y install iproute
-# sudo podman exec --latest -t ip a
+$ sudo podman exec --latest -t dnf -y install iproute
+$ sudo podman exec --latest -t ip a
```
Note the IP address of the *ethernet* device.
@@ -126,30 +126,30 @@ containerized httpd server.
### Viewing the container's logs
You can view the container's logs with Podman as well:
```
-# sudo podman logs --latest
+$ sudo podman logs --latest
```
<!-- (
### Viewing the container's pids
And you can observe the httpd pid in the container with *top*.
```
-# sudo podman top <container_id>
+$ sudo podman top <container_id>
``` ) -->
### Stopping the container
To stop the httpd container:
```
-# sudo podman stop --latest
+$ sudo podman stop --latest
```
You can also check the status of one or more containers using the *ps* subcommand. In this case, we should
use the *-a* argument to list all containers.
```
-# sudo podman ps -a
+$ sudo podman ps -a
```
### Removing the container
To remove the httpd container:
```
-# sudo podman rm --latest
+$ sudo podman rm --latest
```
You can verify the deletion of the container by running *podman ps -a*.
## More information
diff --git a/libpod/common/common.go b/libpod/common/common.go
index 6af3cd232..932f1f6da 100644
--- a/libpod/common/common.go
+++ b/libpod/common/common.go
@@ -2,17 +2,9 @@ package common
import (
"io"
- "strings"
- "syscall"
cp "github.com/containers/image/copy"
"github.com/containers/image/types"
- "github.com/pkg/errors"
-)
-
-var (
- // ErrNoPassword is returned if the user did not supply a password
- ErrNoPassword = errors.Wrapf(syscall.EINVAL, "password was not supplied")
)
// GetCopyOptions constructs a new containers/image/copy.Options{} struct from the given parameters
@@ -60,23 +52,3 @@ func IsFalse(str string) bool {
func IsValidBool(str string) bool {
return IsTrue(str) || IsFalse(str)
}
-
-// ParseRegistryCreds takes a credentials string in the form USERNAME:PASSWORD
-// and returns a DockerAuthConfig
-func ParseRegistryCreds(creds string) (*types.DockerAuthConfig, error) {
- if creds == "" {
- return nil, errors.New("no credentials supplied")
- }
- if !strings.Contains(creds, ":") {
- return &types.DockerAuthConfig{
- Username: creds,
- Password: "",
- }, ErrNoPassword
- }
- v := strings.SplitN(creds, ":", 2)
- cfg := &types.DockerAuthConfig{
- Username: v[0],
- Password: v[1],
- }
- return cfg, nil
-}
diff --git a/libpod/container_api.go b/libpod/container_api.go
index 05b3e89e6..3693ab78b 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -313,6 +313,11 @@ func (c *Container) Start() error {
return errors.Wrapf(ErrCtrStateInvalid, "container %s must be in Created or Stopped state to be started", c.ID())
}
+ // TODO remove this when we patch conmon to support restarting containers
+ if c.state.State == ContainerStateStopped {
+ return errors.Wrapf(ErrNotImplemented, "restarting a stopped container is not yet supported")
+ }
+
// Mount storage for the container
if err := c.mountStorage(); err != nil {
return err
@@ -519,8 +524,8 @@ func (c *Container) Pause() error {
if c.state.State == ContainerStatePaused {
return errors.Wrapf(ErrCtrStateInvalid, "%q is already paused", c.ID())
}
- if c.state.State != ContainerStateRunning && c.state.State != ContainerStateCreated {
- return errors.Wrapf(ErrCtrStateInvalid, "%q is not running/created, can't pause", c.state.State)
+ if c.state.State != ContainerStateRunning {
+ return errors.Wrapf(ErrCtrStateInvalid, "%q is not running, can't pause", c.state.State)
}
if err := c.runtime.ociRuntime.pauseContainer(c); err != nil {
return err
diff --git a/libpod/oci.go b/libpod/oci.go
index 4ca0bfbef..86313a493 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -394,6 +394,7 @@ func (r *OCIRuntime) startContainer(ctr *Container) error {
// killContainer sends the given signal to the given container
func (r *OCIRuntime) killContainer(ctr *Container, signal uint) error {
+ logrus.Debugf("Sending signal %d to container %s", signal, ctr.ID())
if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "kill", ctr.ID(), fmt.Sprintf("%d", signal)); err != nil {
return errors.Wrapf(err, "error sending signal to container %s", ctr.ID())
}
diff --git a/package_specs/podman.spec b/package_specs/podman.spec
new file mode 100644
index 000000000..215e45e7b
--- /dev/null
+++ b/package_specs/podman.spec
@@ -0,0 +1,464 @@
+# If any of the following macros should be set otherwise,
+# you can wrap any of them with the following conditions:
+# - %%if 0%%{centos} == 7
+# - %%if 0%%{?rhel} == 7
+# - %%if 0%%{?fedora} == 23
+# Or just test for particular distribution:
+# - %%if 0%%{centos}
+# - %%if 0%%{?rhel}
+# - %%if 0%%{?fedora}
+#
+# Be aware, on centos, both %%rhel and %%centos are set. If you want to test
+# rhel specific macros, you can use %%if 0%%{?rhel} && 0%%{?centos} == 0 condition.
+# (Don't forget to replace double percentage symbol with single one in order to apply a condition)
+
+# Generate devel rpm
+%global with_devel 0
+# Build project from bundled dependencies
+%global with_bundled 1
+# Build with debug info rpm
+%global with_debug 1
+# Run tests in check section
+%global with_check 0
+# Generate unit-test rpm
+%global with_unit_test 0
+
+%if 0%{?with_debug}
+%global _dwz_low_mem_die_limit 0
+%else
+%global debug_package %{nil}
+%endif
+
+# %if ! 0% {?gobuild:1}
+%define gobuild(o:) go build -tags="$BUILDTAGS selinux seccomp" -ldflags "${LDFLAGS:-} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \\n')" -a -v -x %{?**};
+#% endif
+
+%global provider github
+%global provider_tld com
+%global project projectatomic
+%global repo libpod
+# https://github.com/projectatomic/libpod
+%global provider_prefix %{provider}.%{provider_tld}/%{project}/%{repo}
+%global import_path %{provider_prefix}
+%global commit 367213a3943961126c6f7c1dce45c7fafea9e6b2
+%global shortcommit %(c=%{commit}; echo ${c:0:7})
+
+Name: podman
+Version: 0
+Release: 0.3.git%{shortcommit}%{?dist}
+Summary: Manage Pods, Containers and Container Images
+License: ASL 2.0
+URL: https://%{provider_prefix}
+Source0: https://%{provider_prefix}/archive/%{commit}/%{repo}-%{shortcommit}.tar.gz
+
+# e.g. el6 has ppc64 arch without gcc-go, so EA tag is required
+#ExclusiveArch: %%{?go_arches:%%{go_arches}}%%{!?go_arches:%%{ix86} x86_64 aarch64 %%{arm}}
+ExclusiveArch: x86_64
+# If go_compiler is not set to 1, there is no virtual provide. Use golang instead.
+BuildRequires: %{?go_compiler:compiler(go-compiler)}%{!?go_compiler:golang}
+BuildRequires: btrfs-progs-devel
+BuildRequires: device-mapper-devel
+BuildRequires: glib2-devel
+BuildRequires: glibc-devel
+BuildRequires: glibc-static
+BuildRequires: git
+BuildRequires: go-md2man
+BuildRequires: gpgme-devel
+BuildRequires: libassuan-devel
+BuildRequires: libgpg-error-devel
+BuildRequires: libseccomp-devel
+BuildRequires: libselinux-devel
+BuildRequires: pkgconfig
+BuildRequires: runc
+BuildRequires: skopeo-containers
+Requires: runc
+Requires: skopeo-containers
+Requires: conmon
+
+# vendored libraries
+# awk '{print "Provides: bundled(golang("$1")) = "$2}' containerd-*/vendor.conf | sort
+# [thanks to Carl George <carl@george.computer> for containerd.spec]
+Provides: bundled(golang(github.com/asaskevich/govalidator)) = v6
+Provides: bundled(golang(github.com/Azure/go-ansiterm)) = 19f72df4d05d31cbe1c56bfc8045c96babff6c7e
+Provides: bundled(golang(github.com/beorn7/perks)) = 3ac7bf7a47d159a033b107610db8a1b6575507a4
+Provides: bundled(golang(github.com/blang/semver)) = v3.5.0
+Provides: bundled(golang(github.com/buger/goterm)) = 2f8dfbc7dbbff5dd1d391ed91482c24df243b2d3
+Provides: bundled(golang(github.com/BurntSushi/toml)) = v0.2.0
+Provides: bundled(golang(github.com/containerd/cgroups)) = 7a5fdd8330119dc70d850260db8f3594d89d6943
+Provides: bundled(golang(github.com/containerd/continuity)) = master
+Provides: bundled(golang(github.com/containernetworking/cni)) = v0.4.0
+Provides: bundled(golang(github.com/containers/image)) = 9b4510f6d1627c8e53c3303a8fe48ca7842c2ace
+Provides: bundled(golang(github.com/containers/storage)) = 1824cf917a6b42d8c41179e807bb20a5fd6c0f0a
+Provides: bundled(golang(github.com/coreos/go-systemd)) = v14
+Provides: bundled(golang(github.com/coreos/pkg)) = v3
+Provides: bundled(golang(github.com/davecgh/go-spew)) = v1.1.0
+Provides: bundled(golang(github.com/dgrijalva/jwt-go)) = v3.0.0
+Provides: bundled(golang(github.com/docker/distribution)) = 7a8efe719e55bbfaff7bc5718cdf0ed51ca821df
+Provides: bundled(golang(github.com/docker/docker)) = ce452fb72ffcdb7605ce98bde9302238f47c63c5
+Provides: bundled(golang(github.com/docker/docker-credential-helpers)) = d68f9aeca33f5fd3f08eeae5e9d175edf4e731d1
+Provides: bundled(golang(github.com/docker/go-connections)) = 3ede32e2033de7505e6500d6c868c2b9ed9f169d
+Provides: bundled(golang(github.com/docker/go-units)) = v0.3.2
+Provides: bundled(golang(github.com/docker/libtrust)) = aabc10ec26b754e797f9028f4589c5b7bd90dc20
+Provides: bundled(golang(github.com/docker/spdystream)) = ed496381df8283605c435b86d4fdd6f4f20b8c6e
+Provides: bundled(golang(github.com/emicklei/go-restful)) = ff4f55a206334ef123e4f79bbf348980da81ca46
+Provides: bundled(golang(github.com/emicklei/go-restful-swagger12)) = 1.0.1
+Provides: bundled(golang(github.com/exponent-io/jsonpath)) = d6023ce2651d8eafb5c75bb0c7167536102ec9f5
+Provides: bundled(golang(github.com/fatih/camelcase)) = f6a740d52f961c60348ebb109adde9f4635d7540
+Provides: bundled(golang(github.com/ghodss/yaml)) = 04f313413ffd65ce25f2541bfd2b2ceec5c0908c
+Provides: bundled(golang(github.com/godbus/dbus)) = a389bdde4dd695d414e47b755e95e72b7826432c
+Provides: bundled(golang(github.com/gogo/protobuf)) = v0.3
+Provides: bundled(golang(github.com/golang/glog)) = 23def4e6c14b4da8ac2ed8007337bc5eb5007998
+Provides: bundled(golang(github.com/golang/groupcache)) = b710c8433bd175204919eb38776e944233235d03
+Provides: bundled(golang(github.com/golang/protobuf)) = 748d386b5c1ea99658fd69fe9f03991ce86a90c1
+Provides: bundled(golang(github.com/google/gofuzz)) = 44d81051d367757e1c7c6a5a86423ece9afcf63c
+Provides: bundled(golang(github.com/go-openapi/analysis)) = b44dc874b601d9e4e2f6e19140e794ba24bead3b
+Provides: bundled(golang(github.com/go-openapi/errors)) = d24ebc2075bad502fac3a8ae27aa6dd58e1952dc
+Provides: bundled(golang(github.com/go-openapi/jsonpointer)) = 779f45308c19820f1a69e9a4cd965f496e0da10f
+Provides: bundled(golang(github.com/go-openapi/jsonreference)) = 36d33bfe519efae5632669801b180bf1a245da3b
+Provides: bundled(golang(github.com/go-openapi/loads)) = 18441dfa706d924a39a030ee2c3b1d8d81917b38
+Provides: bundled(golang(github.com/go-openapi/spec)) = 6aced65f8501fe1217321abf0749d354824ba2ff
+Provides: bundled(golang(github.com/go-openapi/strfmt)) = 93a31ef21ac23f317792fff78f9539219dd74619
+Provides: bundled(golang(github.com/go-openapi/swag)) = 1d0bd113de87027671077d3c71eb3ac5d7dbba72
+Provides: bundled(golang(github.com/gorilla/context)) = v1.1
+Provides: bundled(golang(github.com/gorilla/mux)) = v1.3.0
+Provides: bundled(golang(github.com/hashicorp/errwrap)) = 7554cd9344cec97297fa6649b055a8c98c2a1e55
+Provides: bundled(golang(github.com/hashicorp/golang-lru)) = 0a025b7e63adc15a622f29b0b2c4c3848243bbf6
+Provides: bundled(golang(github.com/hashicorp/go-multierror)) = 83588e72410abfbe4df460eeb6f30841ae47d4c4
+Provides: bundled(golang(github.com/hpcloud/tail)) = v1.0.0
+Provides: bundled(golang(github.com/imdario/mergo)) = 0.2.2
+Provides: bundled(golang(github.com/juju/ratelimit)) = 5b9ff866471762aa2ab2dced63c9fb6f53921342
+Provides: bundled(golang(github.com/kr/pty)) = v1.0.0
+Provides: bundled(golang(github.com/mailru/easyjson)) = 99e922cf9de1bc0ab38310c277cff32c2147e747
+Provides: bundled(golang(github.com/mattn/go-runewidth)) = v0.0.1
+Provides: bundled(golang(github.com/matttproud/golang_protobuf_extensions)) = fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a
+Provides: bundled(golang(github.com/Microsoft/go-winio)) = 78439966b38d69bf38227fbf57ac8a6fee70f69a
+Provides: bundled(golang(github.com/Microsoft/hcsshim)) = 43f9725307998e09f2e3816c2c0c36dc98f0c982
+Provides: bundled(golang(github.com/mistifyio/go-zfs)) = v2.1.1
+Provides: bundled(golang(github.com/mitchellh/mapstructure)) = d0303fe809921458f417bcf828397a65db30a7e4
+Provides: bundled(golang(github.com/mrunalp/fileutils)) = master
+Provides: bundled(golang(github.com/mtrmac/gpgme)) = b2432428689ca58c2b8e8dea9449d3295cf96fc9
+Provides: bundled(golang(github.com/opencontainers/go-digest)) = v1.0.0-rc0
+Provides: bundled(golang(github.com/opencontainers/image-spec)) = v1.0.0
+Provides: bundled(golang(github.com/opencontainers/runc)) = 45bde006ca8c90e089894508708bcf0e2cdf9e13
+Provides: bundled(golang(github.com/opencontainers/runtime-spec)) = v1.0.0
+Provides: bundled(golang(github.com/opencontainers/runtime-tools)) = 625e2322645b151a7cbb93a8b42920933e72167f
+Provides: bundled(golang(github.com/opencontainers/selinux)) = b29023b86e4a69d1b46b7e7b4e2b6fda03f0b9cd
+Provides: bundled(golang(github.com/ostreedev/ostree-go)) = master
+Provides: bundled(golang(github.com/pkg/errors)) = v0.8.0
+Provides: bundled(golang(github.com/pmezard/go-difflib)) = 792786c7400a136282c1664665ae0a8db921c6c2
+Provides: bundled(golang(github.com/pquerna/ffjson)) = d49c2bc1aa135aad0c6f4fc2056623ec78f5d5ac
+Provides: bundled(golang(github.com/prometheus/client_golang)) = e7e903064f5e9eb5da98208bae10b475d4db0f8c
+Provides: bundled(golang(github.com/prometheus/client_model)) = fa8ad6fec33561be4280a8f0514318c79d7f6cb6
+Provides: bundled(golang(github.com/prometheus/common)) = 13ba4ddd0caa9c28ca7b7bffe1dfa9ed8d5ef207
+Provides: bundled(golang(github.com/prometheus/procfs)) = 65c1f6f8f0fc1e2185eb9863a3bc751496404259
+Provides: bundled(golang(github.com/PuerkitoBio/purell)) = v1.1.0
+Provides: bundled(golang(github.com/PuerkitoBio/urlesc)) = 5bd2802263f21d8788851d5305584c82a5c75d7e
+Provides: bundled(golang(github.com/renstrom/dedent)) = v1.0.0
+Provides: bundled(golang(github.com/seccomp/libseccomp-golang)) = v0.9.0
+Provides: bundled(golang(github.com/sirupsen/logrus)) = v1.0.0
+Provides: bundled(golang(github.com/spf13/pflag)) = 9ff6c6923cfffbcd502984b8e0c80539a94968b7
+Provides: bundled(golang(github.com/stretchr/testify)) = 4d4bfba8f1d1027c4fdbe371823030df51419987
+Provides: bundled(golang(github.com/syndtr/gocapability)) = e7cb7fa329f456b3855136a2642b197bad7366ba
+Provides: bundled(golang(github.com/tchap/go-patricia)) = v2.2.6
+Provides: bundled(golang(github.com/ugorji/go)) = d23841a297e5489e787e72fceffabf9d2994b52a
+Provides: bundled(golang(github.com/urfave/cli)) = 39908eb08fee7c10d842622a114a5c133fb0a3c6
+Provides: bundled(golang(github.com/vbatts/tar-split)) = v0.10.2
+Provides: bundled(golang(github.com/vishvananda/netlink)) = master
+Provides: bundled(golang(github.com/vishvananda/netns)) = master
+Provides: bundled(golang(github.com/xeipuuv/gojsonpointer)) = master
+Provides: bundled(golang(github.com/xeipuuv/gojsonreference)) = master
+Provides: bundled(golang(github.com/xeipuuv/gojsonschema)) = master
+Provides: bundled(golang(golang.org/x/crypto)) = 3fbbcd23f1cb824e69491a5930cfeff09b12f4d2
+Provides: bundled(golang(golang.org/x/net)) = c427ad74c6d7a814201695e9ffde0c5d400a7674
+Provides: bundled(golang(golang.org/x/sys)) = 9aade4d3a3b7e6d876cd3823ad20ec45fc035402
+Provides: bundled(golang(golang.org/x/text)) = f72d8390a633d5dfb0cc84043294db9f6c935756
+Provides: bundled(golang(google.golang.org/grpc)) = v1.0.4
+Provides: bundled(golang(gopkg.in/cheggaaa/pb.v1)) = v1.0.7
+Provides: bundled(golang(gopkg.in/fsnotify.v1)) = v1.4.2
+Provides: bundled(golang(gopkg.in/inf.v0)) = v0.9.0
+Provides: bundled(golang(gopkg.in/mgo.v2)) = v2
+Provides: bundled(golang(gopkg.in/tomb.v1)) = v1
+Provides: bundled(golang(gopkg.in/yaml.v2)) = v2
+
+%description
+%{summary}
+libpod provides a library for applications looking to use
+the Container Pod concept popularized by Kubernetes.
+
+%if 0%{?with_devel}
+%package -n libpod-devel
+Summary: Library for applications looking to use Container Pods
+BuildArch: noarch
+
+%if 0%{?with_check} && ! 0%{?with_bundled}
+BuildRequires: golang(github.com/BurntSushi/toml)
+BuildRequires: golang(github.com/containerd/cgroups)
+BuildRequires: golang(github.com/containernetworking/plugins/pkg/ns)
+BuildRequires: golang(github.com/containers/image/copy)
+BuildRequires: golang(github.com/containers/image/directory)
+BuildRequires: golang(github.com/containers/image/docker)
+BuildRequires: golang(github.com/containers/image/docker/archive)
+BuildRequires: golang(github.com/containers/image/docker/reference)
+BuildRequires: golang(github.com/containers/image/docker/tarfile)
+BuildRequires: golang(github.com/containers/image/image)
+BuildRequires: golang(github.com/containers/image/oci/archive)
+BuildRequires: golang(github.com/containers/image/pkg/strslice)
+BuildRequires: golang(github.com/containers/image/pkg/sysregistries)
+BuildRequires: golang(github.com/containers/image/signature)
+BuildRequires: golang(github.com/containers/image/storage)
+BuildRequires: golang(github.com/containers/image/tarball)
+BuildRequires: golang(github.com/containers/image/transports/alltransports)
+BuildRequires: golang(github.com/containers/image/types)
+BuildRequires: golang(github.com/containers/storage)
+BuildRequires: golang(github.com/containers/storage/pkg/archive)
+BuildRequires: golang(github.com/containers/storage/pkg/idtools)
+BuildRequires: golang(github.com/containers/storage/pkg/reexec)
+BuildRequires: golang(github.com/coreos/go-systemd/dbus)
+BuildRequires: golang(github.com/cri-o/ocicni/pkg/ocicni)
+BuildRequires: golang(github.com/docker/distribution/reference)
+BuildRequires: golang(github.com/docker/docker/daemon/caps)
+BuildRequires: golang(github.com/docker/docker/pkg/mount)
+BuildRequires: golang(github.com/docker/docker/pkg/namesgenerator)
+BuildRequires: golang(github.com/docker/docker/pkg/stringid)
+BuildRequires: golang(github.com/docker/docker/pkg/system)
+BuildRequires: golang(github.com/docker/docker/pkg/term)
+BuildRequires: golang(github.com/docker/docker/pkg/truncindex)
+BuildRequires: golang(github.com/ghodss/yaml)
+BuildRequires: golang(github.com/godbus/dbus)
+BuildRequires: golang(github.com/mattn/go-sqlite3)
+BuildRequires: golang(github.com/mrunalp/fileutils)
+BuildRequires: golang(github.com/opencontainers/go-digest)
+BuildRequires: golang(github.com/opencontainers/image-spec/specs-go/v1)
+BuildRequires: golang(github.com/opencontainers/runc/libcontainer)
+BuildRequires: golang(github.com/opencontainers/runtime-spec/specs-go)
+BuildRequires: golang(github.com/opencontainers/runtime-tools/generate)
+BuildRequires: golang(github.com/opencontainers/selinux/go-selinux)
+BuildRequires: golang(github.com/opencontainers/selinux/go-selinux/label)
+BuildRequires: golang(github.com/pkg/errors)
+BuildRequires: golang(github.com/sirupsen/logrus)
+BuildRequires: golang(github.com/ulule/deepcopier)
+BuildRequires: golang(golang.org/x/crypto/ssh/terminal)
+BuildRequires: golang(golang.org/x/sys/unix)
+BuildRequires: golang(k8s.io/apimachinery/pkg/util/wait)
+BuildRequires: golang(k8s.io/client-go/tools/remotecommand)
+BuildRequires: golang(k8s.io/kubernetes/pkg/kubelet/container)
+%endif
+
+Requires: golang(github.com/BurntSushi/toml)
+Requires: golang(github.com/containerd/cgroups)
+Requires: golang(github.com/containernetworking/plugins/pkg/ns)
+Requires: golang(github.com/containers/image/copy)
+Requires: golang(github.com/containers/image/directory)
+Requires: golang(github.com/containers/image/docker)
+Requires: golang(github.com/containers/image/docker/archive)
+Requires: golang(github.com/containers/image/docker/reference)
+Requires: golang(github.com/containers/image/docker/tarfile)
+Requires: golang(github.com/containers/image/image)
+Requires: golang(github.com/containers/image/oci/archive)
+Requires: golang(github.com/containers/image/pkg/strslice)
+Requires: golang(github.com/containers/image/pkg/sysregistries)
+Requires: golang(github.com/containers/image/signature)
+Requires: golang(github.com/containers/image/storage)
+Requires: golang(github.com/containers/image/tarball)
+Requires: golang(github.com/containers/image/transports/alltransports)
+Requires: golang(github.com/containers/image/types)
+Requires: golang(github.com/containers/storage)
+Requires: golang(github.com/containers/storage/pkg/archive)
+Requires: golang(github.com/containers/storage/pkg/idtools)
+Requires: golang(github.com/containers/storage/pkg/reexec)
+Requires: golang(github.com/coreos/go-systemd/dbus)
+Requires: golang(github.com/cri-o/ocicni/pkg/ocicni)
+Requires: golang(github.com/docker/distribution/reference)
+Requires: golang(github.com/docker/docker/daemon/caps)
+Requires: golang(github.com/docker/docker/pkg/mount)
+Requires: golang(github.com/docker/docker/pkg/namesgenerator)
+Requires: golang(github.com/docker/docker/pkg/stringid)
+Requires: golang(github.com/docker/docker/pkg/system)
+Requires: golang(github.com/docker/docker/pkg/term)
+Requires: golang(github.com/docker/docker/pkg/truncindex)
+Requires: golang(github.com/ghodss/yaml)
+Requires: golang(github.com/godbus/dbus)
+Requires: golang(github.com/mattn/go-sqlite3)
+Requires: golang(github.com/mrunalp/fileutils)
+Requires: golang(github.com/opencontainers/go-digest)
+Requires: golang(github.com/opencontainers/image-spec/specs-go/v1)
+Requires: golang(github.com/opencontainers/runc/libcontainer)
+Requires: golang(github.com/opencontainers/runtime-spec/specs-go)
+Requires: golang(github.com/opencontainers/runtime-tools/generate)
+Requires: golang(github.com/opencontainers/selinux/go-selinux)
+Requires: golang(github.com/opencontainers/selinux/go-selinux/label)
+Requires: golang(github.com/pkg/errors)
+Requires: golang(github.com/sirupsen/logrus)
+Requires: golang(github.com/ulule/deepcopier)
+Requires: golang(golang.org/x/crypto/ssh/terminal)
+Requires: golang(golang.org/x/sys/unix)
+Requires: golang(k8s.io/apimachinery/pkg/util/wait)
+Requires: golang(k8s.io/client-go/tools/remotecommand)
+Requires: golang(k8s.io/kubernetes/pkg/kubelet/container)
+
+Provides: golang(%{import_path}/cmd/%{name}/docker) = %{version}-%{release}
+Provides: golang(%{import_path}/cmd/%{name}/formats) = %{version}-%{release}
+Provides: golang(%{import_path}/libkpod) = %{version}-%{release}
+Provides: golang(%{import_path}/libpod) = %{version}-%{release}
+Provides: golang(%{import_path}/libpod/common) = %{version}-%{release}
+Provides: golang(%{import_path}/libpod/driver) = %{version}-%{release}
+Provides: golang(%{import_path}/libpod/layers) = %{version}-%{release}
+Provides: golang(%{import_path}/pkg/annotations) = %{version}-%{release}
+Provides: golang(%{import_path}/pkg/chrootuser) = %{version}-%{release}
+Provides: golang(%{import_path}/pkg/registrar) = %{version}-%{release}
+Provides: golang(%{import_path}/pkg/storage) = %{version}-%{release}
+Provides: golang(%{import_path}/utils) = %{version}-%{release}
+
+%description -n libpod-devel
+%{summary}
+
+This package contains library source intended for
+building other packages which use import path with
+%{import_path} prefix.
+%endif
+
+%if 0%{?with_unit_test} && 0%{?with_devel}
+%package unit-test-devel
+Summary: Unit tests for %{name} package
+%if 0%{?with_check}
+#Here comes all BuildRequires: PACKAGE the unit tests
+#in %%check section need for running
+%endif
+
+# test subpackage tests code from devel subpackage
+Requires: %{name}-devel = %{version}-%{release}
+
+%if 0%{?with_check} && ! 0%{?with_bundled}
+BuildRequires: golang(github.com/stretchr/testify/assert)
+BuildRequires: golang(github.com/urfave/cli)
+%endif
+
+Requires: golang(github.com/stretchr/testify/assert)
+Requires: golang(github.com/urfave/cli)
+
+%description unit-test-devel
+%{summary}
+libpod provides a library for applications looking to use the Container Pod concept popularized by Kubernetes.
+
+This package contains unit tests for project
+providing packages with %{import_path} prefix.
+%endif
+
+%prep
+%autosetup -Sgit -n %{repo}-%{commit}
+sed -i '/\/bin\/bash/d' completions/bash/%{name}
+
+%build
+mkdir _build
+pushd _build
+mkdir -p src/%{provider}.%{provider_tld}/%{project}
+ln -s ../../../../ src/%{import_path}
+popd
+ln -s vendor src
+export GOPATH=$(pwd)/_build:$(pwd):$(pwd):%{gopath}
+export BUILDTAGS="selinux seccomp $(hack/btrfs_installed_tag.sh) $(hack/btrfs_tag.sh) $(hack/libdm_tag.sh) containers_image_ostree_stub"
+
+GOPATH=$GOPATH BUILDTAGS=$BUILDTAGS %gobuild -o bin/%{name} %{import_path}/cmd/%{name}
+BUILDTAGS=$BUILDTAGS make docs
+
+%install
+%make_install PREFIX=%{buildroot}%{_prefix} install install.completions
+
+# source codes for building projects
+%if 0%{?with_devel}
+install -d -p %{buildroot}/%{gopath}/src/%{import_path}/
+
+echo "%%dir %%{gopath}/src/%%{import_path}/." >> devel.file-list
+# find all *.go but no *_test.go files and generate devel.file-list
+for file in $(find . \( -iname "*.go" -or -iname "*.s" \) \! -iname "*_test.go" | grep -v "vendor") ; do
+ dirprefix=$(dirname $file)
+ install -d -p %{buildroot}/%{gopath}/src/%{import_path}/$dirprefix
+ cp -pav $file %{buildroot}/%{gopath}/src/%{import_path}/$file
+ echo "%%{gopath}/src/%%{import_path}/$file" >> devel.file-list
+
+ while [ "$dirprefix" != "." ]; do
+ echo "%%dir %%{gopath}/src/%%{import_path}/$dirprefix" >> devel.file-list
+ dirprefix=$(dirname $dirprefix)
+ done
+done
+%endif
+
+# testing files for this project
+%if 0%{?with_unit_test} && 0%{?with_devel}
+install -d -p %{buildroot}/%{gopath}/src/%{import_path}/
+# find all *_test.go files and generate unit-test-devel.file-list
+for file in $(find . -iname "*_test.go" | grep -v "vendor") ; do
+ dirprefix=$(dirname $file)
+ install -d -p %{buildroot}/%{gopath}/src/%{import_path}/$dirprefix
+ cp -pav $file %{buildroot}/%{gopath}/src/%{import_path}/$file
+ echo "%%{gopath}/src/%%{import_path}/$file" >> unit-test-devel.file-list
+
+ while [ "$dirprefix" != "." ]; do
+ echo "%%dir %%{gopath}/src/%%{import_path}/$dirprefix" >> devel.file-list
+ dirprefix=$(dirname $dirprefix)
+ done
+done
+%endif
+
+%if 0%{?with_devel}
+sort -u -o devel.file-list devel.file-list
+%endif
+
+%check
+%if 0%{?with_check} && 0%{?with_unit_test} && 0%{?with_devel}
+%if ! 0%{?with_bundled}
+export GOPATH=%{buildroot}/%{gopath}:%{gopath}
+%else
+# Since we aren't packaging up the vendor directory we need to link
+# back to it somehow. Hack it up so that we can add the vendor
+# directory from BUILD dir as a gopath to be searched when executing
+# tests from the BUILDROOT dir.
+ln -s ./ ./vendor/src # ./vendor/src -> ./vendor
+
+export GOPATH=%{buildroot}/%{gopath}:$(pwd)/vendor:%{gopath}
+%endif
+
+%if ! 0%{?gotest:1}
+%global gotest go test
+%endif
+
+%gotest %{import_path}/cmd/%{name}
+%gotest %{import_path}/libkpod
+%gotest %{import_path}/libpod
+%gotest %{import_path}/pkg/registrar
+%endif
+
+#define license tag if not already defined
+%{!?_licensedir:%global license %doc}
+
+%files
+%license LICENSE
+%doc README.md CONTRIBUTING.md hooks.md install.md code-of-conduct.md transfer.md
+%{_bindir}/%{name}
+%{_mandir}/man1/*.1*
+%{_datadir}/bash-completion/completions/*
+%config(noreplace) %{_sysconfdir}/cni/net.d/87-%{name}-bridge.conflist
+
+%if 0%{?with_devel}
+%files -n libpod-devel -f devel.file-list
+%license LICENSE
+%doc README.md CONTRIBUTING.md hooks.md install.md code-of-conduct.md transfer.md
+%dir %{gopath}/src/%{provider}.%{provider_tld}/%{project}
+%endif
+
+%if 0%{?with_unit_test} && 0%{?with_devel}
+%files unit-test-devel -f unit-test-devel.file-list
+%license LICENSE
+%doc README.md CONTRIBUTING.md hooks.md install.md code-of-conduct.md transfer.md
+%endif
+
+%changelog
+* Tue Feb 06 2018 Lokesh Mandvekar <lsm5@fedoraproject.org> - 0-0.3.git367213a
+- Resolves: #1541554 - first official build
+- built commit 367213a
+
+* Fri Feb 02 2018 Lokesh Mandvekar <lsm5@fedoraproject.org> - 0-0.2.git0387f69
+- built commit 0387f69
+
+* Wed Jan 10 2018 Frantisek Kluknavsky <fkluknav@redhat.com> - 0-0.1.gitc1b2278
+- First package for Fedora
diff --git a/pkg/inspect/inspect.go b/pkg/inspect/inspect.go
index 9e7137560..11a252535 100644
--- a/pkg/inspect/inspect.go
+++ b/pkg/inspect/inspect.go
@@ -12,9 +12,9 @@ import (
// ContainerData holds the podman inspect data for a container
type ContainerData struct {
- CtrInspectData *ContainerInspectData `json:"CtrInspectData"`
- HostConfig *HostConfig `json:"HostConfig"`
- Config *CtrConfig `json:"Config"`
+ *ContainerInspectData
+ HostConfig *HostConfig `json:"HostConfig"`
+ Config *CtrConfig `json:"Config"`
}
// HostConfig represents the host configuration for the container
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
new file mode 100644
index 000000000..9a93021e4
--- /dev/null
+++ b/pkg/util/utils.go
@@ -0,0 +1,46 @@
+package util
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/containers/image/types"
+ "github.com/pkg/errors"
+ "golang.org/x/crypto/ssh/terminal"
+)
+
+// Helper function to determine the username/password passed
+// in the creds string. It could be either or both.
+func parseCreds(creds string) (string, string) {
+ if creds == "" {
+ return "", ""
+ }
+ up := strings.SplitN(creds, ":", 2)
+ if len(up) == 1 {
+ return up[0], ""
+ }
+ return up[0], up[1]
+}
+
+// ParseRegistryCreds takes a credentials string in the form USERNAME:PASSWORD
+// and returns a DockerAuthConfig
+func ParseRegistryCreds(creds string) (*types.DockerAuthConfig, error) {
+ username, password := parseCreds(creds)
+ if username == "" {
+ fmt.Print("Username: ")
+ fmt.Scanln(&username)
+ }
+ if password == "" {
+ fmt.Print("Password: ")
+ termPassword, err := terminal.ReadPassword(0)
+ if err != nil {
+ return nil, errors.Wrapf(err, "could not read password from terminal")
+ }
+ password = string(termPassword)
+ }
+
+ return &types.DockerAuthConfig{
+ Username: username,
+ Password: password,
+ }, nil
+}
diff --git a/test/demos.sh b/test/demos.sh
new file mode 100755
index 000000000..4ce29e160
--- /dev/null
+++ b/test/demos.sh
@@ -0,0 +1,93 @@
+#!/bin/bash
+
+echo "This is a demo of the podman search command."
+echo ""
+
+read -p "--> cat /etc/containers/registries.conf"
+cat /etc/containers/registries.conf
+echo ""
+
+read -p "--> podman search fedora"
+podman search fedora
+echo ""
+
+read -p "--> podman search --filter stars=34 fedora"
+podman search --filter stars=34 fedora
+echo ""
+
+read -p "--> podman search --filter is-automated=false --filter stars=34 --filter is-official fedora"
+podman search --filter is-automated=false --filter stars=34 --filter is-official fedora
+echo ""
+
+read -p "--> podman search --no-trunc --limit 3 fedora"
+podman search --no-trunc --limit 3 fedora
+echo ""
+
+read -p "--> podman search --registry registry.access.redhat.com rhel7"
+podman search --registry registry.access.redhat.com rhel7
+echo ""
+
+read -p "--> podman search --format \"table {{.Name}} {{.Description}}\" fedora"
+podman search --format "table {{.Name}} {{.Description}}" fedora
+echo ""
+
+read -p "Demo of a few podman run and create options"
+echo ""
+
+read -p "--> podman run --memory 80m fedora cat /sys/fs/cgroup/memory/memory.limit_in_bytes"
+podman run --rm --memory 80m fedora cat /sys/fs/cgroup/memory/memory.limit_in_bytes
+echo ""
+
+read -p "--> podman run --memory 80m --memory-reservation 40m fedora cat /sys/fs/cgroup/memory/memory.soft_limit_in_bytes"
+podman run --rm --memory 80m --memory-reservation 40m fedora cat /sys/fs/cgroup/memory/memory.soft_limit_in_bytes
+echo ""
+
+read -p "--> podman run --memory 40m --memory-reservation 80m fedora cat /sys/fs/cgroup/memory/memory.soft_limit_in_bytes"
+podman run --rm --memory 40m --memory-reservation 80m fedora cat /sys/fs/cgroup/memory/memory.soft_limit_in_bytes
+echo ""
+
+read -p "--> podman run --memory-swappiness 15 fedora cat /sys/fs/cgroup/memory/memory.swappiness"
+podman run --rm --memory-swappiness 15 fedora cat /sys/fs/cgroup/memory/memory.swappiness
+echo ""
+
+read -p "--> podman run --kernel-memory 40m fedora cat /sys/fs/cgroup/memory/memory.kmem.limit_in_bytes"
+podman run --rm --kernel-memory 40m fedora cat /sys/fs/cgroup/memory/memory.kmem.limit_in_bytes
+echo ""
+
+read -p "--> podman run --cpu-period 5000 fedora cat /sys/fs/cgroup/cpu/cpu.cfs_period_us"
+podman run --rm --cpu-period 5000 fedora cat /sys/fs/cgroup/cpu/cpu.cfs_period_us
+echo ""
+
+read -p "--> podman run --cpu-quota 15000 --cpu-period 5000 fedora cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us"
+podman run --rm --cpu-quota 15000 --cpu-period 5000 fedora cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us
+echo ""
+
+read -p "--> podman run --cpus 0.5 fedora /bin/bash"
+read -p "cat /sys/fs/cgroup/cpu/cpu.cfs_period_us"
+podman run --rm --cpus 0.5 fedora cat /sys/fs/cgroup/cpu/cpu.cfs_period_us
+read -p "cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us"
+podman run --rm --cpus 0.5 fedora cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us
+echo ""
+
+read -p "--> podman run --cpu-shares 2 fedora cat /sys/fs/cgroup/cpu/cpu.shares"
+podman run --rm --cpu-shares 2 fedora cat /sys/fs/cgroup/cpu/cpu.shares
+echo ""
+
+read -p "--> podman run --cpuset-cpus=0,2 fedora cat /sys/fs/cgroup/cpuset/cpuset.cpus"
+podman run --rm --cpuset-cpus=0,2 fedora cat /sys/fs/cgroup/cpuset/cpuset.cpus
+echo ""
+
+read -p "--> podman run --sysctl net.core.somaxconn=65535 alpine sysctl net.core.somaxconn"
+podman run --rm --sysctl net.core.somaxconn=65535 alpine sysctl net.core.somaxconn
+echo ""
+
+read -p "--> podman run --ulimit nofile=1024:1028 fedora ulimit -n"
+podman run --rm --ulimit nofile=1024:1028 fedora ulimit -n
+echo ""
+
+read -p "--> podman run --blkio-weight 15 fedora cat /sys/fs/cgroup/blkio/blkio.weight"
+podman run --rm --blkio-weight 15 fedora cat /sys/fs/cgroup/blkio/blkio.weight
+echo ""
+
+read -p "End of Demo."
+echo "Thank you!" \ No newline at end of file
diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go
index c116cea7d..e54e35761 100644
--- a/test/e2e/create_test.go
+++ b/test/e2e/create_test.go
@@ -38,7 +38,7 @@ var _ = Describe("Podman create", func() {
check := podmanTest.Podman([]string{"inspect", "-l"})
check.WaitWithDefaultTimeout()
data := check.InspectContainerToJSON()
- Expect(data.CtrInspectData.ID).To(ContainSubstring(cid))
+ Expect(data.ID).To(ContainSubstring(cid))
})
It("podman create container based on a remote image", func() {
diff --git a/test/e2e/inspect_test.go b/test/e2e/inspect_test.go
index b22774575..b6020f53b 100644
--- a/test/e2e/inspect_test.go
+++ b/test/e2e/inspect_test.go
@@ -3,9 +3,10 @@ package integration
import (
"os"
+ "strings"
+
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
- "strings"
)
var _ = Describe("Podman inspect", func() {
@@ -69,6 +70,6 @@ var _ = Describe("Podman inspect", func() {
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
conData := result.InspectContainerToJSON()
- Expect(conData.CtrInspectData.SizeRootFs).To(BeNumerically(">", 0))
+ Expect(conData.SizeRootFs).To(BeNumerically(">", 0))
})
})
diff --git a/test/podman_search.bats b/test/podman_search.bats
new file mode 100644
index 000000000..07621d722
--- /dev/null
+++ b/test/podman_search.bats
@@ -0,0 +1,43 @@
+#!/usr/bin/env bats
+
+load helpers
+
+function teardown() {
+ cleanup_test
+}
+
+@test "podman search" {
+ run ${PODMAN_BINARY} ${PODMAN_OPTIONS} search alpine
+ echo "$output"
+ [ "$status" -eq 0 ]
+}
+
+@test "podman search registry flag" {
+ run ${PODMAN_BINARY} ${PODMAN_OPTIONS} search --registry registry.fedoraproject.org fedora
+ echo "$output"
+ [ "$status" -eq 0 ]
+}
+
+@test "podman search filter flag" {
+ run ${PODMAN_BINARY} ${PODMAN_OPTIONS} search --filter=is-official alpine
+ echo "$output"
+ [ "$status" -eq 0 ]
+}
+
+@test "podman search format flag" {
+ run ${PODMAN_BINARY} ${PODMAN_OPTIONS} search --format "table {{.Index}} {{.Name}}" alpine
+ echo "$output"
+ [ "$status" -eq 0 ]
+}
+
+@test "podman search no-trunc flag" {
+ run ${PODMAN_BINARY} ${PODMAN_OPTIONS} search --no-trunc alpine
+ echo "$output"
+ [ "$status" -eq 0 ]
+}
+
+@test "podman search limit flag" {
+ run ${PODMAN_BINARY} ${PODMAN_OPTIONS} search --limit 3 alpine
+ echo "$output"
+ [ "$status" -eq 0 ]
+} \ No newline at end of file
diff --git a/transfer.md b/transfer.md
index 30e277a86..53d6c472c 100644
--- a/transfer.md
+++ b/transfer.md
@@ -60,6 +60,7 @@ There are other equivalents for these tools
| `docker rmi` | [`podman rmi`](./docs/podman-rmi.1.md) |
| `docker run` | [`podman run`](./docs/podman-run.1.md) |
| `docker save` | [`podman save`](./docs/podman-save.1.md) |
+| `docker search` | [`podman search`](./docs/podman-search.1.md) |
| `docker start` | [`podman start`](./docs/podman-start.1.md) |
| `docker stop` | [`podman stop`](./docs/podman-stop.1.md) |
| `docker tag` | [`podman tag`](./docs/podman-tag.1.md) |
@@ -85,7 +86,6 @@ Those Docker commands currently do not have equivalents in `podman`:
| `docker port` ||
| `docker rename` | podman does not support rename, you need to use `podman rm` and `podman create` to rename a container.|
| `docker restart` | podman does not support restart. We recommend that you put your podman containers into a systemd unit file and use it for restarting applications.|
-| `docker search` ||
| `docker secret` ||
| `docker service` ||
| `docker stack` ||
diff --git a/vendor.conf b/vendor.conf
index 4ce659199..ea659eab8 100644
--- a/vendor.conf
+++ b/vendor.conf
@@ -1,6 +1,6 @@
#
github.com/sirupsen/logrus v1.0.0
-github.com/containers/image 9b4510f6d1627c8e53c3303a8fe48ca7842c2ace
+github.com/containers/image 3ab2e31e6ff9fc2b21b81188c1f6cf545658ff4a
github.com/docker/docker-credential-helpers d68f9aeca33f5fd3f08eeae5e9d175edf4e731d1
github.com/ostreedev/ostree-go master
github.com/containers/storage 1824cf917a6b42d8c41179e807bb20a5fd6c0f0a
diff --git a/vendor/github.com/containers/image/directory/directory_dest.go b/vendor/github.com/containers/image/directory/directory_dest.go
index 47d59d9fe..5f7443fa0 100644
--- a/vendor/github.com/containers/image/directory/directory_dest.go
+++ b/vendor/github.com/containers/image/directory/directory_dest.go
@@ -70,7 +70,7 @@ func newImageDestination(ref dirReference, compress bool) (types.ImageDestinatio
}
}
// create version file
- err = ioutil.WriteFile(d.ref.versionPath(), []byte(version), 0755)
+ err = ioutil.WriteFile(d.ref.versionPath(), []byte(version), 0644)
if err != nil {
return nil, errors.Wrapf(err, "error creating version file %q", d.ref.versionPath())
}
diff --git a/vendor/github.com/containers/image/docker/docker_client.go b/vendor/github.com/containers/image/docker/docker_client.go
index 217e9dcbf..ff1af8f65 100644
--- a/vendor/github.com/containers/image/docker/docker_client.go
+++ b/vendor/github.com/containers/image/docker/docker_client.go
@@ -8,7 +8,10 @@ import (
"io"
"io/ioutil"
"net/http"
+ "net/url"
+ "os"
"path/filepath"
+ "strconv"
"strings"
"time"
@@ -24,10 +27,9 @@ import (
)
const (
- dockerHostname = "docker.io"
- dockerRegistry = "registry-1.docker.io"
-
- systemPerHostCertDirPath = "/etc/docker/certs.d"
+ dockerHostname = "docker.io"
+ dockerV1Hostname = "index.docker.io"
+ dockerRegistry = "registry-1.docker.io"
resolvedPingV2URL = "%s://%s/v2/"
resolvedPingV1URL = "%s://%s/v1/_ping"
@@ -49,6 +51,7 @@ var (
ErrV1NotSupported = errors.New("can't talk to a V1 docker registry")
// ErrUnauthorizedForCredentials is returned when the status code returned is 401
ErrUnauthorizedForCredentials = errors.New("unable to retrieve auth token: invalid username/password")
+ systemPerHostCertDirPaths = [2]string{"/etc/containers/certs.d", "/etc/docker/certs.d"}
)
// extensionSignature and extensionSignatureList come from github.com/openshift/origin/pkg/dockerregistry/server/signaturedispatcher.go:
@@ -66,9 +69,10 @@ type extensionSignatureList struct {
}
type bearerToken struct {
- Token string `json:"token"`
- ExpiresIn int `json:"expires_in"`
- IssuedAt time.Time `json:"issued_at"`
+ Token string `json:"token"`
+ AccessToken string `json:"access_token"`
+ ExpiresIn int `json:"expires_in"`
+ IssuedAt time.Time `json:"issued_at"`
}
// dockerClient is configuration for dealing with a single Docker registry.
@@ -96,6 +100,24 @@ type authScope struct {
actions string
}
+func newBearerTokenFromJSONBlob(blob []byte) (*bearerToken, error) {
+ token := new(bearerToken)
+ if err := json.Unmarshal(blob, &token); err != nil {
+ return nil, err
+ }
+ if token.Token == "" {
+ token.Token = token.AccessToken
+ }
+ if token.ExpiresIn < minimumTokenLifetimeSeconds {
+ token.ExpiresIn = minimumTokenLifetimeSeconds
+ logrus.Debugf("Increasing token expiration to: %d seconds", token.ExpiresIn)
+ }
+ if token.IssuedAt.IsZero() {
+ token.IssuedAt = time.Now().UTC()
+ }
+ return token, nil
+}
+
// this is cloned from docker/go-connections because upstream docker has changed
// it and make deps here fails otherwise.
// We'll drop this once we upgrade to docker 1.13.x deps.
@@ -109,19 +131,42 @@ func serverDefault() *tls.Config {
}
// dockerCertDir returns a path to a directory to be consumed by tlsclientconfig.SetupCertificates() depending on ctx and hostPort.
-func dockerCertDir(ctx *types.SystemContext, hostPort string) string {
+func dockerCertDir(ctx *types.SystemContext, hostPort string) (string, error) {
if ctx != nil && ctx.DockerCertPath != "" {
- return ctx.DockerCertPath
+ return ctx.DockerCertPath, nil
}
- var hostCertDir string
if ctx != nil && ctx.DockerPerHostCertDirPath != "" {
- hostCertDir = ctx.DockerPerHostCertDirPath
- } else if ctx != nil && ctx.RootForImplicitAbsolutePaths != "" {
- hostCertDir = filepath.Join(ctx.RootForImplicitAbsolutePaths, systemPerHostCertDirPath)
- } else {
- hostCertDir = systemPerHostCertDirPath
+ return filepath.Join(ctx.DockerPerHostCertDirPath, hostPort), nil
+ }
+
+ var (
+ hostCertDir string
+ fullCertDirPath string
+ )
+ for _, systemPerHostCertDirPath := range systemPerHostCertDirPaths {
+ if ctx != nil && ctx.RootForImplicitAbsolutePaths != "" {
+ hostCertDir = filepath.Join(ctx.RootForImplicitAbsolutePaths, systemPerHostCertDirPath)
+ } else {
+ hostCertDir = systemPerHostCertDirPath
+ }
+
+ fullCertDirPath = filepath.Join(hostCertDir, hostPort)
+ _, err := os.Stat(fullCertDirPath)
+ if err == nil {
+ break
+ }
+ if os.IsNotExist(err) {
+ continue
+ }
+ if os.IsPermission(err) {
+ logrus.Debugf("error accessing certs directory due to permissions: %v", err)
+ continue
+ }
+ if err != nil {
+ return "", err
+ }
}
- return filepath.Join(hostCertDir, hostPort)
+ return fullCertDirPath, nil
}
// newDockerClientFromRef returns a new dockerClient instance for refHostname (a host a specified in the Docker image reference, not canonicalized to dockerRegistry)
@@ -155,7 +200,10 @@ func newDockerClientWithDetails(ctx *types.SystemContext, registry, username, pa
// dockerHostname here, because it is more symmetrical to read the configuration in that case as well, and because
// generally the UI hides the existence of the different dockerRegistry. But note that this behavior is
// undocumented and may change if docker/docker changes.
- certDir := dockerCertDir(ctx, hostName)
+ certDir, err := dockerCertDir(ctx, hostName)
+ if err != nil {
+ return nil, err
+ }
if err := tlsclientconfig.SetupCertificates(certDir, tr.TLSClientConfig); err != nil {
return nil, err
}
@@ -202,6 +250,100 @@ func CheckAuth(ctx context.Context, sCtx *types.SystemContext, username, passwor
}
}
+// SearchResult holds the information of each matching image
+// It matches the output returned by the v1 endpoint
+type SearchResult struct {
+ Name string `json:"name"`
+ Description string `json:"description"`
+ // StarCount states the number of stars the image has
+ StarCount int `json:"star_count"`
+ IsTrusted bool `json:"is_trusted"`
+ // IsAutomated states whether the image is an automated build
+ IsAutomated bool `json:"is_automated"`
+ // IsOfficial states whether the image is an official build
+ IsOfficial bool `json:"is_official"`
+}
+
+// SearchRegistry queries a registry for images that contain "image" in their name
+// The limit is the max number of results desired
+// Note: The limit value doesn't work with all registries
+// for example registry.access.redhat.com returns all the results without limiting it to the limit value
+func SearchRegistry(ctx context.Context, sCtx *types.SystemContext, registry, image string, limit int) ([]SearchResult, error) {
+ type V2Results struct {
+ // Repositories holds the results returned by the /v2/_catalog endpoint
+ Repositories []string `json:"repositories"`
+ }
+ type V1Results struct {
+ // Results holds the results returned by the /v1/search endpoint
+ Results []SearchResult `json:"results"`
+ }
+ v2Res := &V2Results{}
+ v1Res := &V1Results{}
+
+ // The /v2/_catalog endpoint has been disabled for docker.io therefore the call made to that endpoint will fail
+ // So using the v1 hostname for docker.io for simplicity of implementation and the fact that it returns search results
+ if registry == dockerHostname {
+ registry = dockerV1Hostname
+ }
+
+ client, err := newDockerClientWithDetails(sCtx, registry, "", "", "", nil, "")
+ if err != nil {
+ return nil, errors.Wrapf(err, "error creating new docker client")
+ }
+
+ logrus.Debugf("trying to talk to v2 search endpoint\n")
+ resp, err := client.makeRequest(ctx, "GET", "/v2/_catalog", nil, nil)
+ if err != nil {
+ logrus.Debugf("error getting search results from v2 endpoint %q: %v", registry, err)
+ } else {
+ defer resp.Body.Close()
+ if resp.StatusCode != http.StatusOK {
+ logrus.Debugf("error getting search results from v2 endpoint %q, status code %q", registry, resp.StatusCode)
+ } else {
+ if err := json.NewDecoder(resp.Body).Decode(v2Res); err != nil {
+ return nil, err
+ }
+ searchRes := []SearchResult{}
+ for _, repo := range v2Res.Repositories {
+ if strings.Contains(repo, image) {
+ res := SearchResult{
+ Name: repo,
+ }
+ searchRes = append(searchRes, res)
+ }
+ }
+ return searchRes, nil
+ }
+ }
+
+ // set up the query values for the v1 endpoint
+ u := url.URL{
+ Path: "/v1/search",
+ }
+ q := u.Query()
+ q.Set("q", image)
+ q.Set("n", strconv.Itoa(limit))
+ u.RawQuery = q.Encode()
+
+ logrus.Debugf("trying to talk to v1 search endpoint\n")
+ resp, err = client.makeRequest(ctx, "GET", u.String(), nil, nil)
+ if err != nil {
+ logrus.Debugf("error getting search results from v1 endpoint %q: %v", registry, err)
+ } else {
+ defer resp.Body.Close()
+ if resp.StatusCode != http.StatusOK {
+ logrus.Debugf("error getting search results from v1 endpoint %q, status code %q", registry, resp.StatusCode)
+ } else {
+ if err := json.NewDecoder(resp.Body).Decode(v1Res); err != nil {
+ return nil, err
+ }
+ return v1Res.Results, nil
+ }
+ }
+
+ return nil, errors.Wrapf(err, "couldn't search registry %q", registry)
+}
+
// makeRequest creates and executes a http.Request with the specified parameters, adding authentication and TLS options for the Docker client.
// The host name and schema is taken from the client or autodetected, and the path is relative to it, i.e. the path usually starts with /v2/.
func (c *dockerClient) makeRequest(ctx context.Context, method, path string, headers map[string][]string, stream io.Reader) (*http.Response, error) {
@@ -332,18 +474,8 @@ func (c *dockerClient) getBearerToken(ctx context.Context, realm, service, scope
if err != nil {
return nil, err
}
- var token bearerToken
- if err := json.Unmarshal(tokenBlob, &token); err != nil {
- return nil, err
- }
- if token.ExpiresIn < minimumTokenLifetimeSeconds {
- token.ExpiresIn = minimumTokenLifetimeSeconds
- logrus.Debugf("Increasing token expiration to: %d seconds", token.ExpiresIn)
- }
- if token.IssuedAt.IsZero() {
- token.IssuedAt = time.Now().UTC()
- }
- return &token, nil
+
+ return newBearerTokenFromJSONBlob(tokenBlob)
}
// detectProperties detects various properties of the registry.
diff --git a/vendor/github.com/containers/image/docker/docker_image_dest.go b/vendor/github.com/containers/image/docker/docker_image_dest.go
index 79c386225..2f3b6c2c3 100644
--- a/vendor/github.com/containers/image/docker/docker_image_dest.go
+++ b/vendor/github.com/containers/image/docker/docker_image_dest.go
@@ -131,7 +131,7 @@ func (d *dockerImageDestination) PutBlob(stream io.Reader, inputInfo types.BlobI
defer res.Body.Close()
if res.StatusCode != http.StatusAccepted {
logrus.Debugf("Error initiating layer upload, response %#v", *res)
- return types.BlobInfo{}, errors.Errorf("Error initiating layer upload to %s, status %d", uploadPath, res.StatusCode)
+ return types.BlobInfo{}, errors.Wrapf(client.HandleErrorResponse(res), "Error initiating layer upload to %s", uploadPath)
}
uploadLocation, err := res.Location()
if err != nil {
@@ -167,7 +167,7 @@ func (d *dockerImageDestination) PutBlob(stream io.Reader, inputInfo types.BlobI
defer res.Body.Close()
if res.StatusCode != http.StatusCreated {
logrus.Debugf("Error uploading layer, response %#v", *res)
- return types.BlobInfo{}, errors.Errorf("Error uploading layer to %s, status %d", uploadLocation, res.StatusCode)
+ return types.BlobInfo{}, errors.Wrapf(client.HandleErrorResponse(res), "Error uploading layer to %s", uploadLocation)
}
logrus.Debugf("Upload of layer %s complete", computedDigest)
@@ -196,7 +196,7 @@ func (d *dockerImageDestination) HasBlob(info types.BlobInfo) (bool, int64, erro
return true, getBlobSize(res), nil
case http.StatusUnauthorized:
logrus.Debugf("... not authorized")
- return false, -1, errors.Errorf("not authorized to read from destination repository %s", reference.Path(d.ref.ref))
+ return false, -1, client.HandleErrorResponse(res)
case http.StatusNotFound:
logrus.Debugf("... not present")
return false, -1, nil
@@ -447,7 +447,7 @@ sigExists:
logrus.Debugf("Error body %s", string(body))
}
logrus.Debugf("Error uploading signature, status %d, %#v", res.StatusCode, res)
- return errors.Errorf("Error uploading signature to %s, status %d", path, res.StatusCode)
+ return errors.Wrapf(client.HandleErrorResponse(res), "Error uploading signature to %s", path)
}
}
diff --git a/vendor/github.com/containers/image/image/oci.go b/vendor/github.com/containers/image/image/oci.go
index 3c03e49bb..e7780c5a6 100644
--- a/vendor/github.com/containers/image/image/oci.go
+++ b/vendor/github.com/containers/image/image/oci.go
@@ -149,6 +149,16 @@ func (m *manifestOCI1) UpdatedImage(options types.ManifestUpdateOptions) (types.
switch options.ManifestMIMEType {
case "": // No conversion, OK
+ case manifest.DockerV2Schema1MediaType, manifest.DockerV2Schema1SignedMediaType:
+ // We can't directly convert to V1, but we can transitively convert via a V2 image
+ m2, err := copy.convertToManifestSchema2()
+ if err != nil {
+ return nil, err
+ }
+ return m2.UpdatedImage(types.ManifestUpdateOptions{
+ ManifestMIMEType: options.ManifestMIMEType,
+ InformationOnly: options.InformationOnly,
+ })
case manifest.DockerV2Schema2MediaType:
return copy.convertToManifestSchema2()
default:
diff --git a/vendor/github.com/containers/image/ostree/ostree_dest.go b/vendor/github.com/containers/image/ostree/ostree_dest.go
index 8154c9851..d5f0ff80c 100644
--- a/vendor/github.com/containers/image/ostree/ostree_dest.go
+++ b/vendor/github.com/containers/image/ostree/ostree_dest.go
@@ -14,6 +14,7 @@ import (
"os/exec"
"path/filepath"
"strconv"
+ "strings"
"syscall"
"time"
"unsafe"
@@ -175,7 +176,10 @@ func fixFiles(selinuxHnd *C.struct_selabel_handle, root string, dir string, user
if err != nil {
return err
}
- relPath = fmt.Sprintf("/%s", relPath)
+ // Handle /exports/hostfs as a special case. Files under this directory are copied to the host,
+ // thus we benefit from maintaining the same SELinux label they would have on the host as we could
+ // use hard links instead of copying the files.
+ relPath = fmt.Sprintf("/%s", strings.TrimPrefix(relPath, "exports/hostfs/"))
relPathC := C.CString(relPath)
defer C.free(unsafe.Pointer(relPathC))
@@ -237,7 +241,7 @@ func generateTarSplitMetadata(output *bytes.Buffer, file string) error {
}
defer stream.Close()
- gzReader, err := gzip.NewReader(stream)
+ gzReader, err := archive.DecompressStream(stream)
if err != nil {
return err
}
@@ -383,7 +387,7 @@ func (d *ostreeImageDestination) Commit() error {
var selinuxHnd *C.struct_selabel_handle
if os.Getuid() == 0 && selinux.GetEnabled() {
- selinuxHnd, err := C.selabel_open(C.SELABEL_CTX_FILE, nil, 0)
+ selinuxHnd, err = C.selabel_open(C.SELABEL_CTX_FILE, nil, 0)
if selinuxHnd == nil {
return errors.Wrapf(err, "cannot open the SELinux DB")
}
diff --git a/vendor/github.com/containers/image/tarball/tarball_reference.go b/vendor/github.com/containers/image/tarball/tarball_reference.go
index 4ccfb4063..a0819ac58 100644
--- a/vendor/github.com/containers/image/tarball/tarball_reference.go
+++ b/vendor/github.com/containers/image/tarball/tarball_reference.go
@@ -89,5 +89,5 @@ func (r *tarballReference) DeleteImage(ctx *types.SystemContext) error {
}
func (r *tarballReference) NewImageDestination(ctx *types.SystemContext) (types.ImageDestination, error) {
- return nil, fmt.Errorf("destination not implemented yet")
+ return nil, fmt.Errorf(`"tarball:" locations can only be read from, not written to`)
}