diff options
30 files changed, 431 insertions, 198 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index bfe293601..6071a6fa7 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -108,7 +108,7 @@ automation_task: smoke_task: alias: 'smoke' name: "Smoke Test" - skip: *tags + skip: *branches_and_tags container: &bigcontainer image: ${CTR_FQIN} # Leave some resources for smallcontainer @@ -274,17 +274,19 @@ swagger_task: # Check that all included go modules from other sources match -# what is expected in `vendor/modules.txt` vs `go.mod`. -vendor_task: - name: "Test Vendoring" - alias: vendor +# what is expected in `vendor/modules.txt` vs `go.mod`. Also +# make sure that the generated bindings in pkg/bindings/... +# are in sync with the code. +consistency_task: + name: "Test Code Consistency" + alias: consistency skip: *tags depends_on: - build container: *smallcontainer env: <<: *stdenvars - TEST_FLAVOR: vendor + TEST_FLAVOR: consistency TEST_ENVIRON: container CTR_FQIN: ${FEDORA_CONTAINER_FQIN} clone_script: *full_clone # build-cache not available to container tasks @@ -642,7 +644,7 @@ success_task: - validate - bindings - swagger - - vendor + - consistency - alt_build - static_alt_build - osx_alt_build diff --git a/CODE-OF-CONDUCT.md b/CODE-OF-CONDUCT.md index 850e68db0..b23672b1a 100644 --- a/CODE-OF-CONDUCT.md +++ b/CODE-OF-CONDUCT.md @@ -1,3 +1,3 @@ -## The Libpod Project Community Code of Conduct +## The Podman Project Community Code of Conduct -The Libpod project which includes Podman, follows the [Containers Community Code of Conduct](https://github.com/containers/common/blob/master/CODE-OF-CONDUCT.md). +The Podman project which includes Libpod, follows the [Containers Community Code of Conduct](https://github.com/containers/common/blob/master/CODE-OF-CONDUCT.md). @@ -86,7 +86,7 @@ PODMAN_SERVER_LOG ?= # If GOPATH not specified, use one in the local directory ifeq ($(GOPATH),) -export GOPATH := $(CURDIR)/_output +export GOPATH := $(HOME)/go unexport GOBIN endif FIRST_GOPATH := $(firstword $(subst :, ,$(GOPATH))) @@ -98,6 +98,8 @@ ifeq ($(GOBIN),) GOBIN := $(FIRST_GOPATH)/bin endif +export PATH := $(PATH):$(GOBIN) + GOMD2MAN ?= $(shell command -v go-md2man || echo '$(GOBIN)/go-md2man') CROSS_BUILD_TARGETS := \ @@ -206,7 +208,7 @@ endif podman: bin/podman .PHONY: bin/podman-remote -bin/podman-remote: .gopathok .generate-bindings $(SOURCES) go.mod go.sum ## Build with podman on remote environment +bin/podman-remote: .gopathok $(SOURCES) go.mod go.sum ## Build with podman on remote environment $(GO) build $(BUILDFLAGS) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "${REMOTETAGS}" -o $@ ./cmd/podman .PHONY: bin/podman-remote-static @@ -277,7 +279,6 @@ clean: ## Clean artifacts libpod/container_easyjson.go \ libpod/pod_easyjson.go \ .install.goimports \ - .generate-bindings \ docs/build make -C docs clean @@ -463,12 +464,11 @@ podman-remote-%-release: rm -f release.txt $(MAKE) podman-remote-release-$*.zip -BINDINGS_SOURCE = $(wildcard pkg/bindings/**/types.go) -.generate-bindings: $(BINDINGS_SOURCE) +.PHONY: generate-bindings +generate-bindings: ifneq ($(shell uname -s), Darwin) - $(GO) generate -mod=vendor ./pkg/bindings/... ; + GO111MODULE=off $(GO) generate ./pkg/bindings/... ; endif - touch .generate-bindings .PHONY: docker-docs docker-docs: docs diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index 280175f95..17fba5427 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -402,7 +402,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { logDriverFlagName := "log-driver" createFlags.StringVar( &cf.LogDriver, - logDriverFlagName, "", + logDriverFlagName, logDriver(), "Logging driver for the container", ) _ = cmd.RegisterFlagCompletionFunc(logDriverFlagName, AutocompleteLogDriver) diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go index 9635f4135..f252618ce 100644 --- a/cmd/podman/common/create_opts.go +++ b/cmd/podman/common/create_opts.go @@ -517,3 +517,10 @@ func volumes() []string { } return nil } + +func logDriver() string { + if !registry.IsRemote() { + return containerConfig.Containers.LogDriver + } + return "" +} diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go index 287836d9f..4cc53a630 100644 --- a/cmd/podman/common/specgen.go +++ b/cmd/podman/common/specgen.go @@ -463,7 +463,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string if s.LogConfiguration == nil { s.LogConfiguration = &specgen.LogConfig{} } - s.LogConfiguration.Driver = define.KubernetesLogging + if ld := c.LogDriver; len(ld) > 0 { s.LogConfiguration.Driver = ld } diff --git a/cmd/podman/containers/rm.go b/cmd/podman/containers/rm.go index ee9dc4c78..ea616b6e5 100644 --- a/cmd/podman/containers/rm.go +++ b/cmd/podman/containers/rm.go @@ -3,6 +3,7 @@ package containers import ( "context" "fmt" + "io/ioutil" "strings" "github.com/containers/common/pkg/completion" @@ -54,6 +55,7 @@ var ( var ( rmOptions = entities.RmOptions{} + cidFiles = []string{} ) func rmFlags(cmd *cobra.Command) { @@ -65,7 +67,7 @@ func rmFlags(cmd *cobra.Command) { flags.BoolVarP(&rmOptions.Volumes, "volumes", "v", false, "Remove anonymous volumes associated with the container") cidfileFlagName := "cidfile" - flags.StringArrayVarP(&rmOptions.CIDFiles, cidfileFlagName, "", nil, "Read the container ID from the file") + flags.StringArrayVar(&cidFiles, cidfileFlagName, nil, "Read the container ID from the file") _ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault) if !registry.IsRemote() { @@ -92,7 +94,16 @@ func init() { validate.AddLatestFlag(containerRmCommand, &rmOptions.Latest) } -func rm(_ *cobra.Command, args []string) error { +func rm(cmd *cobra.Command, args []string) error { + for _, cidFile := range cidFiles { + content, err := ioutil.ReadFile(string(cidFile)) + if err != nil { + return errors.Wrap(err, "error reading CIDFile") + } + id := strings.Split(string(content), "\n")[0] + args = append(args, id) + } + return removeContainers(args, rmOptions, true) } diff --git a/contrib/cirrus/runner.sh b/contrib/cirrus/runner.sh index e968fac45..d9f91c7af 100755 --- a/contrib/cirrus/runner.sh +++ b/contrib/cirrus/runner.sh @@ -146,9 +146,11 @@ function _run_swagger() { cp -v $GOSRC/pkg/api/swagger.yaml $GOSRC/ } -function _run_vendor() { +function _run_consistency() { make vendor - ./hack/tree_status.sh + SUGGESTION="run 'make vendor' and commit all changes" ./hack/tree_status.sh + make generate-bindings + SUGGESTION="run 'make generate-bindings' and commit all changes" ./hack/tree_status.sh } function _run_build() { diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh index 5c6f05ac0..7b49caba0 100755 --- a/contrib/cirrus/setup_environment.sh +++ b/contrib/cirrus/setup_environment.sh @@ -214,7 +214,7 @@ case "$TEST_FLAVOR" in install_test_configs ;; - vendor) make clean ;; + consistency) make clean ;; release) ;; *) die_unknown TEST_FLAVOR esac diff --git a/libpod/network/create.go b/libpod/network/create.go index 094fbe349..e7f65358b 100644 --- a/libpod/network/create.go +++ b/libpod/network/create.go @@ -23,7 +23,7 @@ func Create(name string, options entities.NetworkCreateOptions, runtimeConfig *c return nil, err } // Acquire a lock for CNI - l, err := acquireCNILock(filepath.Join(runtimeConfig.Engine.TmpDir, LockFileName)) + l, err := acquireCNILock(runtimeConfig) if err != nil { return nil, err } diff --git a/libpod/network/lock.go b/libpod/network/lock.go index 0395359eb..037f41efa 100644 --- a/libpod/network/lock.go +++ b/libpod/network/lock.go @@ -1,6 +1,10 @@ package network import ( + "os" + "path/filepath" + + "github.com/containers/common/pkg/config" "github.com/containers/storage" ) @@ -8,8 +12,13 @@ import ( // delete cases to avoid unwanted collisions in network names. // TODO this uses a file lock and should be converted to shared memory // when we have a more general shared memory lock in libpod -func acquireCNILock(lockPath string) (*CNILock, error) { - l, err := storage.GetLockfile(lockPath) +func acquireCNILock(config *config.Config) (*CNILock, error) { + cniDir := GetCNIConfDir(config) + err := os.MkdirAll(cniDir, 0755) + if err != nil { + return nil, err + } + l, err := storage.GetLockfile(filepath.Join(cniDir, LockFileName)) if err != nil { return nil, err } diff --git a/libpod/network/network.go b/libpod/network/network.go index 89f0b67ac..0fb878b18 100644 --- a/libpod/network/network.go +++ b/libpod/network/network.go @@ -6,7 +6,6 @@ import ( "encoding/json" "net" "os" - "path/filepath" "github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator" @@ -172,7 +171,7 @@ func ValidateUserNetworkIsAvailable(config *config.Config, userNet *net.IPNet) e // RemoveNetwork removes a given network by name. If the network has container associated with it, that // must be handled outside the context of this. func RemoveNetwork(config *config.Config, name string) error { - l, err := acquireCNILock(filepath.Join(config.Engine.TmpDir, LockFileName)) + l, err := acquireCNILock(config) if err != nil { return err } diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go index 6e1945db1..aa12afc82 100644 --- a/pkg/api/handlers/compat/containers.go +++ b/pkg/api/handlers/compat/containers.go @@ -14,7 +14,9 @@ import ( "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/api/handlers" "github.com/containers/podman/v2/pkg/api/handlers/utils" + "github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/domain/filters" + "github.com/containers/podman/v2/pkg/domain/infra/abi" "github.com/containers/podman/v2/pkg/ps" "github.com/containers/podman/v2/pkg/signal" "github.com/docker/docker/api/types" @@ -29,9 +31,11 @@ import ( func RemoveContainer(w http.ResponseWriter, r *http.Request) { decoder := r.Context().Value("decoder").(*schema.Decoder) query := struct { - Force bool `schema:"force"` - Vols bool `schema:"v"` - Link bool `schema:"link"` + All bool `schema:"all"` + Force bool `schema:"force"` + Ignore bool `schema:"ignore"` + Link bool `schema:"link"` + Volumes bool `schema:"v"` }{ // override any golang type defaults } @@ -49,34 +53,31 @@ func RemoveContainer(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) - con, err := runtime.LookupContainer(name) - if err != nil && errors.Cause(err) == define.ErrNoSuchCtr { - // Failed to get container. If force is specified, get the container's ID - // and evict it - if !query.Force { + options := entities.RmOptions{ + All: query.All, + Force: query.Force, + Volumes: query.Volumes, + Ignore: query.Ignore, + } + report, err := containerEngine.ContainerRm(r.Context(), []string{name}, options) + if err != nil { + if errors.Cause(err) == define.ErrNoSuchCtr { utils.ContainerNotFound(w, name, err) return } - if _, err := runtime.EvictContainer(r.Context(), name, query.Vols); err != nil { - if errors.Cause(err) == define.ErrNoSuchCtr { - logrus.Debugf("Ignoring error (--allow-missing): %q", err) - w.WriteHeader(http.StatusNoContent) - return - } - logrus.Warn(errors.Wrapf(err, "failed to evict container: %q", name)) - utils.InternalServerError(w, err) - return - } - w.WriteHeader(http.StatusNoContent) + utils.InternalServerError(w, err) return } - - if err := runtime.RemoveContainer(r.Context(), con, query.Force, query.Vols); err != nil { - utils.InternalServerError(w, err) + if report[0].Err != nil { + utils.InternalServerError(w, report[0].Err) return } + utils.WriteResponse(w, http.StatusNoContent, nil) } @@ -326,6 +327,11 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON, state.Running = true } + // docker calls the configured state "created" + if state.Status == define.ContainerStateConfigured.String() { + state.Status = define.ContainerStateCreated.String() + } + formatCapabilities(inspect.HostConfig.CapDrop) formatCapabilities(inspect.HostConfig.CapAdd) @@ -337,6 +343,11 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON, if err := json.Unmarshal(h, &hc); err != nil { return nil, err } + + // k8s-file == json-file + if hc.LogConfig.Type == define.KubernetesLogging { + hc.LogConfig.Type = define.JSONLogging + } g, err := json.Marshal(inspect.GraphDriver) if err != nil { return nil, err diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go index 73e4d1d3d..40fcfbded 100644 --- a/pkg/bindings/containers/containers.go +++ b/pkg/bindings/containers/containers.go @@ -71,8 +71,10 @@ func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport, } // Remove removes a container from local storage. The force bool designates -// that the container should be removed forcibly (example, even it is running). The volumes -// bool dictates that a container's volumes should also be removed. +// that the container should be removed forcibly (example, even it is running). +// The volumes bool dictates that a container's volumes should also be removed. +// The All option indicates that all containers should be removed +// The Ignore option indicates that if a container did not exist, ignore the error func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) error { if options == nil { options = new(RemoveOptions) @@ -85,9 +87,15 @@ func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) error if v := options.GetVolumes(); options.Changed("Volumes") { params.Set("v", strconv.FormatBool(v)) } + if all := options.GetAll(); options.Changed("All") { + params.Set("all", strconv.FormatBool(all)) + } if force := options.GetForce(); options.Changed("Force") { params.Set("force", strconv.FormatBool(force)) } + if ignore := options.GetIgnore(); options.Changed("Ignore") { + params.Set("ignore", strconv.FormatBool(ignore)) + } response, err := conn.DoRequest(nil, http.MethodDelete, "/containers/%s", params, nil, nameOrID) if err != nil { return err diff --git a/pkg/bindings/containers/types.go b/pkg/bindings/containers/types.go index 43cb58a54..24604fa83 100644 --- a/pkg/bindings/containers/types.go +++ b/pkg/bindings/containers/types.go @@ -122,6 +122,8 @@ type PruneOptions struct { //go:generate go run ../generator/generator.go RemoveOptions // RemoveOptions are optional options for removing containers type RemoveOptions struct { + All *bool + Ignore *bool Force *bool Volumes *bool } diff --git a/pkg/bindings/containers/types_remove_options.go b/pkg/bindings/containers/types_remove_options.go index e21fb41f7..3ef32fa03 100644 --- a/pkg/bindings/containers/types_remove_options.go +++ b/pkg/bindings/containers/types_remove_options.go @@ -87,6 +87,38 @@ func (o *RemoveOptions) ToParams() (url.Values, error) { return params, nil } +// WithAll +func (o *RemoveOptions) WithAll(value bool) *RemoveOptions { + v := &value + o.All = v + return o +} + +// GetAll +func (o *RemoveOptions) GetAll() bool { + var all bool + if o.All == nil { + return all + } + return *o.All +} + +// WithIgnore +func (o *RemoveOptions) WithIgnore(value bool) *RemoveOptions { + v := &value + o.Ignore = v + return o +} + +// GetIgnore +func (o *RemoveOptions) GetIgnore() bool { + var ignore bool + if o.Ignore == nil { + return ignore + } + return *o.Ignore +} + // WithForce func (o *RemoveOptions) WithForce(value bool) *RemoveOptions { v := &value diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index d8576c101..4c1bd6a7d 100644 --- a/pkg/domain/entities/containers.go +++ b/pkg/domain/entities/containers.go @@ -128,12 +128,11 @@ type RestartReport struct { } type RmOptions struct { - All bool - CIDFiles []string - Force bool - Ignore bool - Latest bool - Volumes bool + All bool + Force bool + Ignore bool + Latest bool + Volumes bool } type RmReport struct { diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index a8f4d44a8..48a32817d 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -264,30 +264,30 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, reports := []*entities.RmReport{} names := namesOrIds - for _, cidFile := range options.CIDFiles { - content, err := ioutil.ReadFile(cidFile) - if err != nil { - return nil, errors.Wrap(err, "error reading CIDFile") - } - id := strings.Split(string(content), "\n")[0] - names = append(names, id) - } - // Attempt to remove named containers directly from storage, if container is defined in libpod // this will fail and code will fall through to removing the container from libpod.` tmpNames := []string{} for _, ctr := range names { report := entities.RmReport{Id: ctr} - if err := ic.Libpod.RemoveStorageContainer(ctr, options.Force); err != nil { + report.Err = ic.Libpod.RemoveStorageContainer(ctr, options.Force) + switch errors.Cause(report.Err) { + case nil: // remove container names that we successfully deleted - tmpNames = append(tmpNames, ctr) - } else { reports = append(reports, &report) + case define.ErrNoSuchCtr: + // There is still a potential this is a libpod container + tmpNames = append(tmpNames, ctr) + default: + if _, err := ic.Libpod.LookupContainer(ctr); errors.Cause(err) == define.ErrNoSuchCtr { + // remove container failed, but not a libpod container + reports = append(reports, &report) + continue + } + // attempt to remove as a libpod container + tmpNames = append(tmpNames, ctr) } } - if len(tmpNames) < len(names) { - names = tmpNames - } + names = tmpNames ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod) if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) { diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 84a07f8e9..524b29553 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -173,14 +173,6 @@ func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []st } func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, opts entities.RmOptions) ([]*entities.RmReport, error) { - for _, cidFile := range opts.CIDFiles { - content, err := ioutil.ReadFile(cidFile) - if err != nil { - return nil, errors.Wrap(err, "error reading CIDFile") - } - id := strings.Split(string(content), "\n")[0] - namesOrIds = append(namesOrIds, id) - } ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, opts.Ignore, namesOrIds) if err != nil { return nil, err diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go index 2feb1d3b2..cc3f7928c 100644 --- a/pkg/specgen/generate/container.go +++ b/pkg/specgen/generate/container.go @@ -257,6 +257,14 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat } } + if s.LogConfiguration == nil { + s.LogConfiguration = &specgen.LogConfig{} + } + // set log-driver from common if not already set + if len(s.LogConfiguration.Driver) < 1 { + s.LogConfiguration.Driver = rtc.Containers.LogDriver + } + warnings, err := verifyContainerResources(s) if err != nil { return warnings, err diff --git a/pkg/systemd/generate/common.go b/pkg/systemd/generate/common.go index 8901298db..de6751a17 100644 --- a/pkg/systemd/generate/common.go +++ b/pkg/systemd/generate/common.go @@ -30,14 +30,14 @@ func validateRestartPolicy(restart string) error { return errors.Errorf("%s is not a valid restart policy", restart) } -const headerTemplate = `# {{.ServiceName}}.service -# autogenerated by Podman {{.PodmanVersion}} -{{- if .TimeStamp}} -# {{.TimeStamp}} -{{- end}} +const headerTemplate = `# {{{{.ServiceName}}}}.service +# autogenerated by Podman {{{{.PodmanVersion}}}} +{{{{- if .TimeStamp}}}} +# {{{{.TimeStamp}}}} +{{{{- end}}}} [Unit] -Description=Podman {{.ServiceName}}.service +Description=Podman {{{{.ServiceName}}}}.service Documentation=man:podman-generate-systemd(1) Wants=network.target After=network-online.target diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go index b64b2593c..5f52b0a77 100644 --- a/pkg/systemd/generate/containers.go +++ b/pkg/systemd/generate/containers.go @@ -72,22 +72,22 @@ type containerInfo struct { } const containerTemplate = headerTemplate + ` -{{- if .BoundToServices}} -BindsTo={{- range $index, $value := .BoundToServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}} -After={{- range $index, $value := .BoundToServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}} -{{- end}} +{{{{- if .BoundToServices}}}} +BindsTo={{{{- range $index, $value := .BoundToServices -}}}}{{{{if $index}}}} {{{{end}}}}{{{{ $value }}}}.service{{{{end}}}} +After={{{{- range $index, $value := .BoundToServices -}}}}{{{{if $index}}}} {{{{end}}}}{{{{ $value }}}}.service{{{{end}}}} +{{{{- end}}}} [Service] -Environment={{.EnvVariable}}=%n -Restart={{.RestartPolicy}} -TimeoutStopSec={{.TimeoutStopSec}} -{{- if .ExecStartPre}} -ExecStartPre={{.ExecStartPre}} -{{- end}} -ExecStart={{.ExecStart}} -ExecStop={{.ExecStop}} -ExecStopPost={{.ExecStopPost}} -PIDFile={{.PIDFile}} +Environment={{{{.EnvVariable}}}}=%n +Restart={{{{.RestartPolicy}}}} +TimeoutStopSec={{{{.TimeoutStopSec}}}} +{{{{- if .ExecStartPre}}}} +ExecStartPre={{{{.ExecStartPre}}}} +{{{{- end}}}} +ExecStart={{{{.ExecStart}}}} +ExecStop={{{{.ExecStop}}}} +ExecStopPost={{{{.ExecStopPost}}}} +PIDFile={{{{.PIDFile}}}} Type=forking [Install] @@ -173,9 +173,9 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst } info.EnvVariable = EnvVariable - info.ExecStart = "{{.Executable}} start {{.ContainerNameOrID}}" - info.ExecStop = "{{.Executable}} stop {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} {{.ContainerNameOrID}}" - info.ExecStopPost = "{{.Executable}} stop {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} {{.ContainerNameOrID}}" + info.ExecStart = "{{{{.Executable}}}} start {{{{.ContainerNameOrID}}}}" + info.ExecStop = "{{{{.Executable}}}} stop {{{{if (ge .StopTimeout 0)}}}}-t {{{{.StopTimeout}}}}{{{{end}}}} {{{{.ContainerNameOrID}}}}" + info.ExecStopPost = "{{{{.Executable}}}} stop {{{{if (ge .StopTimeout 0)}}}}-t {{{{.StopTimeout}}}}{{{{end}}}} {{{{.ContainerNameOrID}}}}" // Assemble the ExecStart command when creating a new container. // @@ -209,8 +209,8 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst } startCommand = append(startCommand, "run", - "--conmon-pidfile", "{{.PIDFile}}", - "--cidfile", "{{.ContainerIDFile}}", + "--conmon-pidfile", "{{{{.PIDFile}}}}", + "--cidfile", "{{{{.ContainerIDFile}}}}", "--cgroups=no-conmon", ) // If the container is in a pod, make sure that the @@ -281,10 +281,10 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst startCommand = append(startCommand, remainingCmd...) startCommand = quoteArguments(startCommand) - info.ExecStartPre = "/bin/rm -f {{.PIDFile}} {{.ContainerIDFile}}" + info.ExecStartPre = "/bin/rm -f {{{{.PIDFile}}}} {{{{.ContainerIDFile}}}}" info.ExecStart = strings.Join(startCommand, " ") - info.ExecStop = "{{.Executable}} {{if .RootFlags}}{{ .RootFlags}} {{end}}stop --ignore --cidfile {{.ContainerIDFile}} {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}}" - info.ExecStopPost = "{{.Executable}} {{if .RootFlags}}{{ .RootFlags}} {{end}}rm --ignore -f --cidfile {{.ContainerIDFile}}" + info.ExecStop = "{{{{.Executable}}}} {{{{if .RootFlags}}}}{{{{ .RootFlags}}}} {{{{end}}}}stop --ignore --cidfile {{{{.ContainerIDFile}}}} {{{{if (ge .StopTimeout 0)}}}}-t {{{{.StopTimeout}}}}{{{{end}}}}" + info.ExecStopPost = "{{{{.Executable}}}} {{{{if .RootFlags}}}}{{{{ .RootFlags}}}} {{{{end}}}}rm --ignore -f --cidfile {{{{.ContainerIDFile}}}}" } info.TimeoutStopSec = minTimeoutStopSec + info.StopTimeout @@ -307,7 +307,7 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst // generation. That's especially needed for embedding the PID and ID // files in other fields which will eventually get replaced in the 2nd // template execution. - templ, err := template.New("container_template").Parse(containerTemplate) + templ, err := template.New("container_template").Delims("{{{{", "}}}}").Parse(containerTemplate) if err != nil { return "", errors.Wrap(err, "error parsing systemd service template") } @@ -318,7 +318,7 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst } // Now parse the generated template (i.e., buf) and execute it. - templ, err = template.New("container_template").Parse(buf.String()) + templ, err = template.New("container_template").Delims("{{{{", "}}}}").Parse(buf.String()) if err != nil { return "", errors.Wrap(err, "error parsing systemd service template") } diff --git a/pkg/systemd/generate/containers_test.go b/pkg/systemd/generate/containers_test.go index c8e65bfe3..96d95644b 100644 --- a/pkg/systemd/generate/containers_test.go +++ b/pkg/systemd/generate/containers_test.go @@ -329,6 +329,29 @@ Type=forking WantedBy=multi-user.target default.target ` + goodNewWithJournaldTag := `# jadda-jadda.service +# autogenerated by Podman CI + +[Unit] +Description=Podman jadda-jadda.service +Documentation=man:podman-generate-systemd(1) +Wants=network.target +After=network-online.target + +[Service] +Environment=PODMAN_SYSTEMD_UNIT=%n +Restart=always +TimeoutStopSec=70 +ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id +ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon -d --replace --name test --log-driver=journald --log-opt=tag={{.Name}} awesome-image:latest +ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10 +ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id +PIDFile=%t/jadda-jadda.pid +Type=forking + +[Install] +WantedBy=multi-user.target default.target +` tests := []struct { name string info containerInfo @@ -608,6 +631,22 @@ WantedBy=multi-user.target default.target true, false, }, + {"good with journald log tag (see #9034)", + containerInfo{ + Executable: "/usr/bin/podman", + ServiceName: "jadda-jadda", + ContainerNameOrID: "jadda-jadda", + RestartPolicy: "always", + PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid", + StopTimeout: 10, + PodmanVersion: "CI", + CreateCommand: []string{"I'll get stripped", "create", "--name", "test", "--log-driver=journald", "--log-opt=tag={{.Name}}", "awesome-image:latest"}, + EnvVariable: EnvVariable, + }, + goodNewWithJournaldTag, + true, + false, + }, } for _, tt := range tests { test := tt diff --git a/pkg/systemd/generate/pods.go b/pkg/systemd/generate/pods.go index 7678a240f..c7e3aa955 100644 --- a/pkg/systemd/generate/pods.go +++ b/pkg/systemd/generate/pods.go @@ -72,23 +72,23 @@ type podInfo struct { ExecStopPost string } -const podTemplate = headerTemplate + `Requires={{- range $index, $value := .RequiredServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}} -Before={{- range $index, $value := .RequiredServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}} +const podTemplate = headerTemplate + `Requires={{{{- range $index, $value := .RequiredServices -}}}}{{{{if $index}}}} {{{{end}}}}{{{{ $value }}}}.service{{{{end}}}} +Before={{{{- range $index, $value := .RequiredServices -}}}}{{{{if $index}}}} {{{{end}}}}{{{{ $value }}}}.service{{{{end}}}} [Service] -Environment={{.EnvVariable}}=%n -Restart={{.RestartPolicy}} -TimeoutStopSec={{.TimeoutStopSec}} -{{- if .ExecStartPre1}} -ExecStartPre={{.ExecStartPre1}} -{{- end}} -{{- if .ExecStartPre2}} -ExecStartPre={{.ExecStartPre2}} -{{- end}} -ExecStart={{.ExecStart}} -ExecStop={{.ExecStop}} -ExecStopPost={{.ExecStopPost}} -PIDFile={{.PIDFile}} +Environment={{{{.EnvVariable}}}}=%n +Restart={{{{.RestartPolicy}}}} +TimeoutStopSec={{{{.TimeoutStopSec}}}} +{{{{- if .ExecStartPre1}}}} +ExecStartPre={{{{.ExecStartPre1}}}} +{{{{- end}}}} +{{{{- if .ExecStartPre2}}}} +ExecStartPre={{{{.ExecStartPre2}}}} +{{{{- end}}}} +ExecStart={{{{.ExecStart}}}} +ExecStop={{{{.ExecStop}}}} +ExecStopPost={{{{.ExecStopPost}}}} +PIDFile={{{{.PIDFile}}}} Type=forking [Install] @@ -236,9 +236,9 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions) } info.EnvVariable = EnvVariable - info.ExecStart = "{{.Executable}} start {{.InfraNameOrID}}" - info.ExecStop = "{{.Executable}} stop {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} {{.InfraNameOrID}}" - info.ExecStopPost = "{{.Executable}} stop {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} {{.InfraNameOrID}}" + info.ExecStart = "{{{{.Executable}}}} start {{{{.InfraNameOrID}}}}" + info.ExecStop = "{{{{.Executable}}}} stop {{{{if (ge .StopTimeout 0)}}}}-t {{{{.StopTimeout}}}}{{{{end}}}} {{{{.InfraNameOrID}}}}" + info.ExecStopPost = "{{{{.Executable}}}} stop {{{{if (ge .StopTimeout 0)}}}}-t {{{{.StopTimeout}}}}{{{{end}}}} {{{{.InfraNameOrID}}}}" // Assemble the ExecStart command when creating a new pod. // @@ -278,8 +278,8 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions) startCommand = append(startCommand, podRootArgs...) startCommand = append(startCommand, []string{"pod", "create", - "--infra-conmon-pidfile", "{{.PIDFile}}", - "--pod-id-file", "{{.PodIDFile}}"}...) + "--infra-conmon-pidfile", "{{{{.PIDFile}}}}", + "--pod-id-file", "{{{{.PodIDFile}}}}"}...) // Presence check for certain flags/options. fs := pflag.NewFlagSet("args", pflag.ContinueOnError) @@ -308,11 +308,11 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions) startCommand = append(startCommand, podCreateArgs...) startCommand = quoteArguments(startCommand) - info.ExecStartPre1 = "/bin/rm -f {{.PIDFile}} {{.PodIDFile}}" + info.ExecStartPre1 = "/bin/rm -f {{{{.PIDFile}}}} {{{{.PodIDFile}}}}" info.ExecStartPre2 = strings.Join(startCommand, " ") - info.ExecStart = "{{.Executable}} {{if .RootFlags}}{{ .RootFlags}} {{end}}pod start --pod-id-file {{.PodIDFile}}" - info.ExecStop = "{{.Executable}} {{if .RootFlags}}{{ .RootFlags}} {{end}}pod stop --ignore --pod-id-file {{.PodIDFile}} {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}}" - info.ExecStopPost = "{{.Executable}} {{if .RootFlags}}{{ .RootFlags}} {{end}}pod rm --ignore -f --pod-id-file {{.PodIDFile}}" + info.ExecStart = "{{{{.Executable}}}} {{{{if .RootFlags}}}}{{{{ .RootFlags}}}} {{{{end}}}}pod start --pod-id-file {{{{.PodIDFile}}}}" + info.ExecStop = "{{{{.Executable}}}} {{{{if .RootFlags}}}}{{{{ .RootFlags}}}} {{{{end}}}}pod stop --ignore --pod-id-file {{{{.PodIDFile}}}} {{{{if (ge .StopTimeout 0)}}}}-t {{{{.StopTimeout}}}}{{{{end}}}}" + info.ExecStopPost = "{{{{.Executable}}}} {{{{if .RootFlags}}}}{{{{ .RootFlags}}}} {{{{end}}}}pod rm --ignore -f --pod-id-file {{{{.PodIDFile}}}}" } info.TimeoutStopSec = minTimeoutStopSec + info.StopTimeout @@ -334,7 +334,7 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions) // generation. That's especially needed for embedding the PID and ID // files in other fields which will eventually get replaced in the 2nd // template execution. - templ, err := template.New("pod_template").Parse(podTemplate) + templ, err := template.New("pod_template").Delims("{{{{", "}}}}").Parse(podTemplate) if err != nil { return "", errors.Wrap(err, "error parsing systemd service template") } @@ -345,7 +345,7 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions) } // Now parse the generated template (i.e., buf) and execute it. - templ, err = template.New("pod_template").Parse(buf.String()) + templ, err = template.New("pod_template").Delims("{{{{", "}}}}").Parse(buf.String()) if err != nil { return "", errors.Wrap(err, "error parsing systemd service template") } diff --git a/pkg/systemd/generate/pods_test.go b/pkg/systemd/generate/pods_test.go index 1c6330160..2b430226b 100644 --- a/pkg/systemd/generate/pods_test.go +++ b/pkg/systemd/generate/pods_test.go @@ -143,6 +143,33 @@ Type=forking WantedBy=multi-user.target default.target ` + podNewLabelWithCurlyBraces := `# pod-123abc.service +# autogenerated by Podman CI + +[Unit] +Description=Podman pod-123abc.service +Documentation=man:podman-generate-systemd(1) +Wants=network.target +After=network-online.target +Requires=container-1.service container-2.service +Before=container-1.service container-2.service + +[Service] +Environment=PODMAN_SYSTEMD_UNIT=%n +Restart=on-failure +TimeoutStopSec=70 +ExecStartPre=/bin/rm -f %t/pod-123abc.pid %t/pod-123abc.pod-id +ExecStartPre=/usr/bin/podman pod create --infra-conmon-pidfile %t/pod-123abc.pid --pod-id-file %t/pod-123abc.pod-id --name foo --label key={{someval}} --replace +ExecStart=/usr/bin/podman pod start --pod-id-file %t/pod-123abc.pod-id +ExecStop=/usr/bin/podman pod stop --ignore --pod-id-file %t/pod-123abc.pod-id -t 10 +ExecStopPost=/usr/bin/podman pod rm --ignore -f --pod-id-file %t/pod-123abc.pod-id +PIDFile=%t/pod-123abc.pid +Type=forking + +[Install] +WantedBy=multi-user.target default.target +` + tests := []struct { name string info podInfo @@ -230,6 +257,22 @@ WantedBy=multi-user.target default.target true, false, }, + {"pod --new with double curly braces", + podInfo{ + Executable: "/usr/bin/podman", + ServiceName: "pod-123abc", + InfraNameOrID: "jadda-jadda-infra", + RestartPolicy: "on-failure", + PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid", + StopTimeout: 10, + PodmanVersion: "CI", + RequiredServices: []string{"container-1", "container-2"}, + CreateCommand: []string{"podman", "pod", "create", "--name", "foo", "--label", "key={{someval}}"}, + }, + podNewLabelWithCurlyBraces, + true, + false, + }, } for _, tt := range tests { diff --git a/test/e2e/generate_systemd_test.go b/test/e2e/generate_systemd_test.go index be9727591..606d756b0 100644 --- a/test/e2e/generate_systemd_test.go +++ b/test/e2e/generate_systemd_test.go @@ -355,4 +355,25 @@ var _ = Describe("Podman generate systemd", func() { Expect(session.ExitCode()).To(Equal(0)) Expect(session.IsJSONOutputValid()).To(BeTrue()) }) + + It("podman generate systemd --new create command with double curly braces", func() { + // Regression test for #9034 + session := podmanTest.Podman([]string{"create", "--name", "foo", "--log-driver=journald", "--log-opt=tag={{.Name}}", ALPINE}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"generate", "systemd", "--new", "foo"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring(" --log-opt=tag={{.Name}} ")) + + session = podmanTest.Podman([]string{"pod", "create", "--name", "pod", "--label", "key={{someval}}"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"generate", "systemd", "--new", "pod"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring(" --label key={{someval}}")) + }) }) diff --git a/test/e2e/network_create_test.go b/test/e2e/network_create_test.go index 7e9a18ab2..73e18cbce 100644 --- a/test/e2e/network_create_test.go +++ b/test/e2e/network_create_test.go @@ -10,6 +10,7 @@ import ( cniversion "github.com/containernetworking/cni/pkg/version" "github.com/containers/podman/v2/libpod/network" . "github.com/containers/podman/v2/test/utils" + "github.com/containers/storage/pkg/stringid" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/pkg/errors" @@ -116,18 +117,19 @@ var _ = Describe("Podman network create", func() { results []network.NcList ) - nc := podmanTest.Podman([]string{"network", "create", "newname"}) + netName := "inspectnet-" + stringid.GenerateNonCryptoID() + nc := podmanTest.Podman([]string{"network", "create", netName}) nc.WaitWithDefaultTimeout() + defer podmanTest.removeCNINetwork(netName) Expect(nc.ExitCode()).To(BeZero()) - defer podmanTest.removeCNINetwork("newname") - inspect := podmanTest.Podman([]string{"network", "inspect", "newname"}) + inspect := podmanTest.Podman([]string{"network", "inspect", netName}) inspect.WaitWithDefaultTimeout() err := json.Unmarshal([]byte(inspect.OutputToString()), &results) Expect(err).To(BeNil()) result := results[0] - Expect(result["name"]).To(Equal("newname")) + Expect(result["name"]).To(Equal(netName)) }) @@ -135,21 +137,21 @@ var _ = Describe("Podman network create", func() { var ( results []network.NcList ) - nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/24", "newnetwork"}) + netName := "subnet-" + stringid.GenerateNonCryptoID() + nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/24", netName}) nc.WaitWithDefaultTimeout() + defer podmanTest.removeCNINetwork(netName) Expect(nc.ExitCode()).To(BeZero()) - defer podmanTest.removeCNINetwork("newnetwork") - // Inspect the network configuration - inspect := podmanTest.Podman([]string{"network", "inspect", "newnetwork"}) + inspect := podmanTest.Podman([]string{"network", "inspect", netName}) inspect.WaitWithDefaultTimeout() // JSON the network configuration into something usable err := json.Unmarshal([]byte(inspect.OutputToString()), &results) Expect(err).To(BeNil()) result := results[0] - Expect(result["name"]).To(Equal("newnetwork")) + Expect(result["name"]).To(Equal(netName)) // JSON the bridge info bridgePlugin, err := genericPluginsToBridge(result["plugins"], "bridge") @@ -161,7 +163,7 @@ var _ = Describe("Podman network create", func() { // best we can defer removeNetworkDevice(bridgePlugin.BrName) - try := podmanTest.Podman([]string{"run", "-it", "--rm", "--network", "newnetwork", ALPINE, "sh", "-c", "ip addr show eth0 | awk ' /inet / {print $2}'"}) + try := podmanTest.Podman([]string{"run", "-it", "--rm", "--network", netName, ALPINE, "sh", "-c", "ip addr show eth0 | awk ' /inet / {print $2}'"}) try.WaitWithDefaultTimeout() _, subnet, err := net.ParseCIDR("10.11.12.0/24") @@ -178,21 +180,21 @@ var _ = Describe("Podman network create", func() { var ( results []network.NcList ) - nc := podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:1:2:3:4::/64", "newIPv6network"}) + netName := "ipv6-" + stringid.GenerateNonCryptoID() + nc := podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:1:2:3:4::/64", netName}) nc.WaitWithDefaultTimeout() + defer podmanTest.removeCNINetwork(netName) Expect(nc.ExitCode()).To(BeZero()) - defer podmanTest.removeCNINetwork("newIPv6network") - // Inspect the network configuration - inspect := podmanTest.Podman([]string{"network", "inspect", "newIPv6network"}) + inspect := podmanTest.Podman([]string{"network", "inspect", netName}) inspect.WaitWithDefaultTimeout() // JSON the network configuration into something usable err := json.Unmarshal([]byte(inspect.OutputToString()), &results) Expect(err).To(BeNil()) result := results[0] - Expect(result["name"]).To(Equal("newIPv6network")) + Expect(result["name"]).To(Equal(netName)) // JSON the bridge info bridgePlugin, err := genericPluginsToBridge(result["plugins"], "bridge") @@ -203,7 +205,7 @@ var _ = Describe("Podman network create", func() { // best we can defer removeNetworkDevice(bridgePlugin.BrName) - try := podmanTest.Podman([]string{"run", "-it", "--rm", "--network", "newIPv6network", ALPINE, "sh", "-c", "ip addr show eth0 | grep global | awk ' /inet6 / {print $2}'"}) + try := podmanTest.Podman([]string{"run", "-it", "--rm", "--network", netName, ALPINE, "sh", "-c", "ip addr show eth0 | grep global | awk ' /inet6 / {print $2}'"}) try.WaitWithDefaultTimeout() _, subnet, err := net.ParseCIDR("fd00:1:2:3:4::/64") @@ -219,21 +221,21 @@ var _ = Describe("Podman network create", func() { var ( results []network.NcList ) - nc := podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:4:3:2:1::/64", "--ipv6", "newDualStacknetwork"}) + netName := "dual-" + stringid.GenerateNonCryptoID() + nc := podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:4:3:2:1::/64", "--ipv6", netName}) nc.WaitWithDefaultTimeout() + defer podmanTest.removeCNINetwork(netName) Expect(nc.ExitCode()).To(BeZero()) - defer podmanTest.removeCNINetwork("newDualStacknetwork") - // Inspect the network configuration - inspect := podmanTest.Podman([]string{"network", "inspect", "newDualStacknetwork"}) + inspect := podmanTest.Podman([]string{"network", "inspect", netName}) inspect.WaitWithDefaultTimeout() // JSON the network configuration into something usable err := json.Unmarshal([]byte(inspect.OutputToString()), &results) Expect(err).To(BeNil()) result := results[0] - Expect(result["name"]).To(Equal("newDualStacknetwork")) + Expect(result["name"]).To(Equal(netName)) // JSON the bridge info bridgePlugin, err := genericPluginsToBridge(result["plugins"], "bridge") @@ -245,7 +247,7 @@ var _ = Describe("Podman network create", func() { // best we can defer removeNetworkDevice(bridgePlugin.BrName) - try := podmanTest.Podman([]string{"run", "-it", "--rm", "--network", "newDualStacknetwork", ALPINE, "sh", "-c", "ip addr show eth0 | grep global | awk ' /inet6 / {print $2}'"}) + try := podmanTest.Podman([]string{"run", "-it", "--rm", "--network", netName, ALPINE, "sh", "-c", "ip addr show eth0 | grep global | awk ' /inet6 / {print $2}'"}) try.WaitWithDefaultTimeout() _, subnet, err := net.ParseCIDR("fd00:4:3:2:1::/64") @@ -255,7 +257,7 @@ var _ = Describe("Podman network create", func() { // Ensure that the IP the container got is within the subnet the user asked for Expect(subnet.Contains(containerIP)).To(BeTrue()) // verify the container has an IPv4 address too (the IPv4 subnet is autogenerated) - try = podmanTest.Podman([]string{"run", "-it", "--rm", "--network", "newDualStacknetwork", ALPINE, "sh", "-c", "ip addr show eth0 | awk ' /inet / {print $2}'"}) + try = podmanTest.Podman([]string{"run", "-it", "--rm", "--network", netName, ALPINE, "sh", "-c", "ip addr show eth0 | awk ' /inet / {print $2}'"}) try.WaitWithDefaultTimeout() containerIP, _, err = net.ParseCIDR(try.OutputToString()) Expect(err).To(BeNil()) @@ -263,66 +265,73 @@ var _ = Describe("Podman network create", func() { }) It("podman network create with invalid subnet", func() { - nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/17000", "fail"}) + nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/17000", stringid.GenerateNonCryptoID()}) nc.WaitWithDefaultTimeout() Expect(nc).To(ExitWithError()) }) It("podman network create with ipv4 subnet and ipv6 flag", func() { - nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/24", "--ipv6", "fail"}) + nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/24", "--ipv6", stringid.GenerateNonCryptoID()}) nc.WaitWithDefaultTimeout() Expect(nc).To(ExitWithError()) }) It("podman network create with empty subnet and ipv6 flag", func() { - nc := podmanTest.Podman([]string{"network", "create", "--ipv6", "fail"}) + nc := podmanTest.Podman([]string{"network", "create", "--ipv6", stringid.GenerateNonCryptoID()}) nc.WaitWithDefaultTimeout() Expect(nc).To(ExitWithError()) }) It("podman network create with invalid IP", func() { - nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.0/17000", "fail"}) + nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.0/17000", stringid.GenerateNonCryptoID()}) nc.WaitWithDefaultTimeout() Expect(nc).To(ExitWithError()) }) It("podman network create with invalid gateway for subnet", func() { - nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/24", "--gateway", "192.168.1.1", "fail"}) + nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.12.0/24", "--gateway", "192.168.1.1", stringid.GenerateNonCryptoID()}) nc.WaitWithDefaultTimeout() Expect(nc).To(ExitWithError()) }) It("podman network create two networks with same name should fail", func() { - nc := podmanTest.Podman([]string{"network", "create", "samename"}) + netName := "same-" + stringid.GenerateNonCryptoID() + nc := podmanTest.Podman([]string{"network", "create", netName}) nc.WaitWithDefaultTimeout() + defer podmanTest.removeCNINetwork(netName) Expect(nc.ExitCode()).To(BeZero()) - defer podmanTest.removeCNINetwork("samename") - ncFail := podmanTest.Podman([]string{"network", "create", "samename"}) + ncFail := podmanTest.Podman([]string{"network", "create", netName}) ncFail.WaitWithDefaultTimeout() Expect(ncFail).To(ExitWithError()) }) It("podman network create two networks with same subnet should fail", func() { - nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.13.0/24", "subnet1"}) + netName1 := "sub1-" + stringid.GenerateNonCryptoID() + nc := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.13.0/24", netName1}) nc.WaitWithDefaultTimeout() + defer podmanTest.removeCNINetwork(netName1) Expect(nc.ExitCode()).To(BeZero()) - defer podmanTest.removeCNINetwork("subnet1") - ncFail := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.13.0/24", "subnet2"}) + netName2 := "sub2-" + stringid.GenerateNonCryptoID() + ncFail := podmanTest.Podman([]string{"network", "create", "--subnet", "10.11.13.0/24", netName2}) ncFail.WaitWithDefaultTimeout() + defer podmanTest.removeCNINetwork(netName2) Expect(ncFail).To(ExitWithError()) }) It("podman network create two IPv6 networks with same subnet should fail", func() { SkipIfRootless("FIXME It needs the ip6tables modules loaded") - nc := podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:4:4:4:4::/64", "--ipv6", "subnet1v6"}) + netName1 := "subipv61-" + stringid.GenerateNonCryptoID() + nc := podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:4:4:4:4::/64", "--ipv6", netName1}) nc.WaitWithDefaultTimeout() + defer podmanTest.removeCNINetwork(netName1) Expect(nc.ExitCode()).To(BeZero()) - defer podmanTest.removeCNINetwork("subnet1v6") - ncFail := podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:4:4:4:4::/64", "--ipv6", "subnet2v6"}) + netName2 := "subipv62-" + stringid.GenerateNonCryptoID() + ncFail := podmanTest.Podman([]string{"network", "create", "--subnet", "fd00:4:4:4:4::/64", "--ipv6", netName2}) ncFail.WaitWithDefaultTimeout() + defer podmanTest.removeCNINetwork(netName2) Expect(ncFail).To(ExitWithError()) }) @@ -333,11 +342,11 @@ var _ = Describe("Podman network create", func() { }) It("podman network create with mtu option", func() { - net := "mtu-test" + net := "mtu-test" + stringid.GenerateNonCryptoID() nc := podmanTest.Podman([]string{"network", "create", "--opt", "mtu=9000", net}) nc.WaitWithDefaultTimeout() - Expect(nc.ExitCode()).To(BeZero()) defer podmanTest.removeCNINetwork(net) + Expect(nc.ExitCode()).To(BeZero()) nc = podmanTest.Podman([]string{"network", "inspect", net}) nc.WaitWithDefaultTimeout() @@ -346,11 +355,11 @@ var _ = Describe("Podman network create", func() { }) It("podman network create with vlan option", func() { - net := "vlan-test" + net := "vlan-test" + stringid.GenerateNonCryptoID() nc := podmanTest.Podman([]string{"network", "create", "--opt", "vlan=9", net}) nc.WaitWithDefaultTimeout() - Expect(nc.ExitCode()).To(BeZero()) defer podmanTest.removeCNINetwork(net) + Expect(nc.ExitCode()).To(BeZero()) nc = podmanTest.Podman([]string{"network", "inspect", net}) nc.WaitWithDefaultTimeout() @@ -359,9 +368,10 @@ var _ = Describe("Podman network create", func() { }) It("podman network create with invalid option", func() { - net := "invalid-test" + net := "invalid-test" + stringid.GenerateNonCryptoID() nc := podmanTest.Podman([]string{"network", "create", "--opt", "foo=bar", net}) nc.WaitWithDefaultTimeout() + defer podmanTest.removeCNINetwork(net) Expect(nc).To(ExitWithError()) }) diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go index 98512f01a..e2080244b 100644 --- a/test/e2e/network_test.go +++ b/test/e2e/network_test.go @@ -238,11 +238,11 @@ var _ = Describe("Podman network", func() { }) It("podman inspect container single CNI network", func() { - netName := "testNetSingleCNI" + netName := "net-" + stringid.GenerateNonCryptoID() network := podmanTest.Podman([]string{"network", "create", "--subnet", "10.50.50.0/24", netName}) network.WaitWithDefaultTimeout() - Expect(network.ExitCode()).To(BeZero()) defer podmanTest.removeCNINetwork(netName) + Expect(network.ExitCode()).To(BeZero()) ctrName := "testCtr" container := podmanTest.Podman([]string{"run", "-dt", "--network", netName, "--name", ctrName, ALPINE, "top"}) @@ -268,17 +268,17 @@ var _ = Describe("Podman network", func() { }) It("podman inspect container two CNI networks (container not running)", func() { - netName1 := "testNetThreeCNI1" + netName1 := "net1-" + stringid.GenerateNonCryptoID() network1 := podmanTest.Podman([]string{"network", "create", netName1}) network1.WaitWithDefaultTimeout() - Expect(network1.ExitCode()).To(BeZero()) defer podmanTest.removeCNINetwork(netName1) + Expect(network1.ExitCode()).To(BeZero()) - netName2 := "testNetThreeCNI2" + netName2 := "net2-" + stringid.GenerateNonCryptoID() network2 := podmanTest.Podman([]string{"network", "create", netName2}) network2.WaitWithDefaultTimeout() - Expect(network2.ExitCode()).To(BeZero()) defer podmanTest.removeCNINetwork(netName2) + Expect(network2.ExitCode()).To(BeZero()) ctrName := "testCtr" container := podmanTest.Podman([]string{"create", "--network", fmt.Sprintf("%s,%s", netName1, netName2), "--name", ctrName, ALPINE, "top"}) @@ -305,17 +305,17 @@ var _ = Describe("Podman network", func() { }) It("podman inspect container two CNI networks", func() { - netName1 := "testNetTwoCNI1" + netName1 := "net1-" + stringid.GenerateNonCryptoID() network1 := podmanTest.Podman([]string{"network", "create", "--subnet", "10.50.51.0/25", netName1}) network1.WaitWithDefaultTimeout() - Expect(network1.ExitCode()).To(BeZero()) defer podmanTest.removeCNINetwork(netName1) + Expect(network1.ExitCode()).To(BeZero()) - netName2 := "testNetTwoCNI2" + netName2 := "net2-" + stringid.GenerateNonCryptoID() network2 := podmanTest.Podman([]string{"network", "create", "--subnet", "10.50.51.128/26", netName2}) network2.WaitWithDefaultTimeout() - Expect(network2.ExitCode()).To(BeZero()) defer podmanTest.removeCNINetwork(netName2) + Expect(network2.ExitCode()).To(BeZero()) ctrName := "testCtr" container := podmanTest.Podman([]string{"run", "-dt", "--network", fmt.Sprintf("%s,%s", netName1, netName2), "--name", ctrName, ALPINE, "top"}) @@ -352,11 +352,11 @@ var _ = Describe("Podman network", func() { }) It("podman network remove --force with pod", func() { - netName := "testnet" + netName := "net-" + stringid.GenerateNonCryptoID() session := podmanTest.Podman([]string{"network", "create", netName}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(BeZero()) defer podmanTest.removeCNINetwork(netName) + Expect(session.ExitCode()).To(BeZero()) session = podmanTest.Podman([]string{"pod", "create", "--network", netName}) session.WaitWithDefaultTimeout() @@ -388,17 +388,17 @@ var _ = Describe("Podman network", func() { }) It("podman network remove with two networks", func() { - netName1 := "net1" + netName1 := "net1-" + stringid.GenerateNonCryptoID() session := podmanTest.Podman([]string{"network", "create", netName1}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(BeZero()) defer podmanTest.removeCNINetwork(netName1) + Expect(session.ExitCode()).To(BeZero()) - netName2 := "net2" + netName2 := "net2-" + stringid.GenerateNonCryptoID() session = podmanTest.Podman([]string{"network", "create", netName2}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(BeZero()) defer podmanTest.removeCNINetwork(netName2) + Expect(session.ExitCode()).To(BeZero()) session = podmanTest.Podman([]string{"network", "rm", netName1, netName2}) session.WaitWithDefaultTimeout() @@ -413,8 +413,8 @@ var _ = Describe("Podman network", func() { netName := "aliasTest" + stringid.GenerateNonCryptoID() session := podmanTest.Podman([]string{"network", "create", netName}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(BeZero()) defer podmanTest.removeCNINetwork(netName) + Expect(session.ExitCode()).To(BeZero()) top := podmanTest.Podman([]string{"run", "-dt", "--name=web", "--network=" + netName, "--network-alias=web1", "--network-alias=web2", nginx}) top.WaitWithDefaultTimeout() @@ -450,6 +450,7 @@ var _ = Describe("Podman network", func() { net := "macvlan" + stringid.GenerateNonCryptoID() nc := podmanTest.Podman([]string{"network", "create", "--macvlan", "lo", net}) nc.WaitWithDefaultTimeout() + defer podmanTest.removeCNINetwork(net) Expect(nc.ExitCode()).To(Equal(0)) nc = podmanTest.Podman([]string{"network", "rm", net}) diff --git a/test/e2e/rm_test.go b/test/e2e/rm_test.go index 524c07cc6..ca142d7f3 100644 --- a/test/e2e/rm_test.go +++ b/test/e2e/rm_test.go @@ -215,6 +215,40 @@ var _ = Describe("Podman rm", func() { Expect(result.ExitCode()).To(Equal(125)) }) + It("podman rm --all", func() { + session := podmanTest.Podman([]string{"create", ALPINE, "ls"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainers()).To(Equal(1)) + + session = podmanTest.Podman([]string{"create", ALPINE, "ls"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainers()).To(Equal(2)) + + session = podmanTest.Podman([]string{"rm", "--all"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainers()).To(Equal(0)) + }) + + It("podman rm --ignore", func() { + session := podmanTest.Podman([]string{"create", ALPINE, "ls"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + cid := session.OutputToStringArray()[0] + Expect(podmanTest.NumberOfContainers()).To(Equal(1)) + + session = podmanTest.Podman([]string{"rm", "bogus", cid}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(1)) + + session = podmanTest.Podman([]string{"rm", "--ignore", "bogus", cid}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainers()).To(Equal(0)) + }) + It("podman rm bogus container", func() { session := podmanTest.Podman([]string{"rm", "bogus"}) session.WaitWithDefaultTimeout() diff --git a/test/system/040-ps.bats b/test/system/040-ps.bats index 0447122b1..0ae8b0ce0 100644 --- a/test/system/040-ps.bats +++ b/test/system/040-ps.bats @@ -111,8 +111,11 @@ EOF run_podman ps --storage -a is "${#lines[@]}" "2" "podman ps -a --storage sees buildah container" - # This is what deletes the container - # FIXME: why doesn't "podman rm --storage $cid" do anything? + # We can't rm it without -f, but podman should issue a helpful message + run_podman 2 rm "$cid" + is "$output" "Error: container .* is mounted and cannot be removed without using force: container state improper" "podman rm <buildah container> without -f" + + # With -f, we can remove it. run_podman rm -f "$cid" run_podman ps --storage -a |