github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/state/networkinterfaces.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state 5 6 import ( 7 "fmt" 8 "strings" 9 10 "github.com/juju/errors" 11 "github.com/juju/names" 12 "gopkg.in/mgo.v2" 13 "gopkg.in/mgo.v2/bson" 14 "gopkg.in/mgo.v2/txn" 15 ) 16 17 // NetworkInterface represents the state of a machine network 18 // interface. 19 type NetworkInterface struct { 20 st *State 21 doc networkInterfaceDoc 22 } 23 24 // NetworkInterfaceInfo describes a single network interface available 25 // on an instance. 26 type NetworkInterfaceInfo struct { 27 // MACAddress is the network interface's hardware MAC address 28 // (e.g. "aa:bb:cc:dd:ee:ff"). 29 MACAddress string 30 31 // InterfaceName is the OS-specific network device name (e.g. 32 // "eth0", or "eth1.42" for a VLAN virtual interface, or 33 // "eth1:suffix" for a network alias). 34 InterfaceName string 35 36 // NetworkName is this interface's network name. 37 NetworkName string 38 39 // IsVirtual is true when the interface is a virtual device, as 40 // opposed to a physical device (e.g. a VLAN or a network alias). 41 IsVirtual bool 42 43 // Disabled returns whether the interface is disabled. 44 Disabled bool 45 } 46 47 // networkInterfaceDoc represents a network interface for a machine on 48 // a given network. 49 type networkInterfaceDoc struct { 50 Id bson.ObjectId `bson:"_id"` 51 EnvUUID string `bson:"env-uuid"` 52 MACAddress string 53 InterfaceName string 54 NetworkName string 55 MachineId string 56 IsVirtual bool 57 IsDisabled bool 58 } 59 60 // GoString implements fmt.GoStringer. 61 func (ni *NetworkInterface) GoString() string { 62 return fmt.Sprintf( 63 "&state.NetworkInterface{machineId: %q, mac: %q, name: %q, networkName: %q, isVirtual: %t, isDisabled: %t}", 64 ni.MachineId(), ni.MACAddress(), ni.InterfaceName(), ni.NetworkName(), ni.IsVirtual(), ni.IsDisabled()) 65 } 66 67 // Id returns the internal juju-specific id of the interface. 68 func (ni *NetworkInterface) Id() string { 69 return ni.doc.Id.String() 70 } 71 72 // MACAddress returns the MAC address of the interface. 73 func (ni *NetworkInterface) MACAddress() string { 74 return ni.doc.MACAddress 75 } 76 77 // InterfaceName returns the name of the interface. 78 func (ni *NetworkInterface) InterfaceName() string { 79 return ni.doc.InterfaceName 80 } 81 82 // RawInterfaceName return the name of the raw interface. 83 func (ni *NetworkInterface) RawInterfaceName() string { 84 nw, err := ni.st.Network(ni.doc.NetworkName) 85 if err == nil { 86 return strings.TrimSuffix(ni.doc.InterfaceName, fmt.Sprintf(".%d", nw.VLANTag())) 87 } 88 return ni.doc.InterfaceName 89 } 90 91 // NetworkName returns the network name of the interface. 92 func (ni *NetworkInterface) NetworkName() string { 93 return ni.doc.NetworkName 94 } 95 96 // NetworkTag returns the network tag of the interface. 97 func (ni *NetworkInterface) NetworkTag() names.NetworkTag { 98 return names.NewNetworkTag(ni.doc.NetworkName) 99 } 100 101 // MachineId returns the machine id of the interface. 102 func (ni *NetworkInterface) MachineId() string { 103 return ni.doc.MachineId 104 } 105 106 // MachineTag returns the machine tag of the interface. 107 func (ni *NetworkInterface) MachineTag() names.MachineTag { 108 return names.NewMachineTag(ni.doc.MachineId) 109 } 110 111 // IsVirtual returns whether the interface represents a virtual 112 // device. 113 func (ni *NetworkInterface) IsVirtual() bool { 114 return ni.doc.IsVirtual 115 } 116 117 // IsPhysical returns whether the interface represents a physical 118 // device. 119 func (ni *NetworkInterface) IsPhysical() bool { 120 return !ni.doc.IsVirtual 121 } 122 123 // IsDisabled returns whether the interface is disabled. 124 func (ni *NetworkInterface) IsDisabled() bool { 125 return ni.doc.IsDisabled 126 } 127 128 // Disable changes the state of the network interface to disabled. In 129 // case of a physical interface that has dependent virtual interfaces 130 // (e.g. VLANs), those will be disabled along with their parent 131 // interface. If the interface is already disabled, nothing happens 132 // and no error is returned. 133 func (ni *NetworkInterface) Disable() (err error) { 134 defer errors.DeferredAnnotatef(&err, "cannot disable network interface %q", ni) 135 return ni.setDisabled(true) 136 } 137 138 // Enable changes the state of the network interface to enabled. If 139 // the interface is already enabled, nothing happens and no error is 140 // returned. 141 func (ni *NetworkInterface) Enable() (err error) { 142 defer errors.DeferredAnnotatef(&err, "cannot enable network interface %q", ni) 143 144 return ni.setDisabled(false) 145 } 146 147 // Refresh refreshes the contents of the network interface from the underlying 148 // state. It returns an error that satisfies errors.IsNotFound if the 149 // machine has been removed. 150 func (ni *NetworkInterface) Refresh() error { 151 networkInterfaces, closer := ni.st.getCollection(networkInterfacesC) 152 defer closer() 153 154 doc := networkInterfaceDoc{} 155 err := networkInterfaces.FindId(ni.doc.Id).One(&doc) 156 if err == mgo.ErrNotFound { 157 return errors.NotFoundf("network interface %#v", ni) 158 } 159 if err != nil { 160 return fmt.Errorf("cannot refresh network interface %q on machine %q: %v", 161 ni.InterfaceName(), ni.MachineId(), err) 162 } 163 ni.doc = doc 164 return nil 165 } 166 167 // Remove removes the network interface from state. 168 func (ni *NetworkInterface) Remove() (err error) { 169 defer errors.DeferredAnnotatef(&err, "cannot remove network interface %q", ni) 170 171 ops := []txn.Op{{ 172 C: networkInterfacesC, 173 Id: ni.doc.Id, 174 Remove: true, 175 }} 176 // The only abort conditions in play indicate that the network interface 177 // has already been removed. 178 return onAbort(ni.st.runTransaction(ops), nil) 179 } 180 181 func newNetworkInterface(st *State, doc *networkInterfaceDoc) *NetworkInterface { 182 return &NetworkInterface{st, *doc} 183 } 184 185 func newNetworkInterfaceDoc(machineID, envUUID string, args NetworkInterfaceInfo) *networkInterfaceDoc { 186 return &networkInterfaceDoc{ 187 Id: bson.NewObjectId(), 188 EnvUUID: envUUID, 189 MachineId: machineID, 190 MACAddress: args.MACAddress, 191 InterfaceName: args.InterfaceName, 192 NetworkName: args.NetworkName, 193 IsVirtual: args.IsVirtual, 194 IsDisabled: args.Disabled, 195 } 196 } 197 198 // setDisabled is the internal implementation for Enable() and 199 // Disable(). 200 func (ni *NetworkInterface) setDisabled(shouldDisable bool) error { 201 if shouldDisable == ni.doc.IsDisabled { 202 // Nothing to do. 203 return nil 204 } 205 ops, err := ni.disableOps(shouldDisable) 206 if err != nil { 207 return err 208 } 209 err = ni.st.runTransaction(ops) 210 if err != nil { 211 return onAbort(err, errors.NotFoundf("network interface")) 212 } 213 ni.doc.IsDisabled = shouldDisable 214 return nil 215 } 216 217 // disableOps generates a list of transaction operations to disable or 218 // enable the network interface. 219 func (ni *NetworkInterface) disableOps(shouldDisable bool) ([]txn.Op, error) { 220 ops := []txn.Op{{ 221 C: networkInterfacesC, 222 Id: ni.doc.Id, 223 Assert: txn.DocExists, 224 Update: bson.D{{"$set", bson.D{{"isdisabled", shouldDisable}}}}, 225 }} 226 if shouldDisable && ni.IsPhysical() { 227 // Fetch and dependent virtual interfaces on the same machine, 228 // so we can disable them along with their parent. 229 m, err := ni.st.Machine(ni.MachineId()) 230 if err != nil { 231 return nil, err 232 } 233 ifaces, err := m.NetworkInterfaces() 234 if err != nil { 235 return nil, err 236 } 237 for _, iface := range ifaces { 238 if iface.Id() == ni.Id() { 239 continue 240 } 241 if iface.MACAddress() == ni.MACAddress() && iface.IsVirtual() { 242 ops = append(ops, txn.Op{ 243 C: networkInterfacesC, 244 Id: iface.doc.Id, 245 Assert: txn.DocExists, 246 Update: bson.D{{"$set", bson.D{{"isdisabled", shouldDisable}}}}, 247 }) 248 } 249 } 250 } 251 return ops, nil 252 }