1
// Copyright 2014 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
10
"github.com/juju/errors"
11
"github.com/juju/names"
13
"gopkg.in/mgo.v2/bson"
17
// NetworkInterface represents the state of a machine network
19
type NetworkInterface struct {
21
doc networkInterfaceDoc
24
// NetworkInterfaceInfo describes a single network interface available
26
type NetworkInterfaceInfo struct {
27
// MACAddress is the network interface's hardware MAC address
28
// (e.g. "aa:bb:cc:dd:ee:ff").
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).
36
// NetworkName is this interface's network name.
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).
43
// Disabled returns whether the interface is disabled.
47
// networkInterfaceDoc represents a network interface for a machine on
49
type networkInterfaceDoc struct {
50
Id bson.ObjectId `bson:"_id"`
51
ModelUUID string `bson:"model-uuid"`
52
MACAddress string `bson:"macaddress"`
53
InterfaceName string `bson:"interfacename"`
54
NetworkName string `bson:"networkname"`
55
MachineId string `bson:"machineid"`
56
IsVirtual bool `bson:"isvirtual"`
57
IsDisabled bool `bson:"isdisabled"`
60
// GoString implements fmt.GoStringer.
61
func (ni *NetworkInterface) GoString() string {
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())
67
// Id returns the internal juju-specific id of the interface.
68
func (ni *NetworkInterface) Id() string {
69
return ni.doc.Id.String()
72
// MACAddress returns the MAC address of the interface.
73
func (ni *NetworkInterface) MACAddress() string {
74
return ni.doc.MACAddress
77
// InterfaceName returns the name of the interface.
78
func (ni *NetworkInterface) InterfaceName() string {
79
return ni.doc.InterfaceName
82
// RawInterfaceName return the name of the raw interface.
83
func (ni *NetworkInterface) RawInterfaceName() string {
84
nw, err := ni.st.Network(ni.doc.NetworkName)
86
return strings.TrimSuffix(ni.doc.InterfaceName, fmt.Sprintf(".%d", nw.VLANTag()))
88
return ni.doc.InterfaceName
91
// NetworkName returns the network name of the interface.
92
func (ni *NetworkInterface) NetworkName() string {
93
return ni.doc.NetworkName
96
// NetworkTag returns the network tag of the interface.
97
func (ni *NetworkInterface) NetworkTag() names.NetworkTag {
98
return names.NewNetworkTag(ni.doc.NetworkName)
101
// MachineId returns the machine id of the interface.
102
func (ni *NetworkInterface) MachineId() string {
103
return ni.doc.MachineId
106
// MachineTag returns the machine tag of the interface.
107
func (ni *NetworkInterface) MachineTag() names.MachineTag {
108
return names.NewMachineTag(ni.doc.MachineId)
111
// IsVirtual returns whether the interface represents a virtual
113
func (ni *NetworkInterface) IsVirtual() bool {
114
return ni.doc.IsVirtual
117
// IsPhysical returns whether the interface represents a physical
119
func (ni *NetworkInterface) IsPhysical() bool {
120
return !ni.doc.IsVirtual
123
// IsDisabled returns whether the interface is disabled.
124
func (ni *NetworkInterface) IsDisabled() bool {
125
return ni.doc.IsDisabled
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)
138
// Enable changes the state of the network interface to enabled. If
139
// the interface is already enabled, nothing happens and no error is
141
func (ni *NetworkInterface) Enable() (err error) {
142
defer errors.DeferredAnnotatef(&err, "cannot enable network interface %q", ni)
144
return ni.setDisabled(false)
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)
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)
160
return fmt.Errorf("cannot refresh network interface %q on machine %q: %v",
161
ni.InterfaceName(), ni.MachineId(), err)
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)
172
C: networkInterfacesC,
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)
181
func newNetworkInterface(st *State, doc *networkInterfaceDoc) *NetworkInterface {
182
return &NetworkInterface{st, *doc}
185
func newNetworkInterfaceDoc(machineID, modelUUID string, args NetworkInterfaceInfo) *networkInterfaceDoc {
186
return &networkInterfaceDoc{
187
Id: bson.NewObjectId(),
188
ModelUUID: modelUUID,
189
MachineId: machineID,
190
MACAddress: args.MACAddress,
191
InterfaceName: args.InterfaceName,
192
NetworkName: args.NetworkName,
193
IsVirtual: args.IsVirtual,
194
IsDisabled: args.Disabled,
198
// setDisabled is the internal implementation for Enable() and
200
func (ni *NetworkInterface) setDisabled(shouldDisable bool) error {
201
if shouldDisable == ni.doc.IsDisabled {
205
ops, err := ni.disableOps(shouldDisable)
209
ops = append(ops, assertModelAliveOp(ni.st.ModelUUID()))
210
err = ni.st.runTransaction(ops)
212
if err := checkModeLife(ni.st); err != nil {
213
return errors.Trace(err)
215
return onAbort(err, errors.NotFoundf("network interface"))
217
ni.doc.IsDisabled = shouldDisable
221
// disableOps generates a list of transaction operations to disable or
222
// enable the network interface.
223
func (ni *NetworkInterface) disableOps(shouldDisable bool) ([]txn.Op, error) {
225
C: networkInterfacesC,
227
Assert: txn.DocExists,
228
Update: bson.D{{"$set", bson.D{{"isdisabled", shouldDisable}}}},
230
if shouldDisable && ni.IsPhysical() {
231
// Fetch and dependent virtual interfaces on the same machine,
232
// so we can disable them along with their parent.
233
m, err := ni.st.Machine(ni.MachineId())
237
ifaces, err := m.NetworkInterfaces()
241
for _, iface := range ifaces {
242
if iface.Id() == ni.Id() {
245
if iface.MACAddress() == ni.MACAddress() && iface.IsVirtual() {
246
ops = append(ops, txn.Op{
247
C: networkInterfacesC,
249
Assert: txn.DocExists,
250
Update: bson.D{{"$set", bson.D{{"isdisabled", shouldDisable}}}},