mirror of
https://github.com/containers/podman.git
synced 2026-04-16 13:00:44 -04:00
@@ -1,3 +1,33 @@
|
||||
- Changelog for HEAD (2020-11-24):
|
||||
* Set PATH env in systemd timer.
|
||||
* Docker compat API fixes
|
||||
* shell completions: remove usage of ShellCompDirectiveError
|
||||
* more shell completion improvements
|
||||
* Fix ip-range for classless subnet masks
|
||||
* Bump github.com/containers/common from 0.27.0 to 0.29.0
|
||||
* Add podman container ps command
|
||||
* clarify ps(1) fallback of `podman top`
|
||||
* APIv2 - create container sets wrong entrypoint
|
||||
* Enable remote shell completion without a running endpoint
|
||||
* Specify what the replace flag replaces in help text
|
||||
* APIv2 - strip CAP_ prefix from capabilities in json
|
||||
* Make c.networks() list include the default network
|
||||
* Allow containers to --restart on-failure with --rm
|
||||
* REST API v2 - list of images - mandatory Created attribute
|
||||
* Allow multiple --network flags for podman run/create
|
||||
* fix container cgroup lookup
|
||||
* Make podman service log events
|
||||
* vendor in containers/storage v1.24.1 containers/image v5.8.1
|
||||
* Document containers.conf settings for remote connections
|
||||
* Shell completion for podman ps and podman pod ps --filter
|
||||
* Add alias for podman network rm -> remove
|
||||
* add network connect|disconnect compat endpoints
|
||||
* Fix sed regex to update version in version/version.go
|
||||
* Github-Actions: Send e-mail on Cirrus cron failure
|
||||
* Align the podman pod ps --filter behavior with podman ps
|
||||
* podman-remote network rm --force is broken
|
||||
* Remove build \!remote flags from test
|
||||
|
||||
- Changelog for v2.2.0-rc1 (2020-11-18):
|
||||
* Add release notes for v2.2.0-RC1
|
||||
* correct numbering typo
|
||||
|
||||
@@ -12,7 +12,9 @@ import (
|
||||
"github.com/containers/podman/v2/libpod/define"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/registries"
|
||||
"github.com/containers/podman/v2/pkg/rootless"
|
||||
systemdGen "github.com/containers/podman/v2/pkg/systemd/generate"
|
||||
"github.com/containers/podman/v2/pkg/util"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -36,7 +38,35 @@ const (
|
||||
|
||||
type keyValueCompletion map[string]func(s string) ([]string, cobra.ShellCompDirective)
|
||||
|
||||
func getContainers(toComplete string, cType completeType, statuses ...string) ([]string, cobra.ShellCompDirective) {
|
||||
func setupContainerEngine(cmd *cobra.Command) (entities.ContainerEngine, error) {
|
||||
containerEngine, err := registry.NewContainerEngine(cmd, []string{})
|
||||
if err != nil {
|
||||
cobra.CompErrorln(err.Error())
|
||||
return nil, err
|
||||
}
|
||||
if !registry.IsRemote() && rootless.IsRootless() {
|
||||
err := containerEngine.SetupRootless(registry.Context(), cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return containerEngine, nil
|
||||
}
|
||||
|
||||
func setupImageEngine(cmd *cobra.Command) (entities.ImageEngine, error) {
|
||||
imageEngine, err := registry.NewImageEngine(cmd, []string{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// we also need to set up the container engine since this
|
||||
// is required to setup the rootless namespace
|
||||
if _, err = setupContainerEngine(cmd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return imageEngine, nil
|
||||
}
|
||||
|
||||
func getContainers(cmd *cobra.Command, toComplete string, cType completeType, statuses ...string) ([]string, cobra.ShellCompDirective) {
|
||||
suggestions := []string{}
|
||||
listOpts := entities.ContainerListOptions{
|
||||
Filters: make(map[string][]string),
|
||||
@@ -47,10 +77,15 @@ func getContainers(toComplete string, cType completeType, statuses ...string) ([
|
||||
listOpts.Filters["status"] = statuses
|
||||
}
|
||||
|
||||
containers, err := registry.ContainerEngine().ContainerList(registry.GetContext(), listOpts)
|
||||
engine, err := setupContainerEngine(cmd)
|
||||
if err != nil {
|
||||
cobra.CompErrorln(err.Error())
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
containers, err := engine.ContainerList(registry.GetContext(), listOpts)
|
||||
if err != nil {
|
||||
cobra.CompErrorln(err.Error())
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
for _, c := range containers {
|
||||
@@ -68,7 +103,7 @@ func getContainers(toComplete string, cType completeType, statuses ...string) ([
|
||||
return suggestions, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
func getPods(toComplete string, cType completeType, statuses ...string) ([]string, cobra.ShellCompDirective) {
|
||||
func getPods(cmd *cobra.Command, toComplete string, cType completeType, statuses ...string) ([]string, cobra.ShellCompDirective) {
|
||||
suggestions := []string{}
|
||||
listOpts := entities.PodPSOptions{
|
||||
Filters: make(map[string][]string),
|
||||
@@ -77,10 +112,15 @@ func getPods(toComplete string, cType completeType, statuses ...string) ([]strin
|
||||
listOpts.Filters["status"] = statuses
|
||||
}
|
||||
|
||||
pods, err := registry.ContainerEngine().PodPs(registry.GetContext(), listOpts)
|
||||
engine, err := setupContainerEngine(cmd)
|
||||
if err != nil {
|
||||
cobra.CompErrorln(err.Error())
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
pods, err := engine.PodPs(registry.GetContext(), listOpts)
|
||||
if err != nil {
|
||||
cobra.CompErrorln(err.Error())
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
for _, pod := range pods {
|
||||
@@ -98,14 +138,19 @@ func getPods(toComplete string, cType completeType, statuses ...string) ([]strin
|
||||
return suggestions, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
func getVolumes(toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
func getVolumes(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
suggestions := []string{}
|
||||
lsOpts := entities.VolumeListOptions{}
|
||||
|
||||
volumes, err := registry.ContainerEngine().VolumeList(registry.GetContext(), lsOpts)
|
||||
engine, err := setupContainerEngine(cmd)
|
||||
if err != nil {
|
||||
cobra.CompErrorln(err.Error())
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
volumes, err := engine.VolumeList(registry.GetContext(), lsOpts)
|
||||
if err != nil {
|
||||
cobra.CompErrorln(err.Error())
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
for _, v := range volumes {
|
||||
@@ -116,14 +161,19 @@ func getVolumes(toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
return suggestions, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
func getImages(toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
func getImages(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
suggestions := []string{}
|
||||
listOptions := entities.ImageListOptions{}
|
||||
|
||||
images, err := registry.ImageEngine().List(registry.GetContext(), listOptions)
|
||||
engine, err := setupImageEngine(cmd)
|
||||
if err != nil {
|
||||
cobra.CompErrorln(err.Error())
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
images, err := engine.List(registry.GetContext(), listOptions)
|
||||
if err != nil {
|
||||
cobra.CompErrorln(err.Error())
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
for _, image := range images {
|
||||
@@ -166,19 +216,24 @@ func getRegistries() ([]string, cobra.ShellCompDirective) {
|
||||
regs, err := registries.GetRegistries()
|
||||
if err != nil {
|
||||
cobra.CompErrorln(err.Error())
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
return regs, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
func getNetworks(toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
func getNetworks(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
suggestions := []string{}
|
||||
networkListOptions := entities.NetworkListOptions{}
|
||||
|
||||
networks, err := registry.ContainerEngine().NetworkList(registry.Context(), networkListOptions)
|
||||
engine, err := setupContainerEngine(cmd)
|
||||
if err != nil {
|
||||
cobra.CompErrorln(err.Error())
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
networks, err := engine.NetworkList(registry.Context(), networkListOptions)
|
||||
if err != nil {
|
||||
cobra.CompErrorln(err.Error())
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
for _, n := range networks {
|
||||
@@ -266,7 +321,7 @@ func AutocompleteContainers(cmd *cobra.Command, args []string, toComplete string
|
||||
if !validCurrentCmdLine(cmd, args, toComplete) {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
return getContainers(toComplete, completeDefault)
|
||||
return getContainers(cmd, toComplete, completeDefault)
|
||||
}
|
||||
|
||||
// AutocompleteContainersCreated - Autocomplete only created container names.
|
||||
@@ -274,7 +329,7 @@ func AutocompleteContainersCreated(cmd *cobra.Command, args []string, toComplete
|
||||
if !validCurrentCmdLine(cmd, args, toComplete) {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
return getContainers(toComplete, completeDefault, "created")
|
||||
return getContainers(cmd, toComplete, completeDefault, "created")
|
||||
}
|
||||
|
||||
// AutocompleteContainersExited - Autocomplete only exited container names.
|
||||
@@ -282,7 +337,7 @@ func AutocompleteContainersExited(cmd *cobra.Command, args []string, toComplete
|
||||
if !validCurrentCmdLine(cmd, args, toComplete) {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
return getContainers(toComplete, completeDefault, "exited")
|
||||
return getContainers(cmd, toComplete, completeDefault, "exited")
|
||||
}
|
||||
|
||||
// AutocompleteContainersPaused - Autocomplete only paused container names.
|
||||
@@ -290,7 +345,7 @@ func AutocompleteContainersPaused(cmd *cobra.Command, args []string, toComplete
|
||||
if !validCurrentCmdLine(cmd, args, toComplete) {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
return getContainers(toComplete, completeDefault, "paused")
|
||||
return getContainers(cmd, toComplete, completeDefault, "paused")
|
||||
}
|
||||
|
||||
// AutocompleteContainersRunning - Autocomplete only running container names.
|
||||
@@ -298,7 +353,7 @@ func AutocompleteContainersRunning(cmd *cobra.Command, args []string, toComplete
|
||||
if !validCurrentCmdLine(cmd, args, toComplete) {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
return getContainers(toComplete, completeDefault, "running")
|
||||
return getContainers(cmd, toComplete, completeDefault, "running")
|
||||
}
|
||||
|
||||
// AutocompleteContainersStartable - Autocomplete only created and exited container names.
|
||||
@@ -306,7 +361,7 @@ func AutocompleteContainersStartable(cmd *cobra.Command, args []string, toComple
|
||||
if !validCurrentCmdLine(cmd, args, toComplete) {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
return getContainers(toComplete, completeDefault, "created", "exited")
|
||||
return getContainers(cmd, toComplete, completeDefault, "created", "exited")
|
||||
}
|
||||
|
||||
// AutocompletePods - Autocomplete all pod names.
|
||||
@@ -314,7 +369,7 @@ func AutocompletePods(cmd *cobra.Command, args []string, toComplete string) ([]s
|
||||
if !validCurrentCmdLine(cmd, args, toComplete) {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
return getPods(toComplete, completeDefault)
|
||||
return getPods(cmd, toComplete, completeDefault)
|
||||
}
|
||||
|
||||
// AutocompletePodsRunning - Autocomplete only running pod names.
|
||||
@@ -323,7 +378,7 @@ func AutocompletePodsRunning(cmd *cobra.Command, args []string, toComplete strin
|
||||
if !validCurrentCmdLine(cmd, args, toComplete) {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
return getPods(toComplete, completeDefault, "running", "degraded")
|
||||
return getPods(cmd, toComplete, completeDefault, "running", "degraded")
|
||||
}
|
||||
|
||||
// AutocompleteContainersAndPods - Autocomplete container names and pod names.
|
||||
@@ -331,8 +386,8 @@ func AutocompleteContainersAndPods(cmd *cobra.Command, args []string, toComplete
|
||||
if !validCurrentCmdLine(cmd, args, toComplete) {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
containers, _ := getContainers(toComplete, completeDefault)
|
||||
pods, _ := getPods(toComplete, completeDefault)
|
||||
containers, _ := getContainers(cmd, toComplete, completeDefault)
|
||||
pods, _ := getPods(cmd, toComplete, completeDefault)
|
||||
return append(containers, pods...), cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
@@ -341,8 +396,8 @@ func AutocompleteContainersAndImages(cmd *cobra.Command, args []string, toComple
|
||||
if !validCurrentCmdLine(cmd, args, toComplete) {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
containers, _ := getContainers(toComplete, completeDefault)
|
||||
images, _ := getImages(toComplete)
|
||||
containers, _ := getContainers(cmd, toComplete, completeDefault)
|
||||
images, _ := getImages(cmd, toComplete)
|
||||
return append(containers, images...), cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
@@ -351,7 +406,7 @@ func AutocompleteVolumes(cmd *cobra.Command, args []string, toComplete string) (
|
||||
if !validCurrentCmdLine(cmd, args, toComplete) {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
return getVolumes(toComplete)
|
||||
return getVolumes(cmd, toComplete)
|
||||
}
|
||||
|
||||
// AutocompleteImages - Autocomplete images.
|
||||
@@ -359,7 +414,7 @@ func AutocompleteImages(cmd *cobra.Command, args []string, toComplete string) ([
|
||||
if !validCurrentCmdLine(cmd, args, toComplete) {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
return getImages(toComplete)
|
||||
return getImages(cmd, toComplete)
|
||||
}
|
||||
|
||||
// AutocompleteCreateRun - Autocomplete only the fist argument as image and then do file completion.
|
||||
@@ -368,7 +423,7 @@ func AutocompleteCreateRun(cmd *cobra.Command, args []string, toComplete string)
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
if len(args) < 1 {
|
||||
return getImages(toComplete)
|
||||
return getImages(cmd, toComplete)
|
||||
}
|
||||
// TODO: add path completion for files in the image
|
||||
return nil, cobra.ShellCompDirectiveDefault
|
||||
@@ -387,7 +442,7 @@ func AutocompleteNetworks(cmd *cobra.Command, args []string, toComplete string)
|
||||
if !validCurrentCmdLine(cmd, args, toComplete) {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
return getNetworks(toComplete)
|
||||
return getNetworks(cmd, toComplete)
|
||||
}
|
||||
|
||||
// AutocompleteCpCommand - Autocomplete podman cp command args.
|
||||
@@ -396,7 +451,7 @@ func AutocompleteCpCommand(cmd *cobra.Command, args []string, toComplete string)
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
if len(args) < 2 {
|
||||
containers, _ := getContainers(toComplete, completeDefault)
|
||||
containers, _ := getContainers(cmd, toComplete, completeDefault)
|
||||
for _, container := range containers {
|
||||
// TODO: Add path completion for inside the container if possible
|
||||
if strings.HasPrefix(container, toComplete) {
|
||||
@@ -410,6 +465,37 @@ func AutocompleteCpCommand(cmd *cobra.Command, args []string, toComplete string)
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
// AutocompleteNetworkConnectCmd - Autocomplete podman network connect/disconnect command args.
|
||||
func AutocompleteNetworkConnectCmd(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
if len(args) == 0 {
|
||||
return getNetworks(cmd, toComplete)
|
||||
}
|
||||
if len(args) == 1 {
|
||||
return getContainers(cmd, toComplete, completeDefault)
|
||||
}
|
||||
// don't complete more than 2 args
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
// AutocompleteTopCmd - Autocomplete podman top/pod top command args.
|
||||
func AutocompleteTopCmd(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
latest := cmd.Flags().Lookup("latest")
|
||||
// only complete containers/pods as first arg if latest is not set
|
||||
if len(args) == 0 && (latest == nil || !latest.Changed) {
|
||||
if cmd.Parent().Name() == "pod" {
|
||||
// need to complete pods since we are using pod top
|
||||
return getPods(cmd, toComplete, completeDefault)
|
||||
}
|
||||
return getContainers(cmd, toComplete, completeDefault)
|
||||
}
|
||||
descriptors, err := util.GetContainerPidInformationDescriptors()
|
||||
if err != nil {
|
||||
cobra.CompErrorln(err.Error())
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
return descriptors, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
// AutocompleteSystemConnections - Autocomplete system connections.
|
||||
func AutocompleteSystemConnections(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
if !validCurrentCmdLine(cmd, args, toComplete) {
|
||||
@@ -419,7 +505,7 @@ func AutocompleteSystemConnections(cmd *cobra.Command, args []string, toComplete
|
||||
cfg, err := config.ReadCustomConfig()
|
||||
if err != nil {
|
||||
cobra.CompErrorln(err.Error())
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
for k, v := range cfg.Engine.ServiceDestinations {
|
||||
@@ -464,7 +550,7 @@ func AutocompleteCreateAttach(cmd *cobra.Command, args []string, toComplete stri
|
||||
// -> host,container:[name],ns:[path],private
|
||||
func AutocompleteNamespace(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
kv := keyValueCompletion{
|
||||
"container:": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeDefault) },
|
||||
"container:": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeDefault) },
|
||||
"ns:": func(s string) ([]string, cobra.ShellCompDirective) { return nil, cobra.ShellCompDirectiveDefault },
|
||||
"host": nil,
|
||||
"private": nil,
|
||||
@@ -567,7 +653,8 @@ func AutocompleteUserFlag(cmd *cobra.Command, args []string, toComplete string)
|
||||
// but at this point we don't know the image.
|
||||
file, err := os.Open("/etc/group")
|
||||
if err != nil {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
cobra.CompErrorln(err.Error())
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
@@ -583,7 +670,8 @@ func AutocompleteUserFlag(cmd *cobra.Command, args []string, toComplete string)
|
||||
}
|
||||
}
|
||||
if err = scanner.Err(); err != nil {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
cobra.CompErrorln(err.Error())
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
return groups, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
@@ -592,7 +680,8 @@ func AutocompleteUserFlag(cmd *cobra.Command, args []string, toComplete string)
|
||||
// but at this point we don't know the image.
|
||||
file, err := os.Open("/etc/passwd")
|
||||
if err != nil {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
cobra.CompErrorln(err.Error())
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
@@ -607,7 +696,7 @@ func AutocompleteUserFlag(cmd *cobra.Command, args []string, toComplete string)
|
||||
}
|
||||
}
|
||||
if err = scanner.Err(); err != nil {
|
||||
return nil, cobra.ShellCompDirectiveError
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
return users, cobra.ShellCompDirectiveNoSpace
|
||||
}
|
||||
@@ -623,7 +712,7 @@ func AutocompleteMountFlag(cmd *cobra.Command, args []string, toComplete string)
|
||||
// AutocompleteVolumeFlag - Autocomplete volume flag options.
|
||||
// -> volumes and paths
|
||||
func AutocompleteVolumeFlag(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
volumes, _ := getVolumes(toComplete)
|
||||
volumes, _ := getVolumes(cmd, toComplete)
|
||||
directive := cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveDefault
|
||||
if strings.Contains(toComplete, ":") {
|
||||
// add space after second path
|
||||
@@ -641,8 +730,22 @@ func AutocompleteJSONFormat(cmd *cobra.Command, args []string, toComplete string
|
||||
// AutocompleteEventFilter - Autocomplete event filter flag options.
|
||||
// -> "container=", "event=", "image=", "pod=", "volume=", "type="
|
||||
func AutocompleteEventFilter(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
filters := []string{"container=", "event=", "image=", "pod=", "volume=", "type="}
|
||||
return filters, cobra.ShellCompDirectiveNoSpace
|
||||
eventTypes := func(_ string) ([]string, cobra.ShellCompDirective) {
|
||||
return []string{"attach", "checkpoint", "cleanup", "commit", "create", "exec",
|
||||
"export", "import", "init", "kill", "mount", "pause", "prune", "remove",
|
||||
"restart", "restore", "start", "stop", "sync", "unmount", "unpause",
|
||||
"pull", "push", "save", "tag", "untag", "refresh", "renumber",
|
||||
}, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
kv := keyValueCompletion{
|
||||
"container=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeDefault) },
|
||||
"image=": func(s string) ([]string, cobra.ShellCompDirective) { return getImages(cmd, s) },
|
||||
"pod=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(cmd, s, completeDefault) },
|
||||
"volume=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(cmd, s) },
|
||||
"event=": eventTypes,
|
||||
"type=": eventTypes,
|
||||
}
|
||||
return completeKeyValues(toComplete, kv)
|
||||
}
|
||||
|
||||
// AutocompleteSystemdRestartOptions - Autocomplete systemd restart options.
|
||||
@@ -753,15 +856,15 @@ var containerStatuses = []string{"created", "running", "paused", "stopped", "exi
|
||||
// AutocompletePsFilters - Autocomplete ps filter options.
|
||||
func AutocompletePsFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
kv := keyValueCompletion{
|
||||
"id=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeIDs) },
|
||||
"name=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeNames) },
|
||||
"id=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeIDs) },
|
||||
"name=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeNames) },
|
||||
"status=": func(_ string) ([]string, cobra.ShellCompDirective) {
|
||||
return containerStatuses, cobra.ShellCompDirectiveNoFileComp
|
||||
},
|
||||
"ancestor": func(s string) ([]string, cobra.ShellCompDirective) { return getImages(s) },
|
||||
"before=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeDefault) },
|
||||
"since=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeDefault) },
|
||||
"volume=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(s) },
|
||||
"ancestor": func(s string) ([]string, cobra.ShellCompDirective) { return getImages(cmd, s) },
|
||||
"before=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeDefault) },
|
||||
"since=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeDefault) },
|
||||
"volume=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(cmd, s) },
|
||||
"health=": func(_ string) ([]string, cobra.ShellCompDirective) {
|
||||
return []string{define.HealthCheckHealthy,
|
||||
define.HealthCheckUnhealthy}, cobra.ShellCompDirectiveNoFileComp
|
||||
@@ -776,14 +879,14 @@ func AutocompletePsFilters(cmd *cobra.Command, args []string, toComplete string)
|
||||
// AutocompletePodPsFilters - Autocomplete pod ps filter options.
|
||||
func AutocompletePodPsFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
kv := keyValueCompletion{
|
||||
"id=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(s, completeIDs) },
|
||||
"name=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(s, completeNames) },
|
||||
"id=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(cmd, s, completeIDs) },
|
||||
"name=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(cmd, s, completeNames) },
|
||||
"status=": func(_ string) ([]string, cobra.ShellCompDirective) {
|
||||
return []string{"stopped", "running",
|
||||
"paused", "exited", "dead", "created", "degraded"}, cobra.ShellCompDirectiveNoFileComp
|
||||
},
|
||||
"ctr-ids=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeIDs) },
|
||||
"ctr-names=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeNames) },
|
||||
"ctr-ids=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeIDs) },
|
||||
"ctr-names=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeNames) },
|
||||
"ctr-number=": nil,
|
||||
"ctr-status=": func(_ string) ([]string, cobra.ShellCompDirective) {
|
||||
return containerStatuses, cobra.ShellCompDirectiveNoFileComp
|
||||
@@ -792,3 +895,47 @@ func AutocompletePodPsFilters(cmd *cobra.Command, args []string, toComplete stri
|
||||
}
|
||||
return completeKeyValues(toComplete, kv)
|
||||
}
|
||||
|
||||
// AutocompleteImageFilters - Autocomplete image ls --filter options.
|
||||
func AutocompleteImageFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
getBool := func(_ string) ([]string, cobra.ShellCompDirective) {
|
||||
return []string{"true", "false"}, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
getImg := func(s string) ([]string, cobra.ShellCompDirective) { return getImages(cmd, s) }
|
||||
kv := keyValueCompletion{
|
||||
"before=": getImg,
|
||||
"since=": getImg,
|
||||
"label=": nil,
|
||||
"reference=": nil,
|
||||
"dangling=": getBool,
|
||||
"readonly=": getBool,
|
||||
}
|
||||
return completeKeyValues(toComplete, kv)
|
||||
}
|
||||
|
||||
// AutocompleteNetworkFilters - Autocomplete network ls --filter options.
|
||||
func AutocompleteNetworkFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
kv := keyValueCompletion{
|
||||
"name=": func(s string) ([]string, cobra.ShellCompDirective) { return getNetworks(cmd, s) },
|
||||
"plugin=": nil,
|
||||
}
|
||||
return completeKeyValues(toComplete, kv)
|
||||
}
|
||||
|
||||
// AutocompleteVolumeFilters - Autocomplete volume ls --filter options.
|
||||
func AutocompleteVolumeFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
local := func(_ string) ([]string, cobra.ShellCompDirective) {
|
||||
return []string{"local"}, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
kv := keyValueCompletion{
|
||||
"name=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(cmd, s) },
|
||||
"driver=": local,
|
||||
"scope=": local,
|
||||
"label=": nil,
|
||||
"opt=": nil,
|
||||
"dangling=": func(_ string) ([]string, cobra.ShellCompDirective) {
|
||||
return []string{"true", "false"}, cobra.ShellCompDirectiveNoFileComp
|
||||
},
|
||||
}
|
||||
return completeKeyValues(toComplete, kv)
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
|
||||
cgroupsFlagName := "cgroups"
|
||||
createFlags.StringVar(
|
||||
&cf.CGroupsMode,
|
||||
cgroupsFlagName, containerConfig.Cgroups(),
|
||||
cgroupsFlagName, cgroupConfig(),
|
||||
`control container cgroup configuration ("enabled"|"disabled"|"no-conmon"|"split")`,
|
||||
)
|
||||
_ = cmd.RegisterFlagCompletionFunc(cgroupsFlagName, AutocompleteCgroupMode)
|
||||
@@ -180,7 +180,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
|
||||
deviceFlagName := "device"
|
||||
createFlags.StringSliceVar(
|
||||
&cf.Devices,
|
||||
deviceFlagName, containerConfig.Devices(),
|
||||
deviceFlagName, devices(),
|
||||
fmt.Sprintf("Add a host device to the container"),
|
||||
)
|
||||
_ = cmd.RegisterFlagCompletionFunc(deviceFlagName, completion.AutocompleteDefault)
|
||||
@@ -238,7 +238,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
|
||||
|
||||
envFlagName := "env"
|
||||
createFlags.StringArrayP(
|
||||
envFlagName, "e", containerConfig.Env(),
|
||||
envFlagName, "e", env(),
|
||||
"Set environment variables in container",
|
||||
)
|
||||
_ = cmd.RegisterFlagCompletionFunc(envFlagName, completion.AutocompleteNone)
|
||||
@@ -357,7 +357,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
|
||||
initPathFlagName := "init-path"
|
||||
createFlags.StringVar(
|
||||
&cf.InitPath,
|
||||
initPathFlagName, containerConfig.InitPath(),
|
||||
initPathFlagName, initPath(),
|
||||
// Do not use the Value field for setting the default value to determine user input (i.e., non-empty string)
|
||||
fmt.Sprintf("Path to the container-init binary"),
|
||||
)
|
||||
@@ -508,7 +508,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
|
||||
|
||||
pidsLimitFlagName := "pids-limit"
|
||||
createFlags.Int64(
|
||||
pidsLimitFlagName, containerConfig.PidsLimit(),
|
||||
pidsLimitFlagName, pidsLimit(),
|
||||
"Tune container pids limit (set 0 for unlimited, -1 for server defaults)",
|
||||
)
|
||||
_ = cmd.RegisterFlagCompletionFunc(pidsLimitFlagName, completion.AutocompleteNone)
|
||||
@@ -543,7 +543,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
|
||||
pullFlagName := "pull"
|
||||
createFlags.StringVar(
|
||||
&cf.Pull,
|
||||
pullFlagName, containerConfig.Engine.PullPolicy,
|
||||
pullFlagName, policy(),
|
||||
`Pull image before creating ("always"|"missing"|"never")`,
|
||||
)
|
||||
_ = cmd.RegisterFlagCompletionFunc(pullFlagName, AutocompletePullOption)
|
||||
@@ -606,7 +606,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
|
||||
|
||||
shmSizeFlagName := "shm-size"
|
||||
createFlags.String(
|
||||
shmSizeFlagName, containerConfig.ShmSize(),
|
||||
shmSizeFlagName, shmSize(),
|
||||
"Size of /dev/shm "+sizeWithUnitFormat,
|
||||
)
|
||||
_ = cmd.RegisterFlagCompletionFunc(shmSizeFlagName, completion.AutocompleteNone)
|
||||
@@ -715,7 +715,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
|
||||
ulimitFlagName := "ulimit"
|
||||
createFlags.StringSliceVar(
|
||||
&cf.Ulimit,
|
||||
ulimitFlagName, containerConfig.Ulimits(),
|
||||
ulimitFlagName, ulimits(),
|
||||
"Ulimit options",
|
||||
)
|
||||
_ = cmd.RegisterFlagCompletionFunc(ulimitFlagName, completion.AutocompleteNone)
|
||||
@@ -753,7 +753,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
|
||||
volumeFlagName := "volume"
|
||||
createFlags.StringArrayVarP(
|
||||
&cf.Volume,
|
||||
volumeFlagName, "v", containerConfig.Volumes(),
|
||||
volumeFlagName, "v", volumes(),
|
||||
"Bind mount a volume into the container",
|
||||
)
|
||||
_ = cmd.RegisterFlagCompletionFunc(volumeFlagName, AutocompleteVolumeFlag)
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/podman/v2/cmd/podman/registry"
|
||||
"github.com/containers/podman/v2/pkg/api/handlers"
|
||||
"github.com/containers/podman/v2/pkg/cgroups"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
@@ -133,10 +134,9 @@ func stringMaptoArray(m map[string]string) []string {
|
||||
// a specgen spec.
|
||||
func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroupsManager string) (*ContainerCLIOpts, []string, error) {
|
||||
var (
|
||||
aliases []string
|
||||
capAdd []string
|
||||
cappDrop []string
|
||||
entrypoint string
|
||||
entrypoint *string
|
||||
init bool
|
||||
specPorts []specgen.PortMapping
|
||||
)
|
||||
@@ -180,13 +180,14 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
|
||||
// marshall it to json; otherwise it should just be the string
|
||||
// value
|
||||
if len(cc.Config.Entrypoint) > 0 {
|
||||
entrypoint = cc.Config.Entrypoint[0]
|
||||
entrypoint = &cc.Config.Entrypoint[0]
|
||||
if len(cc.Config.Entrypoint) > 1 {
|
||||
b, err := json.Marshal(cc.Config.Entrypoint)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
entrypoint = string(b)
|
||||
var jsonString = string(b)
|
||||
entrypoint = &jsonString
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,7 +211,7 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
|
||||
mounts = append(mounts, mount)
|
||||
}
|
||||
|
||||
//volumes
|
||||
// volumes
|
||||
volumes := make([]string, 0, len(cc.Config.Volumes))
|
||||
for v := range cc.Config.Volumes {
|
||||
volumes = append(volumes, v)
|
||||
@@ -240,16 +241,6 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
|
||||
}
|
||||
}
|
||||
|
||||
// network names
|
||||
endpointsConfig := cc.NetworkingConfig.EndpointsConfig
|
||||
cniNetworks := make([]string, 0, len(endpointsConfig))
|
||||
for netName, endpoint := range endpointsConfig {
|
||||
cniNetworks = append(cniNetworks, netName)
|
||||
if len(endpoint.Aliases) > 0 {
|
||||
aliases = append(aliases, endpoint.Aliases...)
|
||||
}
|
||||
}
|
||||
|
||||
// netMode
|
||||
nsmode, _, err := specgen.ParseNetworkNamespace(cc.HostConfig.NetworkMode.NetworkName())
|
||||
if err != nil {
|
||||
@@ -266,8 +257,6 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
|
||||
// defined when there is only one network.
|
||||
netInfo := entities.NetOptions{
|
||||
AddHosts: cc.HostConfig.ExtraHosts,
|
||||
Aliases: aliases,
|
||||
CNINetworks: cniNetworks,
|
||||
DNSOptions: cc.HostConfig.DNSOptions,
|
||||
DNSSearch: cc.HostConfig.DNSSearch,
|
||||
DNSServers: dns,
|
||||
@@ -275,31 +264,58 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
|
||||
PublishPorts: specPorts,
|
||||
}
|
||||
|
||||
// static IP and MAC
|
||||
if len(endpointsConfig) == 1 {
|
||||
for _, ep := range endpointsConfig {
|
||||
// if IP address is provided
|
||||
if len(ep.IPAddress) > 0 {
|
||||
staticIP := net.ParseIP(ep.IPAddress)
|
||||
netInfo.StaticIP = &staticIP
|
||||
// network names
|
||||
switch {
|
||||
case len(cc.NetworkingConfig.EndpointsConfig) > 0:
|
||||
var aliases []string
|
||||
|
||||
endpointsConfig := cc.NetworkingConfig.EndpointsConfig
|
||||
cniNetworks := make([]string, 0, len(endpointsConfig))
|
||||
for netName, endpoint := range endpointsConfig {
|
||||
|
||||
cniNetworks = append(cniNetworks, netName)
|
||||
|
||||
if endpoint == nil {
|
||||
continue
|
||||
}
|
||||
// If MAC address is provided
|
||||
if len(ep.MacAddress) > 0 {
|
||||
staticMac, err := net.ParseMAC(ep.MacAddress)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
netInfo.StaticMAC = &staticMac
|
||||
if len(endpoint.Aliases) > 0 {
|
||||
aliases = append(aliases, endpoint.Aliases...)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// static IP and MAC
|
||||
if len(endpointsConfig) == 1 {
|
||||
for _, ep := range endpointsConfig {
|
||||
if ep == nil {
|
||||
continue
|
||||
}
|
||||
// if IP address is provided
|
||||
if len(ep.IPAddress) > 0 {
|
||||
staticIP := net.ParseIP(ep.IPAddress)
|
||||
netInfo.StaticIP = &staticIP
|
||||
}
|
||||
// If MAC address is provided
|
||||
if len(ep.MacAddress) > 0 {
|
||||
staticMac, err := net.ParseMAC(ep.MacAddress)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
netInfo.StaticMAC = &staticMac
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
netInfo.Aliases = aliases
|
||||
netInfo.CNINetworks = cniNetworks
|
||||
case len(cc.HostConfig.NetworkMode) > 0:
|
||||
netInfo.CNINetworks = []string{string(cc.HostConfig.NetworkMode)}
|
||||
}
|
||||
|
||||
// Note: several options here are marked as "don't need". this is based
|
||||
// on speculation by Matt and I. We think that these come into play later
|
||||
// like with start. We believe this is just a difference in podman/compat
|
||||
cliOpts := ContainerCLIOpts{
|
||||
//Attach: nil, // dont need?
|
||||
// Attach: nil, // dont need?
|
||||
Authfile: "",
|
||||
CapAdd: append(capAdd, cc.HostConfig.CapAdd...),
|
||||
CapDrop: append(cappDrop, cc.HostConfig.CapDrop...),
|
||||
@@ -310,18 +326,18 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
|
||||
CPURTPeriod: uint64(cc.HostConfig.CPURealtimePeriod),
|
||||
CPURTRuntime: cc.HostConfig.CPURealtimeRuntime,
|
||||
CPUShares: uint64(cc.HostConfig.CPUShares),
|
||||
//CPUS: 0, // dont need?
|
||||
// CPUS: 0, // dont need?
|
||||
CPUSetCPUs: cc.HostConfig.CpusetCpus,
|
||||
CPUSetMems: cc.HostConfig.CpusetMems,
|
||||
//Detach: false, // dont need
|
||||
//DetachKeys: "", // dont need
|
||||
// Detach: false, // dont need
|
||||
// DetachKeys: "", // dont need
|
||||
Devices: devices,
|
||||
DeviceCGroupRule: nil,
|
||||
DeviceReadBPs: readBps,
|
||||
DeviceReadIOPs: readIops,
|
||||
DeviceWriteBPs: writeBps,
|
||||
DeviceWriteIOPs: writeIops,
|
||||
Entrypoint: &entrypoint,
|
||||
Entrypoint: entrypoint,
|
||||
Env: cc.Config.Env,
|
||||
Expose: expose,
|
||||
GroupAdd: cc.HostConfig.GroupAdd,
|
||||
@@ -436,7 +452,70 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
|
||||
}
|
||||
|
||||
// specgen assumes the image name is arg[0]
|
||||
cmd := []string{cc.Image}
|
||||
cmd := []string{cc.Config.Image}
|
||||
cmd = append(cmd, cc.Config.Cmd...)
|
||||
return &cliOpts, cmd, nil
|
||||
}
|
||||
|
||||
func ulimits() []string {
|
||||
if !registry.IsRemote() {
|
||||
return containerConfig.Ulimits()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func cgroupConfig() string {
|
||||
if !registry.IsRemote() {
|
||||
return containerConfig.Cgroups()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func devices() []string {
|
||||
if !registry.IsRemote() {
|
||||
return containerConfig.Devices()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func env() []string {
|
||||
if !registry.IsRemote() {
|
||||
return containerConfig.Env()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func initPath() string {
|
||||
if !registry.IsRemote() {
|
||||
return containerConfig.InitPath()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func pidsLimit() int64 {
|
||||
if !registry.IsRemote() {
|
||||
return containerConfig.PidsLimit()
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func policy() string {
|
||||
if !registry.IsRemote() {
|
||||
return containerConfig.Engine.PullPolicy
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func shmSize() string {
|
||||
if !registry.IsRemote() {
|
||||
return containerConfig.ShmSize()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func volumes() []string {
|
||||
if !registry.IsRemote() {
|
||||
return containerConfig.Volumes()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
// by validate must not need any state information on the flag (i.e. changed)
|
||||
func (c *ContainerCLIOpts) validate() error {
|
||||
var ()
|
||||
if c.Rm && c.Restart != "" && c.Restart != "no" {
|
||||
if c.Rm && (c.Restart != "" && c.Restart != "no" && c.Restart != "on-failure") {
|
||||
return errors.Errorf(`the --rm option conflicts with --restart, when the restartPolicy is not "" and "no"`)
|
||||
}
|
||||
|
||||
|
||||
@@ -59,8 +59,8 @@ func DefineNetFlags(cmd *cobra.Command) {
|
||||
_ = cmd.RegisterFlagCompletionFunc(macAddressFlagName, completion.AutocompleteNone)
|
||||
|
||||
networkFlagName := "network"
|
||||
netFlags.String(
|
||||
networkFlagName, containerConfig.NetNS(),
|
||||
netFlags.StringArray(
|
||||
networkFlagName, []string{containerConfig.NetNS()},
|
||||
"Connect a container to a network",
|
||||
)
|
||||
_ = cmd.RegisterFlagCompletionFunc(networkFlagName, AutocompleteNetworks)
|
||||
@@ -194,25 +194,29 @@ func NetFlagsToNetOptions(cmd *cobra.Command) (*entities.NetOptions, error) {
|
||||
}
|
||||
|
||||
if cmd.Flags().Changed("network") {
|
||||
network, err := cmd.Flags().GetString("network")
|
||||
networks, err := cmd.Flags().GetStringArray("network")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i, network := range networks {
|
||||
parts := strings.SplitN(network, ":", 2)
|
||||
|
||||
parts := strings.SplitN(network, ":", 2)
|
||||
ns, cniNets, err := specgen.ParseNetworkNamespace(network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if i > 0 && (len(cniNets) == 0 || len(opts.CNINetworks) == 0) {
|
||||
return nil, errors.Errorf("network conflict between type %s and %s", opts.Network.NSMode, ns.NSMode)
|
||||
}
|
||||
|
||||
ns, cniNets, err := specgen.ParseNetworkNamespace(network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if len(parts) > 1 {
|
||||
opts.NetworkOptions = make(map[string][]string)
|
||||
opts.NetworkOptions[parts[0]] = strings.Split(parts[1], ",")
|
||||
cniNets = nil
|
||||
}
|
||||
opts.Network = ns
|
||||
opts.CNINetworks = append(opts.CNINetworks, cniNets...)
|
||||
}
|
||||
|
||||
if len(parts) > 1 {
|
||||
opts.NetworkOptions = make(map[string][]string)
|
||||
opts.NetworkOptions[parts[0]] = strings.Split(parts[1], ",")
|
||||
cniNets = nil
|
||||
}
|
||||
opts.Network = ns
|
||||
opts.CNINetworks = cniNets
|
||||
}
|
||||
|
||||
aliases, err := cmd.Flags().GetStringSlice("network-alias")
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/containers/podman/v2/pkg/util"
|
||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -45,7 +44,7 @@ func parseVolumes(volumeFlag, mountFlag, tmpfsFlag []string, addReadOnlyTmpfs bo
|
||||
}
|
||||
|
||||
// Next --volumes flag.
|
||||
volumeMounts, volumeVolumes, overlayVolumes, err := getVolumeMounts(volumeFlag)
|
||||
volumeMounts, volumeVolumes, overlayVolumes, err := specgen.GenVolumeMounts(volumeFlag)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
@@ -594,105 +593,6 @@ func getImageVolume(args []string) (*specgen.ImageVolume, error) {
|
||||
return newVolume, nil
|
||||
}
|
||||
|
||||
func getVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*specgen.NamedVolume, map[string]*specgen.OverlayVolume, error) {
|
||||
mounts := make(map[string]spec.Mount)
|
||||
volumes := make(map[string]*specgen.NamedVolume)
|
||||
overlayVolumes := make(map[string]*specgen.OverlayVolume)
|
||||
|
||||
volumeFormatErr := errors.Errorf("incorrect volume format, should be [host-dir:]ctr-dir[:option]")
|
||||
|
||||
for _, vol := range volumeFlag {
|
||||
var (
|
||||
options []string
|
||||
src string
|
||||
dest string
|
||||
err error
|
||||
)
|
||||
|
||||
splitVol := strings.Split(vol, ":")
|
||||
if len(splitVol) > 3 {
|
||||
return nil, nil, nil, errors.Wrapf(volumeFormatErr, vol)
|
||||
}
|
||||
|
||||
src = splitVol[0]
|
||||
if len(splitVol) == 1 {
|
||||
// This is an anonymous named volume. Only thing given
|
||||
// is destination.
|
||||
// Name/source will be blank, and populated by libpod.
|
||||
src = ""
|
||||
dest = splitVol[0]
|
||||
} else if len(splitVol) > 1 {
|
||||
dest = splitVol[1]
|
||||
}
|
||||
if len(splitVol) > 2 {
|
||||
if options, err = parse.ValidateVolumeOpts(strings.Split(splitVol[2], ",")); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Do not check source dir for anonymous volumes
|
||||
if len(splitVol) > 1 {
|
||||
if err := parse.ValidateVolumeHostDir(src); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
if err := parse.ValidateVolumeCtrDir(dest); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
cleanDest := filepath.Clean(dest)
|
||||
|
||||
if strings.HasPrefix(src, "/") || strings.HasPrefix(src, ".") {
|
||||
// This is not a named volume
|
||||
overlayFlag := false
|
||||
for _, o := range options {
|
||||
if o == "O" {
|
||||
overlayFlag = true
|
||||
if len(options) > 1 {
|
||||
return nil, nil, nil, errors.New("can't use 'O' with other options")
|
||||
}
|
||||
}
|
||||
}
|
||||
if overlayFlag {
|
||||
// This is a overlay volume
|
||||
newOverlayVol := new(specgen.OverlayVolume)
|
||||
newOverlayVol.Destination = cleanDest
|
||||
newOverlayVol.Source = src
|
||||
if _, ok := overlayVolumes[newOverlayVol.Destination]; ok {
|
||||
return nil, nil, nil, errors.Wrapf(errDuplicateDest, newOverlayVol.Destination)
|
||||
}
|
||||
overlayVolumes[newOverlayVol.Destination] = newOverlayVol
|
||||
} else {
|
||||
newMount := spec.Mount{
|
||||
Destination: cleanDest,
|
||||
Type: string(TypeBind),
|
||||
Source: src,
|
||||
Options: options,
|
||||
}
|
||||
if _, ok := mounts[newMount.Destination]; ok {
|
||||
return nil, nil, nil, errors.Wrapf(errDuplicateDest, newMount.Destination)
|
||||
}
|
||||
mounts[newMount.Destination] = newMount
|
||||
}
|
||||
} else {
|
||||
// This is a named volume
|
||||
newNamedVol := new(specgen.NamedVolume)
|
||||
newNamedVol.Name = src
|
||||
newNamedVol.Dest = cleanDest
|
||||
newNamedVol.Options = options
|
||||
|
||||
if _, ok := volumes[newNamedVol.Dest]; ok {
|
||||
return nil, nil, nil, errors.Wrapf(errDuplicateDest, newNamedVol.Dest)
|
||||
}
|
||||
volumes[newNamedVol.Dest] = newNamedVol
|
||||
}
|
||||
|
||||
logrus.Debugf("User mount %s:%s options %v", src, dest, options)
|
||||
}
|
||||
|
||||
return mounts, volumes, overlayVolumes, nil
|
||||
}
|
||||
|
||||
// GetTmpfsMounts creates spec.Mount structs for user-requested tmpfs mounts
|
||||
func getTmpfsMounts(tmpfsFlag []string) (map[string]spec.Mount, error) {
|
||||
m := make(map[string]spec.Mount)
|
||||
|
||||
@@ -29,15 +29,25 @@ var (
|
||||
psDescription = "Prints out information about the containers"
|
||||
psCommand = &cobra.Command{
|
||||
Use: "ps [options]",
|
||||
Args: validate.NoArgs,
|
||||
Short: "List containers",
|
||||
Long: psDescription,
|
||||
RunE: ps,
|
||||
Args: validate.NoArgs,
|
||||
ValidArgsFunction: completion.AutocompleteNone,
|
||||
Example: `podman ps -a
|
||||
podman ps -a --format "{{.ID}} {{.Image}} {{.Labels}} {{.Mounts}}"
|
||||
podman ps --size --sort names`,
|
||||
}
|
||||
|
||||
psContainerCommand = &cobra.Command{
|
||||
Use: psCommand.Use,
|
||||
Short: psCommand.Short,
|
||||
Long: psCommand.Long,
|
||||
RunE: psCommand.RunE,
|
||||
Args: psCommand.Args,
|
||||
ValidArgsFunction: psCommand.ValidArgsFunction,
|
||||
Example: strings.ReplaceAll(psCommand.Example, "podman ps", "podman container ps"),
|
||||
}
|
||||
)
|
||||
var (
|
||||
listOpts = entities.ContainerListOptions{
|
||||
@@ -54,6 +64,14 @@ func init() {
|
||||
})
|
||||
listFlagSet(psCommand)
|
||||
validate.AddLatestFlag(psCommand, &listOpts.Latest)
|
||||
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: psContainerCommand,
|
||||
Parent: containerCmd,
|
||||
})
|
||||
listFlagSet(psContainerCommand)
|
||||
validate.AddLatestFlag(psContainerCommand, &listOpts.Latest)
|
||||
}
|
||||
|
||||
func listFlagSet(cmd *cobra.Command) {
|
||||
|
||||
@@ -18,12 +18,10 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
topDescription = `Similar to system "top" command.
|
||||
|
||||
Specify format descriptors to alter the output.
|
||||
|
||||
Running "podman top -l pid pcpu seccomp" will print the process ID, the CPU percentage and the seccomp mode of each process of the latest container.`
|
||||
topDescription = `Display the running processes of a container.
|
||||
|
||||
The top command extends the ps(1) compatible AIX descriptors with container-specific ones as shown below. In the presence of ps(1) specific flags (e.g, -eo), Podman will execute ps(1) inside the container.
|
||||
`
|
||||
topOptions = entities.TopOptions{}
|
||||
|
||||
topCommand = &cobra.Command{
|
||||
@@ -32,7 +30,7 @@ var (
|
||||
Long: topDescription,
|
||||
RunE: top,
|
||||
Args: cobra.ArbitraryArgs,
|
||||
ValidArgsFunction: common.AutocompleteContainersRunning,
|
||||
ValidArgsFunction: common.AutocompleteTopCmd,
|
||||
Example: `podman top ctrID
|
||||
podman top --latest
|
||||
podman top ctrID pid seccomp args %C
|
||||
|
||||
@@ -79,8 +79,7 @@ func imageListFlagSet(cmd *cobra.Command) {
|
||||
|
||||
filterFlagName := "filter"
|
||||
flags.StringSliceVarP(&listOptions.Filter, filterFlagName, "f", []string{}, "Filter output based on conditions provided (default [])")
|
||||
// TODO: add completion function for filters
|
||||
_ = cmd.RegisterFlagCompletionFunc(filterFlagName, completion.AutocompleteNone)
|
||||
_ = cmd.RegisterFlagCompletionFunc(filterFlagName, common.AutocompleteImageFilters)
|
||||
|
||||
formatFlagName := "format"
|
||||
flags.StringVar(&listFlag.format, formatFlagName, "", "Change the output format to JSON or a Go template")
|
||||
|
||||
@@ -23,7 +23,7 @@ var (
|
||||
loadDescription = "Loads an image from a locally stored archive (tar file) into container storage."
|
||||
loadCommand = &cobra.Command{
|
||||
Use: "load [options] [NAME[:TAG]]",
|
||||
Short: "Load an image from container archive",
|
||||
Short: "Load image(s) from a tar archive",
|
||||
Long: loadDescription,
|
||||
RunE: load,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
|
||||
@@ -17,7 +17,7 @@ var (
|
||||
RunE: networkConnect,
|
||||
Example: `podman network connect web secondary`,
|
||||
Args: cobra.ExactArgs(2),
|
||||
ValidArgsFunction: common.AutocompleteNetworks,
|
||||
ValidArgsFunction: common.AutocompleteNetworkConnectCmd,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ var (
|
||||
RunE: networkDisconnect,
|
||||
Example: `podman network disconnect web secondary`,
|
||||
Args: cobra.ExactArgs(2),
|
||||
ValidArgsFunction: common.AutocompleteNetworks,
|
||||
ValidArgsFunction: common.AutocompleteNetworkConnectCmd,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ func networkListFlags(flags *pflag.FlagSet) {
|
||||
|
||||
filterFlagName := "filter"
|
||||
flags.StringVarP(&networkListOptions.Filter, filterFlagName, "", "", "Provide filter values (e.g. 'name=podman')")
|
||||
_ = networklistCommand.RegisterFlagCompletionFunc(filterFlagName, completion.AutocompleteNone)
|
||||
_ = networklistCommand.RegisterFlagCompletionFunc(filterFlagName, common.AutocompleteNetworkFilters)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ var (
|
||||
networkrmDescription = `Remove networks`
|
||||
networkrmCommand = &cobra.Command{
|
||||
Use: "rm [options] NETWORK [NETWORK...]",
|
||||
Aliases: []string{"remove"},
|
||||
Short: "network rm",
|
||||
Long: networkrmDescription,
|
||||
RunE: networkRm,
|
||||
|
||||
@@ -94,7 +94,7 @@ func init() {
|
||||
flags.StringVar(&podIDFile, podIDFileFlagName, "", "Write the pod ID to the file")
|
||||
_ = createCommand.RegisterFlagCompletionFunc(podIDFileFlagName, completion.AutocompleteDefault)
|
||||
|
||||
flags.BoolVar(&replace, "replace", false, "If a pod with the same exists, replace it")
|
||||
flags.BoolVar(&replace, "replace", false, "If a pod with the same name exists, replace it")
|
||||
|
||||
shareFlagName := "share"
|
||||
flags.StringVar(&share, shareFlagName, specgen.DefaultKernelNamespaces, "A comma delimited list of kernel namespaces the pod will share")
|
||||
@@ -171,33 +171,7 @@ func create(cmd *cobra.Command, args []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
createOptions.Net.Network = specgen.Namespace{}
|
||||
if cmd.Flag("network").Changed {
|
||||
netInput, err := cmd.Flags().GetString("network")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parts := strings.SplitN(netInput, ":", 2)
|
||||
|
||||
n := specgen.Namespace{}
|
||||
switch {
|
||||
case netInput == "bridge":
|
||||
n.NSMode = specgen.Bridge
|
||||
case netInput == "host":
|
||||
n.NSMode = specgen.Host
|
||||
case netInput == "slirp4netns", strings.HasPrefix(netInput, "slirp4netns:"):
|
||||
n.NSMode = specgen.Slirp
|
||||
if len(parts) > 1 {
|
||||
createOptions.Net.NetworkOptions = make(map[string][]string)
|
||||
createOptions.Net.NetworkOptions[parts[0]] = strings.Split(parts[1], ",")
|
||||
}
|
||||
default:
|
||||
// Container and NS mode are presently unsupported
|
||||
n.NSMode = specgen.Bridge
|
||||
createOptions.Net.CNINetworks = strings.Split(netInput, ",")
|
||||
}
|
||||
createOptions.Net.Network = n
|
||||
}
|
||||
if len(createOptions.Net.PublishPorts) > 0 {
|
||||
if !createOptions.Infra {
|
||||
return errors.Errorf("you must have an infra container to publish port bindings to the host")
|
||||
|
||||
@@ -29,7 +29,7 @@ var (
|
||||
Long: topDescription,
|
||||
RunE: top,
|
||||
Args: cobra.ArbitraryArgs,
|
||||
ValidArgsFunction: common.AutocompletePodsRunning,
|
||||
ValidArgsFunction: common.AutocompleteTopCmd,
|
||||
Example: `podman pod top podID
|
||||
podman pod top --latest
|
||||
podman pod top podID pid seccomp args %C
|
||||
|
||||
@@ -113,6 +113,28 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
cfg := registry.PodmanConfig()
|
||||
|
||||
// --connection is not as "special" as --remote so we can wait and process it here
|
||||
conn := cmd.Root().LocalFlags().Lookup("connection")
|
||||
if conn != nil && conn.Changed {
|
||||
cfg.Engine.ActiveService = conn.Value.String()
|
||||
|
||||
var err error
|
||||
cfg.URI, cfg.Identity, err = cfg.ActiveDestination()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to resolve active destination")
|
||||
}
|
||||
|
||||
if err := cmd.Root().LocalFlags().Set("url", cfg.URI); err != nil {
|
||||
return errors.Wrap(err, "failed to override --url flag")
|
||||
}
|
||||
|
||||
if err := cmd.Root().LocalFlags().Set("identity", cfg.Identity); err != nil {
|
||||
return errors.Wrap(err, "failed to override --identity flag")
|
||||
}
|
||||
}
|
||||
|
||||
// Special case if command is hidden completion command ("__complete","__completeNoDesc")
|
||||
// Since __completeNoDesc is an alias the cm.Name is always __complete
|
||||
if cmd.Name() == cobra.ShellCompRequestCmd {
|
||||
@@ -129,37 +151,9 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
|
||||
flag.Hidden = true
|
||||
})
|
||||
}
|
||||
// No need for further setup when completing commands with subcommands.
|
||||
if compCmd.HasSubCommands() {
|
||||
requireCleanup = false
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
cfg := registry.PodmanConfig()
|
||||
|
||||
// --connection is not as "special" as --remote so we can wait and process it here
|
||||
var connErr error
|
||||
conn := cmd.Root().LocalFlags().Lookup("connection")
|
||||
if conn != nil && conn.Changed {
|
||||
cfg.Engine.ActiveService = conn.Value.String()
|
||||
|
||||
var err error
|
||||
cfg.URI, cfg.Identity, err = cfg.ActiveDestination()
|
||||
if err != nil {
|
||||
connErr = errors.Wrap(err, "failed to resolve active destination")
|
||||
}
|
||||
|
||||
if err := cmd.Root().LocalFlags().Set("url", cfg.URI); err != nil {
|
||||
connErr = errors.Wrap(err, "failed to override --url flag")
|
||||
}
|
||||
|
||||
if err := cmd.Root().LocalFlags().Set("identity", cfg.Identity); err != nil {
|
||||
connErr = errors.Wrap(err, "failed to override --identity flag")
|
||||
}
|
||||
}
|
||||
if connErr != nil {
|
||||
return connErr
|
||||
// No need for further setup the completion logic setups the engines as needed.
|
||||
requireCleanup = false
|
||||
return nil
|
||||
}
|
||||
|
||||
// Prep the engines
|
||||
|
||||
@@ -56,7 +56,7 @@ func init() {
|
||||
|
||||
filterFlagName := "filter"
|
||||
flags.StringSliceVarP(&cliOpts.Filter, filterFlagName, "f", []string{}, "Filter volume output")
|
||||
_ = lsCommand.RegisterFlagCompletionFunc(filterFlagName, completion.AutocompleteNone)
|
||||
_ = lsCommand.RegisterFlagCompletionFunc(filterFlagName, common.AutocompleteVolumeFilters)
|
||||
|
||||
formatFlagName := "format"
|
||||
flags.StringVar(&cliOpts.Format, formatFlagName, "{{.Driver}}\t{{.Name}}\n", "Format volume output using Go template")
|
||||
|
||||
@@ -8,4 +8,5 @@ StartLimitIntervalSec=0
|
||||
[Service]
|
||||
Type=notify
|
||||
KillMode=process
|
||||
ExecStart=/usr/bin/podman system service
|
||||
Environment=LOGGING="--log-level=info"
|
||||
ExecStart=/usr/bin/podman $LOGGING system service
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Tutorials
|
||||
=========
|
||||
Here are a number of useful tutorials to get you up and running with Podman. If you are familiar with the Docker `Container Engine`_ the command in Podman_ should be quite familiar. If are brand new to containers, take a look at our `Introduction`.
|
||||
Here are a number of useful tutorials to get you up and running with Podman. If you are familiar with the Docker `Container Engine`_ the command in Podman_ should be quite familiar. If you are brand new to containers, take a look at our `Introduction`.
|
||||
|
||||
* `Basic Setup and Use of Podman <https://github.com/containers/podman/blob/master/docs/tutorials/podman_tutorial.md>`_: Learn how to setup Podman and perform some basic commands with the utility.
|
||||
* `Basic Setup and Use of Podman in a Rootless environment <https://github.com/containers/podman/blob/master/docs/tutorials/rootless_tutorial.md>`_: The steps required to setup rootless Podman are enumerated.
|
||||
|
||||
@@ -28,11 +28,11 @@ author = "team"
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx_markdown_tables',
|
||||
"sphinx_markdown_tables",
|
||||
]
|
||||
|
||||
source_parsers = {
|
||||
'.md': 'recommonmark.parser.CommonMarkParser',
|
||||
".md": "recommonmark.parser.CommonMarkParser",
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -39,6 +39,8 @@ Manage Containers
|
||||
|
||||
:doc:`prune <markdown/podman-container-prune.1>` Remove all stopped containers
|
||||
|
||||
:doc:`ps <markdown/podman-ps.1>` List containers
|
||||
|
||||
:doc:`restart <markdown/podman-restart.1>` Restart one or more containers
|
||||
|
||||
:doc:`restore <markdown/podman-container-restore.1>` Restores one or more containers from a checkpoint
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
.so man1/podman-ps.1
|
||||
@@ -1 +0,0 @@
|
||||
.so man1/podman-ps.1
|
||||
@@ -32,6 +32,7 @@ The container command allows you to manage containers
|
||||
| pause | [podman-pause(1)](podman-pause.1.md) | Pause one or more containers. |
|
||||
| port | [podman-port(1)](podman-port.1.md) | List port mappings for the container. |
|
||||
| prune | [podman-container-prune(1)](podman-container-prune.1.md)| Remove all stopped containers from local storage. |
|
||||
| ps | [podman-ps(1)](podman-ps.1.md) | Prints out information about containers. |
|
||||
| restart | [podman-restart(1)](podman-restart.1.md) | Restart one or more containers. |
|
||||
| restore | [podman-container-restore(1)](podman-container-restore.1.md) | Restores one or more containers from a checkpoint. |
|
||||
| rm | [podman-rm(1)](podman-rm.1.md) | Remove one or more containers. |
|
||||
|
||||
@@ -18,6 +18,10 @@ any point.
|
||||
|
||||
The initial status of the container created with **podman create** is 'created'.
|
||||
|
||||
Default settings for flags are defined in `containers.conf`. Most settings for
|
||||
remote connections use the server's containers.conf, except when documented in
|
||||
man pages.
|
||||
|
||||
## OPTIONS
|
||||
#### **--add-host**=*host*
|
||||
|
||||
@@ -584,7 +588,7 @@ Valid _mode_ values are:
|
||||
- **none**: no networking;
|
||||
- **container:**_id_: reuse another container's network stack;
|
||||
- **host**: use the Podman host network stack. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure;
|
||||
- _network-id_: connect to a user-defined network, multiple networks should be comma separated;
|
||||
- **cni-network**: connect to a user-defined network, multiple networks should be comma-separated or they can be specified with multiple uses of the **--network** option;
|
||||
- **ns:**_path_: path to a network namespace to join;
|
||||
- **private**: create a new namespace for the container (default)
|
||||
- **slirp4netns[:OPTIONS,...]**: use **slirp4netns**(1) to create a user network stack. This is the default for rootless containers. It is possible to specify these additional options:
|
||||
@@ -817,6 +821,7 @@ Signal to stop a container. Default is SIGTERM.
|
||||
#### **--stop-timeout**=*seconds*
|
||||
|
||||
Timeout (in seconds) to stop a container. Default is 10.
|
||||
Remote connections use local containers.conf for defaults
|
||||
|
||||
#### **--subgidname**=*name*
|
||||
|
||||
@@ -893,10 +898,12 @@ standard input.
|
||||
#### **--tz**=*timezone*
|
||||
|
||||
Set timezone in container. This flag takes area-based timezones, GMT time, as well as `local`, which sets the timezone in the container to match the host machine. See `/usr/share/zoneinfo/` for valid timezones.
|
||||
Remote connections use local containers.conf for defaults
|
||||
|
||||
#### **--umask**=*umask*
|
||||
|
||||
Set the umask inside the container. Defaults to `0022`.
|
||||
Remote connections use local containers.conf for defaults
|
||||
|
||||
#### **--uidmap**=*container_uid:host_uid:amount*
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ podman\-export - Export a container's filesystem contents as a tar archive
|
||||
**podman export** exports the filesystem of a container and saves it as a tarball
|
||||
on the local machine. **podman export** writes to STDOUT by default and can be
|
||||
redirected to a file using the `--output` flag.
|
||||
The image of the container exported by **podman export** can be imported by **podman import**.
|
||||
To export image(s) with parent layers, use **podman save**.
|
||||
Note: `:` is a restricted character and cannot be part of the file name.
|
||||
|
||||
**podman [GLOBAL OPTIONS]**
|
||||
|
||||
@@ -14,6 +14,7 @@ and saves it as a filesystem image. Remote tarballs can be specified using a URL
|
||||
Various image instructions can be configured with the **--change** flag and
|
||||
a commit message can be set using the **--message** flag.
|
||||
**reference**, if present, is a tag to assign to the image.
|
||||
**podman import** is used for importing from the archive generated by **podman export**, that includes the container's filesystem. To import the archive of image layers created by **podman save**, use **podman load**.
|
||||
Note: `:` is a restricted character and cannot be part of the file name.
|
||||
|
||||
## OPTIONS
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
% podman-load(1)
|
||||
|
||||
## NAME
|
||||
podman\-load - Load an image from a container image archive into container storage
|
||||
podman\-load - Load image(s) from a tar archive into container storage
|
||||
|
||||
## SYNOPSIS
|
||||
**podman load** [*options*] [*name*[:*tag*]]
|
||||
@@ -11,6 +11,7 @@ podman\-load - Load an image from a container image archive into container stora
|
||||
## DESCRIPTION
|
||||
**podman load** loads an image from either an **oci-archive** or a **docker-archive** stored on the local machine into container storage. **podman load** reads from stdin by default or a file if the **input** option is set.
|
||||
You can also specify a name for the image if the archive does not contain a named reference, of if you want an additional name for the local image.
|
||||
**podman load** is used for loading from the archive generated by **podman save**, that includes the image parent layers. To load the archive of container's filesystem created by **podman export**, use **podman import**.
|
||||
|
||||
The local client further supports loading an **oci-dir** or a **docker-dir** as created with **podman save** (1).
|
||||
|
||||
|
||||
@@ -6,16 +6,12 @@ podman\-ps - Prints out information about containers
|
||||
## SYNOPSIS
|
||||
**podman ps** [*options*]
|
||||
|
||||
**podman container ps** [*options*]
|
||||
|
||||
**podman container list** [*options*]
|
||||
|
||||
**podman container ls** [*options*]
|
||||
|
||||
**podman container ps** [*options*]
|
||||
|
||||
**podman list** [*options*]
|
||||
|
||||
**podman ls** [*options*]
|
||||
|
||||
## DESCRIPTION
|
||||
**podman ps** lists the running containers on the system. Use the **--all** flag to view
|
||||
all the containers information. By default it lists:
|
||||
|
||||
@@ -33,6 +33,10 @@ is located at _/run/.containerenv_.
|
||||
When running from a user defined network namespace, the _/etc/netns/NSNAME/resolv.conf_
|
||||
will be used if it exists, otherwise _/etc/resolv.conf_ will be used.
|
||||
|
||||
Default settings are defined in `containers.conf`. Most settings for remote
|
||||
connections use the servers containers.conf, except when documented in man
|
||||
pages.
|
||||
|
||||
## OPTIONS
|
||||
#### **--add-host**=_host_:_ip_
|
||||
|
||||
@@ -610,7 +614,7 @@ Valid _mode_ values are:
|
||||
- **none**: no networking;
|
||||
- **container:**_id_: reuse another container's network stack;
|
||||
- **host**: use the Podman host network stack. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure;
|
||||
- _network-id_: connect to a user-defined network, multiple networks should be comma separated;
|
||||
- **cni-network**: connect to a user-defined network, multiple networks should be comma-separated or they can be specified with multiple uses of the **--network** option;
|
||||
- **ns:**_path_: path to a network namespace to join;
|
||||
- **private**: create a new namespace for the container (default)
|
||||
- **slirp4netns[:OPTIONS,...]**: use **slirp4netns**(1) to create a user network stack. This is the default for rootless containers. It is possible to specify these additional options:
|
||||
@@ -857,6 +861,7 @@ Signal to stop a container. Default is **SIGTERM**.
|
||||
#### **--stop-timeout**=*seconds*
|
||||
|
||||
Timeout to stop a container. Default is **10**.
|
||||
Remote connections use local containers.conf for defaults
|
||||
|
||||
#### **--subgidname**=*name*
|
||||
|
||||
@@ -952,10 +957,12 @@ standard input.
|
||||
#### **--tz**=*timezone*
|
||||
|
||||
Set timezone in container. This flag takes area-based timezones, GMT time, as well as `local`, which sets the timezone in the container to match the host machine. See `/usr/share/zoneinfo/` for valid timezones.
|
||||
Remote connections use local containers.conf for defaults
|
||||
|
||||
#### **--umask**=*umask*
|
||||
|
||||
Set the umask inside the container. Defaults to `0022`.
|
||||
Remote connections use local containers.conf for defaults
|
||||
|
||||
#### **--uidmap**=*container_uid*:*host_uid*:*amount*
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
% podman-save(1)
|
||||
|
||||
## NAME
|
||||
podman\-save - Save an image to a container archive
|
||||
podman\-save - Save image(s) to an archive
|
||||
|
||||
## SYNOPSIS
|
||||
**podman save** [*options*] *name*[:*tag*]
|
||||
@@ -12,6 +12,8 @@ podman\-save - Save an image to a container archive
|
||||
**podman save** saves an image to either **docker-archive**, **oci-archive**, **oci-dir** (directory with oci manifest type), or **docker-dir** (directory with v2s2 manifest type) on the local machine,
|
||||
default is **docker-archive**. **podman save** writes to STDOUT by default and can be redirected to a
|
||||
file using the **output** flag. The **quiet** flag suppresses the output when set.
|
||||
**podman save** will save parent layers of the image(s) and the image(s) can be loaded using **podman load**.
|
||||
To export the containers, use the **podman export**.
|
||||
Note: `:` is a restricted character and cannot be part of the file name.
|
||||
|
||||
**podman [GLOBAL OPTIONS]**
|
||||
|
||||
@@ -17,12 +17,14 @@ The REST API provided by **podman system service** is split into two parts: a co
|
||||
Documentation for the latter is available at *https://docs.podman.io/en/latest/_static/api.html*.
|
||||
Both APIs are versioned, but the server will not reject requests with an unsupported version set.
|
||||
|
||||
Note: The default systemd unit files (system and user) change the log-level option to *info* from *error*. This change provides additional information on each API call.
|
||||
|
||||
## OPTIONS
|
||||
|
||||
#### **--time**, **-t**
|
||||
|
||||
The time until the session expires in _seconds_. The default is 5
|
||||
seconds. A value of `0` means no timeout and the session will not expire.
|
||||
seconds. A value of `0` means no timeout, therefore the session will not expire.
|
||||
|
||||
#### **--help**, **-h**
|
||||
|
||||
@@ -40,3 +42,4 @@ podman(1), podman-system-service(1), podman-system-connection(1)
|
||||
|
||||
## HISTORY
|
||||
January 2020, Originally compiled by Brent Baude<bbaude@redhat.com>
|
||||
November 2020, Updated by Jhon Honce <jhonce at redhat.com>
|
||||
|
||||
@@ -9,7 +9,7 @@ podman\-top - Display the running processes of a container
|
||||
**podman container top** [*options*] *container* [*format-descriptors*]
|
||||
|
||||
## DESCRIPTION
|
||||
Display the running processes of the container. The *format-descriptors* are ps (1) compatible AIX format descriptors but extended to print additional information, such as the seccomp mode or the effective capabilities of a given process. The descriptors can either be passed as separated arguments or as a single comma-separated argument. Note that you can also specify options and or flags of ps(1); in this case, Podman will fallback to executing ps with the specified arguments and flags in the container.
|
||||
Display the running processes of the container. The *format-descriptors* are ps (1) compatible AIX format descriptors but extended to print additional information, such as the seccomp mode or the effective capabilities of a given process. The descriptors can either be passed as separated arguments or as a single comma-separated argument. Note that you can also specify options and or flags of ps(1); in this case, Podman will fallback to executing ps with the specified arguments and flags in the container. Please use the "h*" descriptors if you want to extract host-related information. For instance, `podman top $name hpid huser` to display the PID and user of the processes in the host context.
|
||||
|
||||
## OPTIONS
|
||||
|
||||
|
||||
@@ -17,6 +17,10 @@ Podman uses Buildah(1) internally to create container images. Both tools share i
|
||||
(not container) storage, hence each can use or manipulate images (but not containers)
|
||||
created by the other.
|
||||
|
||||
Default settings for flags are defined in `containers.conf`. Most settings for
|
||||
Remote connections use the server's containers.conf, except when documented in
|
||||
man pages.
|
||||
|
||||
**podman [GLOBAL OPTIONS]**
|
||||
|
||||
## GLOBAL OPTIONS
|
||||
@@ -33,6 +37,7 @@ Path of the configuration directory for CNI networks. (Default: `/etc/cni/net.d
|
||||
|
||||
#### **--connection**, **-c**
|
||||
Connection to use for remote podman (Default connection is configured in `containers.conf`)
|
||||
Remote connections use local containers.conf for default.
|
||||
|
||||
#### **--conmon**
|
||||
Path of the conmon binary (Default path is configured in `containers.conf`)
|
||||
@@ -71,6 +76,7 @@ Identity value resolution precedence:
|
||||
- command line value
|
||||
- environment variable `CONTAINER_SSHKEY`, if `CONTAINER_HOST` is found
|
||||
- `containers.conf`
|
||||
Remote connections use local containers.conf for default.
|
||||
|
||||
#### **--log-level**=*level*
|
||||
|
||||
@@ -86,6 +92,7 @@ Path to the command binary to use for setting up a network. It is currently onl
|
||||
|
||||
#### **--remote**, **-r**
|
||||
Access Podman service will be remote
|
||||
Remote connections use local containers.conf for default.
|
||||
|
||||
#### **--url**=*value*
|
||||
URL to access Podman service (default from `containers.conf`, rootless `unix://run/user/$UID/podman/podman.sock` or as root `unix://run/podman/podman.sock`).
|
||||
@@ -104,6 +111,7 @@ URL value resolution precedence:
|
||||
- environment variable `CONTAINER_HOST`
|
||||
- `containers.conf`
|
||||
- `unix://run/podman/podman.sock`
|
||||
Remote connections use local containers.conf for default.
|
||||
|
||||
#### **--root**=*value*
|
||||
|
||||
@@ -223,7 +231,7 @@ the exit codes follow the `chroot` standard, see below:
|
||||
| [podman-init(1)](podman-init.1.md) | Initialize one or more containers |
|
||||
| [podman-inspect(1)](podman-inspect.1.md) | Display a container, image, volume, network, or pod's configuration. |
|
||||
| [podman-kill(1)](podman-kill.1.md) | Kill the main process in one or more containers. |
|
||||
| [podman-load(1)](podman-load.1.md) | Load an image from a container image archive into container storage. |
|
||||
| [podman-load(1)](podman-load.1.md) | Load image(s) from a tar archive into container storage. |
|
||||
| [podman-login(1)](podman-login.1.md) | Login to a container registry. |
|
||||
| [podman-logout(1)](podman-logout.1.md) | Logout of a container registry. |
|
||||
| [podman-logs(1)](podman-logs.1.md) | Display the logs of one or more containers. |
|
||||
@@ -241,7 +249,7 @@ the exit codes follow the `chroot` standard, see below:
|
||||
| [podman-rm(1)](podman-rm.1.md) | Remove one or more containers. |
|
||||
| [podman-rmi(1)](podman-rmi.1.md) | Removes one or more locally stored images. |
|
||||
| [podman-run(1)](podman-run.1.md) | Run a command in a new container. |
|
||||
| [podman-save(1)](podman-save.1.md) | Save an image to a container archive. |
|
||||
| [podman-save(1)](podman-save.1.md) | Save image(s) to an archive. |
|
||||
| [podman-search(1)](podman-search.1.md) | Search a registry for an image. |
|
||||
| [podman-start(1)](podman-start.1.md) | Start one or more containers. |
|
||||
| [podman-stats(1)](podman-stats.1.md) | Display a live stream of one or more container's resource usage statistics. |
|
||||
|
||||
@@ -55,7 +55,7 @@ host:
|
||||
|
||||
In order for the client to communicate with the server you need to enable and start the SSH daemon on your Linux machine, if it is not currently enabled.
|
||||
```
|
||||
sudo systemctl enable --now -s sshd
|
||||
sudo systemctl enable --now sshd
|
||||
```
|
||||
|
||||
#### Setting up SSH
|
||||
|
||||
6
go.mod
6
go.mod
@@ -11,11 +11,11 @@ require (
|
||||
github.com/containernetworking/cni v0.8.0
|
||||
github.com/containernetworking/plugins v0.8.7
|
||||
github.com/containers/buildah v1.18.0
|
||||
github.com/containers/common v0.27.0
|
||||
github.com/containers/common v0.29.0
|
||||
github.com/containers/conmon v2.0.20+incompatible
|
||||
github.com/containers/image/v5 v5.8.0
|
||||
github.com/containers/image/v5 v5.8.1
|
||||
github.com/containers/psgo v1.5.1
|
||||
github.com/containers/storage v1.24.0
|
||||
github.com/containers/storage v1.24.1
|
||||
github.com/coreos/go-systemd/v22 v22.1.0
|
||||
github.com/cri-o/ocicni v0.2.1-0.20201102180012-75c612fda1a2
|
||||
github.com/cyphar/filepath-securejoin v0.2.2
|
||||
|
||||
12
go.sum
12
go.sum
@@ -96,13 +96,15 @@ github.com/containernetworking/plugins v0.8.7/go.mod h1:R7lXeZaBzpfqapcAbHRW8/CY
|
||||
github.com/containers/buildah v1.18.0 h1:mWEm013LVNGecF++sYo0T7fe/4pqMas/PQxQ/qviC68=
|
||||
github.com/containers/buildah v1.18.0/go.mod h1:qHLk7RUL7cHfA7ve1MKkZ6cyKUxHD0YxiLJcKY+mJe8=
|
||||
github.com/containers/common v0.26.3/go.mod h1:hJWZIlrl5MsE2ELNRa+MPp6I1kPbXHauuj0Ym4BsLG4=
|
||||
github.com/containers/common v0.27.0 h1:+QlYEOitVYtU9/x8xebRgxdGqt4sLaIqV6MBOns+zLk=
|
||||
github.com/containers/common v0.27.0/go.mod h1:ZTswJJfu4aGF6Anyi2yON8Getda9NDYcdIzurOEHHXI=
|
||||
github.com/containers/common v0.29.0 h1:hTMC+urdkk5bKfhL/OgCixIX5xjJgQ2l2jPG745ECFQ=
|
||||
github.com/containers/common v0.29.0/go.mod h1:yT4GTUHsKRmpaDb+mecXRnIMre7W3ZgwXqaYMywXlaA=
|
||||
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
|
||||
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
|
||||
github.com/containers/image/v5 v5.7.0/go.mod h1:8aOy+YaItukxghRORkvhq5ibWttHErzDLy6egrKfKos=
|
||||
github.com/containers/image/v5 v5.8.0 h1:B3FGHi0bdGXgg698kBIGOlHCXN5n+scJr6/5354GOPU=
|
||||
github.com/containers/image/v5 v5.8.0/go.mod h1:jKxdRtyIDumVa56hdsZvV+gwx4zB50hRou6pIuCWLkg=
|
||||
github.com/containers/image/v5 v5.8.1 h1:aHW8a/Kd0dTJ7PTL/fc6y12sJqHxWgqilu+XyHfjD8Q=
|
||||
github.com/containers/image/v5 v5.8.1/go.mod h1:blOEFd/iFdeyh891ByhCVUc+xAcaI3gBegXECwz9UbQ=
|
||||
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDplZ7U33NwHZkrVELsZP5fYj9pM5WBZB2GE=
|
||||
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
|
||||
github.com/containers/ocicrypt v1.0.3 h1:vYgl+RZ9Q3DPMuTfxmN+qp0X2Bj52uuY2vnt6GzVe1c=
|
||||
@@ -111,10 +113,10 @@ github.com/containers/psgo v1.5.1 h1:MQNb7FLbXqBdqz6u4lI2QWizVz4RSTzs1+Nk9XT1iVA
|
||||
github.com/containers/psgo v1.5.1/go.mod h1:2ubh0SsreMZjSXW1Hif58JrEcFudQyIy9EzPUWfawVU=
|
||||
github.com/containers/storage v1.23.6/go.mod h1:haFs0HRowKwyzvWEx9EgI3WsL8XCSnBDb5f8P5CAxJY=
|
||||
github.com/containers/storage v1.23.7/go.mod h1:cUT2zHjtx+WlVri30obWmM2gpqpi8jfPsmIzP1TVpEI=
|
||||
github.com/containers/storage v1.23.9 h1:qbgnTp76pLSyW3vYwY5GH4vk5cHYVXFJ+CsUEBp9TMw=
|
||||
github.com/containers/storage v1.23.9/go.mod h1:3b2ktpB6pw53SEeIoFfO0sQfP9+IoJJKPq5iJk74gxE=
|
||||
github.com/containers/storage v1.24.0 h1:Fo2LkF7tkMLmo38sTZ/G8wHjcn8JfUFPfyTxM4WwMfk=
|
||||
github.com/containers/storage v1.24.0/go.mod h1:A4d3BzuZK9b3oLVEsiSRhZLPIx3z7utgiPyXLK/YMhY=
|
||||
github.com/containers/storage v1.24.1 h1:1+f8fy6ly35c8SLet5jzZ8t0WJJs5+xSpfMAYw0R3kc=
|
||||
github.com/containers/storage v1.24.1/go.mod h1:0xJL06Dmd+ZYXIUdnBUPN0JnhHGgwMkLvnnAonJfWJU=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-iptables v0.4.5 h1:DpHb9vJrZQEFMcVLFKAAGMUVX0XoRC0ptCthinRYm38=
|
||||
@@ -322,6 +324,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
|
||||
github.com/klauspost/compress v1.11.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.11.2 h1:MiK62aErc3gIiVEtyzKfeOHgW7atJb5g/KNX5m3c2nQ=
|
||||
github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.11.3 h1:dB4Bn0tN3wdCzQxnS8r06kV74qN/TAfaIS0bVE8h3jc=
|
||||
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
|
||||
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
|
||||
@@ -13,10 +13,12 @@ import (
|
||||
"github.com/containers/image/v5/manifest"
|
||||
"github.com/containers/podman/v2/libpod/define"
|
||||
"github.com/containers/podman/v2/libpod/lock"
|
||||
"github.com/containers/podman/v2/pkg/rootless"
|
||||
"github.com/containers/storage"
|
||||
"github.com/cri-o/ocicni/pkg/ocicni"
|
||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// CgroupfsDefaultCgroupParent is the cgroup parent for CGroupFS in libpod
|
||||
@@ -920,19 +922,39 @@ func (c *Container) CGroupPath() (string, error) {
|
||||
return "", errors.Wrapf(define.ErrNoCgroups, "this container is not creating cgroups")
|
||||
}
|
||||
|
||||
// Read /proc/[PID]/cgroup and look at the first line. cgroups(7)
|
||||
// nails it down to three fields with the 3rd pointing to the cgroup's
|
||||
// path which works both on v1 and v2.
|
||||
// Read /proc/[PID]/cgroup and find the *longest* cgroup entry. That's
|
||||
// needed to account for hacks in cgroups v1, where each line in the
|
||||
// file could potentially point to a cgroup. The longest one, however,
|
||||
// is the libpod-specific one we're looking for.
|
||||
//
|
||||
// See #8397 on the need for the longest-path look up.
|
||||
procPath := fmt.Sprintf("/proc/%d/cgroup", c.state.PID)
|
||||
lines, err := ioutil.ReadFile(procPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
fields := bytes.Split(bytes.Split(lines, []byte("\n"))[0], []byte(":"))
|
||||
if len(fields) != 3 {
|
||||
return "", errors.Errorf("expected 3 fields but got %d: %s", len(fields), procPath)
|
||||
|
||||
var cgroupPath string
|
||||
for _, line := range bytes.Split(lines, []byte("\n")) {
|
||||
// cgroups(7) nails it down to three fields with the 3rd
|
||||
// pointing to the cgroup's path which works both on v1 and v2.
|
||||
fields := bytes.Split(line, []byte(":"))
|
||||
if len(fields) != 3 {
|
||||
logrus.Debugf("Error parsing cgroup: expected 3 fields but got %d: %s", len(fields), procPath)
|
||||
continue
|
||||
}
|
||||
path := string(fields[2])
|
||||
if len(path) > len(cgroupPath) {
|
||||
cgroupPath = path
|
||||
}
|
||||
|
||||
}
|
||||
return string(fields[2]), nil
|
||||
|
||||
if len(cgroupPath) == 0 {
|
||||
return "", errors.Errorf("could not find any cgroup in %q", procPath)
|
||||
}
|
||||
|
||||
return cgroupPath, nil
|
||||
}
|
||||
|
||||
// RootFsSize returns the root FS size of the container
|
||||
@@ -1074,13 +1096,17 @@ func (c *Container) Umask() string {
|
||||
// values at runtime via network connect and disconnect.
|
||||
// If the container is configured to use CNI and this function returns an empty
|
||||
// array, the container will still be connected to the default network.
|
||||
func (c *Container) Networks() ([]string, error) {
|
||||
// The second return parameter, a bool, indicates that the container container
|
||||
// is joining the default CNI network - the network name will be included in the
|
||||
// returned array of network names, but the container did not explicitly join
|
||||
// this network.
|
||||
func (c *Container) Networks() ([]string, bool, error) {
|
||||
if !c.batched {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
if err := c.syncContainer(); err != nil {
|
||||
return nil, err
|
||||
return nil, false, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1088,19 +1114,22 @@ func (c *Container) Networks() ([]string, error) {
|
||||
}
|
||||
|
||||
// Unlocked accessor for networks
|
||||
func (c *Container) networks() ([]string, error) {
|
||||
func (c *Container) networks() ([]string, bool, error) {
|
||||
networks, err := c.runtime.state.GetNetworks(c)
|
||||
if err != nil && errors.Cause(err) == define.ErrNoSuchNetwork {
|
||||
return c.config.Networks, nil
|
||||
if len(c.config.Networks) == 0 && !rootless.IsRootless() {
|
||||
return []string{c.runtime.netPlugin.GetDefaultNetworkName()}, true, nil
|
||||
}
|
||||
return c.config.Networks, false, nil
|
||||
}
|
||||
|
||||
return networks, err
|
||||
return networks, false, err
|
||||
}
|
||||
|
||||
// networksByNameIndex provides us with a map of container networks where key
|
||||
// is network name and value is the index position
|
||||
func (c *Container) networksByNameIndex() (map[string]int, error) {
|
||||
networks, err := c.networks()
|
||||
networks, _, err := c.networks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -714,3 +714,17 @@ func (c *Container) Restore(ctx context.Context, options ContainerCheckpointOpti
|
||||
defer c.newContainerEvent(events.Restore)
|
||||
return c.restore(ctx, options)
|
||||
}
|
||||
|
||||
// Indicate whether or not the container should restart
|
||||
func (c *Container) ShouldRestart(ctx context.Context) bool {
|
||||
logrus.Debugf("Checking if container %s should restart", c.ID())
|
||||
if !c.batched {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
if err := c.syncContainer(); err != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return c.shouldRestart()
|
||||
}
|
||||
|
||||
@@ -206,37 +206,39 @@ func (c *Container) handleExitFile(exitFile string, fi os.FileInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handle container restart policy.
|
||||
// This is called when a container has exited, and was not explicitly stopped by
|
||||
// an API call to stop the container or pod it is in.
|
||||
func (c *Container) handleRestartPolicy(ctx context.Context) (_ bool, retErr error) {
|
||||
// If we did not get a restart policy match, exit immediately.
|
||||
func (c *Container) shouldRestart() bool {
|
||||
// If we did not get a restart policy match, return false
|
||||
// Do the same if we're not a policy that restarts.
|
||||
if !c.state.RestartPolicyMatch ||
|
||||
c.config.RestartPolicy == RestartPolicyNo ||
|
||||
c.config.RestartPolicy == RestartPolicyNone {
|
||||
return false, nil
|
||||
return false
|
||||
}
|
||||
|
||||
// If we're RestartPolicyOnFailure, we need to check retries and exit
|
||||
// code.
|
||||
if c.config.RestartPolicy == RestartPolicyOnFailure {
|
||||
if c.state.ExitCode == 0 {
|
||||
return false, nil
|
||||
return false
|
||||
}
|
||||
|
||||
// If we don't have a max retries set, continue
|
||||
if c.config.RestartRetries > 0 {
|
||||
if c.state.RestartCount < c.config.RestartRetries {
|
||||
logrus.Debugf("Container %s restart policy trigger: on retry %d (of %d)",
|
||||
c.ID(), c.state.RestartCount, c.config.RestartRetries)
|
||||
} else {
|
||||
logrus.Debugf("Container %s restart policy trigger: retries exhausted", c.ID())
|
||||
return false, nil
|
||||
if c.state.RestartCount >= c.config.RestartRetries {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Handle container restart policy.
|
||||
// This is called when a container has exited, and was not explicitly stopped by
|
||||
// an API call to stop the container or pod it is in.
|
||||
func (c *Container) handleRestartPolicy(ctx context.Context) (_ bool, retErr error) {
|
||||
if !c.shouldRestart() {
|
||||
return false, nil
|
||||
}
|
||||
logrus.Debugf("Restarting container %s due to restart policy %s", c.ID(), c.config.RestartPolicy)
|
||||
|
||||
// Need to check if dependencies are alive.
|
||||
@@ -641,18 +643,13 @@ func (c *Container) removeIPv4Allocations() error {
|
||||
cniDefaultNetwork = c.runtime.netPlugin.GetDefaultNetworkName()
|
||||
}
|
||||
|
||||
networks, err := c.networks()
|
||||
networks, _, err := c.networks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch {
|
||||
case len(networks) > 0 && len(networks) != len(c.state.NetworkStatus):
|
||||
if len(networks) != len(c.state.NetworkStatus) {
|
||||
return errors.Wrapf(define.ErrInternal, "network mismatch: asked to join %d CNI networks but got %d CNI results", len(networks), len(c.state.NetworkStatus))
|
||||
case len(networks) == 0 && len(c.state.NetworkStatus) != 1:
|
||||
return errors.Wrapf(define.ErrInternal, "network mismatch: did not specify CNI networks but joined more than one (%d)", len(c.state.NetworkStatus))
|
||||
case len(networks) == 0 && cniDefaultNetwork == "":
|
||||
return errors.Wrapf(define.ErrInternal, "could not retrieve name of CNI default network")
|
||||
}
|
||||
|
||||
for index, result := range c.state.NetworkStatus {
|
||||
|
||||
@@ -26,6 +26,10 @@ func (c *Container) createTimer() error {
|
||||
if rootless.IsRootless() {
|
||||
cmd = append(cmd, "--user")
|
||||
}
|
||||
path := os.Getenv("PATH")
|
||||
if path != "" {
|
||||
cmd = append(cmd, "--setenv=PATH="+path)
|
||||
}
|
||||
cmd = append(cmd, "--unit", c.ID(), fmt.Sprintf("--on-unit-inactive=%s", c.HealthCheckConfig().Interval.String()), "--timer-property=AccuracySec=1s", podman, "healthcheck", "run", c.ID())
|
||||
|
||||
conn, err := systemd.ConnectToDBUS()
|
||||
|
||||
@@ -2,13 +2,14 @@ package image
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/containers/buildah/manifests"
|
||||
"github.com/containers/image/v5/docker"
|
||||
"github.com/containers/image/v5/manifest"
|
||||
"github.com/containers/image/v5/transports/alltransports"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Options for adding a manifest
|
||||
@@ -69,19 +70,10 @@ func CreateManifestList(rt *Runtime, systemContext types.SystemContext, names []
|
||||
list := manifests.Create()
|
||||
opts := ManifestAddOpts{Images: names, All: all}
|
||||
for _, img := range imgs {
|
||||
var ref types.ImageReference
|
||||
newImage, err := rt.NewFromLocal(img)
|
||||
if err == nil {
|
||||
ir, err := newImage.toImageRef(context.Background())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if ir == nil {
|
||||
return "", errors.New("unable to convert image to ImageReference")
|
||||
}
|
||||
ref = ir.Reference()
|
||||
} else {
|
||||
ref, err = alltransports.ParseImageName(img)
|
||||
ref, err := alltransports.ParseImageName(img)
|
||||
if err != nil {
|
||||
dockerPrefix := fmt.Sprintf("%s://", docker.Transport.Name())
|
||||
ref, err = alltransports.ParseImageName(fmt.Sprintf("%s%s", dockerPrefix, img))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -134,18 +126,10 @@ func addManifestToList(ref types.ImageReference, list manifests.List, systemCont
|
||||
|
||||
// AddManifest adds a manifest to a given manifest list.
|
||||
func (i *Image) AddManifest(systemContext types.SystemContext, opts ManifestAddOpts) (string, error) {
|
||||
var (
|
||||
ref types.ImageReference
|
||||
)
|
||||
newImage, err := i.imageruntime.NewFromLocal(opts.Images[0])
|
||||
if err == nil {
|
||||
ir, err := newImage.toImageRef(context.Background())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ref = ir.Reference()
|
||||
} else {
|
||||
ref, err = alltransports.ParseImageName(opts.Images[0])
|
||||
ref, err := alltransports.ParseImageName(opts.Images[0])
|
||||
if err != nil {
|
||||
dockerPrefix := fmt.Sprintf("%s://", docker.Transport.Name())
|
||||
ref, err = alltransports.ParseImageName(fmt.Sprintf("%s%s", dockerPrefix, opts.Images[0]))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -129,6 +129,16 @@ func (f FirewallConfig) Bytes() ([]byte, error) {
|
||||
return json.MarshalIndent(f, "", "\t")
|
||||
}
|
||||
|
||||
// TuningConfig describes the tuning plugin
|
||||
type TuningConfig struct {
|
||||
PluginType string `json:"type"`
|
||||
}
|
||||
|
||||
// Bytes outputs the configuration as []byte
|
||||
func (f TuningConfig) Bytes() ([]byte, error) {
|
||||
return json.MarshalIndent(f, "", "\t")
|
||||
}
|
||||
|
||||
// DNSNameConfig describes the dns container name resolution plugin config
|
||||
type DNSNameConfig struct {
|
||||
PluginType string `json:"type"`
|
||||
|
||||
@@ -176,6 +176,7 @@ func createBridge(name string, options entities.NetworkCreateOptions, runtimeCon
|
||||
plugins = append(plugins, bridge)
|
||||
plugins = append(plugins, NewPortMapPlugin())
|
||||
plugins = append(plugins, NewFirewallPlugin())
|
||||
plugins = append(plugins, NewTuningPlugin())
|
||||
// if we find the dnsname plugin or are rootless, we add configuration for it
|
||||
// the rootless-cni-infra container has the dnsname plugin always installed
|
||||
if (HasDNSNamePlugin(runtimeConfig.Network.CNIPluginDirs) || rootless.IsRootless()) && !options.DisableDNS {
|
||||
|
||||
@@ -119,6 +119,13 @@ func NewFirewallPlugin() FirewallConfig {
|
||||
}
|
||||
}
|
||||
|
||||
// NewTuningPlugin creates a generic tuning section
|
||||
func NewTuningPlugin() TuningConfig {
|
||||
return TuningConfig{
|
||||
PluginType: "tuning",
|
||||
}
|
||||
}
|
||||
|
||||
// NewDNSNamePlugin creates the dnsname config with a given
|
||||
// domainname
|
||||
func NewDNSNamePlugin(domainName string) DNSNameConfig {
|
||||
|
||||
@@ -54,14 +54,10 @@ func LastIPInSubnet(addr *net.IPNet) (net.IP, error) { //nolint:interfacer
|
||||
|
||||
ones, bits := cidr.Mask.Size()
|
||||
if ones == bits {
|
||||
return FirstIPInSubnet(cidr)
|
||||
return cidr.IP, nil
|
||||
}
|
||||
hostStart := ones / 8
|
||||
// Handle the first host byte
|
||||
cidr.IP[hostStart] |= 0xff & cidr.Mask[hostStart]
|
||||
// Fill the rest with ones
|
||||
for i := hostStart; i < len(cidr.IP); i++ {
|
||||
cidr.IP[i] = 0xff
|
||||
for i := range cidr.IP {
|
||||
cidr.IP[i] = cidr.IP[i] | ^cidr.Mask[i]
|
||||
}
|
||||
return cidr.IP, nil
|
||||
}
|
||||
@@ -73,6 +69,10 @@ func FirstIPInSubnet(addr *net.IPNet) (net.IP, error) { //nolint:interfacer
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ones, bits := cidr.Mask.Size()
|
||||
if ones == bits {
|
||||
return cidr.IP, nil
|
||||
}
|
||||
cidr.IP[len(cidr.IP)-1]++
|
||||
return cidr.IP, nil
|
||||
}
|
||||
|
||||
@@ -33,3 +33,65 @@ func TestNextSubnet(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFirstIPInSubnet(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args *net.IPNet
|
||||
want net.IP
|
||||
wantErr bool
|
||||
}{
|
||||
{"class b", parseCIDR("192.168.0.0/16"), net.ParseIP("192.168.0.1"), false},
|
||||
{"class c", parseCIDR("192.168.1.0/24"), net.ParseIP("192.168.1.1"), false},
|
||||
{"cidr /23", parseCIDR("192.168.0.0/23"), net.ParseIP("192.168.0.1"), false},
|
||||
{"cidr /25", parseCIDR("192.168.1.0/25"), net.ParseIP("192.168.1.1"), false},
|
||||
{"cidr /26", parseCIDR("172.16.1.128/26"), net.ParseIP("172.16.1.129"), false},
|
||||
{"class a", parseCIDR("10.0.0.0/8"), net.ParseIP("10.0.0.1"), false},
|
||||
{"cidr /32", parseCIDR("192.168.255.4/32"), net.ParseIP("192.168.255.4"), false},
|
||||
{"cidr /31", parseCIDR("192.168.255.4/31"), net.ParseIP("192.168.255.5"), false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
test := tt
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
got, err := FirstIPInSubnet(test.args)
|
||||
if (err != nil) != test.wantErr {
|
||||
t.Errorf("FirstIPInSubnet() error = %v, wantErr %v", err, test.wantErr)
|
||||
return
|
||||
}
|
||||
if !got.Equal(test.want) {
|
||||
t.Errorf("FirstIPInSubnet() got = %v, want %v", got, test.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLastIPInSubnet(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args *net.IPNet
|
||||
want net.IP
|
||||
wantErr bool
|
||||
}{
|
||||
{"class b", parseCIDR("192.168.0.0/16"), net.ParseIP("192.168.255.255"), false},
|
||||
{"class c", parseCIDR("192.168.1.0/24"), net.ParseIP("192.168.1.255"), false},
|
||||
{"cidr /23", parseCIDR("192.168.0.0/23"), net.ParseIP("192.168.1.255"), false},
|
||||
{"cidr /25", parseCIDR("192.168.1.0/25"), net.ParseIP("192.168.1.127"), false},
|
||||
{"cidr /26", parseCIDR("172.16.1.128/26"), net.ParseIP("172.16.1.191"), false},
|
||||
{"class a", parseCIDR("10.0.0.0/8"), net.ParseIP("10.255.255.255"), false},
|
||||
{"cidr /32", parseCIDR("192.168.255.4/32"), net.ParseIP("192.168.255.4"), false},
|
||||
{"cidr /31", parseCIDR("192.168.255.4/31"), net.ParseIP("192.168.255.5"), false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
test := tt
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
got, err := LastIPInSubnet(test.args)
|
||||
if (err != nil) != test.wantErr {
|
||||
t.Errorf("LastIPInSubnet() error = %v, wantErr %v", err, test.wantErr)
|
||||
return
|
||||
}
|
||||
if !got.Equal(test.want) {
|
||||
t.Errorf("LastIPInSubnet() got = %v, want %v", got, test.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,10 +110,15 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Re
|
||||
|
||||
podName := getCNIPodName(ctr)
|
||||
|
||||
networks, err := ctr.networks()
|
||||
networks, _, err := ctr.networks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// All networks have been removed from the container.
|
||||
// This is effectively forcing net=none.
|
||||
if len(networks) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Update container map of interface descriptions
|
||||
if err := ctr.setupNetworkDescriptions(networks); err != nil {
|
||||
@@ -224,7 +229,7 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) error {
|
||||
if ctr.config.NetMode.IsSlirp4netns() {
|
||||
return r.setupSlirp4netns(ctr)
|
||||
}
|
||||
networks, err := ctr.networks()
|
||||
networks, _, err := ctr.networks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -744,13 +749,13 @@ func (r *Runtime) teardownNetNS(ctr *Container) error {
|
||||
|
||||
logrus.Debugf("Tearing down network namespace at %s for container %s", ctr.state.NetNS.Path(), ctr.ID())
|
||||
|
||||
networks, err := ctr.networks()
|
||||
networks, _, err := ctr.networks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// rootless containers do not use the CNI plugin directly
|
||||
if !rootless.IsRootless() && !ctr.config.NetMode.IsSlirp4netns() {
|
||||
if !rootless.IsRootless() && !ctr.config.NetMode.IsSlirp4netns() && len(networks) > 0 {
|
||||
var requestedIP net.IP
|
||||
if ctr.requestedIP != nil {
|
||||
requestedIP = ctr.requestedIP
|
||||
@@ -863,7 +868,7 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
|
||||
settings := new(define.InspectNetworkSettings)
|
||||
settings.Ports = makeInspectPortBindings(c.config.PortMappings)
|
||||
|
||||
networks, err := c.networks()
|
||||
networks, isDefault, err := c.networks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -872,7 +877,7 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
|
||||
if c.state.NetNS == nil {
|
||||
// We still want to make dummy configurations for each CNI net
|
||||
// the container joined.
|
||||
if len(networks) > 0 {
|
||||
if len(networks) > 0 && !isDefault {
|
||||
settings.Networks = make(map[string]*define.InspectAdditionalNetwork, len(networks))
|
||||
for _, net := range networks {
|
||||
cniNet := new(define.InspectAdditionalNetwork)
|
||||
@@ -893,9 +898,9 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
|
||||
}
|
||||
|
||||
// If we have CNI networks - handle that here
|
||||
if len(networks) > 0 {
|
||||
if len(networks) > 0 && !isDefault {
|
||||
if len(networks) != len(c.state.NetworkStatus) {
|
||||
return nil, errors.Wrapf(define.ErrInternal, "network inspection mismatch: asked to join %d CNI networks but have information on %d networks", len(networks), len(c.state.NetworkStatus))
|
||||
return nil, errors.Wrapf(define.ErrInternal, "network inspection mismatch: asked to join %d CNI network(s) %v, but have information on %d network(s)", len(networks), networks, len(c.state.NetworkStatus))
|
||||
}
|
||||
|
||||
settings.Networks = make(map[string]*define.InspectAdditionalNetwork)
|
||||
@@ -1101,7 +1106,7 @@ func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) e
|
||||
return err
|
||||
}
|
||||
|
||||
ctrNetworks, err := c.networks()
|
||||
ctrNetworks, _, err := c.networks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1139,8 +1144,8 @@ func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) e
|
||||
// build a list of network names so we can sort and
|
||||
// get the new name's index
|
||||
var networkNames []string
|
||||
for netName := range networks {
|
||||
networkNames = append(networkNames, netName)
|
||||
for name := range networks {
|
||||
networkNames = append(networkNames, name)
|
||||
}
|
||||
networkNames = append(networkNames, netName)
|
||||
// sort
|
||||
@@ -1152,6 +1157,7 @@ func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) e
|
||||
// populate network status
|
||||
copy(networkStatus[index+1:], networkStatus[index:])
|
||||
networkStatus[index] = networkResults[0]
|
||||
c.state.NetworkStatus = networkStatus
|
||||
}
|
||||
c.newNetworkEvent(events.NetworkConnect, netName)
|
||||
return c.save()
|
||||
|
||||
@@ -40,7 +40,7 @@ const (
|
||||
//
|
||||
// AllocRootlessCNI does not lock c. c should be already locked.
|
||||
func AllocRootlessCNI(ctx context.Context, c *Container) (ns.NetNS, []*cnitypes.Result, error) {
|
||||
networks, err := c.networks()
|
||||
networks, _, err := c.networks()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -81,7 +81,7 @@ func AllocRootlessCNI(ctx context.Context, c *Container) (ns.NetNS, []*cnitypes.
|
||||
//
|
||||
// DeallocRootlessCNI does not lock c. c should be already locked.
|
||||
func DeallocRootlessCNI(ctx context.Context, c *Container) error {
|
||||
networks, err := c.networks()
|
||||
networks, _, err := c.networks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -298,6 +298,9 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
|
||||
state.Running = true
|
||||
}
|
||||
|
||||
formatCapabilities(inspect.HostConfig.CapDrop)
|
||||
formatCapabilities(inspect.HostConfig.CapAdd)
|
||||
|
||||
h, err := json.Marshal(inspect.HostConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -318,8 +321,8 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
|
||||
cb := types.ContainerJSONBase{
|
||||
ID: l.ID(),
|
||||
Created: l.CreatedTime().Format(time.RFC3339Nano),
|
||||
Path: "",
|
||||
Args: nil,
|
||||
Path: inspect.Path,
|
||||
Args: inspect.Args,
|
||||
State: &state,
|
||||
Image: imageName,
|
||||
ResolvConfPath: inspect.ResolvConfPath,
|
||||
@@ -328,7 +331,7 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
|
||||
LogPath: l.LogPath(),
|
||||
Node: nil,
|
||||
Name: fmt.Sprintf("/%s", l.Name()),
|
||||
RestartCount: 0,
|
||||
RestartCount: int(inspect.RestartCount),
|
||||
Driver: inspect.Driver,
|
||||
Platform: "linux",
|
||||
MountLabel: inspect.MountLabel,
|
||||
@@ -428,3 +431,9 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
|
||||
}
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
func formatCapabilities(slice []string) {
|
||||
for i := range slice {
|
||||
slice[i] = strings.TrimPrefix(slice[i], "CAP_")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
func CreateContainer(w http.ResponseWriter, r *http.Request) {
|
||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
||||
input := handlers.CreateContainerConfig{}
|
||||
query := struct {
|
||||
Name string `schema:"name"`
|
||||
}{
|
||||
@@ -30,11 +29,15 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
|
||||
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
||||
return
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
||||
|
||||
// compatible configuration
|
||||
body := handlers.CreateContainerConfig{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
|
||||
return
|
||||
}
|
||||
if len(input.HostConfig.Links) > 0 {
|
||||
|
||||
if len(body.HostConfig.Links) > 0 {
|
||||
utils.Error(w, utils.ErrLinkNotSupport.Error(), http.StatusBadRequest, errors.Wrapf(utils.ErrLinkNotSupport, "bad parameter"))
|
||||
return
|
||||
}
|
||||
@@ -43,7 +46,7 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
|
||||
utils.Error(w, "unable to obtain runtime config", http.StatusInternalServerError, errors.Wrap(err, "unable to get runtime config"))
|
||||
}
|
||||
|
||||
newImage, err := runtime.ImageRuntime().NewFromLocal(input.Image)
|
||||
newImage, err := runtime.ImageRuntime().NewFromLocal(body.Config.Image)
|
||||
if err != nil {
|
||||
if errors.Cause(err) == define.ErrNoSuchImage {
|
||||
utils.Error(w, "No such image", http.StatusNotFound, err)
|
||||
@@ -54,11 +57,8 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Add the container name to the input struct
|
||||
input.Name = query.Name
|
||||
|
||||
// Take input structure and convert to cliopts
|
||||
cliOpts, args, err := common.ContainerCreateToContainerCLIOpts(input, rtc.Engine.CgroupManager)
|
||||
// Take body structure and convert to cliopts
|
||||
cliOpts, args, err := common.ContainerCreateToContainerCLIOpts(body, rtc.Engine.CgroupManager)
|
||||
if err != nil {
|
||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "make cli opts()"))
|
||||
return
|
||||
@@ -69,6 +69,9 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Override the container name in the body struct
|
||||
body.Name = query.Name
|
||||
|
||||
ic := abi.ContainerEngine{Libpod: runtime}
|
||||
report, err := ic.ContainerCreate(r.Context(), sg)
|
||||
if err != nil {
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/containers/podman/v2/pkg/api/handlers/utils"
|
||||
"github.com/containers/podman/v2/pkg/rootless"
|
||||
docker "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
@@ -103,7 +104,7 @@ func GetInfo(w http.ResponseWriter, r *http.Request) {
|
||||
PidsLimit: sysInfo.PidsLimit,
|
||||
Plugins: docker.PluginsInfo{},
|
||||
ProductLicense: "Apache-2.0",
|
||||
RegistryConfig: nil,
|
||||
RegistryConfig: new(registry.ServiceConfig),
|
||||
RuncCommit: docker.Commit{},
|
||||
Runtimes: getRuntimes(configInfo),
|
||||
SecurityOptions: getSecOpts(sysInfo),
|
||||
|
||||
@@ -344,3 +344,27 @@ func InitContainer(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
utils.WriteResponse(w, http.StatusNoContent, "")
|
||||
}
|
||||
|
||||
func ShouldRestart(w http.ResponseWriter, r *http.Request) {
|
||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||
// Now use the ABI implementation to prevent us from having duplicate
|
||||
// code.
|
||||
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||
|
||||
name := utils.GetName(r)
|
||||
report, err := containerEngine.ShouldRestart(r.Context(), name)
|
||||
if err != nil {
|
||||
if errors.Cause(err) == define.ErrNoSuchCtr {
|
||||
utils.ContainerNotFound(w, name, err)
|
||||
return
|
||||
}
|
||||
utils.InternalServerError(w, err)
|
||||
return
|
||||
|
||||
}
|
||||
if report.Value {
|
||||
utils.WriteResponse(w, http.StatusNoContent, "")
|
||||
} else {
|
||||
utils.ContainerNotFound(w, name, define.ErrNoSuchCtr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,11 +110,12 @@ type ContainerWaitOKBody struct {
|
||||
}
|
||||
}
|
||||
|
||||
// CreateContainerConfig used when compatible endpoint creates a container
|
||||
type CreateContainerConfig struct {
|
||||
Name string
|
||||
dockerContainer.Config
|
||||
HostConfig dockerContainer.HostConfig
|
||||
NetworkingConfig dockerNetwork.NetworkingConfig
|
||||
Name string // container name
|
||||
dockerContainer.Config // desired container configuration
|
||||
HostConfig dockerContainer.HostConfig // host dependent configuration for container
|
||||
NetworkingConfig dockerNetwork.NetworkingConfig // network configuration for container
|
||||
}
|
||||
|
||||
// swagger:model IDResponse
|
||||
@@ -253,7 +254,7 @@ func ImageDataToImageInspect(ctx context.Context, l *libpodImage.Image) (*ImageI
|
||||
// StdinOnce: false,
|
||||
Env: info.Config.Env,
|
||||
Cmd: info.Config.Cmd,
|
||||
//Healthcheck: l.ImageData.HealthCheck,
|
||||
// Healthcheck: l.ImageData.HealthCheck,
|
||||
// ArgsEscaped: false,
|
||||
// Image: "",
|
||||
Volumes: info.Config.Volumes,
|
||||
@@ -261,7 +262,7 @@ func ImageDataToImageInspect(ctx context.Context, l *libpodImage.Image) (*ImageI
|
||||
Entrypoint: info.Config.Entrypoint,
|
||||
// NetworkDisabled: false,
|
||||
// MacAddress: "",
|
||||
//OnBuild: info.Config.OnBuild,
|
||||
// OnBuild: info.Config.OnBuild,
|
||||
Labels: info.Labels,
|
||||
StopSignal: info.Config.StopSignal,
|
||||
// StopTimeout: nil,
|
||||
|
||||
@@ -30,14 +30,14 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
|
||||
// Wrapper to hide some boiler plate
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
rid := uuid.New().String()
|
||||
logrus.Infof("APIHandler(%s) -- %s %s BEGIN", rid, r.Method, r.URL.String())
|
||||
if logrus.IsLevelEnabled(logrus.DebugLevel) {
|
||||
logrus.Debugf("APIHandler(%s) -- Method: %s URL: %s", rid, r.Method, r.URL.String())
|
||||
for k, v := range r.Header {
|
||||
switch auth.HeaderAuthName(k) {
|
||||
case auth.XRegistryConfigHeader, auth.XRegistryAuthHeader:
|
||||
logrus.Debugf("APIHandler(%s) -- Header: %s: <hidden>", rid, k)
|
||||
logrus.Debugf("APIHandler(%s) -- Header: %s=<hidden>", rid, k)
|
||||
default:
|
||||
logrus.Debugf("APIHandler(%s) -- Header: %s: %v", rid, k, v)
|
||||
logrus.Debugf("APIHandler(%s) -- Header: %s=%v", rid, k, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,7 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
|
||||
w.Header().Set("Server", "Libpod/"+lv+" ("+runtime.GOOS+")")
|
||||
|
||||
h(w, r)
|
||||
logrus.Debugf("APIHandler(%s) -- %s %s END", rid, r.Method, r.URL.String())
|
||||
}
|
||||
fn(w, r)
|
||||
}
|
||||
|
||||
@@ -27,5 +27,6 @@ func ListenUnix(network string, path string) (net.Listener, error) {
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "net.Listen(%s, %s) failed to report the failure to create socket", network, path)
|
||||
}
|
||||
|
||||
return listener, nil
|
||||
}
|
||||
|
||||
@@ -51,10 +51,7 @@ func NewServer(runtime *libpod.Runtime) (*APIServer, error) {
|
||||
}
|
||||
|
||||
// NewServerWithSettings will create and configure a new API server using provided settings
|
||||
func NewServerWithSettings(runtime *libpod.Runtime, duration time.Duration, listener *net.Listener) (
|
||||
*APIServer,
|
||||
error,
|
||||
) {
|
||||
func NewServerWithSettings(runtime *libpod.Runtime, duration time.Duration, listener *net.Listener) (*APIServer, error) {
|
||||
return newServer(runtime, duration, listener)
|
||||
}
|
||||
|
||||
@@ -75,6 +72,7 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
|
||||
listener = &listeners[0]
|
||||
}
|
||||
|
||||
logrus.Infof("API server listening on %q", (*listener).Addr())
|
||||
router := mux.NewRouter().UseEncodedPath()
|
||||
idle := idle.NewTracker(duration)
|
||||
|
||||
|
||||
@@ -390,3 +390,15 @@ func ContainerInit(ctx context.Context, nameOrID string) error {
|
||||
}
|
||||
return response.Process(nil)
|
||||
}
|
||||
|
||||
func ShouldRestart(ctx context.Context, nameOrID string) (bool, error) {
|
||||
conn, err := bindings.GetClient(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/shouldrestart", nil, nil, nameOrID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return response.IsSuccess(), nil
|
||||
}
|
||||
|
||||
@@ -51,10 +51,10 @@ func (i *Image) Id() string { // nolint
|
||||
}
|
||||
|
||||
type ImageSummary struct {
|
||||
ID string `json:"Id"`
|
||||
ParentId string `json:",omitempty"` // nolint
|
||||
RepoTags []string `json:",omitempty"`
|
||||
Created int64 `json:",omitempty"`
|
||||
ID string `json:"Id"`
|
||||
ParentId string // nolint
|
||||
RepoTags []string `json:",omitempty"`
|
||||
Created int64
|
||||
Size int64 `json:",omitempty"`
|
||||
SharedSize int `json:",omitempty"`
|
||||
VirtualSize int64 `json:",omitempty"`
|
||||
|
||||
@@ -911,7 +911,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
|
||||
} else {
|
||||
report.ExitCode = int(ecode)
|
||||
}
|
||||
if opts.Rm {
|
||||
if opts.Rm && !ctr.ShouldRestart(ctx) {
|
||||
if err := ic.Libpod.RemoveContainer(ctx, ctr, false, true); err != nil {
|
||||
if errors.Cause(err) == define.ErrNoSuchCtr ||
|
||||
errors.Cause(err) == define.ErrCtrRemoved {
|
||||
@@ -992,7 +992,7 @@ func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []st
|
||||
return []*entities.ContainerCleanupReport{}, nil
|
||||
}
|
||||
|
||||
if options.Remove {
|
||||
if options.Remove && !ctr.ShouldRestart(ctx) {
|
||||
err = ic.Libpod.RemoveContainer(ctx, ctr, false, true)
|
||||
if err != nil {
|
||||
report.RmErr = errors.Wrapf(err, "failed to cleanup and remove container %v", ctr.ID())
|
||||
@@ -1015,6 +1015,7 @@ func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []st
|
||||
_, err = ic.Libpod.RemoveImage(ctx, ctrImage, false)
|
||||
report.RmiErr = err
|
||||
}
|
||||
|
||||
reports = append(reports, &report)
|
||||
}
|
||||
return reports, nil
|
||||
@@ -1314,3 +1315,13 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
|
||||
|
||||
return statsChan, nil
|
||||
}
|
||||
|
||||
// ShouldRestart returns whether the container should be restarted
|
||||
func (ic *ContainerEngine) ShouldRestart(ctx context.Context, nameOrID string) (*entities.BoolReport, error) {
|
||||
ctr, err := ic.Libpod.LookupContainer(nameOrID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &entities.BoolReport{Value: ctr.ShouldRestart(ctx)}, nil
|
||||
}
|
||||
|
||||
@@ -595,12 +595,20 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
|
||||
// Defer the removal, so we can return early if needed and
|
||||
// de-spaghetti the code.
|
||||
defer func() {
|
||||
if err := containers.Remove(ic.ClientCxt, con.ID, bindings.PFalse, bindings.PTrue); err != nil {
|
||||
if errorhandling.Contains(err, define.ErrNoSuchCtr) ||
|
||||
errorhandling.Contains(err, define.ErrCtrRemoved) {
|
||||
logrus.Warnf("Container %s does not exist: %v", con.ID, err)
|
||||
} else {
|
||||
logrus.Errorf("Error removing container %s: %v", con.ID, err)
|
||||
shouldRestart, err := containers.ShouldRestart(ic.ClientCxt, con.ID)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to check if %s should restart: %v", con.ID, err)
|
||||
return
|
||||
}
|
||||
|
||||
if !shouldRestart {
|
||||
if err := containers.Remove(ic.ClientCxt, con.ID, bindings.PFalse, bindings.PTrue); err != nil {
|
||||
if errorhandling.Contains(err, define.ErrNoSuchCtr) ||
|
||||
errorhandling.Contains(err, define.ErrCtrRemoved) {
|
||||
logrus.Warnf("Container %s does not exist: %v", con.ID, err)
|
||||
} else {
|
||||
logrus.Errorf("Error removing container %s: %v", con.ID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
@@ -737,3 +745,8 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
|
||||
}
|
||||
return containers.Stats(ic.ClientCxt, namesOrIds, &options.Stream)
|
||||
}
|
||||
|
||||
// ShouldRestart reports back whether the containre will restart
|
||||
func (ic *ContainerEngine) ShouldRestart(_ context.Context, id string) (bool, error) {
|
||||
return containers.ShouldRestart(ic.ClientCxt, id)
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
|
||||
return nil, errors.Wrap(err, "invalid config provided")
|
||||
}
|
||||
|
||||
finalMounts, finalVolumes, err := finalizeMounts(ctx, s, rt, rtc, newImage)
|
||||
finalMounts, finalVolumes, finalOverlays, err := finalizeMounts(ctx, s, rt, rtc, newImage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -121,7 +121,7 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
|
||||
return nil, err
|
||||
}
|
||||
|
||||
opts, err := createContainerOptions(ctx, rt, s, pod, finalVolumes, newImage, command)
|
||||
opts, err := createContainerOptions(ctx, rt, s, pod, finalVolumes, finalOverlays, newImage, command)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -144,7 +144,7 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
|
||||
return rt.NewContainer(ctx, runtimeSpec, options...)
|
||||
}
|
||||
|
||||
func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator, pod *libpod.Pod, volumes []*specgen.NamedVolume, img *image.Image, command []string) ([]libpod.CtrCreateOption, error) {
|
||||
func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator, pod *libpod.Pod, volumes []*specgen.NamedVolume, overlays []*specgen.OverlayVolume, img *image.Image, command []string) ([]libpod.CtrCreateOption, error) {
|
||||
var options []libpod.CtrCreateOption
|
||||
var err error
|
||||
|
||||
@@ -224,7 +224,7 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
|
||||
for _, volume := range volumes {
|
||||
destinations = append(destinations, volume.Dest)
|
||||
}
|
||||
for _, overlayVolume := range s.OverlayVolumes {
|
||||
for _, overlayVolume := range overlays {
|
||||
destinations = append(destinations, overlayVolume.Destination)
|
||||
}
|
||||
for _, imageVolume := range s.ImageVolumes {
|
||||
@@ -244,9 +244,9 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
|
||||
options = append(options, libpod.WithNamedVolumes(vols))
|
||||
}
|
||||
|
||||
if len(s.OverlayVolumes) != 0 {
|
||||
if len(overlays) != 0 {
|
||||
var vols []*libpod.ContainerOverlayVolume
|
||||
for _, v := range s.OverlayVolumes {
|
||||
for _, v := range overlays {
|
||||
vols = append(vols, &libpod.ContainerOverlayVolume{
|
||||
Dest: v.Destination,
|
||||
Source: v.Source,
|
||||
|
||||
@@ -33,17 +33,17 @@ var (
|
||||
)
|
||||
|
||||
// Produce final mounts and named volumes for a container
|
||||
func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, img *image.Image) ([]spec.Mount, []*specgen.NamedVolume, error) {
|
||||
func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, img *image.Image) ([]spec.Mount, []*specgen.NamedVolume, []*specgen.OverlayVolume, error) {
|
||||
// Get image volumes
|
||||
baseMounts, baseVolumes, err := getImageVolumes(ctx, img, s)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
// Get volumes-from mounts
|
||||
volFromMounts, volFromVolumes, err := getVolumesFrom(s.VolumesFrom, rt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
// Supersede from --volumes-from.
|
||||
@@ -57,19 +57,53 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru
|
||||
// Need to make map forms of specgen mounts/volumes.
|
||||
unifiedMounts := map[string]spec.Mount{}
|
||||
unifiedVolumes := map[string]*specgen.NamedVolume{}
|
||||
unifiedOverlays := map[string]*specgen.OverlayVolume{}
|
||||
|
||||
// Need to make map forms of specgen mounts/volumes.
|
||||
commonMounts, commonVolumes, commonOverlayVolumes, err := specgen.GenVolumeMounts(rtc.Volumes())
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
for _, m := range s.Mounts {
|
||||
if _, ok := unifiedMounts[m.Destination]; ok {
|
||||
return nil, nil, errors.Wrapf(errDuplicateDest, "conflict in specified mounts - multiple mounts at %q", m.Destination)
|
||||
return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict in specified mounts - multiple mounts at %q", m.Destination)
|
||||
}
|
||||
unifiedMounts[m.Destination] = m
|
||||
}
|
||||
|
||||
for _, m := range commonMounts {
|
||||
if _, ok := unifiedMounts[m.Destination]; !ok {
|
||||
unifiedMounts[m.Destination] = m
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range s.Volumes {
|
||||
if _, ok := unifiedVolumes[v.Dest]; ok {
|
||||
return nil, nil, errors.Wrapf(errDuplicateDest, "conflict in specified volumes - multiple volumes at %q", v.Dest)
|
||||
return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict in specified volumes - multiple volumes at %q", v.Dest)
|
||||
}
|
||||
unifiedVolumes[v.Dest] = v
|
||||
}
|
||||
|
||||
for _, v := range commonVolumes {
|
||||
if _, ok := unifiedVolumes[v.Dest]; !ok {
|
||||
unifiedVolumes[v.Dest] = v
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range s.OverlayVolumes {
|
||||
if _, ok := unifiedOverlays[v.Destination]; ok {
|
||||
return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict in specified volumes - multiple volumes at %q", v.Destination)
|
||||
}
|
||||
unifiedOverlays[v.Destination] = v
|
||||
}
|
||||
|
||||
for _, v := range commonOverlayVolumes {
|
||||
if _, ok := unifiedOverlays[v.Destination]; ok {
|
||||
unifiedOverlays[v.Destination] = v
|
||||
}
|
||||
}
|
||||
|
||||
// If requested, add container init binary
|
||||
if s.Init {
|
||||
initPath := s.InitPath
|
||||
@@ -78,10 +112,10 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru
|
||||
}
|
||||
initMount, err := addContainerInitBinary(s, initPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
if _, ok := unifiedMounts[initMount.Destination]; ok {
|
||||
return nil, nil, errors.Wrapf(errDuplicateDest, "conflict with mount added by --init to %q", initMount.Destination)
|
||||
return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict with mount added by --init to %q", initMount.Destination)
|
||||
}
|
||||
unifiedMounts[initMount.Destination] = initMount
|
||||
}
|
||||
@@ -115,12 +149,12 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru
|
||||
// Check for conflicts between named volumes and mounts
|
||||
for dest := range baseMounts {
|
||||
if _, ok := baseVolumes[dest]; ok {
|
||||
return nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
|
||||
return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
|
||||
}
|
||||
}
|
||||
for dest := range baseVolumes {
|
||||
if _, ok := baseMounts[dest]; ok {
|
||||
return nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
|
||||
return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
|
||||
}
|
||||
}
|
||||
// Final step: maps to arrays
|
||||
@@ -129,7 +163,7 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru
|
||||
if mount.Type == TypeBind {
|
||||
absSrc, err := filepath.Abs(mount.Source)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "error getting absolute path of %s", mount.Source)
|
||||
return nil, nil, nil, errors.Wrapf(err, "error getting absolute path of %s", mount.Source)
|
||||
}
|
||||
mount.Source = absSrc
|
||||
}
|
||||
@@ -140,7 +174,12 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru
|
||||
finalVolumes = append(finalVolumes, volume)
|
||||
}
|
||||
|
||||
return finalMounts, finalVolumes, nil
|
||||
finalOverlays := make([]*specgen.OverlayVolume, 0, len(unifiedOverlays))
|
||||
for _, volume := range unifiedOverlays {
|
||||
finalOverlays = append(finalOverlays, volume)
|
||||
}
|
||||
|
||||
return finalMounts, finalVolumes, finalOverlays, nil
|
||||
}
|
||||
|
||||
// Get image volumes from the given image
|
||||
|
||||
@@ -272,16 +272,10 @@ func ParseNetworkNamespace(ns string) (Namespace, []string, error) {
|
||||
toReturn.NSMode = Private
|
||||
case strings.HasPrefix(ns, "ns:"):
|
||||
split := strings.SplitN(ns, ":", 2)
|
||||
if len(split) != 2 {
|
||||
return toReturn, nil, errors.Errorf("must provide a path to a namespace when specifying ns:")
|
||||
}
|
||||
toReturn.NSMode = Path
|
||||
toReturn.Value = split[1]
|
||||
case strings.HasPrefix(ns, "container:"):
|
||||
split := strings.SplitN(ns, ":", 2)
|
||||
if len(split) != 2 {
|
||||
return toReturn, nil, errors.Errorf("must provide name or ID or a container when specifying container:")
|
||||
}
|
||||
toReturn.NSMode = FromContainer
|
||||
toReturn.Value = split[1]
|
||||
default:
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package specgen
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"github.com/containers/image/v5/manifest"
|
||||
"github.com/containers/storage"
|
||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// LogConfig describes the logging characteristics for a container
|
||||
@@ -459,42 +459,6 @@ type SpecGenerator struct {
|
||||
ContainerHealthCheckConfig
|
||||
}
|
||||
|
||||
// NamedVolume holds information about a named volume that will be mounted into
|
||||
// the container.
|
||||
type NamedVolume struct {
|
||||
// Name is the name of the named volume to be mounted. May be empty.
|
||||
// If empty, a new named volume with a pseudorandomly generated name
|
||||
// will be mounted at the given destination.
|
||||
Name string
|
||||
// Destination to mount the named volume within the container. Must be
|
||||
// an absolute path. Path will be created if it does not exist.
|
||||
Dest string
|
||||
// Options are options that the named volume will be mounted with.
|
||||
Options []string
|
||||
}
|
||||
|
||||
// OverlayVolume holds information about a overlay volume that will be mounted into
|
||||
// the container.
|
||||
type OverlayVolume struct {
|
||||
// Destination is the absolute path where the mount will be placed in the container.
|
||||
Destination string `json:"destination"`
|
||||
// Source specifies the source path of the mount.
|
||||
Source string `json:"source,omitempty"`
|
||||
}
|
||||
|
||||
// ImageVolume is a volume based on a container image. The container image is
|
||||
// first mounted on the host and is then bind-mounted into the container. An
|
||||
// ImageVolume is always mounted read only.
|
||||
type ImageVolume struct {
|
||||
// Source is the source of the image volume. The image can be referred
|
||||
// to by name and by ID.
|
||||
Source string
|
||||
// Destination is the absolute path of the mount in the container.
|
||||
Destination string
|
||||
// ReadWrite sets the volume writable.
|
||||
ReadWrite bool
|
||||
}
|
||||
|
||||
// PortMapping is one or more ports that will be mapped into the container.
|
||||
type PortMapping struct {
|
||||
// HostIP is the IP that we will bind to on the host.
|
||||
|
||||
149
pkg/specgen/volumes.go
Normal file
149
pkg/specgen/volumes.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package specgen
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/buildah/pkg/parse"
|
||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// NamedVolume holds information about a named volume that will be mounted into
|
||||
// the container.
|
||||
type NamedVolume struct {
|
||||
// Name is the name of the named volume to be mounted. May be empty.
|
||||
// If empty, a new named volume with a pseudorandomly generated name
|
||||
// will be mounted at the given destination.
|
||||
Name string
|
||||
// Destination to mount the named volume within the container. Must be
|
||||
// an absolute path. Path will be created if it does not exist.
|
||||
Dest string
|
||||
// Options are options that the named volume will be mounted with.
|
||||
Options []string
|
||||
}
|
||||
|
||||
// OverlayVolume holds information about a overlay volume that will be mounted into
|
||||
// the container.
|
||||
type OverlayVolume struct {
|
||||
// Destination is the absolute path where the mount will be placed in the container.
|
||||
Destination string `json:"destination"`
|
||||
// Source specifies the source path of the mount.
|
||||
Source string `json:"source,omitempty"`
|
||||
}
|
||||
|
||||
// ImageVolume is a volume based on a container image. The container image is
|
||||
// first mounted on the host and is then bind-mounted into the container. An
|
||||
// ImageVolume is always mounted read only.
|
||||
type ImageVolume struct {
|
||||
// Source is the source of the image volume. The image can be referred
|
||||
// to by name and by ID.
|
||||
Source string
|
||||
// Destination is the absolute path of the mount in the container.
|
||||
Destination string
|
||||
// ReadWrite sets the volume writable.
|
||||
ReadWrite bool
|
||||
}
|
||||
|
||||
// GenVolumeMounts parses user input into mounts, volumes and overlay volumes
|
||||
func GenVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*NamedVolume, map[string]*OverlayVolume, error) {
|
||||
errDuplicateDest := errors.Errorf("duplicate mount destination")
|
||||
|
||||
mounts := make(map[string]spec.Mount)
|
||||
volumes := make(map[string]*NamedVolume)
|
||||
overlayVolumes := make(map[string]*OverlayVolume)
|
||||
|
||||
volumeFormatErr := errors.Errorf("incorrect volume format, should be [host-dir:]ctr-dir[:option]")
|
||||
|
||||
for _, vol := range volumeFlag {
|
||||
var (
|
||||
options []string
|
||||
src string
|
||||
dest string
|
||||
err error
|
||||
)
|
||||
|
||||
splitVol := strings.Split(vol, ":")
|
||||
if len(splitVol) > 3 {
|
||||
return nil, nil, nil, errors.Wrapf(volumeFormatErr, vol)
|
||||
}
|
||||
|
||||
src = splitVol[0]
|
||||
if len(splitVol) == 1 {
|
||||
// This is an anonymous named volume. Only thing given
|
||||
// is destination.
|
||||
// Name/source will be blank, and populated by libpod.
|
||||
src = ""
|
||||
dest = splitVol[0]
|
||||
} else if len(splitVol) > 1 {
|
||||
dest = splitVol[1]
|
||||
}
|
||||
if len(splitVol) > 2 {
|
||||
if options, err = parse.ValidateVolumeOpts(strings.Split(splitVol[2], ",")); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Do not check source dir for anonymous volumes
|
||||
if len(splitVol) > 1 {
|
||||
if err := parse.ValidateVolumeHostDir(src); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
if err := parse.ValidateVolumeCtrDir(dest); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
cleanDest := filepath.Clean(dest)
|
||||
|
||||
if strings.HasPrefix(src, "/") || strings.HasPrefix(src, ".") {
|
||||
// This is not a named volume
|
||||
overlayFlag := false
|
||||
for _, o := range options {
|
||||
if o == "O" {
|
||||
overlayFlag = true
|
||||
if len(options) > 1 {
|
||||
return nil, nil, nil, errors.New("can't use 'O' with other options")
|
||||
}
|
||||
}
|
||||
}
|
||||
if overlayFlag {
|
||||
// This is a overlay volume
|
||||
newOverlayVol := new(OverlayVolume)
|
||||
newOverlayVol.Destination = cleanDest
|
||||
newOverlayVol.Source = src
|
||||
if _, ok := overlayVolumes[newOverlayVol.Destination]; ok {
|
||||
return nil, nil, nil, errors.Wrapf(errDuplicateDest, newOverlayVol.Destination)
|
||||
}
|
||||
overlayVolumes[newOverlayVol.Destination] = newOverlayVol
|
||||
} else {
|
||||
newMount := spec.Mount{
|
||||
Destination: cleanDest,
|
||||
Type: "bind",
|
||||
Source: src,
|
||||
Options: options,
|
||||
}
|
||||
if _, ok := mounts[newMount.Destination]; ok {
|
||||
return nil, nil, nil, errors.Wrapf(errDuplicateDest, newMount.Destination)
|
||||
}
|
||||
mounts[newMount.Destination] = newMount
|
||||
}
|
||||
} else {
|
||||
// This is a named volume
|
||||
newNamedVol := new(NamedVolume)
|
||||
newNamedVol.Name = src
|
||||
newNamedVol.Dest = cleanDest
|
||||
newNamedVol.Options = options
|
||||
|
||||
if _, ok := volumes[newNamedVol.Dest]; ok {
|
||||
return nil, nil, nil, errors.Wrapf(errDuplicateDest, newNamedVol.Dest)
|
||||
}
|
||||
volumes[newNamedVol.Dest] = newNamedVol
|
||||
}
|
||||
|
||||
logrus.Debugf("User mount %s:%s options %v", src, dest, options)
|
||||
}
|
||||
|
||||
return mounts, volumes, overlayVolumes, nil
|
||||
}
|
||||
@@ -16,19 +16,18 @@ class Podman(object):
|
||||
binary = os.getenv("PODMAN", "bin/podman")
|
||||
self.cmd = [binary, "--storage-driver=vfs"]
|
||||
|
||||
cgroupfs = os.getenv("CGROUP_MANAGER", "cgroupfs")
|
||||
cgroupfs = os.getenv("CGROUP_MANAGER", "systemd")
|
||||
self.cmd.append(f"--cgroup-manager={cgroupfs}")
|
||||
|
||||
if os.getenv("DEBUG"):
|
||||
self.cmd.append("--log-level=debug")
|
||||
self.cmd.append("--syslog=true")
|
||||
|
||||
self.anchor_directory = tempfile.mkdtemp(prefix="podman_restapi_")
|
||||
self.cmd.append("--root=" + os.path.join(self.anchor_directory, "crio"))
|
||||
self.cmd.append("--runroot=" + os.path.join(self.anchor_directory, "crio-run"))
|
||||
|
||||
os.environ["REGISTRIES_CONFIG_PATH"] = os.path.join(
|
||||
self.anchor_directory, "registry.conf"
|
||||
)
|
||||
os.environ["REGISTRIES_CONFIG_PATH"] = os.path.join(self.anchor_directory, "registry.conf")
|
||||
p = configparser.ConfigParser()
|
||||
p.read_dict(
|
||||
{
|
||||
@@ -40,14 +39,10 @@ class Podman(object):
|
||||
with open(os.environ["REGISTRIES_CONFIG_PATH"], "w") as w:
|
||||
p.write(w)
|
||||
|
||||
os.environ["CNI_CONFIG_PATH"] = os.path.join(
|
||||
self.anchor_directory, "cni", "net.d"
|
||||
)
|
||||
os.environ["CNI_CONFIG_PATH"] = os.path.join(self.anchor_directory, "cni", "net.d")
|
||||
os.makedirs(os.environ["CNI_CONFIG_PATH"], exist_ok=True)
|
||||
self.cmd.append("--cni-config-dir=" + os.environ["CNI_CONFIG_PATH"])
|
||||
cni_cfg = os.path.join(
|
||||
os.environ["CNI_CONFIG_PATH"], "87-podman-bridge.conflist"
|
||||
)
|
||||
cni_cfg = os.path.join(os.environ["CNI_CONFIG_PATH"], "87-podman-bridge.conflist")
|
||||
# json decoded and encoded to ensure legal json
|
||||
buf = json.loads(
|
||||
"""
|
||||
|
||||
@@ -61,9 +61,7 @@ class TestApi(unittest.TestCase):
|
||||
super().setUpClass()
|
||||
|
||||
TestApi.podman = Podman()
|
||||
TestApi.service = TestApi.podman.open(
|
||||
"system", "service", "tcp:localhost:8080", "--time=0"
|
||||
)
|
||||
TestApi.service = TestApi.podman.open("system", "service", "tcp:localhost:8080", "--time=0")
|
||||
# give the service some time to be ready...
|
||||
time.sleep(2)
|
||||
|
||||
@@ -165,11 +163,71 @@ class TestApi(unittest.TestCase):
|
||||
r = requests.get(_url(ctnr("/containers/{}/logs?stdout=true")))
|
||||
self.assertEqual(r.status_code, 200, r.text)
|
||||
|
||||
def test_post_create_compat(self):
|
||||
# TODO Need to support Docker-py order of network/container creates
|
||||
def test_post_create_compat_connect(self):
|
||||
"""Create network and container then connect to network"""
|
||||
net = requests.post(
|
||||
PODMAN_URL + "/v1.40/networks/create", json={"Name": "TestNetwork"}
|
||||
net_default = requests.post(
|
||||
PODMAN_URL + "/v1.40/networks/create", json={"Name": "TestDefaultNetwork"}
|
||||
)
|
||||
self.assertEqual(net_default.status_code, 201, net_default.text)
|
||||
|
||||
create = requests.post(
|
||||
PODMAN_URL + "/v1.40/containers/create?name=postCreate",
|
||||
json={
|
||||
"Cmd": ["top"],
|
||||
"Image": "alpine:latest",
|
||||
"NetworkDisabled": False,
|
||||
# FIXME adding these 2 lines cause: (This is sampled from docker-py)
|
||||
# "network already exists","message":"container
|
||||
# 01306e499df5441560d70071a54342611e422a94de20865add50a9565fd79fb9 is already connected to CNI network \"TestDefaultNetwork\": network already exists"
|
||||
# "HostConfig": {"NetworkMode": "TestDefaultNetwork"},
|
||||
# "NetworkingConfig": {"EndpointsConfig": {"TestDefaultNetwork": None}},
|
||||
# FIXME These two lines cause:
|
||||
# CNI network \"TestNetwork\" not found","message":"error configuring network namespace for container 369ddfa7d3211ebf1fbd5ddbff91bd33fa948858cea2985c133d6b6507546dff: CNI network \"TestNetwork\" not found"
|
||||
# "HostConfig": {"NetworkMode": "TestNetwork"},
|
||||
# "NetworkingConfig": {"EndpointsConfig": {"TestNetwork": None}},
|
||||
# FIXME no networking defined cause: (note this error is from the container inspect below)
|
||||
# "internal libpod error","message":"network inspection mismatch: asked to join 2 CNI network(s) [TestDefaultNetwork podman], but have information on 1 network(s): internal libpod error"
|
||||
},
|
||||
)
|
||||
self.assertEqual(create.status_code, 201, create.text)
|
||||
payload = json.loads(create.text)
|
||||
self.assertIsNotNone(payload["Id"])
|
||||
|
||||
start = requests.post(PODMAN_URL + f"/v1.40/containers/{payload['Id']}/start")
|
||||
self.assertEqual(start.status_code, 204, start.text)
|
||||
|
||||
connect = requests.post(
|
||||
PODMAN_URL + "/v1.40/networks/TestDefaultNetwork/connect",
|
||||
json={"Container": payload["Id"]},
|
||||
)
|
||||
self.assertEqual(connect.status_code, 200, connect.text)
|
||||
self.assertEqual(connect.text, "OK\n")
|
||||
|
||||
inspect = requests.get(f"{PODMAN_URL}/v1.40/containers/{payload['Id']}/json")
|
||||
self.assertEqual(inspect.status_code, 200, inspect.text)
|
||||
|
||||
payload = json.loads(inspect.text)
|
||||
self.assertFalse(payload["Config"].get("NetworkDisabled", False))
|
||||
|
||||
self.assertEqual(
|
||||
"TestDefaultNetwork",
|
||||
payload["NetworkSettings"]["Networks"]["TestDefaultNetwork"]["NetworkID"],
|
||||
)
|
||||
# TODO restore this to test, when joining multiple networks possible
|
||||
# self.assertEqual(
|
||||
# "TestNetwork",
|
||||
# payload["NetworkSettings"]["Networks"]["TestNetwork"]["NetworkID"],
|
||||
# )
|
||||
# TODO Need to support network aliases
|
||||
# self.assertIn(
|
||||
# "test_post_create",
|
||||
# payload["NetworkSettings"]["Networks"]["TestNetwork"]["Aliases"],
|
||||
# )
|
||||
|
||||
def test_post_create_compat(self):
|
||||
"""Create network and connect container during create"""
|
||||
net = requests.post(PODMAN_URL + "/v1.40/networks/create", json={"Name": "TestNetwork"})
|
||||
self.assertEqual(net.status_code, 201, net.text)
|
||||
|
||||
create = requests.post(
|
||||
@@ -178,23 +236,21 @@ class TestApi(unittest.TestCase):
|
||||
"Cmd": ["date"],
|
||||
"Image": "alpine:latest",
|
||||
"NetworkDisabled": False,
|
||||
"NetworkConfig": {
|
||||
"EndpointConfig": {"TestNetwork": {"Aliases": ["test_post_create"]}}
|
||||
},
|
||||
"HostConfig": {"NetworkMode": "TestNetwork"},
|
||||
},
|
||||
)
|
||||
self.assertEqual(create.status_code, 201, create.text)
|
||||
payload = json.loads(create.text)
|
||||
self.assertIsNotNone(payload["Id"])
|
||||
|
||||
# This cannot be done until full completion of the network connect
|
||||
# stack and network disconnect stack are complete
|
||||
# connect = requests.post(
|
||||
# PODMAN_URL + "/v1.40/networks/TestNetwork/connect",
|
||||
# json={"Container": payload["Id"]},
|
||||
# )
|
||||
# self.assertEqual(connect.status_code, 200, connect.text)
|
||||
# self.assertEqual(connect.text, "OK\n")
|
||||
inspect = requests.get(f"{PODMAN_URL}/v1.40/containers/{payload['Id']}/json")
|
||||
self.assertEqual(inspect.status_code, 200, inspect.text)
|
||||
payload = json.loads(inspect.text)
|
||||
self.assertFalse(payload["Config"].get("NetworkDisabled", False))
|
||||
self.assertEqual(
|
||||
"TestNetwork",
|
||||
payload["NetworkSettings"]["Networks"]["TestNetwork"]["NetworkID"],
|
||||
)
|
||||
|
||||
def test_commit(self):
|
||||
r = requests.post(_url(ctnr("/commit?container={}")))
|
||||
|
||||
@@ -84,9 +84,7 @@ class TestApi(unittest.TestCase):
|
||||
print("\nService Stderr:\n" + stderr.decode("utf-8"))
|
||||
|
||||
if TestApi.podman.returncode > 0:
|
||||
sys.stderr.write(
|
||||
"podman exited with error code {}\n".format(TestApi.podman.returncode)
|
||||
)
|
||||
sys.stderr.write("podman exited with error code {}\n".format(TestApi.podman.returncode))
|
||||
sys.exit(2)
|
||||
|
||||
return super().tearDownClass()
|
||||
|
||||
51
test/e2e/config/containers-remote.conf
Normal file
51
test/e2e/config/containers-remote.conf
Normal file
@@ -0,0 +1,51 @@
|
||||
[containers]
|
||||
|
||||
# A list of ulimits to be set in containers by default, specified as
|
||||
# "<ulimit name>=<soft limit>:<hard limit>", for example:
|
||||
# "nofile=1024:2048"
|
||||
# See setrlimit(2) for a list of resource names.
|
||||
# Any limit not specified here will be inherited from the process launching the
|
||||
# container engine.
|
||||
# Ulimits has limits for non privileged container engines.
|
||||
#
|
||||
default_ulimits = [
|
||||
"nofile=100:100",
|
||||
]
|
||||
|
||||
# Environment variable list for the conmon process; used for passing necessary
|
||||
# environment variables to conmon or the runtime.
|
||||
#
|
||||
env = [
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
"foo=bar1",
|
||||
]
|
||||
|
||||
# container engines use container separation using MAC(SELinux) labeling.
|
||||
# Flag is ignored on label disabled systems.
|
||||
#
|
||||
label = false
|
||||
|
||||
# Size of /dev/shm. Specified as <number><unit>.
|
||||
# Unit is optional, values:
|
||||
# b (bytes), k (kilobytes), m (megabytes), or g (gigabytes).
|
||||
# If the unit is omitted, the system uses bytes.
|
||||
#
|
||||
shm_size = "202k"
|
||||
|
||||
# List of devices. Specified as
|
||||
# "<device-on-host>:<device-on-container>:<permissions>", for example:
|
||||
# "/dev/sdc:/dev/xvdc:rwm".
|
||||
# If it is empty or commented out, only the default devices will be used
|
||||
#
|
||||
devices = []
|
||||
|
||||
default_sysctls = [
|
||||
"net.ipv4.ping_group_range=0 0",
|
||||
]
|
||||
|
||||
dns_searches=[ "barfoo.com", ]
|
||||
dns_servers=[ "4.3.2.1", ]
|
||||
|
||||
tz = "America/New_York"
|
||||
|
||||
umask = "0022"
|
||||
@@ -177,6 +177,9 @@ var _ = Describe("Podman run", func() {
|
||||
}
|
||||
|
||||
os.Setenv("CONTAINERS_CONF", conffile)
|
||||
if IsRemote() {
|
||||
podmanTest.RestartRemoteService()
|
||||
}
|
||||
result := podmanTest.Podman([]string{"run", ALPINE, "ls", tempdir})
|
||||
result.WaitWithDefaultTimeout()
|
||||
Expect(result.ExitCode()).To(Equal(0))
|
||||
@@ -224,6 +227,17 @@ var _ = Describe("Podman run", func() {
|
||||
Expect(session.LineInOuputStartsWith("search")).To(BeFalse())
|
||||
})
|
||||
|
||||
It("podman run use containers.conf search domain", func() {
|
||||
session := podmanTest.Podman([]string{"run", ALPINE, "cat", "/etc/resolv.conf"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(session.LineInOuputStartsWith("search")).To(BeTrue())
|
||||
Expect(session.OutputToString()).To(ContainSubstring("foobar.com"))
|
||||
|
||||
Expect(session.OutputToString()).To(ContainSubstring("1.2.3.4"))
|
||||
Expect(session.OutputToString()).To(ContainSubstring("debug"))
|
||||
})
|
||||
|
||||
It("podman run containers.conf timezone", func() {
|
||||
//containers.conf timezone set to Pacific/Honolulu
|
||||
session := podmanTest.Podman([]string{"run", ALPINE, "date", "+'%H %Z'"})
|
||||
@@ -231,6 +245,7 @@ var _ = Describe("Podman run", func() {
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(session.OutputToString()).To(ContainSubstring("HST"))
|
||||
})
|
||||
|
||||
It("podman run containers.conf umask", func() {
|
||||
//containers.conf umask set to 0002
|
||||
if !strings.Contains(podmanTest.OCIRuntime, "crun") {
|
||||
@@ -243,4 +258,57 @@ var _ = Describe("Podman run", func() {
|
||||
Expect(session.OutputToString()).To(Equal("0002"))
|
||||
})
|
||||
|
||||
It("podman-remote test localcontainers.conf versus remote containers.conf", func() {
|
||||
if !IsRemote() {
|
||||
Skip("this test is only for remote")
|
||||
}
|
||||
|
||||
os.Setenv("CONTAINERS_CONF", "config/containers-remote.conf")
|
||||
// Configuration that comes from remote server
|
||||
// env
|
||||
session := podmanTest.Podman([]string{"run", ALPINE, "printenv", "foo"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(session.OutputToString()).To(Equal("bar"))
|
||||
|
||||
// dns-search, server, options
|
||||
session = podmanTest.Podman([]string{"run", ALPINE, "cat", "/etc/resolv.conf"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(session.LineInOuputStartsWith("search")).To(BeTrue())
|
||||
Expect(session.OutputToString()).To(ContainSubstring("foobar.com"))
|
||||
Expect(session.OutputToString()).To(ContainSubstring("1.2.3.4"))
|
||||
Expect(session.OutputToString()).To(ContainSubstring("debug"))
|
||||
|
||||
// sysctls
|
||||
session = podmanTest.Podman([]string{"run", "--rm", ALPINE, "cat", "/proc/sys/net/ipv4/ping_group_range"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(session.OutputToString()).To(ContainSubstring("1000"))
|
||||
|
||||
// shm-size
|
||||
session = podmanTest.Podman([]string{"run", ALPINE, "grep", "shm", "/proc/self/mounts"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(session.OutputToString()).To(ContainSubstring("size=200k"))
|
||||
|
||||
// ulimits
|
||||
session = podmanTest.Podman([]string{"run", "--rm", fedoraMinimal, "ulimit", "-n"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(session.OutputToString()).To(ContainSubstring("500"))
|
||||
|
||||
// Configuration that comes from remote client
|
||||
// Timezone
|
||||
session = podmanTest.Podman([]string{"run", ALPINE, "date", "+'%H %Z'"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(session.OutputToString()).To(ContainSubstring("EST"))
|
||||
|
||||
// Umask
|
||||
session = podmanTest.Podman([]string{"run", "--rm", ALPINE, "sh", "-c", "umask"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(session.OutputToString()).To(Equal("0022"))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/containers/podman/v2/pkg/rootless"
|
||||
. "github.com/containers/podman/v2/test/utils"
|
||||
"github.com/containers/storage/pkg/stringid"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
@@ -45,4 +46,21 @@ var _ = Describe("Podman run with --mac-address flag", func() {
|
||||
Expect(result.OutputToString()).To(ContainSubstring("92:d0:c6:0a:29:34"))
|
||||
}
|
||||
})
|
||||
|
||||
It("Podman run --mac-address with custom network", func() {
|
||||
net := "n1" + stringid.GenerateNonCryptoID()
|
||||
session := podmanTest.Podman([]string{"network", "create", net})
|
||||
session.WaitWithDefaultTimeout()
|
||||
defer podmanTest.removeCNINetwork(net)
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
|
||||
result := podmanTest.Podman([]string{"run", "--network", net, "--mac-address", "92:d0:c6:00:29:34", ALPINE, "ip", "addr"})
|
||||
result.WaitWithDefaultTimeout()
|
||||
if rootless.IsRootless() {
|
||||
Expect(result.ExitCode()).To(Equal(125))
|
||||
} else {
|
||||
Expect(result.ExitCode()).To(Equal(0))
|
||||
Expect(result.OutputToString()).To(ContainSubstring("92:d0:c6:00:29:34"))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -76,31 +76,36 @@ var _ = Describe("Podman network", func() {
|
||||
Expect(session.LineInOutputContains(name)).To(BeFalse())
|
||||
})
|
||||
|
||||
It("podman network rm no args", func() {
|
||||
session := podmanTest.Podman([]string{"network", "rm"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).ToNot(BeZero())
|
||||
})
|
||||
rm_func := func(rm string) {
|
||||
It(fmt.Sprintf("podman network %s no args", rm), func() {
|
||||
session := podmanTest.Podman([]string{"network", rm})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).ToNot(BeZero())
|
||||
|
||||
It("podman network rm", func() {
|
||||
SkipIfRootless("FIXME: This one is definitely broken in rootless mode")
|
||||
name, path := generateNetworkConfig(podmanTest)
|
||||
defer removeConf(path)
|
||||
})
|
||||
|
||||
session := podmanTest.Podman([]string{"network", "ls", "--quiet"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(session.LineInOutputContains(name)).To(BeTrue())
|
||||
It(fmt.Sprintf("podman network %s", rm), func() {
|
||||
name, path := generateNetworkConfig(podmanTest)
|
||||
defer removeConf(path)
|
||||
|
||||
rm := podmanTest.Podman([]string{"network", "rm", name})
|
||||
rm.WaitWithDefaultTimeout()
|
||||
Expect(rm.ExitCode()).To(BeZero())
|
||||
session := podmanTest.Podman([]string{"network", "ls", "--quiet"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(session.LineInOutputContains(name)).To(BeTrue())
|
||||
|
||||
results := podmanTest.Podman([]string{"network", "ls", "--quiet"})
|
||||
results.WaitWithDefaultTimeout()
|
||||
Expect(results.ExitCode()).To(Equal(0))
|
||||
Expect(results.LineInOutputContains(name)).To(BeFalse())
|
||||
})
|
||||
rm := podmanTest.Podman([]string{"network", rm, name})
|
||||
rm.WaitWithDefaultTimeout()
|
||||
Expect(rm.ExitCode()).To(BeZero())
|
||||
|
||||
results := podmanTest.Podman([]string{"network", "ls", "--quiet"})
|
||||
results.WaitWithDefaultTimeout()
|
||||
Expect(results.ExitCode()).To(Equal(0))
|
||||
Expect(results.LineInOutputContains(name)).To(BeFalse())
|
||||
})
|
||||
}
|
||||
|
||||
rm_func("rm")
|
||||
rm_func("remove")
|
||||
|
||||
It("podman network inspect no args", func() {
|
||||
session := podmanTest.Podman([]string{"network", "inspect"})
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/containers/podman/v2/pkg/rootless"
|
||||
. "github.com/containers/podman/v2/test/utils"
|
||||
"github.com/containers/storage/pkg/stringid"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
@@ -476,4 +477,23 @@ entrypoint ["/fromimage"]
|
||||
Expect(status3.ExitCode()).To(Equal(0))
|
||||
Expect(strings.Contains(status3.OutputToString(), "Degraded")).To(BeTrue())
|
||||
})
|
||||
|
||||
It("podman create pod invalid network config", func() {
|
||||
net1 := "n1" + stringid.GenerateNonCryptoID()
|
||||
session := podmanTest.Podman([]string{"network", "create", net1})
|
||||
session.WaitWithDefaultTimeout()
|
||||
defer podmanTest.removeCNINetwork(net1)
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
|
||||
session = podmanTest.Podman([]string{"pod", "create", "--network", "host", "--network", net1})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(125))
|
||||
Expect(session.ErrorToString()).To(ContainSubstring("host"))
|
||||
Expect(session.ErrorToString()).To(ContainSubstring("bridge"))
|
||||
|
||||
session = podmanTest.Podman([]string{"pod", "create", "--network", "container:abc"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(125))
|
||||
Expect(session.ErrorToString()).To(ContainSubstring("pods presently do not support network mode container"))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -44,6 +44,12 @@ var _ = Describe("Podman ps", func() {
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
})
|
||||
|
||||
It("podman container ps no containers", func() {
|
||||
session := podmanTest.Podman([]string{"container", "ps"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
})
|
||||
|
||||
It("podman ps default", func() {
|
||||
session := podmanTest.RunTopContainer("")
|
||||
session.WaitWithDefaultTimeout()
|
||||
|
||||
@@ -665,4 +665,33 @@ var _ = Describe("Podman run networking", func() {
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
})
|
||||
|
||||
It("podman run with multiple networks", func() {
|
||||
net1 := "n1" + stringid.GenerateNonCryptoID()
|
||||
session := podmanTest.Podman([]string{"network", "create", net1})
|
||||
session.WaitWithDefaultTimeout()
|
||||
defer podmanTest.removeCNINetwork(net1)
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
|
||||
net2 := "n2" + stringid.GenerateNonCryptoID()
|
||||
session = podmanTest.Podman([]string{"network", "create", net2})
|
||||
session.WaitWithDefaultTimeout()
|
||||
defer podmanTest.removeCNINetwork(net2)
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
|
||||
run := podmanTest.Podman([]string{"run", "--network", net1, "--network", net2, ALPINE, "ip", "-o", "-4", "addr"})
|
||||
run.WaitWithDefaultTimeout()
|
||||
Expect(run.ExitCode()).To(BeZero())
|
||||
Expect(len(run.OutputToStringArray())).To(Equal(3))
|
||||
Expect(run.OutputToString()).To(ContainSubstring("lo"))
|
||||
Expect(run.OutputToString()).To(ContainSubstring("eth0"))
|
||||
Expect(run.OutputToString()).To(ContainSubstring("eth1"))
|
||||
|
||||
//invalid config network host and cni should fail
|
||||
run = podmanTest.Podman([]string{"run", "--network", "host", "--network", net2, ALPINE, "ip", "-o", "-4", "addr"})
|
||||
run.WaitWithDefaultTimeout()
|
||||
Expect(run.ExitCode()).To(Equal(125))
|
||||
Expect(run.ErrorToString()).To(ContainSubstring("host"))
|
||||
Expect(run.ErrorToString()).To(ContainSubstring("bridge"))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -75,11 +75,9 @@ var _ = Describe("Podman run", func() {
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
// the --rm option conflicts with --restart, when the restartPolicy is not "" and "no"
|
||||
// so the exitCode should not equal 0
|
||||
session = podmanTest.Podman([]string{"run", "--rm", "--restart", "on-failure", ALPINE})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Not(Equal(0)))
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
session = podmanTest.Podman([]string{"run", "--rm", "--restart", "always", ALPINE})
|
||||
session.WaitWithDefaultTimeout()
|
||||
|
||||
@@ -39,9 +39,7 @@ class Podman(object):
|
||||
self.cmd.append("--root=" + os.path.join(self.anchor_directory, "crio"))
|
||||
self.cmd.append("--runroot=" + os.path.join(self.anchor_directory, "crio-run"))
|
||||
|
||||
os.environ["REGISTRIES_CONFIG_PATH"] = os.path.join(
|
||||
self.anchor_directory, "registry.conf"
|
||||
)
|
||||
os.environ["REGISTRIES_CONFIG_PATH"] = os.path.join(self.anchor_directory, "registry.conf")
|
||||
p = configparser.ConfigParser()
|
||||
p.read_dict(
|
||||
{
|
||||
@@ -53,20 +51,16 @@ class Podman(object):
|
||||
with open(os.environ["REGISTRIES_CONFIG_PATH"], "w") as w:
|
||||
p.write(w)
|
||||
|
||||
os.environ["CNI_CONFIG_PATH"] = os.path.join(
|
||||
self.anchor_directory, "cni", "net.d"
|
||||
)
|
||||
os.environ["CNI_CONFIG_PATH"] = os.path.join(self.anchor_directory, "cni", "net.d")
|
||||
os.makedirs(os.environ["CNI_CONFIG_PATH"], exist_ok=True)
|
||||
self.cmd.append("--cni-config-dir=" + os.environ["CNI_CONFIG_PATH"])
|
||||
cni_cfg = os.path.join(
|
||||
os.environ["CNI_CONFIG_PATH"], "87-podman-bridge.conflist"
|
||||
)
|
||||
cni_cfg = os.path.join(os.environ["CNI_CONFIG_PATH"], "87-podman-bridge.conflist")
|
||||
# json decoded and encoded to ensure legal json
|
||||
buf = json.loads(
|
||||
"""
|
||||
{
|
||||
"cniVersion": "0.3.0",
|
||||
"name": "podman",
|
||||
"name": "default",
|
||||
"plugins": [{
|
||||
"type": "bridge",
|
||||
"bridge": "cni0",
|
||||
|
||||
@@ -4,9 +4,7 @@ from test.python.docker import constant
|
||||
|
||||
|
||||
def run_top_container(client: DockerClient):
|
||||
c = client.containers.create(
|
||||
constant.ALPINE, command="top", detach=True, tty=True, name="top"
|
||||
)
|
||||
c = client.containers.create(constant.ALPINE, command="top", detach=True, tty=True, name="top")
|
||||
c.start()
|
||||
return c.id
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ class TestContainers(unittest.TestCase):
|
||||
self.assertEqual(len(containers), 2)
|
||||
|
||||
def test_stop_container(self):
|
||||
top = self.client.containers.get("top")
|
||||
top = self.client.containers.get(TestContainers.topContainerId)
|
||||
self.assertEqual(top.status, "running")
|
||||
|
||||
# Stop a running container and validate the state
|
||||
|
||||
@@ -78,9 +78,7 @@ class TestImages(unittest.TestCase):
|
||||
self.assertEqual(len(self.client.images.list()), 2)
|
||||
|
||||
# List images with filter
|
||||
self.assertEqual(
|
||||
len(self.client.images.list(filters={"reference": "alpine"})), 1
|
||||
)
|
||||
self.assertEqual(len(self.client.images.list(filters={"reference": "alpine"})), 1)
|
||||
|
||||
def test_search_image(self):
|
||||
"""Search for image"""
|
||||
|
||||
4
vendor/github.com/containers/common/pkg/config/config.go
generated
vendored
4
vendor/github.com/containers/common/pkg/config/config.go
generated
vendored
@@ -113,6 +113,10 @@ type ContainersConfig struct {
|
||||
// DNSSearches set default DNS search domains.
|
||||
DNSSearches []string `toml:"dns_searches,omitempty"`
|
||||
|
||||
// EnableKeyring tells the container engines whether to create
|
||||
// a kernel keyring for use within the container
|
||||
EnableKeyring bool `toml:"keyring,omitempty"`
|
||||
|
||||
// EnableLabeling tells the container engines whether to use MAC
|
||||
// Labeling to separate containers (SELinux)
|
||||
EnableLabeling bool `toml:"label,omitempty"`
|
||||
|
||||
10
vendor/github.com/containers/common/pkg/config/containers.conf
generated
vendored
10
vendor/github.com/containers/common/pkg/config/containers.conf
generated
vendored
@@ -146,9 +146,13 @@ default_sysctls = [
|
||||
#
|
||||
# ipcns = "private"
|
||||
|
||||
# Flag tells container engine to whether to use container separation using
|
||||
# MAC(SELinux)labeling or not.
|
||||
# Flag is ignored on label disabled systems.
|
||||
# keyring tells the container engine whether to create
|
||||
# a kernel keyring for use within the container.
|
||||
# keyring = true
|
||||
|
||||
# label tells the container engine whether to use container separation using
|
||||
# MAC(SELinux) labeling or not.
|
||||
# The label flag is ignored on label disabled systems.
|
||||
#
|
||||
# label = true
|
||||
|
||||
|
||||
4
vendor/github.com/containers/common/pkg/config/default.go
generated
vendored
4
vendor/github.com/containers/common/pkg/config/default.go
generated
vendored
@@ -46,8 +46,6 @@ var (
|
||||
DefaultInitPath = "/usr/libexec/podman/catatonit"
|
||||
// DefaultInfraImage to use for infra container
|
||||
DefaultInfraImage = "k8s.gcr.io/pause:3.2"
|
||||
// DefaultInfraCommand to be run in an infra container
|
||||
DefaultInfraCommand = "/pause"
|
||||
// DefaultRootlessSHMLockPath is the default path for rootless SHM locks
|
||||
DefaultRootlessSHMLockPath = "/libpod_rootless_lock"
|
||||
// DefaultDetachKeys is the default keys sequence for detaching a
|
||||
@@ -179,6 +177,7 @@ func DefaultConfig() (*Config, error) {
|
||||
DNSServers: []string{},
|
||||
DNSOptions: []string{},
|
||||
DNSSearches: []string{},
|
||||
EnableKeyring: true,
|
||||
EnableLabeling: selinuxEnabled(),
|
||||
Env: []string{
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
@@ -308,7 +307,6 @@ func defaultConfigFromMemory() (*EngineConfig, error) {
|
||||
c.InitPath = DefaultInitPath
|
||||
c.NoPivotRoot = false
|
||||
|
||||
c.InfraCommand = DefaultInfraCommand
|
||||
c.InfraImage = DefaultInfraImage
|
||||
c.EnablePortReservation = true
|
||||
c.NumLocks = 2048
|
||||
|
||||
2
vendor/github.com/containers/common/pkg/retry/retry.go
generated
vendored
2
vendor/github.com/containers/common/pkg/retry/retry.go
generated
vendored
@@ -30,7 +30,7 @@ func RetryIfNecessary(ctx context.Context, operation func() error, retryOptions
|
||||
if retryOptions.Delay != 0 {
|
||||
delay = retryOptions.Delay
|
||||
}
|
||||
logrus.Infof("Warning: failed, retrying in %s ... (%d/%d)", delay, attempt+1, retryOptions.MaxRetry)
|
||||
logrus.Infof("Warning: failed, retrying in %s ... (%d/%d). Error: %v", delay, attempt+1, retryOptions.MaxRetry, err)
|
||||
select {
|
||||
case <-time.After(delay):
|
||||
break
|
||||
|
||||
2
vendor/github.com/containers/common/pkg/seccomp/default_linux.go
generated
vendored
2
vendor/github.com/containers/common/pkg/seccomp/default_linux.go
generated
vendored
@@ -174,6 +174,7 @@ func DefaultProfile() *Seccomp {
|
||||
"ioprio_get",
|
||||
"ioprio_set",
|
||||
"ipc",
|
||||
"keyctl",
|
||||
"kill",
|
||||
"lchown",
|
||||
"lchown32",
|
||||
@@ -327,6 +328,7 @@ func DefaultProfile() *Seccomp {
|
||||
"signalfd",
|
||||
"signalfd4",
|
||||
"sigreturn",
|
||||
"socket",
|
||||
"socketcall",
|
||||
"socketpair",
|
||||
"splice",
|
||||
|
||||
2
vendor/github.com/containers/common/pkg/seccomp/supported.go
generated
vendored
2
vendor/github.com/containers/common/pkg/seccomp/supported.go
generated
vendored
@@ -1,3 +1,5 @@
|
||||
// +build !windows
|
||||
|
||||
package seccomp
|
||||
|
||||
import (
|
||||
|
||||
2
vendor/github.com/containers/common/version/version.go
generated
vendored
2
vendor/github.com/containers/common/version/version.go
generated
vendored
@@ -1,4 +1,4 @@
|
||||
package version
|
||||
|
||||
// Version is the version of the build.
|
||||
const Version = "0.27.0"
|
||||
const Version = "0.29.0"
|
||||
|
||||
2
vendor/github.com/containers/image/v5/pkg/sysregistriesv2/shortnames.go
generated
vendored
2
vendor/github.com/containers/image/v5/pkg/sysregistriesv2/shortnames.go
generated
vendored
@@ -8,8 +8,8 @@ import (
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/containers/storage/pkg/homedir"
|
||||
"github.com/containers/storage/pkg/lockfile"
|
||||
"github.com/docker/docker/pkg/homedir"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
||||
2
vendor/github.com/containers/image/v5/version/version.go
generated
vendored
2
vendor/github.com/containers/image/v5/version/version.go
generated
vendored
@@ -8,7 +8,7 @@ const (
|
||||
// VersionMinor is for functionality in a backwards-compatible manner
|
||||
VersionMinor = 8
|
||||
// VersionPatch is for backwards-compatible bug fixes
|
||||
VersionPatch = 0
|
||||
VersionPatch = 1
|
||||
|
||||
// VersionDev indicates development branch. Releases will be empty string.
|
||||
VersionDev = ""
|
||||
|
||||
2
vendor/github.com/containers/storage/VERSION
generated
vendored
2
vendor/github.com/containers/storage/VERSION
generated
vendored
@@ -1 +1 @@
|
||||
1.24.0
|
||||
1.24.1
|
||||
|
||||
2
vendor/github.com/containers/storage/go.mod
generated
vendored
2
vendor/github.com/containers/storage/go.mod
generated
vendored
@@ -8,7 +8,7 @@ require (
|
||||
github.com/Microsoft/hcsshim v0.8.9
|
||||
github.com/docker/go-units v0.4.0
|
||||
github.com/hashicorp/go-multierror v1.1.0
|
||||
github.com/klauspost/compress v1.11.2
|
||||
github.com/klauspost/compress v1.11.3
|
||||
github.com/klauspost/pgzip v1.2.5
|
||||
github.com/mattn/go-shellwords v1.0.10
|
||||
github.com/mistifyio/go-zfs v2.1.1+incompatible
|
||||
|
||||
4
vendor/github.com/containers/storage/go.sum
generated
vendored
4
vendor/github.com/containers/storage/go.sum
generated
vendored
@@ -64,8 +64,8 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.11.2 h1:MiK62aErc3gIiVEtyzKfeOHgW7atJb5g/KNX5m3c2nQ=
|
||||
github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.11.3 h1:dB4Bn0tN3wdCzQxnS8r06kV74qN/TAfaIS0bVE8h3jc=
|
||||
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
|
||||
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
|
||||
1
vendor/github.com/containers/storage/pkg/unshare/unshare.go
generated
vendored
1
vendor/github.com/containers/storage/pkg/unshare/unshare.go
generated
vendored
@@ -26,6 +26,7 @@ func HomeDir() (string, error) {
|
||||
return
|
||||
}
|
||||
homeDir, homeDirErr = usr.HomeDir, nil
|
||||
return
|
||||
}
|
||||
homeDir, homeDirErr = home, nil
|
||||
})
|
||||
|
||||
124
vendor/github.com/klauspost/compress/flate/gen_inflate.go
generated
vendored
124
vendor/github.com/klauspost/compress/flate/gen_inflate.go
generated
vendored
@@ -42,16 +42,6 @@ func (f *decompressor) $FUNCNAME$() {
|
||||
stateDict
|
||||
)
|
||||
fr := f.r.($TYPE$)
|
||||
moreBits := func() error {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
return noEOF(err)
|
||||
}
|
||||
f.roffset++
|
||||
f.b |= uint32(c) << f.nb
|
||||
f.nb += 8
|
||||
return nil
|
||||
}
|
||||
|
||||
switch f.stepState {
|
||||
case stateInit:
|
||||
@@ -112,9 +102,7 @@ readLiteral:
|
||||
}
|
||||
}
|
||||
|
||||
var n uint // number of bits extra
|
||||
var length int
|
||||
var err error
|
||||
switch {
|
||||
case v < 256:
|
||||
f.dict.writeByte(byte(v))
|
||||
@@ -131,25 +119,26 @@ readLiteral:
|
||||
// otherwise, reference to older data
|
||||
case v < 265:
|
||||
length = v - (257 - 3)
|
||||
n = 0
|
||||
case v < 269:
|
||||
length = v*2 - (265*2 - 11)
|
||||
n = 1
|
||||
case v < 273:
|
||||
length = v*4 - (269*4 - 19)
|
||||
n = 2
|
||||
case v < 277:
|
||||
length = v*8 - (273*8 - 35)
|
||||
n = 3
|
||||
case v < 281:
|
||||
length = v*16 - (277*16 - 67)
|
||||
n = 4
|
||||
case v < 285:
|
||||
length = v*32 - (281*32 - 131)
|
||||
n = 5
|
||||
case v < maxNumLit:
|
||||
length = 258
|
||||
n = 0
|
||||
val := decCodeToLen[(v - 257)]
|
||||
length = int(val.length) + 3
|
||||
n := uint(val.extra)
|
||||
for f.nb < n {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("morebits n>0:", err)
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
f.roffset++
|
||||
f.b |= uint32(c) << f.nb
|
||||
f.nb += 8
|
||||
}
|
||||
length += int(f.b & uint32(1<<(n®SizeMaskUint32)-1))
|
||||
f.b >>= n & regSizeMaskUint32
|
||||
f.nb -= n
|
||||
default:
|
||||
if debugDecode {
|
||||
fmt.Println(v, ">= maxNumLit")
|
||||
@@ -157,45 +146,70 @@ readLiteral:
|
||||
f.err = CorruptInputError(f.roffset)
|
||||
return
|
||||
}
|
||||
if n > 0 {
|
||||
for f.nb < n {
|
||||
if err = moreBits(); err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("morebits n>0:", err)
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
}
|
||||
length += int(f.b & uint32(1<<(n®SizeMaskUint32)-1))
|
||||
f.b >>= n & regSizeMaskUint32
|
||||
f.nb -= n
|
||||
}
|
||||
|
||||
var dist uint32
|
||||
if f.hd == nil {
|
||||
for f.nb < 5 {
|
||||
if err = f.moreBits(); err != nil {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("morebits f.nb<5:", err)
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
f.roffset++
|
||||
f.b |= uint32(c) << f.nb
|
||||
f.nb += 8
|
||||
}
|
||||
dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3)))
|
||||
f.b >>= 5
|
||||
f.nb -= 5
|
||||
} else {
|
||||
sym, err := f.huffSym(f.hd)
|
||||
if err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("huffsym:", err)
|
||||
// Since a huffmanDecoder can be empty or be composed of a degenerate tree
|
||||
// with single element, huffSym must error on these two edge cases. In both
|
||||
// cases, the chunks slice will be 0 for the invalid sequence, leading it
|
||||
// satisfy the n == 0 check below.
|
||||
n := uint(f.hd.maxRead)
|
||||
// Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
|
||||
// but is smart enough to keep local variables in registers, so use nb and b,
|
||||
// inline call to moreBits and reassign b,nb back to f on return.
|
||||
nb, b := f.nb, f.b
|
||||
for {
|
||||
for nb < n {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
f.b = b
|
||||
f.nb = nb
|
||||
f.err = noEOF(err)
|
||||
return
|
||||
}
|
||||
f.roffset++
|
||||
b |= uint32(c) << (nb & regSizeMaskUint32)
|
||||
nb += 8
|
||||
}
|
||||
chunk := f.hd.chunks[b&(huffmanNumChunks-1)]
|
||||
n = uint(chunk & huffmanCountMask)
|
||||
if n > huffmanChunkBits {
|
||||
chunk = f.hd.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hd.linkMask]
|
||||
n = uint(chunk & huffmanCountMask)
|
||||
}
|
||||
if n <= nb {
|
||||
if n == 0 {
|
||||
f.b = b
|
||||
f.nb = nb
|
||||
if debugDecode {
|
||||
fmt.Println("huffsym: n==0")
|
||||
}
|
||||
f.err = CorruptInputError(f.roffset)
|
||||
return
|
||||
}
|
||||
f.b = b >> (n & regSizeMaskUint32)
|
||||
f.nb = nb - n
|
||||
dist = uint32(chunk >> huffmanValueShift)
|
||||
break
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
dist = uint32(sym)
|
||||
}
|
||||
|
||||
switch {
|
||||
@@ -206,13 +220,17 @@ readLiteral:
|
||||
// have 1 bit in bottom of dist, need nb more.
|
||||
extra := (dist & 1) << (nb & regSizeMaskUint32)
|
||||
for f.nb < nb {
|
||||
if err = f.moreBits(); err != nil {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("morebits f.nb<nb:", err)
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
f.roffset++
|
||||
f.b |= uint32(c) << f.nb
|
||||
f.nb += 8
|
||||
}
|
||||
extra |= f.b & uint32(1<<(nb®SizeMaskUint32)-1)
|
||||
f.b >>= nb & regSizeMaskUint32
|
||||
|
||||
7
vendor/github.com/klauspost/compress/flate/inflate.go
generated
vendored
7
vendor/github.com/klauspost/compress/flate/inflate.go
generated
vendored
@@ -29,6 +29,13 @@ const (
|
||||
debugDecode = false
|
||||
)
|
||||
|
||||
// Value of length - 3 and extra bits.
|
||||
type lengthExtra struct {
|
||||
length, extra uint8
|
||||
}
|
||||
|
||||
var decCodeToLen = [32]lengthExtra{{length: 0x0, extra: 0x0}, {length: 0x1, extra: 0x0}, {length: 0x2, extra: 0x0}, {length: 0x3, extra: 0x0}, {length: 0x4, extra: 0x0}, {length: 0x5, extra: 0x0}, {length: 0x6, extra: 0x0}, {length: 0x7, extra: 0x0}, {length: 0x8, extra: 0x1}, {length: 0xa, extra: 0x1}, {length: 0xc, extra: 0x1}, {length: 0xe, extra: 0x1}, {length: 0x10, extra: 0x2}, {length: 0x14, extra: 0x2}, {length: 0x18, extra: 0x2}, {length: 0x1c, extra: 0x2}, {length: 0x20, extra: 0x3}, {length: 0x28, extra: 0x3}, {length: 0x30, extra: 0x3}, {length: 0x38, extra: 0x3}, {length: 0x40, extra: 0x4}, {length: 0x50, extra: 0x4}, {length: 0x60, extra: 0x4}, {length: 0x70, extra: 0x4}, {length: 0x80, extra: 0x5}, {length: 0xa0, extra: 0x5}, {length: 0xc0, extra: 0x5}, {length: 0xe0, extra: 0x5}, {length: 0xff, extra: 0x0}, {length: 0x0, extra: 0x0}, {length: 0x0, extra: 0x0}, {length: 0x0, extra: 0x0}}
|
||||
|
||||
// Initialize the fixedHuffmanDecoder only once upon first use.
|
||||
var fixedOnce sync.Once
|
||||
var fixedHuffmanDecoder huffmanDecoder
|
||||
|
||||
496
vendor/github.com/klauspost/compress/flate/inflate_gen.go
generated
vendored
496
vendor/github.com/klauspost/compress/flate/inflate_gen.go
generated
vendored
@@ -20,16 +20,6 @@ func (f *decompressor) huffmanBytesBuffer() {
|
||||
stateDict
|
||||
)
|
||||
fr := f.r.(*bytes.Buffer)
|
||||
moreBits := func() error {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
return noEOF(err)
|
||||
}
|
||||
f.roffset++
|
||||
f.b |= uint32(c) << f.nb
|
||||
f.nb += 8
|
||||
return nil
|
||||
}
|
||||
|
||||
switch f.stepState {
|
||||
case stateInit:
|
||||
@@ -90,9 +80,7 @@ readLiteral:
|
||||
}
|
||||
}
|
||||
|
||||
var n uint // number of bits extra
|
||||
var length int
|
||||
var err error
|
||||
switch {
|
||||
case v < 256:
|
||||
f.dict.writeByte(byte(v))
|
||||
@@ -109,25 +97,26 @@ readLiteral:
|
||||
// otherwise, reference to older data
|
||||
case v < 265:
|
||||
length = v - (257 - 3)
|
||||
n = 0
|
||||
case v < 269:
|
||||
length = v*2 - (265*2 - 11)
|
||||
n = 1
|
||||
case v < 273:
|
||||
length = v*4 - (269*4 - 19)
|
||||
n = 2
|
||||
case v < 277:
|
||||
length = v*8 - (273*8 - 35)
|
||||
n = 3
|
||||
case v < 281:
|
||||
length = v*16 - (277*16 - 67)
|
||||
n = 4
|
||||
case v < 285:
|
||||
length = v*32 - (281*32 - 131)
|
||||
n = 5
|
||||
case v < maxNumLit:
|
||||
length = 258
|
||||
n = 0
|
||||
val := decCodeToLen[(v - 257)]
|
||||
length = int(val.length) + 3
|
||||
n := uint(val.extra)
|
||||
for f.nb < n {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("morebits n>0:", err)
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
f.roffset++
|
||||
f.b |= uint32(c) << f.nb
|
||||
f.nb += 8
|
||||
}
|
||||
length += int(f.b & uint32(1<<(n®SizeMaskUint32)-1))
|
||||
f.b >>= n & regSizeMaskUint32
|
||||
f.nb -= n
|
||||
default:
|
||||
if debugDecode {
|
||||
fmt.Println(v, ">= maxNumLit")
|
||||
@@ -135,45 +124,70 @@ readLiteral:
|
||||
f.err = CorruptInputError(f.roffset)
|
||||
return
|
||||
}
|
||||
if n > 0 {
|
||||
for f.nb < n {
|
||||
if err = moreBits(); err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("morebits n>0:", err)
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
}
|
||||
length += int(f.b & uint32(1<<(n®SizeMaskUint32)-1))
|
||||
f.b >>= n & regSizeMaskUint32
|
||||
f.nb -= n
|
||||
}
|
||||
|
||||
var dist uint32
|
||||
if f.hd == nil {
|
||||
for f.nb < 5 {
|
||||
if err = f.moreBits(); err != nil {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("morebits f.nb<5:", err)
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
f.roffset++
|
||||
f.b |= uint32(c) << f.nb
|
||||
f.nb += 8
|
||||
}
|
||||
dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3)))
|
||||
f.b >>= 5
|
||||
f.nb -= 5
|
||||
} else {
|
||||
sym, err := f.huffSym(f.hd)
|
||||
if err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("huffsym:", err)
|
||||
// Since a huffmanDecoder can be empty or be composed of a degenerate tree
|
||||
// with single element, huffSym must error on these two edge cases. In both
|
||||
// cases, the chunks slice will be 0 for the invalid sequence, leading it
|
||||
// satisfy the n == 0 check below.
|
||||
n := uint(f.hd.maxRead)
|
||||
// Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
|
||||
// but is smart enough to keep local variables in registers, so use nb and b,
|
||||
// inline call to moreBits and reassign b,nb back to f on return.
|
||||
nb, b := f.nb, f.b
|
||||
for {
|
||||
for nb < n {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
f.b = b
|
||||
f.nb = nb
|
||||
f.err = noEOF(err)
|
||||
return
|
||||
}
|
||||
f.roffset++
|
||||
b |= uint32(c) << (nb & regSizeMaskUint32)
|
||||
nb += 8
|
||||
}
|
||||
chunk := f.hd.chunks[b&(huffmanNumChunks-1)]
|
||||
n = uint(chunk & huffmanCountMask)
|
||||
if n > huffmanChunkBits {
|
||||
chunk = f.hd.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hd.linkMask]
|
||||
n = uint(chunk & huffmanCountMask)
|
||||
}
|
||||
if n <= nb {
|
||||
if n == 0 {
|
||||
f.b = b
|
||||
f.nb = nb
|
||||
if debugDecode {
|
||||
fmt.Println("huffsym: n==0")
|
||||
}
|
||||
f.err = CorruptInputError(f.roffset)
|
||||
return
|
||||
}
|
||||
f.b = b >> (n & regSizeMaskUint32)
|
||||
f.nb = nb - n
|
||||
dist = uint32(chunk >> huffmanValueShift)
|
||||
break
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
dist = uint32(sym)
|
||||
}
|
||||
|
||||
switch {
|
||||
@@ -184,13 +198,17 @@ readLiteral:
|
||||
// have 1 bit in bottom of dist, need nb more.
|
||||
extra := (dist & 1) << (nb & regSizeMaskUint32)
|
||||
for f.nb < nb {
|
||||
if err = f.moreBits(); err != nil {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("morebits f.nb<nb:", err)
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
f.roffset++
|
||||
f.b |= uint32(c) << f.nb
|
||||
f.nb += 8
|
||||
}
|
||||
extra |= f.b & uint32(1<<(nb®SizeMaskUint32)-1)
|
||||
f.b >>= nb & regSizeMaskUint32
|
||||
@@ -246,16 +264,6 @@ func (f *decompressor) huffmanBytesReader() {
|
||||
stateDict
|
||||
)
|
||||
fr := f.r.(*bytes.Reader)
|
||||
moreBits := func() error {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
return noEOF(err)
|
||||
}
|
||||
f.roffset++
|
||||
f.b |= uint32(c) << f.nb
|
||||
f.nb += 8
|
||||
return nil
|
||||
}
|
||||
|
||||
switch f.stepState {
|
||||
case stateInit:
|
||||
@@ -316,9 +324,7 @@ readLiteral:
|
||||
}
|
||||
}
|
||||
|
||||
var n uint // number of bits extra
|
||||
var length int
|
||||
var err error
|
||||
switch {
|
||||
case v < 256:
|
||||
f.dict.writeByte(byte(v))
|
||||
@@ -335,25 +341,26 @@ readLiteral:
|
||||
// otherwise, reference to older data
|
||||
case v < 265:
|
||||
length = v - (257 - 3)
|
||||
n = 0
|
||||
case v < 269:
|
||||
length = v*2 - (265*2 - 11)
|
||||
n = 1
|
||||
case v < 273:
|
||||
length = v*4 - (269*4 - 19)
|
||||
n = 2
|
||||
case v < 277:
|
||||
length = v*8 - (273*8 - 35)
|
||||
n = 3
|
||||
case v < 281:
|
||||
length = v*16 - (277*16 - 67)
|
||||
n = 4
|
||||
case v < 285:
|
||||
length = v*32 - (281*32 - 131)
|
||||
n = 5
|
||||
case v < maxNumLit:
|
||||
length = 258
|
||||
n = 0
|
||||
val := decCodeToLen[(v - 257)]
|
||||
length = int(val.length) + 3
|
||||
n := uint(val.extra)
|
||||
for f.nb < n {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("morebits n>0:", err)
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
f.roffset++
|
||||
f.b |= uint32(c) << f.nb
|
||||
f.nb += 8
|
||||
}
|
||||
length += int(f.b & uint32(1<<(n®SizeMaskUint32)-1))
|
||||
f.b >>= n & regSizeMaskUint32
|
||||
f.nb -= n
|
||||
default:
|
||||
if debugDecode {
|
||||
fmt.Println(v, ">= maxNumLit")
|
||||
@@ -361,45 +368,70 @@ readLiteral:
|
||||
f.err = CorruptInputError(f.roffset)
|
||||
return
|
||||
}
|
||||
if n > 0 {
|
||||
for f.nb < n {
|
||||
if err = moreBits(); err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("morebits n>0:", err)
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
}
|
||||
length += int(f.b & uint32(1<<(n®SizeMaskUint32)-1))
|
||||
f.b >>= n & regSizeMaskUint32
|
||||
f.nb -= n
|
||||
}
|
||||
|
||||
var dist uint32
|
||||
if f.hd == nil {
|
||||
for f.nb < 5 {
|
||||
if err = f.moreBits(); err != nil {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("morebits f.nb<5:", err)
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
f.roffset++
|
||||
f.b |= uint32(c) << f.nb
|
||||
f.nb += 8
|
||||
}
|
||||
dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3)))
|
||||
f.b >>= 5
|
||||
f.nb -= 5
|
||||
} else {
|
||||
sym, err := f.huffSym(f.hd)
|
||||
if err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("huffsym:", err)
|
||||
// Since a huffmanDecoder can be empty or be composed of a degenerate tree
|
||||
// with single element, huffSym must error on these two edge cases. In both
|
||||
// cases, the chunks slice will be 0 for the invalid sequence, leading it
|
||||
// satisfy the n == 0 check below.
|
||||
n := uint(f.hd.maxRead)
|
||||
// Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
|
||||
// but is smart enough to keep local variables in registers, so use nb and b,
|
||||
// inline call to moreBits and reassign b,nb back to f on return.
|
||||
nb, b := f.nb, f.b
|
||||
for {
|
||||
for nb < n {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
f.b = b
|
||||
f.nb = nb
|
||||
f.err = noEOF(err)
|
||||
return
|
||||
}
|
||||
f.roffset++
|
||||
b |= uint32(c) << (nb & regSizeMaskUint32)
|
||||
nb += 8
|
||||
}
|
||||
chunk := f.hd.chunks[b&(huffmanNumChunks-1)]
|
||||
n = uint(chunk & huffmanCountMask)
|
||||
if n > huffmanChunkBits {
|
||||
chunk = f.hd.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hd.linkMask]
|
||||
n = uint(chunk & huffmanCountMask)
|
||||
}
|
||||
if n <= nb {
|
||||
if n == 0 {
|
||||
f.b = b
|
||||
f.nb = nb
|
||||
if debugDecode {
|
||||
fmt.Println("huffsym: n==0")
|
||||
}
|
||||
f.err = CorruptInputError(f.roffset)
|
||||
return
|
||||
}
|
||||
f.b = b >> (n & regSizeMaskUint32)
|
||||
f.nb = nb - n
|
||||
dist = uint32(chunk >> huffmanValueShift)
|
||||
break
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
dist = uint32(sym)
|
||||
}
|
||||
|
||||
switch {
|
||||
@@ -410,13 +442,17 @@ readLiteral:
|
||||
// have 1 bit in bottom of dist, need nb more.
|
||||
extra := (dist & 1) << (nb & regSizeMaskUint32)
|
||||
for f.nb < nb {
|
||||
if err = f.moreBits(); err != nil {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("morebits f.nb<nb:", err)
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
f.roffset++
|
||||
f.b |= uint32(c) << f.nb
|
||||
f.nb += 8
|
||||
}
|
||||
extra |= f.b & uint32(1<<(nb®SizeMaskUint32)-1)
|
||||
f.b >>= nb & regSizeMaskUint32
|
||||
@@ -472,16 +508,6 @@ func (f *decompressor) huffmanBufioReader() {
|
||||
stateDict
|
||||
)
|
||||
fr := f.r.(*bufio.Reader)
|
||||
moreBits := func() error {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
return noEOF(err)
|
||||
}
|
||||
f.roffset++
|
||||
f.b |= uint32(c) << f.nb
|
||||
f.nb += 8
|
||||
return nil
|
||||
}
|
||||
|
||||
switch f.stepState {
|
||||
case stateInit:
|
||||
@@ -542,9 +568,7 @@ readLiteral:
|
||||
}
|
||||
}
|
||||
|
||||
var n uint // number of bits extra
|
||||
var length int
|
||||
var err error
|
||||
switch {
|
||||
case v < 256:
|
||||
f.dict.writeByte(byte(v))
|
||||
@@ -561,25 +585,26 @@ readLiteral:
|
||||
// otherwise, reference to older data
|
||||
case v < 265:
|
||||
length = v - (257 - 3)
|
||||
n = 0
|
||||
case v < 269:
|
||||
length = v*2 - (265*2 - 11)
|
||||
n = 1
|
||||
case v < 273:
|
||||
length = v*4 - (269*4 - 19)
|
||||
n = 2
|
||||
case v < 277:
|
||||
length = v*8 - (273*8 - 35)
|
||||
n = 3
|
||||
case v < 281:
|
||||
length = v*16 - (277*16 - 67)
|
||||
n = 4
|
||||
case v < 285:
|
||||
length = v*32 - (281*32 - 131)
|
||||
n = 5
|
||||
case v < maxNumLit:
|
||||
length = 258
|
||||
n = 0
|
||||
val := decCodeToLen[(v - 257)]
|
||||
length = int(val.length) + 3
|
||||
n := uint(val.extra)
|
||||
for f.nb < n {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("morebits n>0:", err)
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
f.roffset++
|
||||
f.b |= uint32(c) << f.nb
|
||||
f.nb += 8
|
||||
}
|
||||
length += int(f.b & uint32(1<<(n®SizeMaskUint32)-1))
|
||||
f.b >>= n & regSizeMaskUint32
|
||||
f.nb -= n
|
||||
default:
|
||||
if debugDecode {
|
||||
fmt.Println(v, ">= maxNumLit")
|
||||
@@ -587,45 +612,70 @@ readLiteral:
|
||||
f.err = CorruptInputError(f.roffset)
|
||||
return
|
||||
}
|
||||
if n > 0 {
|
||||
for f.nb < n {
|
||||
if err = moreBits(); err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("morebits n>0:", err)
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
}
|
||||
length += int(f.b & uint32(1<<(n®SizeMaskUint32)-1))
|
||||
f.b >>= n & regSizeMaskUint32
|
||||
f.nb -= n
|
||||
}
|
||||
|
||||
var dist uint32
|
||||
if f.hd == nil {
|
||||
for f.nb < 5 {
|
||||
if err = f.moreBits(); err != nil {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("morebits f.nb<5:", err)
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
f.roffset++
|
||||
f.b |= uint32(c) << f.nb
|
||||
f.nb += 8
|
||||
}
|
||||
dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3)))
|
||||
f.b >>= 5
|
||||
f.nb -= 5
|
||||
} else {
|
||||
sym, err := f.huffSym(f.hd)
|
||||
if err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("huffsym:", err)
|
||||
// Since a huffmanDecoder can be empty or be composed of a degenerate tree
|
||||
// with single element, huffSym must error on these two edge cases. In both
|
||||
// cases, the chunks slice will be 0 for the invalid sequence, leading it
|
||||
// satisfy the n == 0 check below.
|
||||
n := uint(f.hd.maxRead)
|
||||
// Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
|
||||
// but is smart enough to keep local variables in registers, so use nb and b,
|
||||
// inline call to moreBits and reassign b,nb back to f on return.
|
||||
nb, b := f.nb, f.b
|
||||
for {
|
||||
for nb < n {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
f.b = b
|
||||
f.nb = nb
|
||||
f.err = noEOF(err)
|
||||
return
|
||||
}
|
||||
f.roffset++
|
||||
b |= uint32(c) << (nb & regSizeMaskUint32)
|
||||
nb += 8
|
||||
}
|
||||
chunk := f.hd.chunks[b&(huffmanNumChunks-1)]
|
||||
n = uint(chunk & huffmanCountMask)
|
||||
if n > huffmanChunkBits {
|
||||
chunk = f.hd.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hd.linkMask]
|
||||
n = uint(chunk & huffmanCountMask)
|
||||
}
|
||||
if n <= nb {
|
||||
if n == 0 {
|
||||
f.b = b
|
||||
f.nb = nb
|
||||
if debugDecode {
|
||||
fmt.Println("huffsym: n==0")
|
||||
}
|
||||
f.err = CorruptInputError(f.roffset)
|
||||
return
|
||||
}
|
||||
f.b = b >> (n & regSizeMaskUint32)
|
||||
f.nb = nb - n
|
||||
dist = uint32(chunk >> huffmanValueShift)
|
||||
break
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
dist = uint32(sym)
|
||||
}
|
||||
|
||||
switch {
|
||||
@@ -636,13 +686,17 @@ readLiteral:
|
||||
// have 1 bit in bottom of dist, need nb more.
|
||||
extra := (dist & 1) << (nb & regSizeMaskUint32)
|
||||
for f.nb < nb {
|
||||
if err = f.moreBits(); err != nil {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("morebits f.nb<nb:", err)
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
f.roffset++
|
||||
f.b |= uint32(c) << f.nb
|
||||
f.nb += 8
|
||||
}
|
||||
extra |= f.b & uint32(1<<(nb®SizeMaskUint32)-1)
|
||||
f.b >>= nb & regSizeMaskUint32
|
||||
@@ -698,16 +752,6 @@ func (f *decompressor) huffmanStringsReader() {
|
||||
stateDict
|
||||
)
|
||||
fr := f.r.(*strings.Reader)
|
||||
moreBits := func() error {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
return noEOF(err)
|
||||
}
|
||||
f.roffset++
|
||||
f.b |= uint32(c) << f.nb
|
||||
f.nb += 8
|
||||
return nil
|
||||
}
|
||||
|
||||
switch f.stepState {
|
||||
case stateInit:
|
||||
@@ -768,9 +812,7 @@ readLiteral:
|
||||
}
|
||||
}
|
||||
|
||||
var n uint // number of bits extra
|
||||
var length int
|
||||
var err error
|
||||
switch {
|
||||
case v < 256:
|
||||
f.dict.writeByte(byte(v))
|
||||
@@ -787,25 +829,26 @@ readLiteral:
|
||||
// otherwise, reference to older data
|
||||
case v < 265:
|
||||
length = v - (257 - 3)
|
||||
n = 0
|
||||
case v < 269:
|
||||
length = v*2 - (265*2 - 11)
|
||||
n = 1
|
||||
case v < 273:
|
||||
length = v*4 - (269*4 - 19)
|
||||
n = 2
|
||||
case v < 277:
|
||||
length = v*8 - (273*8 - 35)
|
||||
n = 3
|
||||
case v < 281:
|
||||
length = v*16 - (277*16 - 67)
|
||||
n = 4
|
||||
case v < 285:
|
||||
length = v*32 - (281*32 - 131)
|
||||
n = 5
|
||||
case v < maxNumLit:
|
||||
length = 258
|
||||
n = 0
|
||||
val := decCodeToLen[(v - 257)]
|
||||
length = int(val.length) + 3
|
||||
n := uint(val.extra)
|
||||
for f.nb < n {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("morebits n>0:", err)
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
f.roffset++
|
||||
f.b |= uint32(c) << f.nb
|
||||
f.nb += 8
|
||||
}
|
||||
length += int(f.b & uint32(1<<(n®SizeMaskUint32)-1))
|
||||
f.b >>= n & regSizeMaskUint32
|
||||
f.nb -= n
|
||||
default:
|
||||
if debugDecode {
|
||||
fmt.Println(v, ">= maxNumLit")
|
||||
@@ -813,45 +856,70 @@ readLiteral:
|
||||
f.err = CorruptInputError(f.roffset)
|
||||
return
|
||||
}
|
||||
if n > 0 {
|
||||
for f.nb < n {
|
||||
if err = moreBits(); err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("morebits n>0:", err)
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
}
|
||||
length += int(f.b & uint32(1<<(n®SizeMaskUint32)-1))
|
||||
f.b >>= n & regSizeMaskUint32
|
||||
f.nb -= n
|
||||
}
|
||||
|
||||
var dist uint32
|
||||
if f.hd == nil {
|
||||
for f.nb < 5 {
|
||||
if err = f.moreBits(); err != nil {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("morebits f.nb<5:", err)
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
f.roffset++
|
||||
f.b |= uint32(c) << f.nb
|
||||
f.nb += 8
|
||||
}
|
||||
dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3)))
|
||||
f.b >>= 5
|
||||
f.nb -= 5
|
||||
} else {
|
||||
sym, err := f.huffSym(f.hd)
|
||||
if err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("huffsym:", err)
|
||||
// Since a huffmanDecoder can be empty or be composed of a degenerate tree
|
||||
// with single element, huffSym must error on these two edge cases. In both
|
||||
// cases, the chunks slice will be 0 for the invalid sequence, leading it
|
||||
// satisfy the n == 0 check below.
|
||||
n := uint(f.hd.maxRead)
|
||||
// Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
|
||||
// but is smart enough to keep local variables in registers, so use nb and b,
|
||||
// inline call to moreBits and reassign b,nb back to f on return.
|
||||
nb, b := f.nb, f.b
|
||||
for {
|
||||
for nb < n {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
f.b = b
|
||||
f.nb = nb
|
||||
f.err = noEOF(err)
|
||||
return
|
||||
}
|
||||
f.roffset++
|
||||
b |= uint32(c) << (nb & regSizeMaskUint32)
|
||||
nb += 8
|
||||
}
|
||||
chunk := f.hd.chunks[b&(huffmanNumChunks-1)]
|
||||
n = uint(chunk & huffmanCountMask)
|
||||
if n > huffmanChunkBits {
|
||||
chunk = f.hd.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hd.linkMask]
|
||||
n = uint(chunk & huffmanCountMask)
|
||||
}
|
||||
if n <= nb {
|
||||
if n == 0 {
|
||||
f.b = b
|
||||
f.nb = nb
|
||||
if debugDecode {
|
||||
fmt.Println("huffsym: n==0")
|
||||
}
|
||||
f.err = CorruptInputError(f.roffset)
|
||||
return
|
||||
}
|
||||
f.b = b >> (n & regSizeMaskUint32)
|
||||
f.nb = nb - n
|
||||
dist = uint32(chunk >> huffmanValueShift)
|
||||
break
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
dist = uint32(sym)
|
||||
}
|
||||
|
||||
switch {
|
||||
@@ -862,13 +930,17 @@ readLiteral:
|
||||
// have 1 bit in bottom of dist, need nb more.
|
||||
extra := (dist & 1) << (nb & regSizeMaskUint32)
|
||||
for f.nb < nb {
|
||||
if err = f.moreBits(); err != nil {
|
||||
c, err := fr.ReadByte()
|
||||
if err != nil {
|
||||
if debugDecode {
|
||||
fmt.Println("morebits f.nb<nb:", err)
|
||||
}
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
f.roffset++
|
||||
f.b |= uint32(c) << f.nb
|
||||
f.nb += 8
|
||||
}
|
||||
extra |= f.b & uint32(1<<(nb®SizeMaskUint32)-1)
|
||||
f.b >>= nb & regSizeMaskUint32
|
||||
|
||||
4
vendor/github.com/klauspost/compress/zstd/README.md
generated
vendored
4
vendor/github.com/klauspost/compress/zstd/README.md
generated
vendored
@@ -54,11 +54,11 @@ To create a writer with default options, do like this:
|
||||
```Go
|
||||
// Compress input to output.
|
||||
func Compress(in io.Reader, out io.Writer) error {
|
||||
w, err := NewWriter(output)
|
||||
enc, err := zstd.NewWriter(out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := io.Copy(w, input)
|
||||
_, err = io.Copy(enc, in)
|
||||
if err != nil {
|
||||
enc.Close()
|
||||
return err
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user