mirror of
https://github.com/containers/podman.git
synced 2025-08-01 05:54:53 +08:00
Merge pull request #3127 from mheon/fix_start_race
Ensure that start() in StartAndAttach() is locked
This commit is contained in:
@ -298,12 +298,14 @@ testing_task:
|
|||||||
setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}'
|
setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}'
|
||||||
unit_test_script: '$SCRIPT_BASE/unit_test.sh |& ${TIMESTAMP}'
|
unit_test_script: '$SCRIPT_BASE/unit_test.sh |& ${TIMESTAMP}'
|
||||||
integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}'
|
integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}'
|
||||||
|
ginkgo_node_logs_script: 'cat $CIRRUS_WORKING_DIR/test/e2e/ginkgo-node-*.log || echo "Ginkgo node logs not found"'
|
||||||
audit_log_script: 'cat /var/log/audit/audit.log || cat /var/log/kern.log'
|
audit_log_script: 'cat /var/log/audit/audit.log || cat /var/log/kern.log'
|
||||||
journalctl_b_script: 'journalctl -b'
|
journalctl_b_script: 'journalctl -b'
|
||||||
|
|
||||||
on_failure:
|
on_failure:
|
||||||
failed_master_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_master_failure.sh'
|
failed_master_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_master_failure.sh'
|
||||||
# Job has already failed, don't fail again and miss collecting data
|
# Job has already failed, don't fail again and miss collecting data
|
||||||
|
failed_ginkgo_node_logs_script: 'cat $CIRRUS_WORKING_DIR/test/e2e/ginkgo-node-*.log || echo "Ginkgo node logs not found"'
|
||||||
failed_audit_log_script: 'cat /var/log/audit/audit.log || cat /var/log/kern.log || echo "Uh oh, cat audit.log failed"'
|
failed_audit_log_script: 'cat /var/log/audit/audit.log || cat /var/log/kern.log || echo "Uh oh, cat audit.log failed"'
|
||||||
failed_journalctl_b_script: 'journalctl -b || echo "Uh oh, journalctl -b failed"'
|
failed_journalctl_b_script: 'journalctl -b || echo "Uh oh, journalctl -b failed"'
|
||||||
|
|
||||||
|
2
Makefile
2
Makefile
@ -207,7 +207,7 @@ localunit: test/goecho/goecho varlink_generate
|
|||||||
./contrib/cirrus/lib.sh.t
|
./contrib/cirrus/lib.sh.t
|
||||||
|
|
||||||
ginkgo:
|
ginkgo:
|
||||||
ginkgo -v -tags "$(BUILDTAGS)" $(GINKGOTIMEOUT) -cover -flakeAttempts 3 -progress -trace -noColor -nodes 3 test/e2e/.
|
ginkgo -v -tags "$(BUILDTAGS)" $(GINKGOTIMEOUT) -cover -flakeAttempts 3 -progress -trace -noColor -nodes 3 -debug test/e2e/.
|
||||||
|
|
||||||
ginkgo-remote:
|
ginkgo-remote:
|
||||||
ginkgo -v -tags "$(BUILDTAGS) remoteclient" $(GINKGOTIMEOUT) -cover -flakeAttempts 3 -progress -trace -noColor test/e2e/.
|
ginkgo -v -tags "$(BUILDTAGS) remoteclient" $(GINKGOTIMEOUT) -cover -flakeAttempts 3 -progress -trace -noColor test/e2e/.
|
||||||
|
@ -10,7 +10,7 @@ popularized by Kubernetes. Libpod also contains the Pod Manager tool `(Podman)`
|
|||||||
|
|
||||||
## Overview and scope
|
## Overview and scope
|
||||||
|
|
||||||
At a high level, the scope of libpod and podman is the following:
|
At a high level, the scope of libpod and Podman is the following:
|
||||||
|
|
||||||
* Support multiple image formats including the OCI and Docker image formats.
|
* Support multiple image formats including the OCI and Docker image formats.
|
||||||
* Support for multiple means to download images including trust & image verification.
|
* Support for multiple means to download images including trust & image verification.
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containers/libpod/libpod/driver"
|
"github.com/containers/libpod/libpod/driver"
|
||||||
@ -119,13 +120,20 @@ func (c *Container) StartAndAttach(ctx context.Context, streams *AttachStreams,
|
|||||||
|
|
||||||
attachChan := make(chan error)
|
attachChan := make(chan error)
|
||||||
|
|
||||||
|
// We need to ensure that we don't return until start() fired in attach.
|
||||||
|
// Use a WaitGroup to sync this.
|
||||||
|
wg := new(sync.WaitGroup)
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
// Attach to the container before starting it
|
// Attach to the container before starting it
|
||||||
go func() {
|
go func() {
|
||||||
if err := c.attach(streams, keys, resize, true); err != nil {
|
if err := c.attach(streams, keys, resize, true, wg); err != nil {
|
||||||
attachChan <- err
|
attachChan <- err
|
||||||
}
|
}
|
||||||
close(attachChan)
|
close(attachChan)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
c.newContainerEvent(events.Attach)
|
c.newContainerEvent(events.Attach)
|
||||||
return attachChan, nil
|
return attachChan, nil
|
||||||
}
|
}
|
||||||
@ -398,7 +406,7 @@ func (c *Container) Attach(streams *AttachStreams, keys string, resize <-chan re
|
|||||||
return errors.Wrapf(ErrCtrStateInvalid, "can only attach to created or running containers")
|
return errors.Wrapf(ErrCtrStateInvalid, "can only attach to created or running containers")
|
||||||
}
|
}
|
||||||
defer c.newContainerEvent(events.Attach)
|
defer c.newContainerEvent(events.Attach)
|
||||||
return c.attach(streams, keys, resize, false)
|
return c.attach(streams, keys, resize, false, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount mounts a container's filesystem on the host
|
// Mount mounts a container's filesystem on the host
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/containers/libpod/pkg/kubeutils"
|
"github.com/containers/libpod/pkg/kubeutils"
|
||||||
"github.com/containers/libpod/utils"
|
"github.com/containers/libpod/utils"
|
||||||
@ -31,7 +32,7 @@ const (
|
|||||||
|
|
||||||
// Attach to the given container
|
// Attach to the given container
|
||||||
// Does not check if state is appropriate
|
// Does not check if state is appropriate
|
||||||
func (c *Container) attach(streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, startContainer bool) error {
|
func (c *Container) attach(streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, startContainer bool, wg *sync.WaitGroup) error {
|
||||||
if !streams.AttachOutput && !streams.AttachError && !streams.AttachInput {
|
if !streams.AttachOutput && !streams.AttachError && !streams.AttachInput {
|
||||||
return errors.Wrapf(ErrInvalidArg, "must provide at least one stream to attach to")
|
return errors.Wrapf(ErrInvalidArg, "must provide at least one stream to attach to")
|
||||||
}
|
}
|
||||||
@ -48,12 +49,17 @@ func (c *Container) attach(streams *AttachStreams, keys string, resize <-chan re
|
|||||||
|
|
||||||
logrus.Debugf("Attaching to container %s", c.ID())
|
logrus.Debugf("Attaching to container %s", c.ID())
|
||||||
|
|
||||||
return c.attachContainerSocket(resize, detachKeys, streams, startContainer)
|
return c.attachContainerSocket(resize, detachKeys, streams, startContainer, wg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// attachContainerSocket connects to the container's attach socket and deals with the IO
|
// attachContainerSocket connects to the container's attach socket and deals with the IO.
|
||||||
|
// wg is only required if startContainer is true
|
||||||
// TODO add a channel to allow interrupting
|
// TODO add a channel to allow interrupting
|
||||||
func (c *Container) attachContainerSocket(resize <-chan remotecommand.TerminalSize, detachKeys []byte, streams *AttachStreams, startContainer bool) error {
|
func (c *Container) attachContainerSocket(resize <-chan remotecommand.TerminalSize, detachKeys []byte, streams *AttachStreams, startContainer bool, wg *sync.WaitGroup) error {
|
||||||
|
if startContainer && wg == nil {
|
||||||
|
return errors.Wrapf(ErrInternal, "wait group not passed when startContainer set")
|
||||||
|
}
|
||||||
|
|
||||||
kubeutils.HandleResizing(resize, func(size remotecommand.TerminalSize) {
|
kubeutils.HandleResizing(resize, func(size remotecommand.TerminalSize) {
|
||||||
controlPath := filepath.Join(c.bundlePath(), "ctl")
|
controlPath := filepath.Join(c.bundlePath(), "ctl")
|
||||||
controlFile, err := os.OpenFile(controlPath, unix.O_WRONLY, 0)
|
controlFile, err := os.OpenFile(controlPath, unix.O_WRONLY, 0)
|
||||||
@ -84,10 +90,13 @@ func (c *Container) attachContainerSocket(resize <-chan remotecommand.TerminalSi
|
|||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
|
// If starting was requested, start the container and notify when that's
|
||||||
|
// done.
|
||||||
if startContainer {
|
if startContainer {
|
||||||
if err := c.start(); err != nil {
|
if err := c.start(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
wg.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
receiveStdoutError := make(chan error)
|
receiveStdoutError := make(chan error)
|
||||||
|
@ -3,9 +3,11 @@
|
|||||||
package libpod
|
package libpod
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
"k8s.io/client-go/tools/remotecommand"
|
"k8s.io/client-go/tools/remotecommand"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Container) attach(streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, startContainer bool) error {
|
func (c *Container) attach(streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, startContainer bool, wg *sync.WaitGroup) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
@ -40,15 +40,11 @@ var _ = Describe("Podman cp", func() {
|
|||||||
|
|
||||||
It("podman cp file", func() {
|
It("podman cp file", func() {
|
||||||
path, err := os.Getwd()
|
path, err := os.Getwd()
|
||||||
if err != nil {
|
Expect(err).To(BeNil())
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
filePath := filepath.Join(path, "cp_test.txt")
|
filePath := filepath.Join(path, "cp_test.txt")
|
||||||
fromHostToContainer := []byte("copy from host to container")
|
fromHostToContainer := []byte("copy from host to container")
|
||||||
err = ioutil.WriteFile(filePath, fromHostToContainer, 0644)
|
err = ioutil.WriteFile(filePath, fromHostToContainer, 0644)
|
||||||
if err != nil {
|
Expect(err).To(BeNil())
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
session := podmanTest.Podman([]string{"create", ALPINE, "cat", "foo"})
|
session := podmanTest.Podman([]string{"create", ALPINE, "cat", "foo"})
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
@ -69,15 +65,12 @@ var _ = Describe("Podman cp", func() {
|
|||||||
|
|
||||||
It("podman cp file to dir", func() {
|
It("podman cp file to dir", func() {
|
||||||
path, err := os.Getwd()
|
path, err := os.Getwd()
|
||||||
if err != nil {
|
Expect(err).To(BeNil())
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
filePath := filepath.Join(path, "cp_test.txt")
|
filePath := filepath.Join(path, "cp_test.txt")
|
||||||
fromHostToContainer := []byte("copy from host to container directory")
|
fromHostToContainer := []byte("copy from host to container directory")
|
||||||
err = ioutil.WriteFile(filePath, fromHostToContainer, 0644)
|
err = ioutil.WriteFile(filePath, fromHostToContainer, 0644)
|
||||||
if err != nil {
|
Expect(err).To(BeNil())
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
session := podmanTest.Podman([]string{"create", ALPINE, "ls", "foodir/"})
|
session := podmanTest.Podman([]string{"create", ALPINE, "ls", "foodir/"})
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session.ExitCode()).To(Equal(0))
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
@ -97,14 +90,10 @@ var _ = Describe("Podman cp", func() {
|
|||||||
|
|
||||||
It("podman cp dir to dir", func() {
|
It("podman cp dir to dir", func() {
|
||||||
path, err := os.Getwd()
|
path, err := os.Getwd()
|
||||||
if err != nil {
|
Expect(err).To(BeNil())
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
testDirPath := filepath.Join(path, "TestDir")
|
testDirPath := filepath.Join(path, "TestDir")
|
||||||
err = os.Mkdir(testDirPath, 0777)
|
err = os.Mkdir(testDirPath, 0777)
|
||||||
if err != nil {
|
Expect(err).To(BeNil())
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
session := podmanTest.Podman([]string{"create", ALPINE, "ls", "/foodir"})
|
session := podmanTest.Podman([]string{"create", ALPINE, "ls", "/foodir"})
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
@ -124,19 +113,13 @@ var _ = Describe("Podman cp", func() {
|
|||||||
|
|
||||||
It("podman cp stdin/stdout", func() {
|
It("podman cp stdin/stdout", func() {
|
||||||
path, err := os.Getwd()
|
path, err := os.Getwd()
|
||||||
if err != nil {
|
Expect(err).To(BeNil())
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
testDirPath := filepath.Join(path, "TestDir")
|
testDirPath := filepath.Join(path, "TestDir")
|
||||||
err = os.Mkdir(testDirPath, 0777)
|
err = os.Mkdir(testDirPath, 0777)
|
||||||
if err != nil {
|
Expect(err).To(BeNil())
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
cmd := exec.Command("tar", "-zcvf", "file.tar.gz", testDirPath)
|
cmd := exec.Command("tar", "-zcvf", "file.tar.gz", testDirPath)
|
||||||
_, err = cmd.Output()
|
_, err = cmd.Output()
|
||||||
if err != nil {
|
Expect(err).To(BeNil())
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
session := podmanTest.Podman([]string{"create", ALPINE, "ls", "foo"})
|
session := podmanTest.Podman([]string{"create", ALPINE, "ls", "foo"})
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
|
Reference in New Issue
Block a user