~juju-qa/ubuntu/xenial/juju/xenial-2.0-beta3

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/state/legacy_networkinterfaces.go

  • Committer: Martin Packman
  • Date: 2016-03-30 19:31:08 UTC
  • mfrom: (1.1.41)
  • Revision ID: martin.packman@canonical.com-20160330193108-h9iz3ak334uk0z5r
Merge new upstream source 2.0~beta3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
        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"`
 
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, 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,
 
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
        ops = append(ops, assertModelAliveOp(ni.st.ModelUUID()))
 
210
        err = ni.st.runTransaction(ops)
 
211
        if err != nil {
 
212
                if err := checkModeLife(ni.st); err != nil {
 
213
                        return errors.Trace(err)
 
214
                }
 
215
                return onAbort(err, errors.NotFoundf("network interface"))
 
216
        }
 
217
        ni.doc.IsDisabled = shouldDisable
 
218
        return nil
 
219
}
 
220
 
 
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) {
 
224
        ops := []txn.Op{{
 
225
                C:      networkInterfacesC,
 
226
                Id:     ni.doc.Id,
 
227
                Assert: txn.DocExists,
 
228
                Update: bson.D{{"$set", bson.D{{"isdisabled", shouldDisable}}}},
 
229
        }}
 
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())
 
234
                if err != nil {
 
235
                        return nil, err
 
236
                }
 
237
                ifaces, err := m.NetworkInterfaces()
 
238
                if err != nil {
 
239
                        return nil, err
 
240
                }
 
241
                for _, iface := range ifaces {
 
242
                        if iface.Id() == ni.Id() {
 
243
                                continue
 
244
                        }
 
245
                        if iface.MACAddress() == ni.MACAddress() && iface.IsVirtual() {
 
246
                                ops = append(ops, txn.Op{
 
247
                                        C:      networkInterfacesC,
 
248
                                        Id:     iface.doc.Id,
 
249
                                        Assert: txn.DocExists,
 
250
                                        Update: bson.D{{"$set", bson.D{{"isdisabled", shouldDisable}}}},
 
251
                                })
 
252
                        }
 
253
                }
 
254
        }
 
255
        return ops, nil
 
256
}