github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/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 deviceID, deviceType, err := netplan.FindDeviceByNameOrMAC(device.DeviceName, device.MACAddress) 54 if err != nil { 55 return nil, errors.Trace(err) 56 } 57 switch deviceType { 58 case TypeEthernet: 59 err = netplan.BridgeEthernetById(deviceID, device.BridgeName) 60 if err != nil { 61 return nil, err 62 } 63 case TypeBond: 64 err = netplan.BridgeBondById(deviceID, device.BridgeName) 65 if err != nil { 66 return nil, err 67 } 68 case TypeVLAN: 69 err = netplan.BridgeVLANById(deviceID, device.BridgeName) 70 if err != nil { 71 return nil, err 72 } 73 default: 74 return nil, errors.Errorf("unable to create bridge for %q, unknown device type %q", deviceID, deviceType) 75 } 76 } 77 _, err = netplan.Write("") 78 if err != nil { 79 return nil, err 80 } 81 82 err = netplan.MoveYamlsToBak() 83 if err != nil { 84 _ = netplan.Rollback() 85 return nil, err 86 } 87 88 environ := os.Environ() 89 // TODO(wpk) 2017-06-21 Is there a way to verify that apply is finished? 90 // https://bugs.launchpad.net/netplan/+bug/1701436 91 command := fmt.Sprintf("%snetplan generate && netplan apply && sleep 10", params.RunPrefix) 92 93 result, err := scriptrunner.RunCommand(command, environ, params.Clock, params.Timeout) 94 95 activationResult := ActivationResult{ 96 Stderr: string(result.Stderr), 97 Stdout: string(result.Stdout), 98 Code: result.Code, 99 } 100 101 logger.Debugf("Netplan activation result %q %q %d", result.Stderr, result.Stdout, result.Code) 102 103 if err != nil { 104 _ = netplan.Rollback() 105 return &activationResult, errors.Errorf("bridge activation error: %s", err) 106 } 107 if result.Code != 0 { 108 _ = netplan.Rollback() 109 return &activationResult, errors.Errorf("bridge activation error code %d", result.Code) 110 } 111 return nil, nil 112 }