Browse Source

Container: Add restore network functionality.

RestoreNetwork() allows the container to restore its NetworkSettings (IP
and public ports).

Signed-off-by: Andrea Luzzardi <aluzzardi@gmail.com>
Andrea Luzzardi 11 years ago
parent
commit
deffc572ce
1 changed files with 41 additions and 5 deletions
  1. 41 5
      daemon/container.go

+ 41 - 5
daemon/container.go

@@ -441,7 +441,7 @@ func (container *Container) buildHostnameAndHostsFiles(IP string) error {
 	return container.buildHostsFiles(IP)
 	return container.buildHostsFiles(IP)
 }
 }
 
 
-func (container *Container) AllocateNetwork() error {
+func (container *Container) AllocateNetwork() (err error) {
 	mode := container.hostConfig.NetworkMode
 	mode := container.hostConfig.NetworkMode
 	if container.Config.NetworkDisabled || !mode.IsPrivate() {
 	if container.Config.NetworkDisabled || !mode.IsPrivate() {
 		return nil
 		return nil
@@ -449,7 +449,6 @@ func (container *Container) AllocateNetwork() error {
 
 
 	var (
 	var (
 		env *engine.Env
 		env *engine.Env
-		err error
 		eng = container.daemon.eng
 		eng = container.daemon.eng
 	)
 	)
 
 
@@ -461,14 +460,21 @@ func (container *Container) AllocateNetwork() error {
 		return err
 		return err
 	}
 	}
 
 
+	// Error handling: At this point, the interface is allocated so we have to
+	// make sure that it is always released in case of error, otherwise we
+	// might leak resources.
+	defer func() {
+		if err != nil {
+			eng.Job("release_interface", container.ID).Run()
+		}
+	}()
+
 	if container.Config.PortSpecs != nil {
 	if container.Config.PortSpecs != nil {
 		if err := migratePortMappings(container.Config, container.hostConfig); err != nil {
 		if err := migratePortMappings(container.Config, container.hostConfig); err != nil {
-			eng.Job("release_interface", container.ID).Run()
 			return err
 			return err
 		}
 		}
 		container.Config.PortSpecs = nil
 		container.Config.PortSpecs = nil
 		if err := container.WriteHostConfig(); err != nil {
 		if err := container.WriteHostConfig(); err != nil {
-			eng.Job("release_interface", container.ID).Run()
 			return err
 			return err
 		}
 		}
 	}
 	}
@@ -498,7 +504,6 @@ func (container *Container) AllocateNetwork() error {
 
 
 	for port := range portSpecs {
 	for port := range portSpecs {
 		if err := container.allocatePort(eng, port, bindings); err != nil {
 		if err := container.allocatePort(eng, port, bindings); err != nil {
-			eng.Job("release_interface", container.ID).Run()
 			return err
 			return err
 		}
 		}
 	}
 	}
@@ -524,6 +529,37 @@ func (container *Container) ReleaseNetwork() {
 	container.NetworkSettings = &NetworkSettings{}
 	container.NetworkSettings = &NetworkSettings{}
 }
 }
 
 
+func (container *Container) isNetworkAllocated() bool {
+	return container.NetworkSettings.IPAddress != ""
+}
+
+func (container *Container) RestoreNetwork() error {
+	mode := container.hostConfig.NetworkMode
+	// Don't attempt a restore if we previously didn't allocate networking.
+	// This might be a legacy container with no network allocated, in which case the
+	// allocation will happen once and for all at start.
+	if !container.isNetworkAllocated() || container.Config.NetworkDisabled || !mode.IsPrivate() {
+		return nil
+	}
+
+	eng := container.daemon.eng
+
+	// Re-allocate the interface with the same IP address.
+	job := eng.Job("allocate_interface", container.ID)
+	job.Setenv("RequestedIP", container.NetworkSettings.IPAddress)
+	if err := job.Run(); err != nil {
+		return err
+	}
+
+	// Re-allocate any previously allocated ports.
+	for port, _ := range container.NetworkSettings.Ports {
+		if err := container.allocatePort(eng, port, container.NetworkSettings.Ports); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
 // cleanup releases any network resources allocated to the container along with any rules
 // cleanup releases any network resources allocated to the container along with any rules
 // around how containers are linked together.  It also unmounts the container's root filesystem.
 // around how containers are linked together.  It also unmounts the container's root filesystem.
 func (container *Container) cleanup() {
 func (container *Container) cleanup() {