From 3439657f91eccae1e4cec2c3fb291d2c55bbe871 Mon Sep 17 00:00:00 2001
From: Alessandro Rossi <al.rossi87@gmail.com>
Date: Sat, 27 Aug 2022 18:28:24 +0200
Subject: Fix #15499 already connected network

Compat: Treat already attached networks as a no-op
Applies only to containers in created state. Maintain error in running state.

Co-authored-by: Alessandro Rossi <al.rossi87@gmail.com>
Co-authored-by: Brent Baude <bbaude@redhat.com>
Co-authored-by: Jason T. Greene <jason.greene@redhat.com>
Signed-off-by: Alessandro Rossi <al.rossi87@gmail.com>
Signed-off-by: Jason T. Greene <jason.greene@redhat.com>
---
 libpod/boltdb_state.go                      |  2 +-
 libpod/define/errors.go                     |  3 +++
 libpod/networking_linux.go                  |  5 +++++
 test/e2e/network_connect_disconnect_test.go | 12 ++++++++++--
 4 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go
index 81f11410b..e5a7e20fc 100644
--- a/libpod/boltdb_state.go
+++ b/libpod/boltdb_state.go
@@ -1278,7 +1278,7 @@ func (s *BoltState) NetworkConnect(ctr *Container, network string, opts types.Pe
 		}
 		netConnected := ctrNetworksBkt.Get([]byte(network))
 		if netConnected != nil {
-			return fmt.Errorf("container %s is already connected to network %q: %w", ctr.ID(), network, define.ErrNetworkExists)
+			return fmt.Errorf("container %s is already connected to network %q: %w", ctr.ID(), network, define.ErrNetworkConnected)
 		}
 
 		// Add the network
diff --git a/libpod/define/errors.go b/libpod/define/errors.go
index fd27e89de..be471c27e 100644
--- a/libpod/define/errors.go
+++ b/libpod/define/errors.go
@@ -179,6 +179,9 @@ var (
 	// ErrNetworkInUse indicates the requested operation failed because the network was in use
 	ErrNetworkInUse = errors.New("network is being used")
 
+	// ErrNetworkConnected indicates that the required operation failed because the container is already a network endpoint
+	ErrNetworkConnected = errors.New("network is already connected")
+
 	// ErrStoreNotInitialized indicates that the container storage was never
 	// initialized.
 	ErrStoreNotInitialized = errors.New("the container storage was never initialized")
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index c05796768..c10c3c0b2 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -1357,6 +1357,11 @@ func (c *Container) NetworkConnect(nameOrID, netName string, netOpts types.PerNe
 	}
 
 	if err := c.runtime.state.NetworkConnect(c, netName, netOpts); err != nil {
+		// Docker compat: treat requests to attach already attached networks as a no-op, ignoring opts
+		if errors.Is(err, define.ErrNetworkConnected) && c.ensureState(define.ContainerStateConfigured) {
+			return nil
+		}
+
 		return err
 	}
 	c.newNetworkEvent(events.NetworkConnect, netName)
diff --git a/test/e2e/network_connect_disconnect_test.go b/test/e2e/network_connect_disconnect_test.go
index c9ffe6a8d..3bb2d4702 100644
--- a/test/e2e/network_connect_disconnect_test.go
+++ b/test/e2e/network_connect_disconnect_test.go
@@ -156,7 +156,7 @@ var _ = Describe("Podman network connect and disconnect", func() {
 		Expect(con.ErrorToString()).To(ContainSubstring(`"slirp4netns" is not supported: invalid network mode`))
 	})
 
-	It("podman connect on a container that already is connected to the network should error", func() {
+	It("podman connect on a container that already is connected to the network should error after init", func() {
 		netName := "aliasTest" + stringid.GenerateNonCryptoID()
 		session := podmanTest.Podman([]string{"network", "create", netName})
 		session.WaitWithDefaultTimeout()
@@ -176,7 +176,15 @@ var _ = Describe("Podman network connect and disconnect", func() {
 
 		con := podmanTest.Podman([]string{"network", "connect", netName, "test"})
 		con.WaitWithDefaultTimeout()
-		Expect(con).Should(ExitWithError())
+		Expect(con).Should(Exit(0))
+
+		init := podmanTest.Podman([]string{"init", "test"})
+		init.WaitWithDefaultTimeout()
+		Expect(init).Should(Exit(0))
+
+		con2 := podmanTest.Podman([]string{"network", "connect", netName, "test"})
+		con2.WaitWithDefaultTimeout()
+		Expect(con2).Should(ExitWithError())
 	})
 
 	It("podman network connect", func() {
-- 
cgit v1.2.3-54-g00ecf