github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/network/netplan/activate.go (about)

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package netplan
     5  
     6  import (
     7  	"fmt"
     8  	"os"
     9  	"time"
    10  
    11  	"github.com/juju/clock"
    12  	"github.com/juju/errors"
    13  	"github.com/juju/loggo"
    14  
    15  	"github.com/juju/juju/utils/scriptrunner"
    16  )
    17  
    18  var logger = loggo.GetLogger("juju.network.netplan")
    19  
    20  // ActivationParams contains options to use when bridging interfaces
    21  type ActivationParams struct {
    22  	Clock     clock.Clock
    23  	Devices   []DeviceToBridge
    24  	RunPrefix string
    25  	Directory string
    26  	Timeout   time.Duration
    27  }
    28  
    29  // ActivationResult captures the result of actively bridging the
    30  // interfaces using ifup/ifdown.
    31  type ActivationResult struct {
    32  	Stdout string
    33  	Stderr string
    34  	Code   int
    35  }
    36  
    37  // BridgeAndActivate will parse a set of netplan yaml files in a directory,
    38  // create a new netplan config with the provided interfaces bridged
    39  // bridged, then reconfigure the network using the ifupdown package
    40  // for the new bridges.
    41  func BridgeAndActivate(params ActivationParams) (*ActivationResult, error) {
    42  	if len(params.Devices) == 0 {
    43  		return nil, errors.Errorf("no devices specified")
    44  	}
    45  
    46  	netplan, err := ReadDirectory(params.Directory)
    47  
    48  	if err != nil {
    49  		return nil, err
    50  	}
    51  
    52  	for _, device := range params.Devices {
    53  		var deviceId string
    54  		deviceId, deviceType, err := netplan.FindDeviceByNameOrMAC(device.DeviceName, device.MACAddress)
    55  		if err != nil {
    56  			return nil, errors.Trace(err)
    57  		}
    58  		switch deviceType {
    59  		case TypeEthernet:
    60  			err = netplan.BridgeEthernetById(deviceId, device.BridgeName)
    61  			if err != nil {
    62  				return nil, err
    63  			}
    64  		case TypeBond:
    65  			err = netplan.BridgeBondById(deviceId, device.BridgeName)
    66  			if err != nil {
    67  				return nil, err
    68  			}
    69  		case TypeVLAN:
    70  			err = netplan.BridgeVLANById(deviceId, device.BridgeName)
    71  			if err != nil {
    72  				return nil, err
    73  			}
    74  		default:
    75  			return nil, errors.Errorf("unable to create bridge for %q, unknown device type %q", deviceId, deviceType)
    76  		}
    77  	}
    78  	_, err = netplan.Write("")
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  
    83  	err = netplan.MoveYamlsToBak()
    84  	if err != nil {
    85  		netplan.Rollback()
    86  		return nil, err
    87  	}
    88  
    89  	environ := os.Environ()
    90  	// TODO(wpk) 2017-06-21 Is there a way to verify that apply is finished?
    91  	// https://bugs.launchpad.net/netplan/+bug/1701436
    92  	command := fmt.Sprintf("%snetplan generate && netplan apply && sleep 10", params.RunPrefix)
    93  
    94  	result, err := scriptrunner.RunCommand(command, environ, params.Clock, params.Timeout)
    95  
    96  	activationResult := ActivationResult{
    97  		Stderr: string(result.Stderr),
    98  		Stdout: string(result.Stdout),
    99  		Code:   result.Code,
   100  	}
   101  
   102  	logger.Debugf("Netplan activation result %q %q %d", result.Stderr, result.Stdout, result.Code)
   103  
   104  	if err != nil {
   105  		netplan.Rollback()
   106  		return &activationResult, errors.Errorf("bridge activation error: %s", err)
   107  	}
   108  	if result.Code != 0 {
   109  		netplan.Rollback()
   110  		return &activationResult, errors.Errorf("bridge activation error code %d", result.Code)
   111  	}
   112  	return nil, nil
   113  }