Browse code

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 authored on 2014/09/30 08:56:10
Showing 1 changed files
... ...
@@ -441,7 +441,7 @@ func (container *Container) buildHostnameAndHostsFiles(IP string) error {
441 441
 	return container.buildHostsFiles(IP)
442 442
 }
443 443
 
444
-func (container *Container) AllocateNetwork() error {
444
+func (container *Container) AllocateNetwork() (err error) {
445 445
 	mode := container.hostConfig.NetworkMode
446 446
 	if container.Config.NetworkDisabled || !mode.IsPrivate() {
447 447
 		return nil
... ...
@@ -449,7 +449,6 @@ func (container *Container) AllocateNetwork() error {
449 449
 
450 450
 	var (
451 451
 		env *engine.Env
452
-		err error
453 452
 		eng = container.daemon.eng
454 453
 	)
455 454
 
... ...
@@ -461,14 +460,21 @@ func (container *Container) AllocateNetwork() error {
461 461
 		return err
462 462
 	}
463 463
 
464
+	// Error handling: At this point, the interface is allocated so we have to
465
+	// make sure that it is always released in case of error, otherwise we
466
+	// might leak resources.
467
+	defer func() {
468
+		if err != nil {
469
+			eng.Job("release_interface", container.ID).Run()
470
+		}
471
+	}()
472
+
464 473
 	if container.Config.PortSpecs != nil {
465 474
 		if err := migratePortMappings(container.Config, container.hostConfig); err != nil {
466
-			eng.Job("release_interface", container.ID).Run()
467 475
 			return err
468 476
 		}
469 477
 		container.Config.PortSpecs = nil
470 478
 		if err := container.WriteHostConfig(); err != nil {
471
-			eng.Job("release_interface", container.ID).Run()
472 479
 			return err
473 480
 		}
474 481
 	}
... ...
@@ -498,7 +504,6 @@ func (container *Container) AllocateNetwork() error {
498 498
 
499 499
 	for port := range portSpecs {
500 500
 		if err := container.allocatePort(eng, port, bindings); err != nil {
501
-			eng.Job("release_interface", container.ID).Run()
502 501
 			return err
503 502
 		}
504 503
 	}
... ...
@@ -524,6 +529,37 @@ func (container *Container) ReleaseNetwork() {
524 524
 	container.NetworkSettings = &NetworkSettings{}
525 525
 }
526 526
 
527
+func (container *Container) isNetworkAllocated() bool {
528
+	return container.NetworkSettings.IPAddress != ""
529
+}
530
+
531
+func (container *Container) RestoreNetwork() error {
532
+	mode := container.hostConfig.NetworkMode
533
+	// Don't attempt a restore if we previously didn't allocate networking.
534
+	// This might be a legacy container with no network allocated, in which case the
535
+	// allocation will happen once and for all at start.
536
+	if !container.isNetworkAllocated() || container.Config.NetworkDisabled || !mode.IsPrivate() {
537
+		return nil
538
+	}
539
+
540
+	eng := container.daemon.eng
541
+
542
+	// Re-allocate the interface with the same IP address.
543
+	job := eng.Job("allocate_interface", container.ID)
544
+	job.Setenv("RequestedIP", container.NetworkSettings.IPAddress)
545
+	if err := job.Run(); err != nil {
546
+		return err
547
+	}
548
+
549
+	// Re-allocate any previously allocated ports.
550
+	for port, _ := range container.NetworkSettings.Ports {
551
+		if err := container.allocatePort(eng, port, container.NetworkSettings.Ports); err != nil {
552
+			return err
553
+		}
554
+	}
555
+	return nil
556
+}
557
+
527 558
 // cleanup releases any network resources allocated to the container along with any rules
528 559
 // around how containers are linked together.  It also unmounts the container's root filesystem.
529 560
 func (container *Container) cleanup() {