Merge lp:~dimitern/juju-core/400-lp-1307513-multiple-nics-same-mac into lp:~go-bot/juju-core/trunk
- 400-lp-1307513-multiple-nics-same-mac
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Dimiter Naydenov |
Approved revision: | no longer in the source branch. |
Merged at revision: | 2655 |
Proposed branch: | lp:~dimitern/juju-core/400-lp-1307513-multiple-nics-same-mac |
Merge into: | lp:~go-bot/juju-core/trunk |
Diff against target: |
1776 lines (+456/-256) 31 files modified
environs/broker.go (+2/-27) environs/network/network.go (+37/-0) juju/testing/instance.go (+4/-3) provider/azure/environ.go (+2/-1) provider/common/bootstrap_test.go (+5/-4) provider/common/mock_test.go (+3/-2) provider/dummy/environs.go (+13/-11) provider/ec2/ec2.go (+2/-1) provider/joyent/environ_instance.go (+2/-1) provider/local/environ.go (+2/-1) provider/maas/environ.go (+36/-39) provider/maas/environ_test.go (+20/-2) provider/manual/environ.go (+2/-1) provider/openstack/provider.go (+2/-1) state/api/params/internal.go (+6/-1) state/api/provisioner/provisioner_test.go (+31/-11) state/apiserver/provisioner/provisioner.go (+1/-0) state/apiserver/provisioner/provisioner_test.go (+34/-10) state/machine.go (+47/-35) state/machine_test.go (+43/-29) state/networkinterfaces.go (+46/-6) state/networkinterfaces_test.go (+11/-2) state/networks.go (+22/-3) state/networks_test.go (+15/-5) state/open.go (+1/-0) state/state.go (+19/-25) state/state_test.go (+27/-21) worker/provisioner/kvm-broker.go (+2/-1) worker/provisioner/lxc-broker.go (+2/-1) worker/provisioner/provisioner_task.go (+6/-4) worker/provisioner/provisioner_test.go (+11/-8) |
To merge this branch: | bzr merge lp:~dimitern/juju-core/400-lp-1307513-multiple-nics-same-mac |
Related bugs: | |
Related blueprints: |
Support MaaS VLANs in Juju
(Essential)
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju Engineering | Pending | ||
Review via email: mp+216453@code.launchpad.net |
Commit message
various: Support multiple NICs with the same MAC
Fixes bug #1307513, allowing more than one network
interface with the same MAC address, and introduces
the concept of virtual and physical NIC.
This is needed because you can have more than one
network interface with the same MAC address on the
same machine (but it has to be on different networks):
one physical and multiple virtual NICs. Changes were
needed mostly in state to use a different primary
key for networkinterfaces collection. Also added a
unique index on "interfacename" and "networkname",
improved tests.
Fixed the MAAS provider to configure networks properly,
so that you can have more than one VLAN virtual NIC
on the same physical NIC.
Introduced environs/network package and defined an
Id type to make it apparent that network ids are
provider-specific (like instance.Id). Also moved
environs.
In a follow-up, machine addresses and networks will
be integrated, so we can link a network interface's
name and MAC address to its network (IP) address.
Finally, networks and machine interfaces will be
visible in juju status.
https:/
R=fwereade
Description of the change
various: Support multiple NICs with the same MAC
Fixes bug #1307513, allowing more than one network
interface with the same MAC address, and introduces
the concept of virtual and physical NIC.
This is needed because you can have more than one
network interface with the same MAC address on the
same machine (but it has to be on different networks):
one physical and multiple virtual NICs. Changes were
needed mostly in state to use a different primary
key for networkinterfaces collection. Also added a
unique index on "interfacename" and "networkname",
improved tests.
Fixed the MAAS provider to configure networks properly,
so that you can have more than one VLAN virtual NIC
on the same physical NIC.
Introduced environs/network package and defined an
Id type to make it apparent that network ids are
provider-specific (like instance.Id). Also moved
environs.
In a follow-up, machine addresses and networks will
be integrated, so we can link a network interface's
name and MAC address to its network (IP) address.
Finally, networks and machine interfaces will be
visible in juju status.
Dimiter Naydenov (dimitern) wrote : | # |
William Reade (fwereade) wrote : | # |
mostly looking good, but (1) IsVirtual on network still seems ill-formed
to me; and (2) are we explicitly ignoring compatibility with earlier
1.19? these new fields in state worry me a little, the people who want
to work with networks will likely be upgrading from there...
https:/
File environs/broker.go (right):
https:/
environs/
We could make this clearer if we had a type for it, like instance.Id --
as it is I think ProviderId is not much of a win over NetworkId. But
`NetworkId NetworkId` should be less confusing.
https:/
File state/api/
https:/
state/api/
I'm less certain about this one. If it's possible for virtual/physical
interfaces to be mixed, this is meaningless; if it's not possible, it's
not necessary on the interface definition. Right?
https:/
File state/machine.go (right):
https:/
state/machine.
hey, I'm feeling more strongly about this now: please assert that the
machine is Dead in this method, just so that if (when) someone tries to
use it from elsewhere they get something pointing out the race with
adding interfaces.
https:/
state/machine.
interface")
This is on the state server, let's not panic even if it should never
happen.
Dimiter Naydenov (dimitern) wrote : | # |
On 2014/04/18 14:41:17, fwereade wrote:
> mostly looking good, but (1) IsVirtual on network still seems
ill-formed to me;
> and (2) are we explicitly ignoring compatibility with earlier 1.19?
these new
> fields in state worry me a little, the people who want to work with
networks
> will likely be upgrading from there...
1) I'll drop IsVirtual from networks and keep it on interfaces only.
2) 1.19.0 is a dev release which was out recently, so I think we can get
away with saying "if you used networks, please redeploy your environment
when upgrading to 1.19.1" - I'll add a note to the bug and ping sinzui.
Dimiter Naydenov (dimitern) wrote : | # |
Please take a look.
https:/
File environs/broker.go (right):
https:/
environs/
On 2014/04/18 14:41:18, fwereade wrote:
> We could make this clearer if we had a type for it, like instance.Id
-- as it is
> I think ProviderId is not much of a win over NetworkId. But `NetworkId
> NetworkId` should be less confusing.
I wanted to make the code use consistent naming - NetworkId is only used
here. I like the idea of type NetworkId string and then perhaps use
ProviderId NetworkId as a compromise?
https:/
File state/api/
https:/
state/api/
On 2014/04/18 14:41:18, fwereade wrote:
> I'm less certain about this one. If it's possible for virtual/physical
> interfaces to be mixed, this is meaningless; if it's not possible,
it's not
> necessary on the interface definition. Right?
Frankly, I don't know whether it's possible to mix physical and virtual
interfaces on the same network, perhaps it is. But the actual flag makes
more sense for NICs, rather than networks.
I'll drop it from networks and leave it only on interfaces.
https:/
File state/machine.go (right):
https:/
state/machine.
On 2014/04/18 14:41:18, fwereade wrote:
> hey, I'm feeling more strongly about this now: please assert that the
machine is
> Dead in this method, just so that if (when) someone tries to use it
from
> elsewhere they get something pointing out the race with adding
interfaces.
Done.
https:/
state/machine.
interface")
On 2014/04/18 14:41:18, fwereade wrote:
> This is on the state server, let's not panic even if it should never
happen.
I'll log an error instead.
William Reade (fwereade) wrote : | # |
Thanks, LGTM with trivials.
https:/
File environs/broker.go (right):
https:/
environs/
On 2014/04/18 15:37:26, dimitern wrote:
> On 2014/04/18 14:41:18, fwereade wrote:
> > We could make this clearer if we had a type for it, like instance.Id
-- as it
> is
> > I think ProviderId is not much of a win over NetworkId. But
`NetworkId
> > NetworkId` should be less confusing.
> I wanted to make the code use consistent naming - NetworkId is only
used here. I
> like the idea of type NetworkId string and then perhaps use ProviderId
NetworkId
> as a compromise?
Yeah, that works for me. Thanks.
https:/
File state/machine.go (right):
https:/
state/machine.
On 2014/04/18 15:37:27, dimitern wrote:
> On 2014/04/18 14:41:18, fwereade wrote:
> > hey, I'm feeling more strongly about this now: please assert that
the machine
> is
> > Dead in this method, just so that if (when) someone tries to use it
from
> > elsewhere they get something pointing out the race with adding
interfaces.
> Done.
Sorry, I expressed myself poorly. The op is nice, and could/should
happily stay (other invariants *should* make it unnecessary, but +1 to
defence in depth), but what I'm really looking for is a quick check
against m.doc.Life so we can abort with an error before even running the
txn.
https:/
File state/api/
https:/
state/api/
hmm, instance.NetworkId doesn't feel quite right -- I'd say
environs.NetworkId, with the expectation that soon enough we'll want an
environs/network package and we can just call it network.Id.
Or if you want to start the package with a single type, and start
gradually migrating stuff over to it as you go in future CLs, that would
also work for me.
https:/
File state/machine.go (right):
https:/
state/machine.
m.st.networkInt
.One(&doc) perhaps? I suspect you're grabbing the data anyway, even if
you're not storing it, so you may as well return a doc that definitely
completely matches what's in the db.
I know it doesn't make a difference *now* but it feels like an
encouragement to subtle bugs.
Dimiter Naydenov (dimitern) wrote : | # |
Please take a look.
https:/
File state/machine.go (right):
https:/
state/machine.
On 2014/04/18 16:02:54, fwereade wrote:
> On 2014/04/18 15:37:27, dimitern wrote:
> > On 2014/04/18 14:41:18, fwereade wrote:
> > > hey, I'm feeling more strongly about this now: please assert that
the
> machine
> > is
> > > Dead in this method, just so that if (when) someone tries to use
it from
> > > elsewhere they get something pointing out the race with adding
interfaces.
> >
> > Done.
> Sorry, I expressed myself poorly. The op is nice, and could/should
happily stay
> (other invariants *should* make it unnecessary, but +1 to defence in
depth), but
> what I'm really looking for is a quick check against m.doc.Life so we
can abort
> with an error before even running the txn.
As discussed, I'm adding a check for m.doc.Life == Dead at the
beginning.
https:/
File state/api/
https:/
state/api/
On 2014/04/18 16:02:54, fwereade wrote:
> hmm, instance.NetworkId doesn't feel quite right -- I'd say
environs.NetworkId,
> with the expectation that soon enough we'll want an environs/network
package and
> we can just call it network.Id.
> Or if you want to start the package with a single type, and start
gradually
> migrating stuff over to it as you go in future CLs, that would also
work for me.
I tried adding it to environs, but there are import loops. I like the
idea of having environs/network package, so I added that and moved
environs.
https:/
File state/machine.go (right):
https:/
state/machine.
m.st.networkInt
On 2014/04/18 16:02:54, fwereade wrote:
> .One(&doc) perhaps? I suspect you're grabbing the data anyway, even if
you're
> not storing it, so you may as well return a doc that definitely
completely
> matches what's in the db.
> I know it doesn't make a difference *now* but it feels like an
encouragement to
> subtle bugs.
Done.
Dimiter Naydenov (dimitern) wrote : | # |
Please take a look.
https:/
File state/machine.go (right):
https:/
state/machine.
On 2014/04/18 16:02:54, fwereade wrote:
> On 2014/04/18 15:37:27, dimitern wrote:
> > On 2014/04/18 14:41:18, fwereade wrote:
> > > hey, I'm feeling more strongly about this now: please assert that
the
> machine
> > is
> > > Dead in this method, just so that if (when) someone tries to use
it from
> > > elsewhere they get something pointing out the race with adding
interfaces.
> >
> > Done.
> Sorry, I expressed myself poorly. The op is nice, and could/should
happily stay
> (other invariants *should* make it unnecessary, but +1 to defence in
depth), but
> what I'm really looking for is a quick check against m.doc.Life so we
can abort
> with an error before even running the txn.
As discussed, I'm adding a check for m.doc.Life == Dead at the
beginning.
https:/
File state/api/
https:/
state/api/
On 2014/04/18 16:02:54, fwereade wrote:
> hmm, instance.NetworkId doesn't feel quite right -- I'd say
environs.NetworkId,
> with the expectation that soon enough we'll want an environs/network
package and
> we can just call it network.Id.
> Or if you want to start the package with a single type, and start
gradually
> migrating stuff over to it as you go in future CLs, that would also
work for me.
I tried adding it to environs, but there are import loops. I like the
idea of having environs/network package, so I added that and moved
environs.
https:/
File state/machine.go (right):
https:/
state/machine.
m.st.networkInt
On 2014/04/18 16:02:54, fwereade wrote:
> .One(&doc) perhaps? I suspect you're grabbing the data anyway, even if
you're
> not storing it, so you may as well return a doc that definitely
completely
> matches what's in the db.
> I know it doesn't make a difference *now* but it feels like an
encouragement to
> subtle bugs.
Done.
Go Bot (go-bot) wrote : | # |
The attempt to merge lp:~dimitern/juju-core/400-lp-1307513-multiple-nics-same-mac into lp:juju-core failed. Below is the output from the failed tests.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
? launchpad.
? launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
? launchpad.
Preview Diff
1 | === modified file 'environs/broker.go' | |||
2 | --- environs/broker.go 2014-04-11 13:54:51 +0000 | |||
3 | +++ environs/broker.go 2014-04-18 16:46:53 +0000 | |||
4 | @@ -6,6 +6,7 @@ | |||
5 | 6 | import ( | 6 | import ( |
6 | 7 | "launchpad.net/juju-core/constraints" | 7 | "launchpad.net/juju-core/constraints" |
7 | 8 | "launchpad.net/juju-core/environs/cloudinit" | 8 | "launchpad.net/juju-core/environs/cloudinit" |
8 | 9 | "launchpad.net/juju-core/environs/network" | ||
9 | 9 | "launchpad.net/juju-core/instance" | 10 | "launchpad.net/juju-core/instance" |
10 | 10 | "launchpad.net/juju-core/tools" | 11 | "launchpad.net/juju-core/tools" |
11 | 11 | ) | 12 | ) |
12 | @@ -33,32 +34,6 @@ | |||
13 | 33 | DistributionGroup func() ([]instance.Id, error) | 34 | DistributionGroup func() ([]instance.Id, error) |
14 | 34 | } | 35 | } |
15 | 35 | 36 | ||
16 | 36 | // NetworkInfo describes a single network interface available on an | ||
17 | 37 | // instance. For providers that support networks, this will be | ||
18 | 38 | // available at StartInstance() time. | ||
19 | 39 | type NetworkInfo struct { | ||
20 | 40 | // MACAddress is the network interface's hardware MAC address | ||
21 | 41 | // (e.g. "aa:bb:cc:dd:ee:ff"). | ||
22 | 42 | MACAddress string | ||
23 | 43 | |||
24 | 44 | // CIDR of the network, in 123.45.67.89/24 format. | ||
25 | 45 | CIDR string | ||
26 | 46 | |||
27 | 47 | // NetworkName is juju-internal name of the network. | ||
28 | 48 | NetworkName string | ||
29 | 49 | |||
30 | 50 | // NetworkId is a provider-specific network id. | ||
31 | 51 | NetworkId string | ||
32 | 52 | |||
33 | 53 | // VLANTag needs to be between 1 and 4094 for VLANs and 0 for | ||
34 | 54 | // normal networks. It's defined by IEEE 802.1Q standard. | ||
35 | 55 | VLANTag int | ||
36 | 56 | |||
37 | 57 | // InterfaceName is the OS-specific network device name (e.g. | ||
38 | 58 | // "eth0" or "eth1.42" for a VLAN virtual interface). | ||
39 | 59 | InterfaceName string | ||
40 | 60 | } | ||
41 | 61 | |||
42 | 62 | // TODO(wallyworld) - we want this in the environs/instance package but import loops | 37 | // TODO(wallyworld) - we want this in the environs/instance package but import loops |
43 | 63 | // stop that from being possible right now. | 38 | // stop that from being possible right now. |
44 | 64 | type InstanceBroker interface { | 39 | type InstanceBroker interface { |
45 | @@ -68,7 +43,7 @@ | |||
46 | 68 | // unique within an environment, is used by juju to protect against the | 43 | // unique within an environment, is used by juju to protect against the |
47 | 69 | // consequences of multiple instances being started with the same machine | 44 | // consequences of multiple instances being started with the same machine |
48 | 70 | // id. | 45 | // id. |
50 | 71 | StartInstance(args StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []NetworkInfo, error) | 46 | StartInstance(args StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) |
51 | 72 | 47 | ||
52 | 73 | // StopInstances shuts down the given instances. | 48 | // StopInstances shuts down the given instances. |
53 | 74 | StopInstances([]instance.Instance) error | 49 | StopInstances([]instance.Instance) error |
54 | 75 | 50 | ||
55 | === added directory 'environs/network' | |||
56 | === added file 'environs/network/network.go' | |||
57 | --- environs/network/network.go 1970-01-01 00:00:00 +0000 | |||
58 | +++ environs/network/network.go 2014-04-18 16:46:53 +0000 | |||
59 | @@ -0,0 +1,37 @@ | |||
60 | 1 | // Copyright 2014 Canonical Ltd. | ||
61 | 2 | // Licensed under the AGPLv3, see LICENCE file for details. | ||
62 | 3 | |||
63 | 4 | package network | ||
64 | 5 | |||
65 | 6 | // Id defines a provider-specific network id. | ||
66 | 7 | type Id string | ||
67 | 8 | |||
68 | 9 | // Info describes a single network interface available on an instance. | ||
69 | 10 | // For providers that support networks, this will be available at | ||
70 | 11 | // StartInstance() time. | ||
71 | 12 | type Info struct { | ||
72 | 13 | // MACAddress is the network interface's hardware MAC address | ||
73 | 14 | // (e.g. "aa:bb:cc:dd:ee:ff"). | ||
74 | 15 | MACAddress string | ||
75 | 16 | |||
76 | 17 | // CIDR of the network, in 123.45.67.89/24 format. | ||
77 | 18 | CIDR string | ||
78 | 19 | |||
79 | 20 | // NetworkName is juju-internal name of the network. | ||
80 | 21 | NetworkName string | ||
81 | 22 | |||
82 | 23 | // ProviderId is a provider-specific network id. | ||
83 | 24 | ProviderId Id | ||
84 | 25 | |||
85 | 26 | // VLANTag needs to be between 1 and 4094 for VLANs and 0 for | ||
86 | 27 | // normal networks. It's defined by IEEE 802.1Q standard. | ||
87 | 28 | VLANTag int | ||
88 | 29 | |||
89 | 30 | // InterfaceName is the OS-specific network device name (e.g. | ||
90 | 31 | // "eth0" or "eth1.42" for a VLAN virtual interface). | ||
91 | 32 | InterfaceName string | ||
92 | 33 | |||
93 | 34 | // IsVirtual is true when the interface is a virtual device, as | ||
94 | 35 | // opposed to a physical device. | ||
95 | 36 | IsVirtual bool | ||
96 | 37 | } | ||
97 | 0 | 38 | ||
98 | === modified file 'juju/testing/instance.go' | |||
99 | --- juju/testing/instance.go 2014-04-14 16:41:28 +0000 | |||
100 | +++ juju/testing/instance.go 2014-04-18 16:46:53 +0000 | |||
101 | @@ -11,6 +11,7 @@ | |||
102 | 11 | "launchpad.net/juju-core/constraints" | 11 | "launchpad.net/juju-core/constraints" |
103 | 12 | "launchpad.net/juju-core/environs" | 12 | "launchpad.net/juju-core/environs" |
104 | 13 | "launchpad.net/juju-core/environs/config" | 13 | "launchpad.net/juju-core/environs/config" |
105 | 14 | "launchpad.net/juju-core/environs/network" | ||
106 | 14 | "launchpad.net/juju-core/environs/tools" | 15 | "launchpad.net/juju-core/environs/tools" |
107 | 15 | "launchpad.net/juju-core/instance" | 16 | "launchpad.net/juju-core/instance" |
108 | 16 | "launchpad.net/juju-core/names" | 17 | "launchpad.net/juju-core/names" |
109 | @@ -60,7 +61,7 @@ | |||
110 | 60 | func StartInstance( | 61 | func StartInstance( |
111 | 61 | env environs.Environ, machineId string, | 62 | env environs.Environ, machineId string, |
112 | 62 | ) ( | 63 | ) ( |
114 | 63 | instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error, | 64 | instance.Instance, *instance.HardwareCharacteristics, []network.Info, error, |
115 | 64 | ) { | 65 | ) { |
116 | 65 | return StartInstanceWithConstraints(env, machineId, constraints.Value{}) | 66 | return StartInstanceWithConstraints(env, machineId, constraints.Value{}) |
117 | 66 | } | 67 | } |
118 | @@ -84,7 +85,7 @@ | |||
119 | 84 | func StartInstanceWithConstraints( | 85 | func StartInstanceWithConstraints( |
120 | 85 | env environs.Environ, machineId string, cons constraints.Value, | 86 | env environs.Environ, machineId string, cons constraints.Value, |
121 | 86 | ) ( | 87 | ) ( |
123 | 87 | instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error, | 88 | instance.Instance, *instance.HardwareCharacteristics, []network.Info, error, |
124 | 88 | ) { | 89 | ) { |
125 | 89 | return StartInstanceWithConstraintsAndNetworks(env, machineId, cons, nil, nil) | 90 | return StartInstanceWithConstraintsAndNetworks(env, machineId, cons, nil, nil) |
126 | 90 | } | 91 | } |
127 | @@ -111,7 +112,7 @@ | |||
128 | 111 | env environs.Environ, machineId string, cons constraints.Value, | 112 | env environs.Environ, machineId string, cons constraints.Value, |
129 | 112 | includeNetworks, excludeNetworks []string, | 113 | includeNetworks, excludeNetworks []string, |
130 | 113 | ) ( | 114 | ) ( |
132 | 114 | instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error, | 115 | instance.Instance, *instance.HardwareCharacteristics, []network.Info, error, |
133 | 115 | ) { | 116 | ) { |
134 | 116 | series := config.PreferredSeries(env.Config()) | 117 | series := config.PreferredSeries(env.Config()) |
135 | 117 | agentVersion, ok := env.Config().AgentVersion() | 118 | agentVersion, ok := env.Config().AgentVersion() |
136 | 118 | 119 | ||
137 | === modified file 'provider/azure/environ.go' | |||
138 | --- provider/azure/environ.go 2014-04-04 15:55:19 +0000 | |||
139 | +++ provider/azure/environ.go 2014-04-18 16:46:53 +0000 | |||
140 | @@ -19,6 +19,7 @@ | |||
141 | 19 | "launchpad.net/juju-core/environs/config" | 19 | "launchpad.net/juju-core/environs/config" |
142 | 20 | "launchpad.net/juju-core/environs/imagemetadata" | 20 | "launchpad.net/juju-core/environs/imagemetadata" |
143 | 21 | "launchpad.net/juju-core/environs/instances" | 21 | "launchpad.net/juju-core/environs/instances" |
144 | 22 | "launchpad.net/juju-core/environs/network" | ||
145 | 22 | "launchpad.net/juju-core/environs/simplestreams" | 23 | "launchpad.net/juju-core/environs/simplestreams" |
146 | 23 | "launchpad.net/juju-core/environs/storage" | 24 | "launchpad.net/juju-core/environs/storage" |
147 | 24 | envtools "launchpad.net/juju-core/environs/tools" | 25 | envtools "launchpad.net/juju-core/environs/tools" |
148 | @@ -508,7 +509,7 @@ | |||
149 | 508 | } | 509 | } |
150 | 509 | 510 | ||
151 | 510 | // StartInstance is specified in the InstanceBroker interface. | 511 | // StartInstance is specified in the InstanceBroker interface. |
153 | 511 | func (env *azureEnviron) StartInstance(args environs.StartInstanceParams) (_ instance.Instance, _ *instance.HardwareCharacteristics, _ []environs.NetworkInfo, err error) { | 512 | func (env *azureEnviron) StartInstance(args environs.StartInstanceParams) (_ instance.Instance, _ *instance.HardwareCharacteristics, _ []network.Info, err error) { |
154 | 512 | if args.MachineConfig.HasNetworks() { | 513 | if args.MachineConfig.HasNetworks() { |
155 | 513 | return nil, nil, nil, fmt.Errorf("starting instances with networks is not supported yet.") | 514 | return nil, nil, nil, fmt.Errorf("starting instances with networks is not supported yet.") |
156 | 514 | } | 515 | } |
157 | 515 | 516 | ||
158 | === modified file 'provider/common/bootstrap_test.go' | |||
159 | --- provider/common/bootstrap_test.go 2014-04-11 10:12:20 +0000 | |||
160 | +++ provider/common/bootstrap_test.go 2014-04-18 16:46:53 +0000 | |||
161 | @@ -17,6 +17,7 @@ | |||
162 | 17 | "launchpad.net/juju-core/environs" | 17 | "launchpad.net/juju-core/environs" |
163 | 18 | "launchpad.net/juju-core/environs/cloudinit" | 18 | "launchpad.net/juju-core/environs/cloudinit" |
164 | 19 | "launchpad.net/juju-core/environs/config" | 19 | "launchpad.net/juju-core/environs/config" |
165 | 20 | "launchpad.net/juju-core/environs/network" | ||
166 | 20 | "launchpad.net/juju-core/environs/storage" | 21 | "launchpad.net/juju-core/environs/storage" |
167 | 21 | envtesting "launchpad.net/juju-core/environs/testing" | 22 | envtesting "launchpad.net/juju-core/environs/testing" |
168 | 22 | "launchpad.net/juju-core/instance" | 23 | "launchpad.net/juju-core/instance" |
169 | @@ -80,7 +81,7 @@ | |||
170 | 80 | startInstance := func( | 81 | startInstance := func( |
171 | 81 | cons constraints.Value, _, _ []string, possibleTools tools.List, mcfg *cloudinit.MachineConfig, | 82 | cons constraints.Value, _, _ []string, possibleTools tools.List, mcfg *cloudinit.MachineConfig, |
172 | 82 | ) ( | 83 | ) ( |
174 | 83 | instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error, | 84 | instance.Instance, *instance.HardwareCharacteristics, []network.Info, error, |
175 | 84 | ) { | 85 | ) { |
176 | 85 | c.Assert(cons, gc.DeepEquals, checkCons) | 86 | c.Assert(cons, gc.DeepEquals, checkCons) |
177 | 86 | c.Assert(mcfg, gc.DeepEquals, environs.NewBootstrapMachineConfig(mcfg.SystemPrivateSSHKey)) | 87 | c.Assert(mcfg, gc.DeepEquals, environs.NewBootstrapMachineConfig(mcfg.SystemPrivateSSHKey)) |
178 | @@ -105,7 +106,7 @@ | |||
179 | 105 | startInstance := func( | 106 | startInstance := func( |
180 | 106 | _ constraints.Value, _, _ []string, _ tools.List, _ *cloudinit.MachineConfig, | 107 | _ constraints.Value, _, _ []string, _ tools.List, _ *cloudinit.MachineConfig, |
181 | 107 | ) ( | 108 | ) ( |
183 | 108 | instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error, | 109 | instance.Instance, *instance.HardwareCharacteristics, []network.Info, error, |
184 | 109 | ) { | 110 | ) { |
185 | 110 | stor.putErr = fmt.Errorf("suddenly a wild blah") | 111 | stor.putErr = fmt.Errorf("suddenly a wild blah") |
186 | 111 | return &mockInstance{id: "i-blah"}, nil, nil, nil | 112 | return &mockInstance{id: "i-blah"}, nil, nil, nil |
187 | @@ -138,7 +139,7 @@ | |||
188 | 138 | startInstance := func( | 139 | startInstance := func( |
189 | 139 | _ constraints.Value, _, _ []string, _ tools.List, _ *cloudinit.MachineConfig, | 140 | _ constraints.Value, _, _ []string, _ tools.List, _ *cloudinit.MachineConfig, |
190 | 140 | ) ( | 141 | ) ( |
192 | 141 | instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error, | 142 | instance.Instance, *instance.HardwareCharacteristics, []network.Info, error, |
193 | 142 | ) { | 143 | ) { |
194 | 143 | stor.putErr = fmt.Errorf("suddenly a wild blah") | 144 | stor.putErr = fmt.Errorf("suddenly a wild blah") |
195 | 144 | return &mockInstance{id: "i-blah"}, nil, nil, nil | 145 | return &mockInstance{id: "i-blah"}, nil, nil, nil |
196 | @@ -179,7 +180,7 @@ | |||
197 | 179 | startInstance := func( | 180 | startInstance := func( |
198 | 180 | _ constraints.Value, _, _ []string, _ tools.List, mcfg *cloudinit.MachineConfig, | 181 | _ constraints.Value, _, _ []string, _ tools.List, mcfg *cloudinit.MachineConfig, |
199 | 181 | ) ( | 182 | ) ( |
201 | 182 | instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error, | 183 | instance.Instance, *instance.HardwareCharacteristics, []network.Info, error, |
202 | 183 | ) { | 184 | ) { |
203 | 184 | return &mockInstance{id: checkInstanceId}, &checkHardware, nil, nil | 185 | return &mockInstance{id: checkInstanceId}, &checkHardware, nil, nil |
204 | 185 | } | 186 | } |
205 | 186 | 187 | ||
206 | === modified file 'provider/common/mock_test.go' | |||
207 | --- provider/common/mock_test.go 2014-04-04 15:55:19 +0000 | |||
208 | +++ provider/common/mock_test.go 2014-04-18 16:46:53 +0000 | |||
209 | @@ -10,6 +10,7 @@ | |||
210 | 10 | "launchpad.net/juju-core/environs" | 10 | "launchpad.net/juju-core/environs" |
211 | 11 | "launchpad.net/juju-core/environs/cloudinit" | 11 | "launchpad.net/juju-core/environs/cloudinit" |
212 | 12 | "launchpad.net/juju-core/environs/config" | 12 | "launchpad.net/juju-core/environs/config" |
213 | 13 | "launchpad.net/juju-core/environs/network" | ||
214 | 13 | "launchpad.net/juju-core/environs/simplestreams" | 14 | "launchpad.net/juju-core/environs/simplestreams" |
215 | 14 | "launchpad.net/juju-core/environs/storage" | 15 | "launchpad.net/juju-core/environs/storage" |
216 | 15 | "launchpad.net/juju-core/instance" | 16 | "launchpad.net/juju-core/instance" |
217 | @@ -17,7 +18,7 @@ | |||
218 | 17 | ) | 18 | ) |
219 | 18 | 19 | ||
220 | 19 | type allInstancesFunc func() ([]instance.Instance, error) | 20 | type allInstancesFunc func() ([]instance.Instance, error) |
222 | 20 | type startInstanceFunc func(constraints.Value, []string, []string, tools.List, *cloudinit.MachineConfig) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) | 21 | type startInstanceFunc func(constraints.Value, []string, []string, tools.List, *cloudinit.MachineConfig) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) |
223 | 21 | type stopInstancesFunc func([]instance.Instance) error | 22 | type stopInstancesFunc func([]instance.Instance) error |
224 | 22 | type getToolsSourcesFunc func() ([]simplestreams.DataSource, error) | 23 | type getToolsSourcesFunc func() ([]simplestreams.DataSource, error) |
225 | 23 | type configFunc func() *config.Config | 24 | type configFunc func() *config.Config |
226 | @@ -49,7 +50,7 @@ | |||
227 | 49 | func (env *mockEnviron) AllInstances() ([]instance.Instance, error) { | 50 | func (env *mockEnviron) AllInstances() ([]instance.Instance, error) { |
228 | 50 | return env.allInstances() | 51 | return env.allInstances() |
229 | 51 | } | 52 | } |
231 | 52 | func (env *mockEnviron) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) { | 53 | func (env *mockEnviron) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) { |
232 | 53 | return env.startInstance( | 54 | return env.startInstance( |
233 | 54 | args.Constraints, | 55 | args.Constraints, |
234 | 55 | args.MachineConfig.IncludeNetworks, | 56 | args.MachineConfig.IncludeNetworks, |
235 | 56 | 57 | ||
236 | === modified file 'provider/dummy/environs.go' | |||
237 | --- provider/dummy/environs.go 2014-04-14 16:41:28 +0000 | |||
238 | +++ provider/dummy/environs.go 2014-04-18 16:46:53 +0000 | |||
239 | @@ -40,6 +40,7 @@ | |||
240 | 40 | "launchpad.net/juju-core/environs/bootstrap" | 40 | "launchpad.net/juju-core/environs/bootstrap" |
241 | 41 | "launchpad.net/juju-core/environs/config" | 41 | "launchpad.net/juju-core/environs/config" |
242 | 42 | "launchpad.net/juju-core/environs/imagemetadata" | 42 | "launchpad.net/juju-core/environs/imagemetadata" |
243 | 43 | "launchpad.net/juju-core/environs/network" | ||
244 | 43 | "launchpad.net/juju-core/environs/simplestreams" | 44 | "launchpad.net/juju-core/environs/simplestreams" |
245 | 44 | "launchpad.net/juju-core/environs/storage" | 45 | "launchpad.net/juju-core/environs/storage" |
246 | 45 | "launchpad.net/juju-core/environs/tools" | 46 | "launchpad.net/juju-core/environs/tools" |
247 | @@ -115,7 +116,7 @@ | |||
248 | 115 | Constraints constraints.Value | 116 | Constraints constraints.Value |
249 | 116 | IncludeNetworks []string | 117 | IncludeNetworks []string |
250 | 117 | ExcludeNetworks []string | 118 | ExcludeNetworks []string |
252 | 118 | NetworkInfo []environs.NetworkInfo | 119 | NetworkInfo []network.Info |
253 | 119 | Info *state.Info | 120 | Info *state.Info |
254 | 120 | APIInfo *api.Info | 121 | APIInfo *api.Info |
255 | 121 | Secret string | 122 | Secret string |
256 | @@ -693,7 +694,7 @@ | |||
257 | 693 | } | 694 | } |
258 | 694 | 695 | ||
259 | 695 | // StartInstance is specified in the InstanceBroker interface. | 696 | // StartInstance is specified in the InstanceBroker interface. |
261 | 696 | func (e *environ) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) { | 697 | func (e *environ) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) { |
262 | 697 | 698 | ||
263 | 698 | defer delay() | 699 | defer delay() |
264 | 699 | machineId := args.MachineConfig.MachineId | 700 | machineId := args.MachineConfig.MachineId |
265 | @@ -766,23 +767,24 @@ | |||
266 | 766 | } | 767 | } |
267 | 767 | } | 768 | } |
268 | 768 | // Simulate networks added when requested. | 769 | // Simulate networks added when requested. |
272 | 769 | networkInfo := make([]environs.NetworkInfo, len(args.MachineConfig.IncludeNetworks)) | 770 | networkInfo := make([]network.Info, len(args.MachineConfig.IncludeNetworks)) |
273 | 770 | for i, network := range args.MachineConfig.IncludeNetworks { | 771 | for i, netName := range args.MachineConfig.IncludeNetworks { |
274 | 771 | if strings.HasPrefix(network, "bad-") { | 772 | if strings.HasPrefix(netName, "bad-") { |
275 | 772 | // Simulate we didn't get correct information for the network. | 773 | // Simulate we didn't get correct information for the network. |
279 | 773 | networkInfo[i] = environs.NetworkInfo{ | 774 | networkInfo[i] = network.Info{ |
280 | 774 | NetworkId: network, | 775 | ProviderId: network.Id(netName), |
281 | 775 | NetworkName: network, | 776 | NetworkName: netName, |
282 | 776 | CIDR: "invalid", | 777 | CIDR: "invalid", |
283 | 777 | } | 778 | } |
284 | 778 | } else { | 779 | } else { |
288 | 779 | networkInfo[i] = environs.NetworkInfo{ | 780 | networkInfo[i] = network.Info{ |
289 | 780 | NetworkId: network, | 781 | ProviderId: network.Id(netName), |
290 | 781 | NetworkName: network, | 782 | NetworkName: netName, |
291 | 782 | CIDR: fmt.Sprintf("0.%d.2.0/24", i+1), | 783 | CIDR: fmt.Sprintf("0.%d.2.0/24", i+1), |
292 | 783 | InterfaceName: fmt.Sprintf("eth%d", i), | 784 | InterfaceName: fmt.Sprintf("eth%d", i), |
293 | 784 | VLANTag: i, | 785 | VLANTag: i, |
294 | 785 | MACAddress: fmt.Sprintf("aa:bb:cc:dd:ee:f%d", i), | 786 | MACAddress: fmt.Sprintf("aa:bb:cc:dd:ee:f%d", i), |
295 | 787 | IsVirtual: i > 0, | ||
296 | 786 | } | 788 | } |
297 | 787 | } | 789 | } |
298 | 788 | } | 790 | } |
299 | 789 | 791 | ||
300 | === modified file 'provider/ec2/ec2.go' | |||
301 | --- provider/ec2/ec2.go 2014-04-09 16:36:12 +0000 | |||
302 | +++ provider/ec2/ec2.go 2014-04-18 16:46:53 +0000 | |||
303 | @@ -18,6 +18,7 @@ | |||
304 | 18 | "launchpad.net/juju-core/environs/config" | 18 | "launchpad.net/juju-core/environs/config" |
305 | 19 | "launchpad.net/juju-core/environs/imagemetadata" | 19 | "launchpad.net/juju-core/environs/imagemetadata" |
306 | 20 | "launchpad.net/juju-core/environs/instances" | 20 | "launchpad.net/juju-core/environs/instances" |
307 | 21 | "launchpad.net/juju-core/environs/network" | ||
308 | 21 | "launchpad.net/juju-core/environs/simplestreams" | 22 | "launchpad.net/juju-core/environs/simplestreams" |
309 | 22 | "launchpad.net/juju-core/environs/storage" | 23 | "launchpad.net/juju-core/environs/storage" |
310 | 23 | envtools "launchpad.net/juju-core/environs/tools" | 24 | envtools "launchpad.net/juju-core/environs/tools" |
311 | @@ -393,7 +394,7 @@ | |||
312 | 393 | const ebsStorage = "ebs" | 394 | const ebsStorage = "ebs" |
313 | 394 | 395 | ||
314 | 395 | // StartInstance is specified in the InstanceBroker interface. | 396 | // StartInstance is specified in the InstanceBroker interface. |
316 | 396 | func (e *environ) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) { | 397 | func (e *environ) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) { |
317 | 397 | if args.MachineConfig.HasNetworks() { | 398 | if args.MachineConfig.HasNetworks() { |
318 | 398 | return nil, nil, nil, fmt.Errorf("starting instances with networks is not supported yet.") | 399 | return nil, nil, nil, fmt.Errorf("starting instances with networks is not supported yet.") |
319 | 399 | } | 400 | } |
320 | 400 | 401 | ||
321 | === modified file 'provider/joyent/environ_instance.go' | |||
322 | --- provider/joyent/environ_instance.go 2014-04-04 15:55:19 +0000 | |||
323 | +++ provider/joyent/environ_instance.go 2014-04-18 16:46:53 +0000 | |||
324 | @@ -15,6 +15,7 @@ | |||
325 | 15 | "launchpad.net/juju-core/environs" | 15 | "launchpad.net/juju-core/environs" |
326 | 16 | "launchpad.net/juju-core/environs/imagemetadata" | 16 | "launchpad.net/juju-core/environs/imagemetadata" |
327 | 17 | "launchpad.net/juju-core/environs/instances" | 17 | "launchpad.net/juju-core/environs/instances" |
328 | 18 | "launchpad.net/juju-core/environs/network" | ||
329 | 18 | "launchpad.net/juju-core/environs/simplestreams" | 19 | "launchpad.net/juju-core/environs/simplestreams" |
330 | 19 | "launchpad.net/juju-core/instance" | 20 | "launchpad.net/juju-core/instance" |
331 | 20 | "launchpad.net/juju-core/names" | 21 | "launchpad.net/juju-core/names" |
332 | @@ -50,7 +51,7 @@ | |||
333 | 50 | return fmt.Sprintf("juju-%s-%s", env.Name(), names.MachineTag(machineId)) | 51 | return fmt.Sprintf("juju-%s-%s", env.Name(), names.MachineTag(machineId)) |
334 | 51 | } | 52 | } |
335 | 52 | 53 | ||
337 | 53 | func (env *joyentEnviron) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) { | 54 | func (env *joyentEnviron) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) { |
338 | 54 | 55 | ||
339 | 55 | if args.MachineConfig.HasNetworks() { | 56 | if args.MachineConfig.HasNetworks() { |
340 | 56 | return nil, nil, nil, fmt.Errorf("starting instances with networks is not supported yet.") | 57 | return nil, nil, nil, fmt.Errorf("starting instances with networks is not supported yet.") |
341 | 57 | 58 | ||
342 | === modified file 'provider/local/environ.go' | |||
343 | --- provider/local/environ.go 2014-04-14 16:41:28 +0000 | |||
344 | +++ provider/local/environ.go 2014-04-18 16:46:53 +0000 | |||
345 | @@ -30,6 +30,7 @@ | |||
346 | 30 | "launchpad.net/juju-core/environs/config" | 30 | "launchpad.net/juju-core/environs/config" |
347 | 31 | "launchpad.net/juju-core/environs/filestorage" | 31 | "launchpad.net/juju-core/environs/filestorage" |
348 | 32 | "launchpad.net/juju-core/environs/httpstorage" | 32 | "launchpad.net/juju-core/environs/httpstorage" |
349 | 33 | "launchpad.net/juju-core/environs/network" | ||
350 | 33 | "launchpad.net/juju-core/environs/simplestreams" | 34 | "launchpad.net/juju-core/environs/simplestreams" |
351 | 34 | "launchpad.net/juju-core/environs/storage" | 35 | "launchpad.net/juju-core/environs/storage" |
352 | 35 | envtools "launchpad.net/juju-core/environs/tools" | 36 | envtools "launchpad.net/juju-core/environs/tools" |
353 | @@ -301,7 +302,7 @@ | |||
354 | 301 | } | 302 | } |
355 | 302 | 303 | ||
356 | 303 | // StartInstance is specified in the InstanceBroker interface. | 304 | // StartInstance is specified in the InstanceBroker interface. |
358 | 304 | func (env *localEnviron) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) { | 305 | func (env *localEnviron) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) { |
359 | 305 | if args.MachineConfig.HasNetworks() { | 306 | if args.MachineConfig.HasNetworks() { |
360 | 306 | return nil, nil, nil, fmt.Errorf("starting instances with networks is not supported yet.") | 307 | return nil, nil, nil, fmt.Errorf("starting instances with networks is not supported yet.") |
361 | 307 | } | 308 | } |
362 | 308 | 309 | ||
363 | === modified file 'provider/maas/environ.go' | |||
364 | --- provider/maas/environ.go 2014-04-11 15:20:32 +0000 | |||
365 | +++ provider/maas/environ.go 2014-04-18 16:46:53 +0000 | |||
366 | @@ -22,6 +22,7 @@ | |||
367 | 22 | "launchpad.net/juju-core/environs" | 22 | "launchpad.net/juju-core/environs" |
368 | 23 | "launchpad.net/juju-core/environs/config" | 23 | "launchpad.net/juju-core/environs/config" |
369 | 24 | "launchpad.net/juju-core/environs/imagemetadata" | 24 | "launchpad.net/juju-core/environs/imagemetadata" |
370 | 25 | "launchpad.net/juju-core/environs/network" | ||
371 | 25 | "launchpad.net/juju-core/environs/simplestreams" | 26 | "launchpad.net/juju-core/environs/simplestreams" |
372 | 26 | "launchpad.net/juju-core/environs/storage" | 27 | "launchpad.net/juju-core/environs/storage" |
373 | 27 | envtools "launchpad.net/juju-core/environs/tools" | 28 | envtools "launchpad.net/juju-core/environs/tools" |
374 | @@ -331,56 +332,54 @@ | |||
375 | 331 | return `sed -i "s/iface eth0 inet dhcp/source \/etc\/network\/eth0.config/" /etc/network/interfaces` | 332 | return `sed -i "s/iface eth0 inet dhcp/source \/etc\/network\/eth0.config/" /etc/network/interfaces` |
376 | 332 | } | 333 | } |
377 | 333 | 334 | ||
380 | 334 | // setupNetworks prepares a []environs.NetworkInfo for the given instance. | 335 | // setupNetworks prepares a []network.Info for the given instance. |
381 | 335 | func (environ *maasEnviron) setupNetworks(inst instance.Instance) ([]environs.NetworkInfo, error) { | 336 | func (environ *maasEnviron) setupNetworks(inst instance.Instance) ([]network.Info, error) { |
382 | 336 | // Get the instance network interfaces first. | 337 | // Get the instance network interfaces first. |
383 | 337 | interfaces, err := environ.getInstanceNetworkInterfaces(inst) | 338 | interfaces, err := environ.getInstanceNetworkInterfaces(inst) |
384 | 338 | if err != nil { | 339 | if err != nil { |
385 | 339 | return nil, fmt.Errorf("getInstanceNetworkInterfaces failed: %v", err) | 340 | return nil, fmt.Errorf("getInstanceNetworkInterfaces failed: %v", err) |
386 | 340 | } | 341 | } |
387 | 341 | logger.Debugf("node %q has network interfaces %v", inst.Id(), interfaces) | 342 | logger.Debugf("node %q has network interfaces %v", inst.Id(), interfaces) |
388 | 342 | networkInfoMap := make(map[string]environs.NetworkInfo) | ||
389 | 343 | for macAddress, interfaceName := range interfaces { | ||
390 | 344 | networkInfoMap[macAddress] = environs.NetworkInfo{ | ||
391 | 345 | MACAddress: macAddress, | ||
392 | 346 | InterfaceName: interfaceName, | ||
393 | 347 | } | ||
394 | 348 | } | ||
395 | 349 | networks, err := environ.getInstanceNetworks(inst) | 343 | networks, err := environ.getInstanceNetworks(inst) |
396 | 350 | if err != nil { | 344 | if err != nil { |
397 | 351 | return nil, fmt.Errorf("getInstanceNetworks failed: %v", err) | 345 | return nil, fmt.Errorf("getInstanceNetworks failed: %v", err) |
398 | 352 | } | 346 | } |
399 | 353 | logger.Debugf("node %q has networks %v", inst.Id(), networks) | 347 | logger.Debugf("node %q has networks %v", inst.Id(), networks) |
401 | 354 | for _, network := range networks { | 348 | var tempNetworkInfo []network.Info |
402 | 349 | for _, netw := range networks { | ||
403 | 355 | netCIDR := &net.IPNet{ | 350 | netCIDR := &net.IPNet{ |
406 | 356 | IP: net.ParseIP(network.IP), | 351 | IP: net.ParseIP(netw.IP), |
407 | 357 | Mask: net.IPMask(net.ParseIP(network.Mask)), | 352 | Mask: net.IPMask(net.ParseIP(netw.Mask)), |
408 | 358 | } | 353 | } |
410 | 359 | macs, err := environ.getNetworkMACs(network.Name) | 354 | macs, err := environ.getNetworkMACs(netw.Name) |
411 | 360 | if err != nil { | 355 | if err != nil { |
412 | 361 | return nil, fmt.Errorf("getNetworkMACs failed: %v", err) | 356 | return nil, fmt.Errorf("getNetworkMACs failed: %v", err) |
413 | 362 | } | 357 | } |
414 | 358 | logger.Debugf("network %q has MACs: %v", netw.Name, macs) | ||
415 | 363 | for _, mac := range macs { | 359 | for _, mac := range macs { |
423 | 364 | if _, ok := interfaces[mac]; ok { | 360 | if interfaceName, ok := interfaces[mac]; ok { |
424 | 365 | info := networkInfoMap[mac] | 361 | tempNetworkInfo = append(tempNetworkInfo, network.Info{ |
425 | 366 | info.CIDR = netCIDR.String() | 362 | MACAddress: mac, |
426 | 367 | info.VLANTag = network.VLANTag | 363 | InterfaceName: interfaceName, |
427 | 368 | info.NetworkId = network.Name | 364 | CIDR: netCIDR.String(), |
428 | 369 | info.NetworkName = network.Name | 365 | VLANTag: netw.VLANTag, |
429 | 370 | networkInfoMap[mac] = info | 366 | ProviderId: network.Id(netw.Name), |
430 | 367 | NetworkName: netw.Name, | ||
431 | 368 | IsVirtual: netw.VLANTag > 0, | ||
432 | 369 | }) | ||
433 | 371 | } | 370 | } |
434 | 372 | } | 371 | } |
435 | 373 | } | 372 | } |
436 | 374 | // Verify we filled-in everything for all networks/interfaces | 373 | // Verify we filled-in everything for all networks/interfaces |
437 | 375 | // and drop incomplete records. | 374 | // and drop incomplete records. |
441 | 376 | var networkInfo []environs.NetworkInfo | 375 | var networkInfo []network.Info |
442 | 377 | for _, info := range networkInfoMap { | 376 | for _, info := range tempNetworkInfo { |
443 | 378 | if info.NetworkId == "" || info.NetworkName == "" || info.CIDR == "" { | 377 | if info.ProviderId == "" || info.NetworkName == "" || info.CIDR == "" { |
444 | 379 | logger.Warningf("ignoring network interface %q: missing network information", info.InterfaceName) | 378 | logger.Warningf("ignoring network interface %q: missing network information", info.InterfaceName) |
445 | 380 | continue | 379 | continue |
446 | 381 | } | 380 | } |
447 | 382 | if info.MACAddress == "" || info.InterfaceName == "" { | 381 | if info.MACAddress == "" || info.InterfaceName == "" { |
449 | 383 | logger.Warningf("ignoring network %q: missing network interface information", info.NetworkId) | 382 | logger.Warningf("ignoring network %q: missing network interface information", info.ProviderId) |
450 | 384 | continue | 383 | continue |
451 | 385 | } | 384 | } |
452 | 386 | networkInfo = append(networkInfo, info) | 385 | networkInfo = append(networkInfo, info) |
453 | @@ -391,7 +390,7 @@ | |||
454 | 391 | 390 | ||
455 | 392 | // StartInstance is specified in the InstanceBroker interface. | 391 | // StartInstance is specified in the InstanceBroker interface. |
456 | 393 | func (environ *maasEnviron) StartInstance(args environs.StartInstanceParams) ( | 392 | func (environ *maasEnviron) StartInstance(args environs.StartInstanceParams) ( |
458 | 394 | instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error, | 393 | instance.Instance, *instance.HardwareCharacteristics, []network.Info, error, |
459 | 395 | ) { | 394 | ) { |
460 | 396 | var inst *maasInstance | 395 | var inst *maasInstance |
461 | 397 | var err error | 396 | var err error |
462 | @@ -413,7 +412,7 @@ | |||
463 | 413 | } | 412 | } |
464 | 414 | } | 413 | } |
465 | 415 | }() | 414 | }() |
467 | 416 | var networkInfo []environs.NetworkInfo | 415 | var networkInfo []network.Info |
468 | 417 | if args.MachineConfig.HasNetworks() { | 416 | if args.MachineConfig.HasNetworks() { |
469 | 418 | networkInfo, err = environ.setupNetworks(inst) | 417 | networkInfo, err = environ.setupNetworks(inst) |
470 | 419 | if err != nil { | 418 | if err != nil { |
471 | @@ -454,7 +453,7 @@ | |||
472 | 454 | 453 | ||
473 | 455 | // newCloudinitConfig creates a cloudinit.Config structure | 454 | // newCloudinitConfig creates a cloudinit.Config structure |
474 | 456 | // suitable as a base for initialising a MAAS node. | 455 | // suitable as a base for initialising a MAAS node. |
476 | 457 | func newCloudinitConfig(hostname string, networkInfo []environs.NetworkInfo) (*cloudinit.Config, error) { | 456 | func newCloudinitConfig(hostname string, networkInfo []network.Info) (*cloudinit.Config, error) { |
477 | 458 | info := machineInfo{hostname} | 457 | info := machineInfo{hostname} |
478 | 459 | runCmd, err := info.cloudinitRunCmd() | 458 | runCmd, err := info.cloudinitRunCmd() |
479 | 460 | if err != nil { | 459 | if err != nil { |
480 | @@ -477,11 +476,7 @@ | |||
481 | 477 | 476 | ||
482 | 478 | // setupNetworksOnBoot prepares a script to enable and start all given | 477 | // setupNetworksOnBoot prepares a script to enable and start all given |
483 | 479 | // networks on boot. | 478 | // networks on boot. |
489 | 480 | // | 479 | func setupNetworksOnBoot(cloudcfg *cloudinit.Config, networkInfo []network.Info) { |
485 | 481 | // TODO(dimitern) To support more than one VLAN on the same physical | ||
486 | 482 | // interface, we need model changes to allow muliple NICs with the | ||
487 | 483 | // same MAC address, but different network name. | ||
488 | 484 | func setupNetworksOnBoot(cloudcfg *cloudinit.Config, networkInfo []environs.NetworkInfo) { | ||
490 | 485 | const ifaceConfig = `cat >> /etc/network/interfaces << EOF | 480 | const ifaceConfig = `cat >> /etc/network/interfaces << EOF |
491 | 486 | 481 | ||
492 | 487 | auto %s | 482 | auto %s |
493 | @@ -494,6 +489,10 @@ | |||
494 | 494 | script := func(line string, args ...interface{}) { | 489 | script := func(line string, args ...interface{}) { |
495 | 495 | cloudcfg.AddScripts(fmt.Sprintf(line, args...)) | 490 | cloudcfg.AddScripts(fmt.Sprintf(line, args...)) |
496 | 496 | } | 491 | } |
497 | 492 | // Because eth0 is already configured in the br0 bridge, we | ||
498 | 493 | // don't want to break that. | ||
499 | 494 | configured := set.NewStrings("eth0") | ||
500 | 495 | |||
501 | 497 | // In order to support VLANs, we need to include 8021q module | 496 | // In order to support VLANs, we need to include 8021q module |
502 | 498 | // configure vconfig's set_name_type | 497 | // configure vconfig's set_name_type |
503 | 499 | script("modprobe 8021q") | 498 | script("modprobe 8021q") |
504 | @@ -501,14 +500,12 @@ | |||
505 | 501 | script("vconfig set_name_type DEV_PLUS_VID_NO_PAD") | 500 | script("vconfig set_name_type DEV_PLUS_VID_NO_PAD") |
506 | 502 | // Now prepare each interface configuration | 501 | // Now prepare each interface configuration |
507 | 503 | for _, info := range networkInfo { | 502 | for _, info := range networkInfo { |
512 | 504 | // Because eth0 is already configured in the br0 bridge, we | 503 | if !configured.Contains(info.InterfaceName) { |
513 | 505 | // don't want to break that. | 504 | // Register and bring up the physical interface. |
514 | 506 | if info.InterfaceName == "eth0" { | 505 | script(ifaceConfig, info.InterfaceName, info.InterfaceName) |
515 | 507 | continue | 506 | script("ifup %s", info.InterfaceName) |
516 | 507 | configured.Add(info.InterfaceName) | ||
517 | 508 | } | 508 | } |
518 | 509 | // Register and bring up the interface. | ||
519 | 510 | script(ifaceConfig, info.InterfaceName, info.InterfaceName) | ||
520 | 511 | script("ifup %s", info.InterfaceName) | ||
521 | 512 | if info.VLANTag > 0 { | 509 | if info.VLANTag > 0 { |
522 | 513 | // We have a VLAN and need to create and register it after | 510 | // We have a VLAN and need to create and register it after |
523 | 514 | // its parent interface was brought up. | 511 | // its parent interface was brought up. |
524 | 515 | 512 | ||
525 | === modified file 'provider/maas/environ_test.go' | |||
526 | --- provider/maas/environ_test.go 2014-04-10 17:46:52 +0000 | |||
527 | +++ provider/maas/environ_test.go 2014-04-18 16:46:53 +0000 | |||
528 | @@ -10,8 +10,8 @@ | |||
529 | 10 | gc "launchpad.net/gocheck" | 10 | gc "launchpad.net/gocheck" |
530 | 11 | "launchpad.net/gomaasapi" | 11 | "launchpad.net/gomaasapi" |
531 | 12 | 12 | ||
532 | 13 | "launchpad.net/juju-core/environs" | ||
533 | 14 | "launchpad.net/juju-core/environs/config" | 13 | "launchpad.net/juju-core/environs/config" |
534 | 14 | "launchpad.net/juju-core/environs/network" | ||
535 | 15 | envtesting "launchpad.net/juju-core/environs/testing" | 15 | envtesting "launchpad.net/juju-core/environs/testing" |
536 | 16 | "launchpad.net/juju-core/provider/maas" | 16 | "launchpad.net/juju-core/provider/maas" |
537 | 17 | coretesting "launchpad.net/juju-core/testing" | 17 | coretesting "launchpad.net/juju-core/testing" |
538 | @@ -197,10 +197,17 @@ | |||
539 | 197 | } | 197 | } |
540 | 198 | 198 | ||
541 | 199 | func (*environSuite) TestNewCloudinitConfig(c *gc.C) { | 199 | func (*environSuite) TestNewCloudinitConfig(c *gc.C) { |
543 | 200 | nwInfo := []environs.NetworkInfo{ | 200 | nwInfo := []network.Info{ |
544 | 201 | // physical eth0 won't be touched, but it can have VLANs on it. | ||
545 | 201 | {InterfaceName: "eth0", VLANTag: 0}, | 202 | {InterfaceName: "eth0", VLANTag: 0}, |
546 | 203 | {InterfaceName: "eth0", VLANTag: 99}, | ||
547 | 204 | // physical NIC given explicitly, then a couple of virtual ones using it. | ||
548 | 205 | {InterfaceName: "eth1", VLANTag: 0}, | ||
549 | 202 | {InterfaceName: "eth1", VLANTag: 42}, | 206 | {InterfaceName: "eth1", VLANTag: 42}, |
550 | 207 | {InterfaceName: "eth1", VLANTag: 69}, | ||
551 | 203 | {InterfaceName: "eth2", VLANTag: 0}, | 208 | {InterfaceName: "eth2", VLANTag: 0}, |
552 | 209 | // physical NIC not given, ensure it gets brought up first, before the virtual one. | ||
553 | 210 | {InterfaceName: "eth3", VLANTag: 123}, | ||
554 | 204 | } | 211 | } |
555 | 205 | cloudcfg, err := maas.NewCloudinitConfig("testing.invalid", nwInfo) | 212 | cloudcfg, err := maas.NewCloudinitConfig("testing.invalid", nwInfo) |
556 | 206 | c.Assert(err, gc.IsNil) | 213 | c.Assert(err, gc.IsNil) |
557 | @@ -216,12 +223,23 @@ | |||
558 | 216 | "modprobe 8021q", | 223 | "modprobe 8021q", |
559 | 217 | "sh -c 'grep -q 8021q /etc/modules || echo 8021q >> /etc/modules'", | 224 | "sh -c 'grep -q 8021q /etc/modules || echo 8021q >> /etc/modules'", |
560 | 218 | "vconfig set_name_type DEV_PLUS_VID_NO_PAD", | 225 | "vconfig set_name_type DEV_PLUS_VID_NO_PAD", |
561 | 226 | "vconfig add eth0 99", | ||
562 | 227 | "cat >> /etc/network/interfaces << EOF\n\nauto eth0.99\niface eth0.99 inet dhcp\nEOF\n", | ||
563 | 228 | "ifup eth0.99", | ||
564 | 219 | "cat >> /etc/network/interfaces << EOF\n\nauto eth1\niface eth1 inet dhcp\nEOF\n", | 229 | "cat >> /etc/network/interfaces << EOF\n\nauto eth1\niface eth1 inet dhcp\nEOF\n", |
565 | 220 | "ifup eth1", | 230 | "ifup eth1", |
566 | 221 | "vconfig add eth1 42", | 231 | "vconfig add eth1 42", |
567 | 222 | "cat >> /etc/network/interfaces << EOF\n\nauto eth1.42\niface eth1.42 inet dhcp\nEOF\n", | 232 | "cat >> /etc/network/interfaces << EOF\n\nauto eth1.42\niface eth1.42 inet dhcp\nEOF\n", |
568 | 223 | "ifup eth1.42", | 233 | "ifup eth1.42", |
569 | 234 | "vconfig add eth1 69", | ||
570 | 235 | "cat >> /etc/network/interfaces << EOF\n\nauto eth1.69\niface eth1.69 inet dhcp\nEOF\n", | ||
571 | 236 | "ifup eth1.69", | ||
572 | 224 | "cat >> /etc/network/interfaces << EOF\n\nauto eth2\niface eth2 inet dhcp\nEOF\n", | 237 | "cat >> /etc/network/interfaces << EOF\n\nauto eth2\niface eth2 inet dhcp\nEOF\n", |
573 | 225 | "ifup eth2", | 238 | "ifup eth2", |
574 | 239 | "cat >> /etc/network/interfaces << EOF\n\nauto eth3\niface eth3 inet dhcp\nEOF\n", | ||
575 | 240 | "ifup eth3", | ||
576 | 241 | "vconfig add eth3 123", | ||
577 | 242 | "cat >> /etc/network/interfaces << EOF\n\nauto eth3.123\niface eth3.123 inet dhcp\nEOF\n", | ||
578 | 243 | "ifup eth3.123", | ||
579 | 226 | }) | 244 | }) |
580 | 227 | } | 245 | } |
581 | 228 | 246 | ||
582 | === modified file 'provider/manual/environ.go' | |||
583 | --- provider/manual/environ.go 2014-04-11 17:51:58 +0000 | |||
584 | +++ provider/manual/environ.go 2014-04-18 16:46:53 +0000 | |||
585 | @@ -21,6 +21,7 @@ | |||
586 | 21 | "launchpad.net/juju-core/environs/config" | 21 | "launchpad.net/juju-core/environs/config" |
587 | 22 | "launchpad.net/juju-core/environs/httpstorage" | 22 | "launchpad.net/juju-core/environs/httpstorage" |
588 | 23 | "launchpad.net/juju-core/environs/manual" | 23 | "launchpad.net/juju-core/environs/manual" |
589 | 24 | "launchpad.net/juju-core/environs/network" | ||
590 | 24 | "launchpad.net/juju-core/environs/simplestreams" | 25 | "launchpad.net/juju-core/environs/simplestreams" |
591 | 25 | "launchpad.net/juju-core/environs/sshstorage" | 26 | "launchpad.net/juju-core/environs/sshstorage" |
592 | 26 | "launchpad.net/juju-core/environs/storage" | 27 | "launchpad.net/juju-core/environs/storage" |
593 | @@ -65,7 +66,7 @@ | |||
594 | 65 | var errNoStartInstance = errors.New("manual provider cannot start instances") | 66 | var errNoStartInstance = errors.New("manual provider cannot start instances") |
595 | 66 | var errNoStopInstance = errors.New("manual provider cannot stop instances") | 67 | var errNoStopInstance = errors.New("manual provider cannot stop instances") |
596 | 67 | 68 | ||
598 | 68 | func (*manualEnviron) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) { | 69 | func (*manualEnviron) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) { |
599 | 69 | return nil, nil, nil, errNoStartInstance | 70 | return nil, nil, nil, errNoStartInstance |
600 | 70 | } | 71 | } |
601 | 71 | 72 | ||
602 | 72 | 73 | ||
603 | === modified file 'provider/openstack/provider.go' | |||
604 | --- provider/openstack/provider.go 2014-04-12 05:53:58 +0000 | |||
605 | +++ provider/openstack/provider.go 2014-04-18 16:46:53 +0000 | |||
606 | @@ -27,6 +27,7 @@ | |||
607 | 27 | "launchpad.net/juju-core/environs/config" | 27 | "launchpad.net/juju-core/environs/config" |
608 | 28 | "launchpad.net/juju-core/environs/imagemetadata" | 28 | "launchpad.net/juju-core/environs/imagemetadata" |
609 | 29 | "launchpad.net/juju-core/environs/instances" | 29 | "launchpad.net/juju-core/environs/instances" |
610 | 30 | "launchpad.net/juju-core/environs/network" | ||
611 | 30 | "launchpad.net/juju-core/environs/simplestreams" | 31 | "launchpad.net/juju-core/environs/simplestreams" |
612 | 31 | "launchpad.net/juju-core/environs/storage" | 32 | "launchpad.net/juju-core/environs/storage" |
613 | 32 | envtools "launchpad.net/juju-core/environs/tools" | 33 | envtools "launchpad.net/juju-core/environs/tools" |
614 | @@ -745,7 +746,7 @@ | |||
615 | 745 | } | 746 | } |
616 | 746 | 747 | ||
617 | 747 | // StartInstance is specified in the InstanceBroker interface. | 748 | // StartInstance is specified in the InstanceBroker interface. |
619 | 748 | func (e *environ) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) { | 749 | func (e *environ) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) { |
620 | 749 | 750 | ||
621 | 750 | if args.MachineConfig.HasNetworks() { | 751 | if args.MachineConfig.HasNetworks() { |
622 | 751 | return nil, nil, nil, fmt.Errorf("starting instances with networks is not supported yet.") | 752 | return nil, nil, nil, fmt.Errorf("starting instances with networks is not supported yet.") |
623 | 752 | 753 | ||
624 | === modified file 'state/api/params/internal.go' | |||
625 | --- state/api/params/internal.go 2014-04-11 15:16:00 +0000 | |||
626 | +++ state/api/params/internal.go 2014-04-18 16:46:53 +0000 | |||
627 | @@ -7,6 +7,7 @@ | |||
628 | 7 | "time" | 7 | "time" |
629 | 8 | 8 | ||
630 | 9 | "launchpad.net/juju-core/constraints" | 9 | "launchpad.net/juju-core/constraints" |
631 | 10 | "launchpad.net/juju-core/environs/network" | ||
632 | 10 | "launchpad.net/juju-core/instance" | 11 | "launchpad.net/juju-core/instance" |
633 | 11 | "launchpad.net/juju-core/tools" | 12 | "launchpad.net/juju-core/tools" |
634 | 12 | "launchpad.net/juju-core/utils/exec" | 13 | "launchpad.net/juju-core/utils/exec" |
635 | @@ -317,7 +318,7 @@ | |||
636 | 317 | Tag string | 318 | Tag string |
637 | 318 | 319 | ||
638 | 319 | // ProviderId is the provider-specific network id. | 320 | // ProviderId is the provider-specific network id. |
640 | 320 | ProviderId string | 321 | ProviderId network.Id |
641 | 321 | 322 | ||
642 | 322 | // CIDR of the network, in "123.45.67.89/12" format. | 323 | // CIDR of the network, in "123.45.67.89/12" format. |
643 | 323 | CIDR string | 324 | CIDR string |
644 | @@ -340,6 +341,10 @@ | |||
645 | 340 | 341 | ||
646 | 341 | // NetworkTag is this interface's network tag. | 342 | // NetworkTag is this interface's network tag. |
647 | 342 | NetworkTag string | 343 | NetworkTag string |
648 | 344 | |||
649 | 345 | // IsVirtual is true when the interface is a virtual device, as | ||
650 | 346 | // opposed to a physical device. | ||
651 | 347 | IsVirtual bool | ||
652 | 343 | } | 348 | } |
653 | 344 | 349 | ||
654 | 345 | // InstanceInfo holds a machine tag, provider-specific instance id, a | 350 | // InstanceInfo holds a machine tag, provider-specific instance id, a |
655 | 346 | 351 | ||
656 | === modified file 'state/api/provisioner/provisioner_test.go' | |||
657 | --- state/api/provisioner/provisioner_test.go 2014-04-14 12:36:13 +0000 | |||
658 | +++ state/api/provisioner/provisioner_test.go 2014-04-18 16:46:53 +0000 | |||
659 | @@ -230,6 +230,11 @@ | |||
660 | 230 | CIDR: "0.2.2.0/24", | 230 | CIDR: "0.2.2.0/24", |
661 | 231 | VLANTag: 42, | 231 | VLANTag: 42, |
662 | 232 | }, { | 232 | }, { |
663 | 233 | Tag: "network-vlan69", | ||
664 | 234 | ProviderId: "vlan69", | ||
665 | 235 | CIDR: "0.3.2.0/24", | ||
666 | 236 | VLANTag: 69, | ||
667 | 237 | }, { | ||
668 | 233 | Tag: "network-vlan42", // duplicated; ignored | 238 | Tag: "network-vlan42", // duplicated; ignored |
669 | 234 | ProviderId: "vlan42", | 239 | ProviderId: "vlan42", |
670 | 235 | CIDR: "0.2.2.0/24", | 240 | CIDR: "0.2.2.0/24", |
671 | @@ -239,18 +244,32 @@ | |||
672 | 239 | MACAddress: "aa:bb:cc:dd:ee:f0", | 244 | MACAddress: "aa:bb:cc:dd:ee:f0", |
673 | 240 | NetworkTag: "network-net1", | 245 | NetworkTag: "network-net1", |
674 | 241 | InterfaceName: "eth0", | 246 | InterfaceName: "eth0", |
675 | 247 | IsVirtual: false, | ||
676 | 242 | }, { | 248 | }, { |
677 | 243 | MACAddress: "aa:bb:cc:dd:ee:f1", | 249 | MACAddress: "aa:bb:cc:dd:ee:f1", |
678 | 244 | NetworkTag: "network-net1", | 250 | NetworkTag: "network-net1", |
679 | 245 | InterfaceName: "eth1", | 251 | InterfaceName: "eth1", |
688 | 246 | }, { | 252 | IsVirtual: false, |
689 | 247 | MACAddress: "aa:bb:cc:dd:ee:f2", | 253 | }, { |
690 | 248 | NetworkTag: "network-vlan42", | 254 | MACAddress: "aa:bb:cc:dd:ee:f1", |
691 | 249 | InterfaceName: "eth2", | 255 | NetworkTag: "network-vlan42", |
692 | 250 | }, { | 256 | InterfaceName: "eth1.42", |
693 | 251 | MACAddress: "aa:bb:cc:dd:ee:f2", // duplicated; ignored | 257 | IsVirtual: true, |
694 | 252 | NetworkTag: "network-vlan42", | 258 | }, { |
695 | 253 | InterfaceName: "eth2", | 259 | MACAddress: "aa:bb:cc:dd:ee:f1", |
696 | 260 | NetworkTag: "network-vlan69", | ||
697 | 261 | InterfaceName: "eth1.69", | ||
698 | 262 | IsVirtual: true, | ||
699 | 263 | }, { | ||
700 | 264 | MACAddress: "aa:bb:cc:dd:ee:f1", // duplicated mac+net; ignored | ||
701 | 265 | NetworkTag: "network-vlan42", | ||
702 | 266 | InterfaceName: "eth2", | ||
703 | 267 | IsVirtual: true, | ||
704 | 268 | }, { | ||
705 | 269 | MACAddress: "aa:bb:cc:dd:ee:f4", | ||
706 | 270 | NetworkTag: "network-net1", | ||
707 | 271 | InterfaceName: "eth1", // duplicated name+machine id; ignored | ||
708 | 272 | IsVirtual: false, | ||
709 | 254 | }} | 273 | }} |
710 | 255 | 274 | ||
711 | 256 | err = apiMachine.SetInstanceInfo("i-will", "fake_nonce", &hwChars, networks, ifaces) | 275 | err = apiMachine.SetInstanceInfo("i-will", "fake_nonce", &hwChars, networks, ifaces) |
712 | @@ -273,7 +292,7 @@ | |||
713 | 273 | 292 | ||
714 | 274 | // Check the networks are created. | 293 | // Check the networks are created. |
715 | 275 | for i, _ := range networks { | 294 | for i, _ := range networks { |
717 | 276 | if i == 2 { | 295 | if i == 3 { |
718 | 277 | // Last one was ignored, so skip it. | 296 | // Last one was ignored, so skip it. |
719 | 278 | break | 297 | break |
720 | 279 | } | 298 | } |
721 | @@ -291,16 +310,17 @@ | |||
722 | 291 | // And the network interfaces as well. | 310 | // And the network interfaces as well. |
723 | 292 | ifacesMachine, err = notProvisionedMachine.NetworkInterfaces() | 311 | ifacesMachine, err = notProvisionedMachine.NetworkInterfaces() |
724 | 293 | c.Assert(err, gc.IsNil) | 312 | c.Assert(err, gc.IsNil) |
726 | 294 | c.Assert(ifacesMachine, gc.HasLen, 3) | 313 | c.Assert(ifacesMachine, gc.HasLen, 4) |
727 | 295 | actual := make([]params.NetworkInterface, len(ifacesMachine)) | 314 | actual := make([]params.NetworkInterface, len(ifacesMachine)) |
728 | 296 | for i, iface := range ifacesMachine { | 315 | for i, iface := range ifacesMachine { |
729 | 297 | actual[i].InterfaceName = iface.InterfaceName() | 316 | actual[i].InterfaceName = iface.InterfaceName() |
730 | 298 | actual[i].NetworkTag = iface.NetworkTag() | 317 | actual[i].NetworkTag = iface.NetworkTag() |
731 | 299 | actual[i].MACAddress = iface.MACAddress() | 318 | actual[i].MACAddress = iface.MACAddress() |
732 | 319 | actual[i].IsVirtual = iface.IsVirtual() | ||
733 | 300 | c.Check(iface.MachineTag(), gc.Equals, notProvisionedMachine.Tag()) | 320 | c.Check(iface.MachineTag(), gc.Equals, notProvisionedMachine.Tag()) |
734 | 301 | c.Check(iface.MachineId(), gc.Equals, notProvisionedMachine.Id()) | 321 | c.Check(iface.MachineId(), gc.Equals, notProvisionedMachine.Id()) |
735 | 302 | } | 322 | } |
737 | 303 | c.Assert(actual, jc.SameContents, ifaces[:3]) // skip [3] as it's ignored. | 323 | c.Assert(actual, jc.SameContents, ifaces[:4]) // skip the rest as they are ignored. |
738 | 304 | } | 324 | } |
739 | 305 | 325 | ||
740 | 306 | func (s *provisionerSuite) TestSeries(c *gc.C) { | 326 | func (s *provisionerSuite) TestSeries(c *gc.C) { |
741 | 307 | 327 | ||
742 | === modified file 'state/apiserver/provisioner/provisioner.go' | |||
743 | --- state/apiserver/provisioner/provisioner.go 2014-04-11 15:10:48 +0000 | |||
744 | +++ state/apiserver/provisioner/provisioner.go 2014-04-18 16:46:53 +0000 | |||
745 | @@ -435,6 +435,7 @@ | |||
746 | 435 | MACAddress: iface.MACAddress, | 435 | MACAddress: iface.MACAddress, |
747 | 436 | NetworkName: networkName, | 436 | NetworkName: networkName, |
748 | 437 | InterfaceName: iface.InterfaceName, | 437 | InterfaceName: iface.InterfaceName, |
749 | 438 | IsVirtual: iface.IsVirtual, | ||
750 | 438 | } | 439 | } |
751 | 439 | } | 440 | } |
752 | 440 | return stateNetworks, stateInterfaces, nil | 441 | return stateNetworks, stateInterfaces, nil |
753 | 441 | 442 | ||
754 | === modified file 'state/apiserver/provisioner/provisioner_test.go' | |||
755 | --- state/apiserver/provisioner/provisioner_test.go 2014-04-17 12:53:23 +0000 | |||
756 | +++ state/apiserver/provisioner/provisioner_test.go 2014-04-18 16:46:53 +0000 | |||
757 | @@ -862,6 +862,11 @@ | |||
758 | 862 | CIDR: "0.2.2.0/24", | 862 | CIDR: "0.2.2.0/24", |
759 | 863 | VLANTag: 42, | 863 | VLANTag: 42, |
760 | 864 | }, { | 864 | }, { |
761 | 865 | Tag: "network-vlan69", | ||
762 | 866 | ProviderId: "vlan69", | ||
763 | 867 | CIDR: "0.3.2.0/24", | ||
764 | 868 | VLANTag: 69, | ||
765 | 869 | }, { | ||
766 | 865 | Tag: "network-vlan42", // duplicated; ignored | 870 | Tag: "network-vlan42", // duplicated; ignored |
767 | 866 | ProviderId: "vlan42", | 871 | ProviderId: "vlan42", |
768 | 867 | CIDR: "0.2.2.0/24", | 872 | CIDR: "0.2.2.0/24", |
769 | @@ -871,18 +876,32 @@ | |||
770 | 871 | MACAddress: "aa:bb:cc:dd:ee:f0", | 876 | MACAddress: "aa:bb:cc:dd:ee:f0", |
771 | 872 | NetworkTag: "network-net1", | 877 | NetworkTag: "network-net1", |
772 | 873 | InterfaceName: "eth0", | 878 | InterfaceName: "eth0", |
773 | 879 | IsVirtual: false, | ||
774 | 874 | }, { | 880 | }, { |
775 | 875 | MACAddress: "aa:bb:cc:dd:ee:f1", | 881 | MACAddress: "aa:bb:cc:dd:ee:f1", |
776 | 876 | NetworkTag: "network-net1", | 882 | NetworkTag: "network-net1", |
777 | 877 | InterfaceName: "eth1", | 883 | InterfaceName: "eth1", |
778 | 884 | IsVirtual: false, | ||
779 | 885 | }, { | ||
780 | 886 | MACAddress: "aa:bb:cc:dd:ee:f1", | ||
781 | 887 | NetworkTag: "network-vlan42", | ||
782 | 888 | InterfaceName: "eth1.42", | ||
783 | 889 | IsVirtual: true, | ||
784 | 890 | }, { | ||
785 | 891 | MACAddress: "aa:bb:cc:dd:ee:f0", | ||
786 | 892 | NetworkTag: "network-vlan69", | ||
787 | 893 | InterfaceName: "eth0.69", | ||
788 | 894 | IsVirtual: true, | ||
789 | 895 | }, { | ||
790 | 896 | MACAddress: "aa:bb:cc:dd:ee:f1", // duplicated mac+net; ignored | ||
791 | 897 | NetworkTag: "network-vlan42", | ||
792 | 898 | InterfaceName: "eth2", | ||
793 | 899 | IsVirtual: true, | ||
794 | 878 | }, { | 900 | }, { |
795 | 879 | MACAddress: "aa:bb:cc:dd:ee:f2", | 901 | MACAddress: "aa:bb:cc:dd:ee:f2", |
802 | 880 | NetworkTag: "network-vlan42", | 902 | NetworkTag: "network-net1", |
803 | 881 | InterfaceName: "eth2", | 903 | InterfaceName: "eth1", // duplicated name+machine id; ignored for machine 1. |
804 | 882 | }, { | 904 | IsVirtual: false, |
799 | 883 | MACAddress: "aa:bb:cc:dd:ee:f2", // duplicated; ignored | ||
800 | 884 | NetworkTag: "network-vlan42", | ||
801 | 885 | InterfaceName: "eth2", | ||
805 | 886 | }} | 905 | }} |
806 | 887 | args := params.InstancesInfo{Machines: []params.InstanceInfo{{ | 906 | args := params.InstancesInfo{Machines: []params.InstanceInfo{{ |
807 | 888 | Tag: s.machines[0].Tag(), | 907 | Tag: s.machines[0].Tag(), |
808 | @@ -939,21 +958,26 @@ | |||
809 | 939 | c.Check(gotHardware, gc.DeepEquals, &hwChars) | 958 | c.Check(gotHardware, gc.DeepEquals, &hwChars) |
810 | 940 | ifacesMachine1, err := s.machines[1].NetworkInterfaces() | 959 | ifacesMachine1, err := s.machines[1].NetworkInterfaces() |
811 | 941 | c.Assert(err, gc.IsNil) | 960 | c.Assert(err, gc.IsNil) |
813 | 942 | c.Assert(ifacesMachine1, gc.HasLen, 3) | 961 | c.Assert(ifacesMachine1, gc.HasLen, 4) |
814 | 943 | actual := make([]params.NetworkInterface, len(ifacesMachine1)) | 962 | actual := make([]params.NetworkInterface, len(ifacesMachine1)) |
815 | 944 | for i, iface := range ifacesMachine1 { | 963 | for i, iface := range ifacesMachine1 { |
816 | 945 | actual[i].InterfaceName = iface.InterfaceName() | 964 | actual[i].InterfaceName = iface.InterfaceName() |
817 | 946 | actual[i].NetworkTag = iface.NetworkTag() | 965 | actual[i].NetworkTag = iface.NetworkTag() |
818 | 947 | actual[i].MACAddress = iface.MACAddress() | 966 | actual[i].MACAddress = iface.MACAddress() |
819 | 967 | actual[i].IsVirtual = iface.IsVirtual() | ||
820 | 948 | c.Check(iface.MachineId(), gc.Equals, s.machines[1].Id()) | 968 | c.Check(iface.MachineId(), gc.Equals, s.machines[1].Id()) |
821 | 949 | c.Check(iface.MachineTag(), gc.Equals, s.machines[1].Tag()) | 969 | c.Check(iface.MachineTag(), gc.Equals, s.machines[1].Tag()) |
822 | 950 | } | 970 | } |
824 | 951 | c.Assert(actual, jc.SameContents, ifaces[:3]) | 971 | c.Assert(actual, jc.SameContents, ifaces[:4]) |
825 | 952 | ifacesMachine2, err := s.machines[2].NetworkInterfaces() | 972 | ifacesMachine2, err := s.machines[2].NetworkInterfaces() |
826 | 953 | c.Assert(err, gc.IsNil) | 973 | c.Assert(err, gc.IsNil) |
828 | 954 | c.Assert(ifacesMachine2, gc.HasLen, 0) | 974 | c.Assert(ifacesMachine2, gc.HasLen, 1) |
829 | 975 | c.Assert(ifacesMachine2[0].InterfaceName(), gc.Equals, ifaces[5].InterfaceName) | ||
830 | 976 | c.Assert(ifacesMachine2[0].MACAddress(), gc.Equals, ifaces[5].MACAddress) | ||
831 | 977 | c.Assert(ifacesMachine2[0].NetworkTag(), gc.Equals, ifaces[5].NetworkTag) | ||
832 | 978 | c.Assert(ifacesMachine2[0].MachineId(), gc.Equals, s.machines[2].Id()) | ||
833 | 955 | for i, _ := range networks { | 979 | for i, _ := range networks { |
835 | 956 | if i == 2 { | 980 | if i == 3 { |
836 | 957 | // Last one was ignored, so don't check. | 981 | // Last one was ignored, so don't check. |
837 | 958 | break | 982 | break |
838 | 959 | } | 983 | } |
839 | 960 | 984 | ||
840 | === modified file 'state/machine.go' | |||
841 | --- state/machine.go 2014-04-17 16:18:46 +0000 | |||
842 | +++ state/machine.go 2014-04-18 16:46:53 +0000 | |||
843 | @@ -567,16 +567,21 @@ | |||
844 | 567 | } | 567 | } |
845 | 568 | 568 | ||
846 | 569 | func (m *Machine) removeNetworkInterfacesOps() ([]txn.Op, error) { | 569 | func (m *Machine) removeNetworkInterfacesOps() ([]txn.Op, error) { |
849 | 570 | var doc struct { | 570 | if m.doc.Life != Dead { |
850 | 571 | MACAddress string `bson:"_id"` | 571 | return nil, fmt.Errorf("machine is not dead") |
851 | 572 | } | 572 | } |
853 | 573 | ops := []txn.Op{} | 573 | var doc networkInterfaceDoc |
854 | 574 | ops := []txn.Op{{ | ||
855 | 575 | C: m.st.machines.Name, | ||
856 | 576 | Id: m.doc.Id, | ||
857 | 577 | Assert: isDeadDoc, | ||
858 | 578 | }} | ||
859 | 574 | sel := bson.D{{"machineid", m.doc.Id}} | 579 | sel := bson.D{{"machineid", m.doc.Id}} |
860 | 575 | iter := m.st.networkInterfaces.Find(sel).Select(bson.D{{"_id", 1}}).Iter() | 580 | iter := m.st.networkInterfaces.Find(sel).Select(bson.D{{"_id", 1}}).Iter() |
861 | 576 | for iter.Next(&doc) { | 581 | for iter.Next(&doc) { |
862 | 577 | ops = append(ops, txn.Op{ | 582 | ops = append(ops, txn.Op{ |
863 | 578 | C: m.st.networkInterfaces.Name, | 583 | C: m.st.networkInterfaces.Name, |
865 | 579 | Id: doc.MACAddress, | 584 | Id: doc.Id, |
866 | 580 | Remove: true, | 585 | Remove: true, |
867 | 581 | }) | 586 | }) |
868 | 582 | } | 587 | } |
869 | @@ -842,7 +847,7 @@ | |||
870 | 842 | 847 | ||
871 | 843 | // Add the networks and interfaces first. | 848 | // Add the networks and interfaces first. |
872 | 844 | for _, network := range networks { | 849 | for _, network := range networks { |
874 | 845 | _, err := m.st.AddNetwork(network.Name, network.ProviderId, network.CIDR, network.VLANTag) | 850 | _, err := m.st.AddNetwork(network) |
875 | 846 | if err != nil && errors.IsAlreadyExists(err) { | 851 | if err != nil && errors.IsAlreadyExists(err) { |
876 | 847 | // Ignore already existing networks. | 852 | // Ignore already existing networks. |
877 | 848 | continue | 853 | continue |
878 | @@ -851,7 +856,7 @@ | |||
879 | 851 | } | 856 | } |
880 | 852 | } | 857 | } |
881 | 853 | for _, iface := range interfaces { | 858 | for _, iface := range interfaces { |
883 | 854 | _, err := m.AddNetworkInterface(iface.MACAddress, iface.InterfaceName, iface.NetworkName) | 859 | _, err := m.AddNetworkInterface(iface) |
884 | 855 | if err != nil && errors.IsAlreadyExists(err) { | 860 | if err != nil && errors.IsAlreadyExists(err) { |
885 | 856 | // Ignore already existing network interfaces. | 861 | // Ignore already existing network interfaces. |
886 | 857 | continue | 862 | continue |
887 | @@ -996,34 +1001,31 @@ | |||
888 | 996 | return ifaces, nil | 1001 | return ifaces, nil |
889 | 997 | } | 1002 | } |
890 | 998 | 1003 | ||
893 | 999 | // AddNetworkInterface creates a new network interface on the given | 1004 | // AddNetworkInterface creates a new network interface with the given |
894 | 1000 | // network for the machine. The machine must be alive and not yet | 1005 | // args for this machine. The machine must be alive and not yet |
895 | 1001 | // provisioned, and there must be no other interface with the same MAC | 1006 | // provisioned, and there must be no other interface with the same MAC |
901 | 1002 | // address or the same name on that machine for this to succeed. If a | 1007 | // address on the same network, or the same name on that machine for |
902 | 1003 | // network interface already exists, the returned error satisfies | 1008 | // this to succeed. If a network interface already exists, the |
903 | 1004 | // errors.IsAlreadyExists. | 1009 | // returned error satisfies errors.IsAlreadyExists. |
904 | 1005 | func (m *Machine) AddNetworkInterface(macAddress, interfaceName, networkName string) (iface *NetworkInterface, err error) { | 1010 | func (m *Machine) AddNetworkInterface(args NetworkInterfaceInfo) (iface *NetworkInterface, err error) { |
905 | 1006 | defer errors.Contextf(&err, "cannot add network interface %q to machine %q", interfaceName, m.doc.Id) | 1011 | defer errors.Contextf(&err, "cannot add network interface %q to machine %q", args.InterfaceName, m.doc.Id) |
906 | 1007 | 1012 | ||
908 | 1008 | if macAddress == "" { | 1013 | if args.MACAddress == "" { |
909 | 1009 | return nil, fmt.Errorf("MAC address must be not empty") | 1014 | return nil, fmt.Errorf("MAC address must be not empty") |
910 | 1010 | } | 1015 | } |
912 | 1011 | if _, err = net.ParseMAC(macAddress); err != nil { | 1016 | if _, err = net.ParseMAC(args.MACAddress); err != nil { |
913 | 1012 | return nil, err | 1017 | return nil, err |
914 | 1013 | } | 1018 | } |
916 | 1014 | if interfaceName == "" { | 1019 | if args.InterfaceName == "" { |
917 | 1015 | return nil, fmt.Errorf("interface name must be not empty") | 1020 | return nil, fmt.Errorf("interface name must be not empty") |
918 | 1016 | } | 1021 | } |
919 | 1017 | aliveAndNotProvisioned := append(isAliveDoc, bson.D{{"nonce", ""}}...) | 1022 | aliveAndNotProvisioned := append(isAliveDoc, bson.D{{"nonce", ""}}...) |
926 | 1018 | doc := &networkInterfaceDoc{ | 1023 | doc := newNetworkInterfaceDoc(args) |
927 | 1019 | MACAddress: macAddress, | 1024 | doc.MachineId = m.doc.Id |
928 | 1020 | InterfaceName: interfaceName, | 1025 | doc.Id = bson.NewObjectId() |
923 | 1021 | NetworkName: networkName, | ||
924 | 1022 | MachineId: m.doc.Id, | ||
925 | 1023 | } | ||
929 | 1024 | ops := []txn.Op{{ | 1026 | ops := []txn.Op{{ |
930 | 1025 | C: m.st.networks.Name, | 1027 | C: m.st.networks.Name, |
932 | 1026 | Id: networkName, | 1028 | Id: args.NetworkName, |
933 | 1027 | Assert: txn.DocExists, | 1029 | Assert: txn.DocExists, |
934 | 1028 | }, { | 1030 | }, { |
935 | 1029 | C: m.st.machines.Name, | 1031 | C: m.st.machines.Name, |
936 | @@ -1031,7 +1033,7 @@ | |||
937 | 1031 | Assert: aliveAndNotProvisioned, | 1033 | Assert: aliveAndNotProvisioned, |
938 | 1032 | }, { | 1034 | }, { |
939 | 1033 | C: m.st.networkInterfaces.Name, | 1035 | C: m.st.networkInterfaces.Name, |
941 | 1034 | Id: macAddress, | 1036 | Id: doc.Id, |
942 | 1035 | Assert: txn.DocMissing, | 1037 | Assert: txn.DocMissing, |
943 | 1036 | Insert: doc, | 1038 | Insert: doc, |
944 | 1037 | }} | 1039 | }} |
945 | @@ -1039,10 +1041,7 @@ | |||
946 | 1039 | err = m.st.runTransaction(ops) | 1041 | err = m.st.runTransaction(ops) |
947 | 1040 | switch err { | 1042 | switch err { |
948 | 1041 | case txn.ErrAborted: | 1043 | case txn.ErrAborted: |
953 | 1042 | if err = m.st.networkInterfaces.FindId(macAddress).One(nil); err == nil { | 1044 | if _, err = m.st.Network(args.NetworkName); err != nil { |
950 | 1043 | return nil, errors.AlreadyExistsf("interface with MAC address %q", macAddress) | ||
951 | 1044 | } | ||
952 | 1045 | if _, err = m.st.Network(networkName); err != nil { | ||
954 | 1046 | return nil, err | 1045 | return nil, err |
955 | 1047 | } | 1046 | } |
956 | 1048 | if err = m.Refresh(); err != nil { | 1047 | if err = m.Refresh(); err != nil { |
957 | @@ -1053,17 +1052,30 @@ | |||
958 | 1053 | msg := "machine already provisioned: dynamic network interfaces not currently supported" | 1052 | msg := "machine already provisioned: dynamic network interfaces not currently supported" |
959 | 1054 | return nil, fmt.Errorf(msg) | 1053 | return nil, fmt.Errorf(msg) |
960 | 1055 | } | 1054 | } |
961 | 1055 | // Should never happen. | ||
962 | 1056 | logger.Errorf("unhandled assert while adding network interface doc %#v", doc) | ||
963 | 1056 | case nil: | 1057 | case nil: |
967 | 1057 | // We have a unique key restriction on the InterfaceName | 1058 | // We have a unique key restrictions on the following fields: |
968 | 1058 | // field, which will cause the insert to fail if there is | 1059 | // - InterfaceName, MachineId |
969 | 1059 | // another record with the same interface name in the table. | 1060 | // - MACAddress, NetworkName |
970 | 1061 | // These will cause the insert to fail if there is another record | ||
971 | 1062 | // with the same combination of values in the table. | ||
972 | 1060 | // The txn logic does not report insertion errors, so we check | 1063 | // The txn logic does not report insertion errors, so we check |
973 | 1061 | // that the record has actually been inserted correctly before | 1064 | // that the record has actually been inserted correctly before |
974 | 1062 | // reporting success. | 1065 | // reporting success. |
979 | 1063 | if err = m.st.networkInterfaces.FindId(macAddress).One(nil); err != nil { | 1066 | if err = m.st.networkInterfaces.FindId(doc.Id).One(&doc); err == nil { |
980 | 1064 | return nil, errors.AlreadyExistsf("%q on machine %q", interfaceName, m.doc.Id) | 1067 | return newNetworkInterface(m.st, doc), nil |
981 | 1065 | } | 1068 | } |
982 | 1066 | return newNetworkInterface(m.st, doc), nil | 1069 | sel := bson.D{{"interfacename", args.InterfaceName}, {"machineid", m.doc.Id}} |
983 | 1070 | if err = m.st.networkInterfaces.Find(sel).One(nil); err == nil { | ||
984 | 1071 | return nil, errors.AlreadyExistsf("%q on machine %q", args.InterfaceName, m.doc.Id) | ||
985 | 1072 | } | ||
986 | 1073 | sel = bson.D{{"macaddress", args.MACAddress}, {"networkname", args.NetworkName}} | ||
987 | 1074 | if err = m.st.networkInterfaces.Find(sel).One(nil); err == nil { | ||
988 | 1075 | return nil, errors.AlreadyExistsf("MAC address %q on network %q", args.MACAddress, args.NetworkName) | ||
989 | 1076 | } | ||
990 | 1077 | // Should never happen. | ||
991 | 1078 | logger.Errorf("unknown error while adding network interface doc %#v", doc) | ||
992 | 1067 | } | 1079 | } |
993 | 1068 | return nil, err | 1080 | return nil, err |
994 | 1069 | } | 1081 | } |
995 | 1070 | 1082 | ||
996 | === modified file 'state/machine_test.go' | |||
997 | --- state/machine_test.go 2014-04-14 12:36:13 +0000 | |||
998 | +++ state/machine_test.go 2014-04-18 16:46:53 +0000 | |||
999 | @@ -12,6 +12,7 @@ | |||
1000 | 12 | gc "launchpad.net/gocheck" | 12 | gc "launchpad.net/gocheck" |
1001 | 13 | 13 | ||
1002 | 14 | "launchpad.net/juju-core/constraints" | 14 | "launchpad.net/juju-core/constraints" |
1003 | 15 | "launchpad.net/juju-core/environs/network" | ||
1004 | 15 | "launchpad.net/juju-core/errors" | 16 | "launchpad.net/juju-core/errors" |
1005 | 16 | "launchpad.net/juju-core/instance" | 17 | "launchpad.net/juju-core/instance" |
1006 | 17 | "launchpad.net/juju-core/state" | 18 | "launchpad.net/juju-core/state" |
1007 | @@ -389,12 +390,22 @@ | |||
1008 | 389 | } | 390 | } |
1009 | 390 | 391 | ||
1010 | 391 | func addNetworkAndInterface(c *gc.C, st *state.State, machine *state.Machine, | 392 | func addNetworkAndInterface(c *gc.C, st *state.State, machine *state.Machine, |
1012 | 392 | networkName, providerId, cidr string, vlanTag int, | 393 | networkName, providerId, cidr string, vlanTag int, isVirtual bool, |
1013 | 393 | mac, ifaceName string, | 394 | mac, ifaceName string, |
1014 | 394 | ) (*state.Network, *state.NetworkInterface) { | 395 | ) (*state.Network, *state.NetworkInterface) { |
1016 | 395 | net, err := st.AddNetwork(networkName, providerId, cidr, vlanTag) | 396 | net, err := st.AddNetwork(state.NetworkInfo{ |
1017 | 397 | Name: networkName, | ||
1018 | 398 | ProviderId: network.Id(providerId), | ||
1019 | 399 | CIDR: cidr, | ||
1020 | 400 | VLANTag: vlanTag, | ||
1021 | 401 | }) | ||
1022 | 396 | c.Assert(err, gc.IsNil) | 402 | c.Assert(err, gc.IsNil) |
1024 | 397 | iface, err := machine.AddNetworkInterface(mac, ifaceName, networkName) | 403 | iface, err := machine.AddNetworkInterface(state.NetworkInterfaceInfo{ |
1025 | 404 | MACAddress: mac, | ||
1026 | 405 | InterfaceName: ifaceName, | ||
1027 | 406 | NetworkName: networkName, | ||
1028 | 407 | IsVirtual: isVirtual, | ||
1029 | 408 | }) | ||
1030 | 398 | c.Assert(err, gc.IsNil) | 409 | c.Assert(err, gc.IsNil) |
1031 | 399 | return net, iface | 410 | return net, iface |
1032 | 400 | } | 411 | } |
1033 | @@ -419,11 +430,11 @@ | |||
1034 | 419 | 430 | ||
1035 | 420 | net1, _ := addNetworkAndInterface( | 431 | net1, _ := addNetworkAndInterface( |
1036 | 421 | c, s.State, machine, | 432 | c, s.State, machine, |
1038 | 422 | "net1", "net1", "0.1.2.0/24", 0, | 433 | "net1", "net1", "0.1.2.0/24", 0, false, |
1039 | 423 | "aa:bb:cc:dd:ee:f0", "eth0") | 434 | "aa:bb:cc:dd:ee:f0", "eth0") |
1040 | 424 | net2, _ := addNetworkAndInterface( | 435 | net2, _ := addNetworkAndInterface( |
1041 | 425 | c, s.State, machine, | 436 | c, s.State, machine, |
1043 | 426 | "net2", "net2", "0.2.2.0/24", 0, | 437 | "net2", "net2", "0.2.2.0/24", 0, false, |
1044 | 427 | "aa:bb:cc:dd:ee:f1", "eth1") | 438 | "aa:bb:cc:dd:ee:f1", "eth1") |
1045 | 428 | 439 | ||
1046 | 429 | nets, err = machine.Networks() | 440 | nets, err = machine.Networks() |
1047 | @@ -448,15 +459,15 @@ | |||
1048 | 448 | // And a few networks and NICs. | 459 | // And a few networks and NICs. |
1049 | 449 | _, iface0 := addNetworkAndInterface( | 460 | _, iface0 := addNetworkAndInterface( |
1050 | 450 | c, s.State, machine, | 461 | c, s.State, machine, |
1052 | 451 | "net1", "net1", "0.1.2.0/24", 0, | 462 | "net1", "net1", "0.1.2.0/24", 0, false, |
1053 | 452 | "aa:bb:cc:dd:ee:f0", "eth0") | 463 | "aa:bb:cc:dd:ee:f0", "eth0") |
1054 | 453 | _, iface1 := addNetworkAndInterface( | 464 | _, iface1 := addNetworkAndInterface( |
1055 | 454 | c, s.State, machine, | 465 | c, s.State, machine, |
1057 | 455 | "vlan42", "vlan42", "0.1.2.0/30", 42, | 466 | "vlan42", "vlan42", "0.1.2.0/30", 42, true, |
1058 | 456 | "aa:bb:cc:dd:ee:f1", "eth0.42") | 467 | "aa:bb:cc:dd:ee:f1", "eth0.42") |
1059 | 457 | _, iface2 := addNetworkAndInterface( | 468 | _, iface2 := addNetworkAndInterface( |
1060 | 458 | c, s.State, machine, | 469 | c, s.State, machine, |
1062 | 459 | "net2", "net2", "0.2.2.0/24", 0, | 470 | "net2", "net2", "0.2.2.0/24", 0, false, |
1063 | 460 | "aa:bb:cc:dd:ee:f2", "eth1") | 471 | "aa:bb:cc:dd:ee:f2", "eth1") |
1064 | 461 | 472 | ||
1065 | 462 | ifaces, err = machine.NetworkInterfaces() | 473 | ifaces, err = machine.NetworkInterfaces() |
1066 | @@ -476,49 +487,47 @@ | |||
1067 | 476 | } | 487 | } |
1068 | 477 | 488 | ||
1069 | 478 | var addNetworkInterfaceErrorsTests = []struct { | 489 | var addNetworkInterfaceErrorsTests = []struct { |
1075 | 479 | macAddress string | 490 | args state.NetworkInterfaceInfo |
1076 | 480 | interfaceName string | 491 | beforeAdding func(*gc.C, *state.Machine) |
1077 | 481 | networkName string | 492 | expectErr string |
1073 | 482 | beforeAdding func(*gc.C, *state.Machine) | ||
1074 | 483 | expectErr string | ||
1078 | 484 | }{{ | 493 | }{{ |
1080 | 485 | "", "eth1", "net1", | 494 | state.NetworkInterfaceInfo{"", "eth1", "net1", false}, |
1081 | 486 | nil, | 495 | nil, |
1082 | 487 | `cannot add network interface "eth1" to machine "2": MAC address must be not empty`, | 496 | `cannot add network interface "eth1" to machine "2": MAC address must be not empty`, |
1083 | 488 | }, { | 497 | }, { |
1085 | 489 | "invalid", "eth1", "net1", | 498 | state.NetworkInterfaceInfo{"invalid", "eth1", "net1", false}, |
1086 | 490 | nil, | 499 | nil, |
1087 | 491 | `cannot add network interface "eth1" to machine "2": invalid MAC address: invalid`, | 500 | `cannot add network interface "eth1" to machine "2": invalid MAC address: invalid`, |
1088 | 492 | }, { | 501 | }, { |
1090 | 493 | "aa:bb:cc:dd:ee:f0", "eth1", "net1", | 502 | state.NetworkInterfaceInfo{"aa:bb:cc:dd:ee:f0", "eth1", "net1", false}, |
1091 | 494 | nil, | 503 | nil, |
1093 | 495 | `cannot add network interface "eth1" to machine "2": interface with MAC address "aa:bb:cc:dd:ee:f0" already exists`, | 504 | `cannot add network interface "eth1" to machine "2": MAC address "aa:bb:cc:dd:ee:f0" on network "net1" already exists`, |
1094 | 496 | }, { | 505 | }, { |
1096 | 497 | "aa:bb:cc:dd:ee:ff", "", "net1", | 506 | state.NetworkInterfaceInfo{"aa:bb:cc:dd:ee:ff", "", "net1", false}, |
1097 | 498 | nil, | 507 | nil, |
1098 | 499 | `cannot add network interface "" to machine "2": interface name must be not empty`, | 508 | `cannot add network interface "" to machine "2": interface name must be not empty`, |
1099 | 500 | }, { | 509 | }, { |
1101 | 501 | "aa:bb:cc:dd:ee:ff", "eth0", "net1", | 510 | state.NetworkInterfaceInfo{"aa:bb:cc:dd:ee:ff", "eth0", "net1", false}, |
1102 | 502 | nil, | 511 | nil, |
1103 | 503 | `cannot add network interface "eth0" to machine "2": "eth0" on machine "2" already exists`, | 512 | `cannot add network interface "eth0" to machine "2": "eth0" on machine "2" already exists`, |
1104 | 504 | }, { | 513 | }, { |
1106 | 505 | "aa:bb:cc:dd:ee:ff", "eth1", "missing", | 514 | state.NetworkInterfaceInfo{"aa:bb:cc:dd:ee:ff", "eth1", "missing", false}, |
1107 | 506 | nil, | 515 | nil, |
1108 | 507 | `cannot add network interface "eth1" to machine "2": network "missing" not found`, | 516 | `cannot add network interface "eth1" to machine "2": network "missing" not found`, |
1109 | 508 | }, { | 517 | }, { |
1111 | 509 | "aa:bb:cc:dd:ee:f1", "eth1", "net1", | 518 | state.NetworkInterfaceInfo{"aa:bb:cc:dd:ee:f1", "eth1", "net1", false}, |
1112 | 510 | func(c *gc.C, m *state.Machine) { | 519 | func(c *gc.C, m *state.Machine) { |
1113 | 511 | c.Check(m.SetProvisioned("i-am", "fake_nonce", nil), gc.IsNil) | 520 | c.Check(m.SetProvisioned("i-am", "fake_nonce", nil), gc.IsNil) |
1114 | 512 | }, | 521 | }, |
1115 | 513 | `cannot add network interface "eth1" to machine "2": machine already provisioned: dynamic network interfaces not currently supported`, | 522 | `cannot add network interface "eth1" to machine "2": machine already provisioned: dynamic network interfaces not currently supported`, |
1116 | 514 | }, { | 523 | }, { |
1118 | 515 | "aa:bb:cc:dd:ee:f1", "eth1", "net1", | 524 | state.NetworkInterfaceInfo{"aa:bb:cc:dd:ee:f1", "eth1", "net1", false}, |
1119 | 516 | func(c *gc.C, m *state.Machine) { | 525 | func(c *gc.C, m *state.Machine) { |
1120 | 517 | c.Check(m.EnsureDead(), gc.IsNil) | 526 | c.Check(m.EnsureDead(), gc.IsNil) |
1121 | 518 | }, | 527 | }, |
1122 | 519 | `cannot add network interface "eth1" to machine "2": machine is not alive`, | 528 | `cannot add network interface "eth1" to machine "2": machine is not alive`, |
1123 | 520 | }, { | 529 | }, { |
1125 | 521 | "aa:bb:cc:dd:ee:f1", "eth1", "net1", | 530 | state.NetworkInterfaceInfo{"aa:bb:cc:dd:ee:f1", "eth1", "net1", false}, |
1126 | 522 | func(c *gc.C, m *state.Machine) { | 531 | func(c *gc.C, m *state.Machine) { |
1127 | 523 | c.Check(m.Remove(), gc.IsNil) | 532 | c.Check(m.Remove(), gc.IsNil) |
1128 | 524 | }, | 533 | }, |
1129 | @@ -534,18 +543,20 @@ | |||
1130 | 534 | c.Assert(err, gc.IsNil) | 543 | c.Assert(err, gc.IsNil) |
1131 | 535 | addNetworkAndInterface( | 544 | addNetworkAndInterface( |
1132 | 536 | c, s.State, machine, | 545 | c, s.State, machine, |
1134 | 537 | "net1", "provider-net1", "0.1.2.0/24", 0, | 546 | "net1", "provider-net1", "0.1.2.0/24", 0, false, |
1135 | 538 | "aa:bb:cc:dd:ee:f0", "eth0") | 547 | "aa:bb:cc:dd:ee:f0", "eth0") |
1136 | 548 | ifaces, err := machine.NetworkInterfaces() | ||
1137 | 549 | c.Assert(err, gc.IsNil) | ||
1138 | 550 | c.Assert(ifaces, gc.HasLen, 1) | ||
1139 | 539 | 551 | ||
1140 | 540 | for i, test := range addNetworkInterfaceErrorsTests { | 552 | for i, test := range addNetworkInterfaceErrorsTests { |
1143 | 541 | c.Logf("test %d: mac=%q, name=%q, network=%q", | 553 | c.Logf("test %d: %#v", i, test.args) |
1142 | 542 | i, test.macAddress, test.interfaceName, test.networkName) | ||
1144 | 543 | 554 | ||
1145 | 544 | if test.beforeAdding != nil { | 555 | if test.beforeAdding != nil { |
1146 | 545 | test.beforeAdding(c, machine) | 556 | test.beforeAdding(c, machine) |
1147 | 546 | } | 557 | } |
1148 | 547 | 558 | ||
1150 | 548 | _, err = machine.AddNetworkInterface(test.macAddress, test.interfaceName, test.networkName) | 559 | _, err = machine.AddNetworkInterface(test.args) |
1151 | 549 | c.Check(err, gc.ErrorMatches, test.expectErr) | 560 | c.Check(err, gc.ErrorMatches, test.expectErr) |
1152 | 550 | if strings.Contains(test.expectErr, "not found") { | 561 | if strings.Contains(test.expectErr, "not found") { |
1153 | 551 | c.Check(err, jc.Satisfies, errors.IsNotFound) | 562 | c.Check(err, jc.Satisfies, errors.IsNotFound) |
1154 | @@ -685,9 +696,11 @@ | |||
1155 | 685 | 696 | ||
1156 | 686 | func (s *MachineSuite) TestMachineSetInstanceInfoSuccess(c *gc.C) { | 697 | func (s *MachineSuite) TestMachineSetInstanceInfoSuccess(c *gc.C) { |
1157 | 687 | c.Assert(s.machine.CheckProvisioned("fake_nonce"), gc.Equals, false) | 698 | c.Assert(s.machine.CheckProvisioned("fake_nonce"), gc.Equals, false) |
1159 | 688 | networks := []state.NetworkInfo{{Name: "net1", ProviderId: "net1", CIDR: "0.1.2.0/24", VLANTag: 0}} | 699 | networks := []state.NetworkInfo{ |
1160 | 700 | {Name: "net1", ProviderId: "net1", CIDR: "0.1.2.0/24", VLANTag: 0}, | ||
1161 | 701 | } | ||
1162 | 689 | interfaces := []state.NetworkInterfaceInfo{ | 702 | interfaces := []state.NetworkInterfaceInfo{ |
1164 | 690 | {MACAddress: "aa:bb:cc:dd:ee:ff", NetworkName: "net1", InterfaceName: "eth0"}, | 703 | {MACAddress: "aa:bb:cc:dd:ee:ff", NetworkName: "net1", InterfaceName: "eth0", IsVirtual: false}, |
1165 | 691 | } | 704 | } |
1166 | 692 | err := s.machine.SetInstanceInfo("umbrella/0", "fake_nonce", nil, networks, interfaces) | 705 | err := s.machine.SetInstanceInfo("umbrella/0", "fake_nonce", nil, networks, interfaces) |
1167 | 693 | c.Assert(err, gc.IsNil) | 706 | c.Assert(err, gc.IsNil) |
1168 | @@ -705,6 +718,7 @@ | |||
1169 | 705 | c.Check(ifaces[0].NetworkName(), gc.Equals, interfaces[0].NetworkName) | 718 | c.Check(ifaces[0].NetworkName(), gc.Equals, interfaces[0].NetworkName) |
1170 | 706 | c.Check(ifaces[0].MACAddress(), gc.Equals, interfaces[0].MACAddress) | 719 | c.Check(ifaces[0].MACAddress(), gc.Equals, interfaces[0].MACAddress) |
1171 | 707 | c.Check(ifaces[0].MachineTag(), gc.Equals, s.machine.Tag()) | 720 | c.Check(ifaces[0].MachineTag(), gc.Equals, s.machine.Tag()) |
1172 | 721 | c.Check(ifaces[0].IsVirtual(), gc.Equals, interfaces[0].IsVirtual) | ||
1173 | 708 | } | 722 | } |
1174 | 709 | 723 | ||
1175 | 710 | func (s *MachineSuite) TestMachineSetProvisionedWhenNotAlive(c *gc.C) { | 724 | func (s *MachineSuite) TestMachineSetProvisionedWhenNotAlive(c *gc.C) { |
1176 | 711 | 725 | ||
1177 | === modified file 'state/networkinterfaces.go' | |||
1178 | --- state/networkinterfaces.go 2014-04-11 15:10:48 +0000 | |||
1179 | +++ state/networkinterfaces.go 2014-04-18 16:46:53 +0000 | |||
1180 | @@ -4,6 +4,10 @@ | |||
1181 | 4 | package state | 4 | package state |
1182 | 5 | 5 | ||
1183 | 6 | import ( | 6 | import ( |
1184 | 7 | "fmt" | ||
1185 | 8 | |||
1186 | 9 | "labix.org/v2/mgo/bson" | ||
1187 | 10 | |||
1188 | 7 | "launchpad.net/juju-core/names" | 11 | "launchpad.net/juju-core/names" |
1189 | 8 | ) | 12 | ) |
1190 | 9 | 13 | ||
1191 | @@ -27,25 +31,49 @@ | |||
1192 | 27 | 31 | ||
1193 | 28 | // NetworkName is this interface's network name. | 32 | // NetworkName is this interface's network name. |
1194 | 29 | NetworkName string | 33 | NetworkName string |
1195 | 34 | |||
1196 | 35 | // IsVirtual is true when the interface is a virtual device, as | ||
1197 | 36 | // opposed to a physical device. | ||
1198 | 37 | IsVirtual bool | ||
1199 | 30 | } | 38 | } |
1200 | 31 | 39 | ||
1201 | 32 | // networkInterfaceDoc represents a network interface for a machine on | 40 | // networkInterfaceDoc represents a network interface for a machine on |
1202 | 33 | // a given network. | 41 | // a given network. |
1203 | 34 | // | ||
1204 | 35 | // TODO(dimitern) To allow multiple virtual (e.g. VLAN) interfaces on | ||
1205 | 36 | // the same MAC address, we need to change the key and uniqueness | ||
1206 | 37 | // constraints. | ||
1207 | 38 | type networkInterfaceDoc struct { | 42 | type networkInterfaceDoc struct { |
1209 | 39 | MACAddress string `bson:"_id"` | 43 | Id bson.ObjectId `bson:"_id"` |
1210 | 44 | MACAddress string | ||
1211 | 40 | InterfaceName string | 45 | InterfaceName string |
1212 | 41 | NetworkName string | 46 | NetworkName string |
1213 | 42 | MachineId string | 47 | MachineId string |
1214 | 48 | IsVirtual bool | ||
1215 | 43 | } | 49 | } |
1216 | 44 | 50 | ||
1217 | 45 | func newNetworkInterface(st *State, doc *networkInterfaceDoc) *NetworkInterface { | 51 | func newNetworkInterface(st *State, doc *networkInterfaceDoc) *NetworkInterface { |
1218 | 46 | return &NetworkInterface{st, *doc} | 52 | return &NetworkInterface{st, *doc} |
1219 | 47 | } | 53 | } |
1220 | 48 | 54 | ||
1221 | 55 | func newNetworkInterfaceDoc(args NetworkInterfaceInfo) *networkInterfaceDoc { | ||
1222 | 56 | // This does not set the machine id. | ||
1223 | 57 | return &networkInterfaceDoc{ | ||
1224 | 58 | MACAddress: args.MACAddress, | ||
1225 | 59 | InterfaceName: args.InterfaceName, | ||
1226 | 60 | NetworkName: args.NetworkName, | ||
1227 | 61 | IsVirtual: args.IsVirtual, | ||
1228 | 62 | } | ||
1229 | 63 | } | ||
1230 | 64 | |||
1231 | 65 | // GoString implements fmt.GoStringer. | ||
1232 | 66 | func (ni *NetworkInterface) GoString() string { | ||
1233 | 67 | return fmt.Sprintf( | ||
1234 | 68 | "&state.NetworkInterface{machineId: %q, mac: %q, name: %q, networkName: %q, isVirtual: %v}", | ||
1235 | 69 | ni.MachineId(), ni.MACAddress(), ni.InterfaceName(), ni.NetworkName(), ni.IsVirtual()) | ||
1236 | 70 | } | ||
1237 | 71 | |||
1238 | 72 | // Id returns the internal juju-specific id of the interface. | ||
1239 | 73 | func (ni *NetworkInterface) Id() string { | ||
1240 | 74 | return ni.doc.Id.String() | ||
1241 | 75 | } | ||
1242 | 76 | |||
1243 | 49 | // MACAddress returns the MAC address of the interface. | 77 | // MACAddress returns the MAC address of the interface. |
1244 | 50 | func (ni *NetworkInterface) MACAddress() string { | 78 | func (ni *NetworkInterface) MACAddress() string { |
1245 | 51 | return ni.doc.MACAddress | 79 | return ni.doc.MACAddress |
1246 | @@ -56,7 +84,7 @@ | |||
1247 | 56 | return ni.doc.InterfaceName | 84 | return ni.doc.InterfaceName |
1248 | 57 | } | 85 | } |
1249 | 58 | 86 | ||
1251 | 59 | // NetworkId returns the network name of the interface. | 87 | // NetworkName returns the network name of the interface. |
1252 | 60 | func (ni *NetworkInterface) NetworkName() string { | 88 | func (ni *NetworkInterface) NetworkName() string { |
1253 | 61 | return ni.doc.NetworkName | 89 | return ni.doc.NetworkName |
1254 | 62 | } | 90 | } |
1255 | @@ -75,3 +103,15 @@ | |||
1256 | 75 | func (ni *NetworkInterface) MachineTag() string { | 103 | func (ni *NetworkInterface) MachineTag() string { |
1257 | 76 | return names.MachineTag(ni.doc.MachineId) | 104 | return names.MachineTag(ni.doc.MachineId) |
1258 | 77 | } | 105 | } |
1259 | 106 | |||
1260 | 107 | // IsVirtual returns whether the interface represents a virtual | ||
1261 | 108 | // device. | ||
1262 | 109 | func (ni *NetworkInterface) IsVirtual() bool { | ||
1263 | 110 | return ni.doc.IsVirtual | ||
1264 | 111 | } | ||
1265 | 112 | |||
1266 | 113 | // IsPhysical returns whether the interface represents a physical | ||
1267 | 114 | // device. | ||
1268 | 115 | func (ni *NetworkInterface) IsPhysical() bool { | ||
1269 | 116 | return !ni.doc.IsVirtual | ||
1270 | 117 | } | ||
1271 | 78 | 118 | ||
1272 | === modified file 'state/networkinterfaces_test.go' | |||
1273 | --- state/networkinterfaces_test.go 2014-04-10 14:40:34 +0000 | |||
1274 | +++ state/networkinterfaces_test.go 2014-04-18 16:46:53 +0000 | |||
1275 | @@ -4,6 +4,7 @@ | |||
1276 | 4 | package state_test | 4 | package state_test |
1277 | 5 | 5 | ||
1278 | 6 | import ( | 6 | import ( |
1279 | 7 | jc "github.com/juju/testing/checkers" | ||
1280 | 7 | gc "launchpad.net/gocheck" | 8 | gc "launchpad.net/gocheck" |
1281 | 8 | 9 | ||
1282 | 9 | "launchpad.net/juju-core/state" | 10 | "launchpad.net/juju-core/state" |
1283 | @@ -23,17 +24,25 @@ | |||
1284 | 23 | var err error | 24 | var err error |
1285 | 24 | s.machine, err = s.State.AddMachine("quantal", state.JobHostUnits) | 25 | s.machine, err = s.State.AddMachine("quantal", state.JobHostUnits) |
1286 | 25 | c.Assert(err, gc.IsNil) | 26 | c.Assert(err, gc.IsNil) |
1288 | 26 | s.network, err = s.State.AddNetwork("net1", "net1", "0.1.2.3/24", 42) | 27 | s.network, err = s.State.AddNetwork(state.NetworkInfo{"net1", "net1", "0.1.2.3/24", 42}) |
1289 | 27 | c.Assert(err, gc.IsNil) | 28 | c.Assert(err, gc.IsNil) |
1291 | 28 | s.iface, err = s.machine.AddNetworkInterface("aa:bb:cc:dd:ee:ff", "eth0", "net1") | 29 | s.iface, err = s.machine.AddNetworkInterface(state.NetworkInterfaceInfo{ |
1292 | 30 | MACAddress: "aa:bb:cc:dd:ee:ff", | ||
1293 | 31 | InterfaceName: "eth0", | ||
1294 | 32 | NetworkName: "net1", | ||
1295 | 33 | IsVirtual: true, | ||
1296 | 34 | }) | ||
1297 | 29 | c.Assert(err, gc.IsNil) | 35 | c.Assert(err, gc.IsNil) |
1298 | 30 | } | 36 | } |
1299 | 31 | 37 | ||
1300 | 32 | func (s *NetworkInterfaceSuite) TestGetterMethods(c *gc.C) { | 38 | func (s *NetworkInterfaceSuite) TestGetterMethods(c *gc.C) { |
1301 | 39 | c.Assert(s.iface.Id(), gc.Not(gc.Equals), "") | ||
1302 | 33 | c.Assert(s.iface.MACAddress(), gc.Equals, "aa:bb:cc:dd:ee:ff") | 40 | c.Assert(s.iface.MACAddress(), gc.Equals, "aa:bb:cc:dd:ee:ff") |
1303 | 34 | c.Assert(s.iface.InterfaceName(), gc.Equals, "eth0") | 41 | c.Assert(s.iface.InterfaceName(), gc.Equals, "eth0") |
1304 | 35 | c.Assert(s.iface.NetworkName(), gc.Equals, s.network.Name()) | 42 | c.Assert(s.iface.NetworkName(), gc.Equals, s.network.Name()) |
1305 | 36 | c.Assert(s.iface.NetworkTag(), gc.Equals, s.network.Tag()) | 43 | c.Assert(s.iface.NetworkTag(), gc.Equals, s.network.Tag()) |
1306 | 37 | c.Assert(s.iface.MachineId(), gc.Equals, s.machine.Id()) | 44 | c.Assert(s.iface.MachineId(), gc.Equals, s.machine.Id()) |
1307 | 38 | c.Assert(s.iface.MachineTag(), gc.Equals, s.machine.Tag()) | 45 | c.Assert(s.iface.MachineTag(), gc.Equals, s.machine.Tag()) |
1308 | 46 | c.Assert(s.iface.IsVirtual(), jc.IsTrue) | ||
1309 | 47 | c.Assert(s.iface.IsPhysical(), jc.IsFalse) | ||
1310 | 39 | } | 48 | } |
1311 | 40 | 49 | ||
1312 | === modified file 'state/networks.go' | |||
1313 | --- state/networks.go 2014-04-11 15:10:48 +0000 | |||
1314 | +++ state/networks.go 2014-04-18 16:46:53 +0000 | |||
1315 | @@ -4,8 +4,11 @@ | |||
1316 | 4 | package state | 4 | package state |
1317 | 5 | 5 | ||
1318 | 6 | import ( | 6 | import ( |
1319 | 7 | "fmt" | ||
1320 | 8 | |||
1321 | 7 | "labix.org/v2/mgo/bson" | 9 | "labix.org/v2/mgo/bson" |
1322 | 8 | 10 | ||
1323 | 11 | "launchpad.net/juju-core/environs/network" | ||
1324 | 9 | "launchpad.net/juju-core/names" | 12 | "launchpad.net/juju-core/names" |
1325 | 10 | ) | 13 | ) |
1326 | 11 | 14 | ||
1327 | @@ -21,7 +24,7 @@ | |||
1328 | 21 | Name string | 24 | Name string |
1329 | 22 | 25 | ||
1330 | 23 | // ProviderId is a provider-specific network id. | 26 | // ProviderId is a provider-specific network id. |
1332 | 24 | ProviderId string | 27 | ProviderId network.Id |
1333 | 25 | 28 | ||
1334 | 26 | // CIDR of the network, in 123.45.67.89/24 format. | 29 | // CIDR of the network, in 123.45.67.89/24 format. |
1335 | 27 | CIDR string | 30 | CIDR string |
1336 | @@ -38,7 +41,7 @@ | |||
1337 | 38 | // included networks. | 41 | // included networks. |
1338 | 39 | Name string `bson:"_id"` | 42 | Name string `bson:"_id"` |
1339 | 40 | 43 | ||
1341 | 41 | ProviderId string | 44 | ProviderId network.Id |
1342 | 42 | CIDR string | 45 | CIDR string |
1343 | 43 | VLANTag int | 46 | VLANTag int |
1344 | 44 | } | 47 | } |
1345 | @@ -47,13 +50,29 @@ | |||
1346 | 47 | return &Network{st, *doc} | 50 | return &Network{st, *doc} |
1347 | 48 | } | 51 | } |
1348 | 49 | 52 | ||
1349 | 53 | func newNetworkDoc(args NetworkInfo) *networkDoc { | ||
1350 | 54 | return &networkDoc{ | ||
1351 | 55 | Name: args.Name, | ||
1352 | 56 | ProviderId: args.ProviderId, | ||
1353 | 57 | CIDR: args.CIDR, | ||
1354 | 58 | VLANTag: args.VLANTag, | ||
1355 | 59 | } | ||
1356 | 60 | } | ||
1357 | 61 | |||
1358 | 62 | // GoString implements fmt.GoStringer. | ||
1359 | 63 | func (n *Network) GoString() string { | ||
1360 | 64 | return fmt.Sprintf( | ||
1361 | 65 | "&state.Network{name: %q, providerId: %q, cidr: %q, vlanTag: %v}", | ||
1362 | 66 | n.Name(), n.ProviderId(), n.CIDR(), n.VLANTag()) | ||
1363 | 67 | } | ||
1364 | 68 | |||
1365 | 50 | // Name returns the network name. | 69 | // Name returns the network name. |
1366 | 51 | func (n *Network) Name() string { | 70 | func (n *Network) Name() string { |
1367 | 52 | return n.doc.Name | 71 | return n.doc.Name |
1368 | 53 | } | 72 | } |
1369 | 54 | 73 | ||
1370 | 55 | // ProviderId returns the provider-specific id of the network. | 74 | // ProviderId returns the provider-specific id of the network. |
1372 | 56 | func (n *Network) ProviderId() string { | 75 | func (n *Network) ProviderId() network.Id { |
1373 | 57 | return n.doc.ProviderId | 76 | return n.doc.ProviderId |
1374 | 58 | } | 77 | } |
1375 | 59 | 78 | ||
1376 | 60 | 79 | ||
1377 | === modified file 'state/networks_test.go' | |||
1378 | --- state/networks_test.go 2014-04-10 14:40:34 +0000 | |||
1379 | +++ state/networks_test.go 2014-04-18 16:46:53 +0000 | |||
1380 | @@ -24,15 +24,15 @@ | |||
1381 | 24 | var err error | 24 | var err error |
1382 | 25 | s.machine, err = s.State.AddMachine("quantal", state.JobHostUnits) | 25 | s.machine, err = s.State.AddMachine("quantal", state.JobHostUnits) |
1383 | 26 | c.Assert(err, gc.IsNil) | 26 | c.Assert(err, gc.IsNil) |
1385 | 27 | s.network, err = s.State.AddNetwork("net1", "net1", "0.1.2.3/24", 0) | 27 | s.network, err = s.State.AddNetwork(state.NetworkInfo{"net1", "net1", "0.1.2.3/24", 0}) |
1386 | 28 | c.Assert(err, gc.IsNil) | 28 | c.Assert(err, gc.IsNil) |
1388 | 29 | s.vlan, err = s.State.AddNetwork("vlan", "vlan", "0.1.2.3/30", 42) | 29 | s.vlan, err = s.State.AddNetwork(state.NetworkInfo{"vlan", "vlan", "0.1.2.3/30", 42}) |
1389 | 30 | c.Assert(err, gc.IsNil) | 30 | c.Assert(err, gc.IsNil) |
1390 | 31 | } | 31 | } |
1391 | 32 | 32 | ||
1392 | 33 | func (s *NetworkSuite) TestGetterMethods(c *gc.C) { | 33 | func (s *NetworkSuite) TestGetterMethods(c *gc.C) { |
1393 | 34 | c.Assert(s.network.Name(), gc.Equals, "net1") | 34 | c.Assert(s.network.Name(), gc.Equals, "net1") |
1395 | 35 | c.Assert(s.network.ProviderId(), gc.Equals, "net1") | 35 | c.Assert(string(s.network.ProviderId()), gc.Equals, "net1") |
1396 | 36 | c.Assert(s.network.Tag(), gc.Equals, "network-net1") | 36 | c.Assert(s.network.Tag(), gc.Equals, "network-net1") |
1397 | 37 | c.Assert(s.network.CIDR(), gc.Equals, "0.1.2.3/24") | 37 | c.Assert(s.network.CIDR(), gc.Equals, "0.1.2.3/24") |
1398 | 38 | c.Assert(s.network.VLANTag(), gc.Equals, 0) | 38 | c.Assert(s.network.VLANTag(), gc.Equals, 0) |
1399 | @@ -46,9 +46,19 @@ | |||
1400 | 46 | c.Assert(err, gc.IsNil) | 46 | c.Assert(err, gc.IsNil) |
1401 | 47 | c.Assert(ifaces, gc.HasLen, 0) | 47 | c.Assert(ifaces, gc.HasLen, 0) |
1402 | 48 | 48 | ||
1404 | 49 | iface0, err := s.machine.AddNetworkInterface("aa:bb:cc:dd:ee:f0", "eth0", "net1") | 49 | iface0, err := s.machine.AddNetworkInterface(state.NetworkInterfaceInfo{ |
1405 | 50 | MACAddress: "aa:bb:cc:dd:ee:f0", | ||
1406 | 51 | InterfaceName: "eth0", | ||
1407 | 52 | NetworkName: "net1", | ||
1408 | 53 | IsVirtual: false, | ||
1409 | 54 | }) | ||
1410 | 50 | c.Assert(err, gc.IsNil) | 55 | c.Assert(err, gc.IsNil) |
1412 | 51 | iface1, err := s.machine.AddNetworkInterface("aa:bb:cc:dd:ee:f1", "eth1", "net1") | 56 | iface1, err := s.machine.AddNetworkInterface(state.NetworkInterfaceInfo{ |
1413 | 57 | MACAddress: "aa:bb:cc:dd:ee:f1", | ||
1414 | 58 | InterfaceName: "eth1", | ||
1415 | 59 | NetworkName: "net1", | ||
1416 | 60 | IsVirtual: false, | ||
1417 | 61 | }) | ||
1418 | 52 | c.Assert(err, gc.IsNil) | 62 | c.Assert(err, gc.IsNil) |
1419 | 53 | 63 | ||
1420 | 54 | ifaces, err = s.network.Interfaces() | 64 | ifaces, err = s.network.Interfaces() |
1421 | 55 | 65 | ||
1422 | === modified file 'state/open.go' | |||
1423 | --- state/open.go 2014-04-17 17:30:48 +0000 | |||
1424 | +++ state/open.go 2014-04-18 16:46:53 +0000 | |||
1425 | @@ -209,6 +209,7 @@ | |||
1426 | 209 | {"users", []string{"name"}, false}, | 209 | {"users", []string{"name"}, false}, |
1427 | 210 | {"networks", []string{"providerid"}, true}, | 210 | {"networks", []string{"providerid"}, true}, |
1428 | 211 | {"networkinterfaces", []string{"interfacename", "machineid"}, true}, | 211 | {"networkinterfaces", []string{"interfacename", "machineid"}, true}, |
1429 | 212 | {"networkinterfaces", []string{"macaddress", "networkname"}, true}, | ||
1430 | 212 | {"networkinterfaces", []string{"networkname"}, false}, | 213 | {"networkinterfaces", []string{"networkname"}, false}, |
1431 | 213 | {"networkinterfaces", []string{"machineid"}, false}, | 214 | {"networkinterfaces", []string{"machineid"}, false}, |
1432 | 214 | } | 215 | } |
1433 | 215 | 216 | ||
1434 | === modified file 'state/state.go' | |||
1435 | --- state/state.go 2014-04-17 16:18:46 +0000 | |||
1436 | +++ state/state.go 2014-04-18 16:46:53 +0000 | |||
1437 | @@ -1014,47 +1014,41 @@ | |||
1438 | 1014 | return svc, nil | 1014 | return svc, nil |
1439 | 1015 | } | 1015 | } |
1440 | 1016 | 1016 | ||
1449 | 1017 | // AddNetwork creates a new network with the given name, | 1017 | // AddNetwork creates a new network with the given params. If a |
1450 | 1018 | // provider-specific id, CIDR and VLAN tag. If a network with the same | 1018 | // network with the same name or provider id already exists in state, |
1451 | 1019 | // name or provider id already exists in state, an error satisfying | 1019 | // an error satisfying errors.IsAlreadyExists is returned. |
1452 | 1020 | // errors.IsAlreadyExists is returned. | 1020 | func (st *State) AddNetwork(args NetworkInfo) (n *Network, err error) { |
1453 | 1021 | func (st *State) AddNetwork(name, providerId, cidr string, vlanTag int) (n *Network, err error) { | 1021 | defer errors.Contextf(&err, "cannot add network %q", args.Name) |
1454 | 1022 | defer errors.Contextf(&err, "cannot add network %q", name) | 1022 | if args.CIDR != "" { |
1455 | 1023 | if cidr != "" { | 1023 | _, _, err := net.ParseCIDR(args.CIDR) |
1448 | 1024 | _, _, err := net.ParseCIDR(cidr) | ||
1456 | 1025 | if err != nil { | 1024 | if err != nil { |
1457 | 1026 | return nil, err | 1025 | return nil, err |
1458 | 1027 | } | 1026 | } |
1459 | 1028 | } | 1027 | } |
1461 | 1029 | if name == "" { | 1028 | if args.Name == "" { |
1462 | 1030 | return nil, fmt.Errorf("name must be not empty") | 1029 | return nil, fmt.Errorf("name must be not empty") |
1463 | 1031 | } | 1030 | } |
1465 | 1032 | if !names.IsNetwork(name) { | 1031 | if !names.IsNetwork(args.Name) { |
1466 | 1033 | return nil, fmt.Errorf("invalid name") | 1032 | return nil, fmt.Errorf("invalid name") |
1467 | 1034 | } | 1033 | } |
1469 | 1035 | if providerId == "" { | 1034 | if args.ProviderId == "" { |
1470 | 1036 | return nil, fmt.Errorf("provider id must be not empty") | 1035 | return nil, fmt.Errorf("provider id must be not empty") |
1471 | 1037 | } | 1036 | } |
1481 | 1038 | if vlanTag < 0 || vlanTag > 4094 { | 1037 | if args.VLANTag < 0 || args.VLANTag > 4094 { |
1482 | 1039 | return nil, fmt.Errorf("invalid VLAN tag %d: must be between 0 and 4094", vlanTag) | 1038 | return nil, fmt.Errorf("invalid VLAN tag %d: must be between 0 and 4094", args.VLANTag) |
1483 | 1040 | } | 1039 | } |
1484 | 1041 | doc := &networkDoc{ | 1040 | doc := newNetworkDoc(args) |
1476 | 1042 | Name: name, | ||
1477 | 1043 | ProviderId: providerId, | ||
1478 | 1044 | CIDR: cidr, | ||
1479 | 1045 | VLANTag: vlanTag, | ||
1480 | 1046 | } | ||
1485 | 1047 | ops := []txn.Op{{ | 1041 | ops := []txn.Op{{ |
1486 | 1048 | C: st.networks.Name, | 1042 | C: st.networks.Name, |
1488 | 1049 | Id: name, | 1043 | Id: args.Name, |
1489 | 1050 | Assert: txn.DocMissing, | 1044 | Assert: txn.DocMissing, |
1490 | 1051 | Insert: doc, | 1045 | Insert: doc, |
1491 | 1052 | }} | 1046 | }} |
1492 | 1053 | err = st.runTransaction(ops) | 1047 | err = st.runTransaction(ops) |
1493 | 1054 | switch err { | 1048 | switch err { |
1494 | 1055 | case txn.ErrAborted: | 1049 | case txn.ErrAborted: |
1497 | 1056 | if _, err = st.Network(name); err == nil { | 1050 | if _, err = st.Network(args.Name); err == nil { |
1498 | 1057 | return nil, errors.AlreadyExistsf("network %q", name) | 1051 | return nil, errors.AlreadyExistsf("network %q", args.Name) |
1499 | 1058 | } else if err != nil { | 1052 | } else if err != nil { |
1500 | 1059 | return nil, err | 1053 | return nil, err |
1501 | 1060 | } | 1054 | } |
1502 | @@ -1065,8 +1059,8 @@ | |||
1503 | 1065 | // logic does not report insertion errors, so we check that | 1059 | // logic does not report insertion errors, so we check that |
1504 | 1066 | // the record has actually been inserted correctly before | 1060 | // the record has actually been inserted correctly before |
1505 | 1067 | // reporting success. | 1061 | // reporting success. |
1508 | 1068 | if _, err = st.Network(name); err != nil { | 1062 | if _, err = st.Network(args.Name); err != nil { |
1509 | 1069 | return nil, errors.AlreadyExistsf("network with provider id %q", providerId) | 1063 | return nil, errors.AlreadyExistsf("network with provider id %q", args.ProviderId) |
1510 | 1070 | } | 1064 | } |
1511 | 1071 | return newNetwork(st, doc), nil | 1065 | return newNetwork(st, doc), nil |
1512 | 1072 | } | 1066 | } |
1513 | 1073 | 1067 | ||
1514 | === modified file 'state/state_test.go' | |||
1515 | --- state/state_test.go 2014-04-17 15:32:49 +0000 | |||
1516 | +++ state/state_test.go 2014-04-18 16:46:53 +0000 | |||
1517 | @@ -963,34 +963,31 @@ | |||
1518 | 963 | } | 963 | } |
1519 | 964 | 964 | ||
1520 | 965 | var addNetworkErrorsTests = []struct { | 965 | var addNetworkErrorsTests = []struct { |
1526 | 966 | name string | 966 | args state.NetworkInfo |
1527 | 967 | providerId string | 967 | expectErr string |
1523 | 968 | cidr string | ||
1524 | 969 | vlanTag int | ||
1525 | 970 | expectErr string | ||
1528 | 971 | }{{ | 968 | }{{ |
1530 | 972 | "", "provider-id", "0.3.1.0/24", 0, | 969 | state.NetworkInfo{"", "provider-id", "0.3.1.0/24", 0}, |
1531 | 973 | `cannot add network "": name must be not empty`, | 970 | `cannot add network "": name must be not empty`, |
1532 | 974 | }, { | 971 | }, { |
1534 | 975 | "-invalid-", "provider-id", "0.3.1.0/24", 0, | 972 | state.NetworkInfo{"-invalid-", "provider-id", "0.3.1.0/24", 0}, |
1535 | 976 | `cannot add network "-invalid-": invalid name`, | 973 | `cannot add network "-invalid-": invalid name`, |
1536 | 977 | }, { | 974 | }, { |
1538 | 978 | "net2", "", "0.3.1.0/24", 0, | 975 | state.NetworkInfo{"net2", "", "0.3.1.0/24", 0}, |
1539 | 979 | `cannot add network "net2": provider id must be not empty`, | 976 | `cannot add network "net2": provider id must be not empty`, |
1540 | 980 | }, { | 977 | }, { |
1542 | 981 | "net2", "provider-id", "invalid", 0, | 978 | state.NetworkInfo{"net2", "provider-id", "invalid", 0}, |
1543 | 982 | `cannot add network "net2": invalid CIDR address: invalid`, | 979 | `cannot add network "net2": invalid CIDR address: invalid`, |
1544 | 983 | }, { | 980 | }, { |
1546 | 984 | "net2", "provider-id", "0.3.1.0/24", -1, | 981 | state.NetworkInfo{"net2", "provider-id", "0.3.1.0/24", -1}, |
1547 | 985 | `cannot add network "net2": invalid VLAN tag -1: must be between 0 and 4094`, | 982 | `cannot add network "net2": invalid VLAN tag -1: must be between 0 and 4094`, |
1548 | 986 | }, { | 983 | }, { |
1550 | 987 | "net2", "provider-id", "0.3.1.0/24", 9999, | 984 | state.NetworkInfo{"net2", "provider-id", "0.3.1.0/24", 9999}, |
1551 | 988 | `cannot add network "net2": invalid VLAN tag 9999: must be between 0 and 4094`, | 985 | `cannot add network "net2": invalid VLAN tag 9999: must be between 0 and 4094`, |
1552 | 989 | }, { | 986 | }, { |
1554 | 990 | "net1", "provider-id", "0.3.1.0/24", 0, | 987 | state.NetworkInfo{"net1", "provider-id", "0.3.1.0/24", 0}, |
1555 | 991 | `cannot add network "net1": network "net1" already exists`, | 988 | `cannot add network "net1": network "net1" already exists`, |
1556 | 992 | }, { | 989 | }, { |
1558 | 993 | "net2", "provider-net1", "0.3.1.0/24", 0, | 990 | state.NetworkInfo{"net2", "provider-net1", "0.3.1.0/24", 0}, |
1559 | 994 | `cannot add network "net2": network with provider id "provider-net1" already exists`, | 991 | `cannot add network "net2": network with provider id "provider-net1" already exists`, |
1560 | 995 | }} | 992 | }} |
1561 | 996 | 993 | ||
1562 | @@ -1005,22 +1002,21 @@ | |||
1563 | 1005 | 1002 | ||
1564 | 1006 | net1, _ := addNetworkAndInterface( | 1003 | net1, _ := addNetworkAndInterface( |
1565 | 1007 | c, s.State, machine, | 1004 | c, s.State, machine, |
1567 | 1008 | "net1", "provider-net1", "0.1.2.0/24", 0, | 1005 | "net1", "provider-net1", "0.1.2.0/24", 0, false, |
1568 | 1009 | "aa:bb:cc:dd:ee:f0", "eth0") | 1006 | "aa:bb:cc:dd:ee:f0", "eth0") |
1569 | 1010 | 1007 | ||
1570 | 1011 | net, err := s.State.Network("net1") | 1008 | net, err := s.State.Network("net1") |
1571 | 1012 | c.Assert(err, gc.IsNil) | 1009 | c.Assert(err, gc.IsNil) |
1572 | 1013 | c.Assert(net, gc.DeepEquals, net1) | 1010 | c.Assert(net, gc.DeepEquals, net1) |
1573 | 1014 | c.Assert(net.Name(), gc.Equals, "net1") | 1011 | c.Assert(net.Name(), gc.Equals, "net1") |
1575 | 1015 | c.Assert(net.ProviderId(), gc.Equals, "provider-net1") | 1012 | c.Assert(string(net.ProviderId()), gc.Equals, "provider-net1") |
1576 | 1016 | _, err = s.State.Network("missing") | 1013 | _, err = s.State.Network("missing") |
1577 | 1017 | c.Assert(err, jc.Satisfies, errors.IsNotFound) | 1014 | c.Assert(err, jc.Satisfies, errors.IsNotFound) |
1578 | 1018 | c.Assert(err, gc.ErrorMatches, `network "missing" not found`) | 1015 | c.Assert(err, gc.ErrorMatches, `network "missing" not found`) |
1579 | 1019 | 1016 | ||
1580 | 1020 | for i, test := range addNetworkErrorsTests { | 1017 | for i, test := range addNetworkErrorsTests { |
1584 | 1021 | c.Logf("test %d: name=%q, providerId=%q, cidr=%q, vlanTag=%d", | 1018 | c.Logf("test %d: %#v", i, test.args) |
1585 | 1022 | i, test.name, test.providerId, test.cidr, test.vlanTag) | 1019 | _, err := s.State.AddNetwork(test.args) |
1583 | 1023 | _, err := s.State.AddNetwork(test.name, test.providerId, test.cidr, test.vlanTag) | ||
1586 | 1024 | c.Check(err, gc.ErrorMatches, test.expectErr) | 1020 | c.Check(err, gc.ErrorMatches, test.expectErr) |
1587 | 1025 | if strings.Contains(test.expectErr, "already exists") { | 1021 | if strings.Contains(test.expectErr, "already exists") { |
1588 | 1026 | c.Check(err, jc.Satisfies, errors.IsAlreadyExists) | 1022 | c.Check(err, jc.Satisfies, errors.IsAlreadyExists) |
1589 | @@ -2280,10 +2276,15 @@ | |||
1590 | 2280 | rel, err := s.State.AddRelation(eps...) | 2276 | rel, err := s.State.AddRelation(eps...) |
1591 | 2281 | c.Assert(err, gc.IsNil) | 2277 | c.Assert(err, gc.IsNil) |
1592 | 2282 | c.Assert(rel.String(), gc.Equals, "wordpress:db ser-vice2:server") | 2278 | c.Assert(rel.String(), gc.Equals, "wordpress:db ser-vice2:server") |
1594 | 2283 | net1, err := s.State.AddNetwork("net1", "provider-id", "0.1.2.0/24", 0) | 2279 | net1, err := s.State.AddNetwork(state.NetworkInfo{ |
1595 | 2280 | Name: "net1", | ||
1596 | 2281 | ProviderId: "provider-id", | ||
1597 | 2282 | CIDR: "0.1.2.0/24", | ||
1598 | 2283 | VLANTag: 0, | ||
1599 | 2284 | }) | ||
1600 | 2284 | c.Assert(err, gc.IsNil) | 2285 | c.Assert(err, gc.IsNil) |
1601 | 2285 | c.Assert(net1.Tag(), gc.Equals, "network-net1") | 2286 | c.Assert(net1.Tag(), gc.Equals, "network-net1") |
1603 | 2286 | c.Assert(net1.ProviderId(), gc.Equals, "provider-id") | 2287 | c.Assert(string(net1.ProviderId()), gc.Equals, "provider-id") |
1604 | 2287 | 2288 | ||
1605 | 2288 | // environment tag is dynamically generated | 2289 | // environment tag is dynamically generated |
1606 | 2289 | env, err := s.State.Environment() | 2290 | env, err := s.State.Environment() |
1607 | @@ -2375,7 +2376,12 @@ | |||
1608 | 2375 | c.Assert(err, gc.IsNil) | 2376 | c.Assert(err, gc.IsNil) |
1609 | 2376 | 2377 | ||
1610 | 2377 | // Parse a network name. | 2378 | // Parse a network name. |
1612 | 2378 | net1, err := s.State.AddNetwork("net1", "provider-id", "0.1.2.0/24", 0) | 2379 | net1, err := s.State.AddNetwork(state.NetworkInfo{ |
1613 | 2380 | Name: "net1", | ||
1614 | 2381 | ProviderId: "provider-id", | ||
1615 | 2382 | CIDR: "0.1.2.0/24", | ||
1616 | 2383 | VLANTag: 0, | ||
1617 | 2384 | }) | ||
1618 | 2379 | c.Assert(err, gc.IsNil) | 2385 | c.Assert(err, gc.IsNil) |
1619 | 2380 | coll, id, err = state.ParseTag(s.State, net1.Tag()) | 2386 | coll, id, err = state.ParseTag(s.State, net1.Tag()) |
1620 | 2381 | c.Assert(coll, gc.Equals, "networks") | 2387 | c.Assert(coll, gc.Equals, "networks") |
1621 | 2382 | 2388 | ||
1622 | === modified file 'worker/provisioner/kvm-broker.go' | |||
1623 | --- worker/provisioner/kvm-broker.go 2014-04-08 03:37:14 +0000 | |||
1624 | +++ worker/provisioner/kvm-broker.go 2014-04-18 16:46:53 +0000 | |||
1625 | @@ -12,6 +12,7 @@ | |||
1626 | 12 | "launchpad.net/juju-core/container" | 12 | "launchpad.net/juju-core/container" |
1627 | 13 | "launchpad.net/juju-core/container/kvm" | 13 | "launchpad.net/juju-core/container/kvm" |
1628 | 14 | "launchpad.net/juju-core/environs" | 14 | "launchpad.net/juju-core/environs" |
1629 | 15 | "launchpad.net/juju-core/environs/network" | ||
1630 | 15 | "launchpad.net/juju-core/instance" | 16 | "launchpad.net/juju-core/instance" |
1631 | 16 | "launchpad.net/juju-core/tools" | 17 | "launchpad.net/juju-core/tools" |
1632 | 17 | ) | 18 | ) |
1633 | @@ -54,7 +55,7 @@ | |||
1634 | 54 | } | 55 | } |
1635 | 55 | 56 | ||
1636 | 56 | // StartInstance is specified in the Broker interface. | 57 | // StartInstance is specified in the Broker interface. |
1638 | 57 | func (broker *kvmBroker) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) { | 58 | func (broker *kvmBroker) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) { |
1639 | 58 | if args.MachineConfig.HasNetworks() { | 59 | if args.MachineConfig.HasNetworks() { |
1640 | 59 | return nil, nil, nil, fmt.Errorf("starting kvm containers with networks is not supported yet.") | 60 | return nil, nil, nil, fmt.Errorf("starting kvm containers with networks is not supported yet.") |
1641 | 60 | } | 61 | } |
1642 | 61 | 62 | ||
1643 | === modified file 'worker/provisioner/lxc-broker.go' | |||
1644 | --- worker/provisioner/lxc-broker.go 2014-04-08 03:37:14 +0000 | |||
1645 | +++ worker/provisioner/lxc-broker.go 2014-04-18 16:46:53 +0000 | |||
1646 | @@ -12,6 +12,7 @@ | |||
1647 | 12 | "launchpad.net/juju-core/container" | 12 | "launchpad.net/juju-core/container" |
1648 | 13 | "launchpad.net/juju-core/container/lxc" | 13 | "launchpad.net/juju-core/container/lxc" |
1649 | 14 | "launchpad.net/juju-core/environs" | 14 | "launchpad.net/juju-core/environs" |
1650 | 15 | "launchpad.net/juju-core/environs/network" | ||
1651 | 15 | "launchpad.net/juju-core/instance" | 16 | "launchpad.net/juju-core/instance" |
1652 | 16 | "launchpad.net/juju-core/state/api/params" | 17 | "launchpad.net/juju-core/state/api/params" |
1653 | 17 | "launchpad.net/juju-core/tools" | 18 | "launchpad.net/juju-core/tools" |
1654 | @@ -55,7 +56,7 @@ | |||
1655 | 55 | } | 56 | } |
1656 | 56 | 57 | ||
1657 | 57 | // StartInstance is specified in the Broker interface. | 58 | // StartInstance is specified in the Broker interface. |
1659 | 58 | func (broker *lxcBroker) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) { | 59 | func (broker *lxcBroker) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) { |
1660 | 59 | if args.MachineConfig.HasNetworks() { | 60 | if args.MachineConfig.HasNetworks() { |
1661 | 60 | return nil, nil, nil, fmt.Errorf("starting lxc containers with networks is not supported yet.") | 61 | return nil, nil, nil, fmt.Errorf("starting lxc containers with networks is not supported yet.") |
1662 | 61 | } | 62 | } |
1663 | 62 | 63 | ||
1664 | === modified file 'worker/provisioner/provisioner_task.go' | |||
1665 | --- worker/provisioner/provisioner_task.go 2014-04-17 13:21:44 +0000 | |||
1666 | +++ worker/provisioner/provisioner_task.go 2014-04-18 16:46:53 +0000 | |||
1667 | @@ -11,6 +11,7 @@ | |||
1668 | 11 | "launchpad.net/juju-core/constraints" | 11 | "launchpad.net/juju-core/constraints" |
1669 | 12 | "launchpad.net/juju-core/environs" | 12 | "launchpad.net/juju-core/environs" |
1670 | 13 | "launchpad.net/juju-core/environs/cloudinit" | 13 | "launchpad.net/juju-core/environs/cloudinit" |
1671 | 14 | "launchpad.net/juju-core/environs/network" | ||
1672 | 14 | "launchpad.net/juju-core/environs/tools" | 15 | "launchpad.net/juju-core/environs/tools" |
1673 | 15 | "launchpad.net/juju-core/instance" | 16 | "launchpad.net/juju-core/instance" |
1674 | 16 | "launchpad.net/juju-core/names" | 17 | "launchpad.net/juju-core/names" |
1675 | @@ -421,7 +422,7 @@ | |||
1676 | 421 | return nil | 422 | return nil |
1677 | 422 | } | 423 | } |
1678 | 423 | 424 | ||
1680 | 424 | func (task *provisionerTask) prepareNetworkAndInterfaces(networkInfo []environs.NetworkInfo) ( | 425 | func (task *provisionerTask) prepareNetworkAndInterfaces(networkInfo []network.Info) ( |
1681 | 425 | networks []params.Network, ifaces []params.NetworkInterface) { | 426 | networks []params.Network, ifaces []params.NetworkInterface) { |
1682 | 426 | if len(networkInfo) == 0 { | 427 | if len(networkInfo) == 0 { |
1683 | 427 | return nil, nil | 428 | return nil, nil |
1684 | @@ -429,19 +430,20 @@ | |||
1685 | 429 | visitedNetworks := set.NewStrings() | 430 | visitedNetworks := set.NewStrings() |
1686 | 430 | for _, info := range networkInfo { | 431 | for _, info := range networkInfo { |
1687 | 431 | networkTag := names.NetworkTag(info.NetworkName) | 432 | networkTag := names.NetworkTag(info.NetworkName) |
1689 | 432 | if !visitedNetworks.Contains(info.NetworkId) { | 433 | if !visitedNetworks.Contains(networkTag) { |
1690 | 433 | networks = append(networks, params.Network{ | 434 | networks = append(networks, params.Network{ |
1691 | 434 | Tag: networkTag, | 435 | Tag: networkTag, |
1693 | 435 | ProviderId: info.NetworkId, | 436 | ProviderId: info.ProviderId, |
1694 | 436 | CIDR: info.CIDR, | 437 | CIDR: info.CIDR, |
1695 | 437 | VLANTag: info.VLANTag, | 438 | VLANTag: info.VLANTag, |
1696 | 438 | }) | 439 | }) |
1698 | 439 | visitedNetworks.Add(info.NetworkId) | 440 | visitedNetworks.Add(networkTag) |
1699 | 440 | } | 441 | } |
1700 | 441 | ifaces = append(ifaces, params.NetworkInterface{ | 442 | ifaces = append(ifaces, params.NetworkInterface{ |
1701 | 442 | InterfaceName: info.InterfaceName, | 443 | InterfaceName: info.InterfaceName, |
1702 | 443 | MACAddress: info.MACAddress, | 444 | MACAddress: info.MACAddress, |
1703 | 444 | NetworkTag: networkTag, | 445 | NetworkTag: networkTag, |
1704 | 446 | IsVirtual: info.IsVirtual, | ||
1705 | 445 | }) | 447 | }) |
1706 | 446 | } | 448 | } |
1707 | 447 | return networks, ifaces | 449 | return networks, ifaces |
1708 | 448 | 450 | ||
1709 | === modified file 'worker/provisioner/provisioner_test.go' | |||
1710 | --- worker/provisioner/provisioner_test.go 2014-04-14 12:36:13 +0000 | |||
1711 | +++ worker/provisioner/provisioner_test.go 2014-04-18 16:46:53 +0000 | |||
1712 | @@ -14,6 +14,7 @@ | |||
1713 | 14 | "launchpad.net/juju-core/constraints" | 14 | "launchpad.net/juju-core/constraints" |
1714 | 15 | "launchpad.net/juju-core/environs" | 15 | "launchpad.net/juju-core/environs" |
1715 | 16 | "launchpad.net/juju-core/environs/config" | 16 | "launchpad.net/juju-core/environs/config" |
1716 | 17 | "launchpad.net/juju-core/environs/network" | ||
1717 | 17 | "launchpad.net/juju-core/environs/simplestreams" | 18 | "launchpad.net/juju-core/environs/simplestreams" |
1718 | 18 | "launchpad.net/juju-core/environs/tools" | 19 | "launchpad.net/juju-core/environs/tools" |
1719 | 19 | "launchpad.net/juju-core/errors" | 20 | "launchpad.net/juju-core/errors" |
1720 | @@ -165,7 +166,7 @@ | |||
1721 | 165 | return s.checkStartInstanceCustom(c, m, "pork", s.defaultConstraints, nil, nil, nil, true) | 166 | return s.checkStartInstanceCustom(c, m, "pork", s.defaultConstraints, nil, nil, nil, true) |
1722 | 166 | } | 167 | } |
1723 | 167 | 168 | ||
1725 | 168 | func (s *CommonProvisionerSuite) checkStartInstanceCustom(c *gc.C, m *state.Machine, secret string, cons constraints.Value, includeNetworks, excludeNetworks []string, networkInfo []environs.NetworkInfo, waitInstanceId bool) (inst instance.Instance) { | 169 | func (s *CommonProvisionerSuite) checkStartInstanceCustom(c *gc.C, m *state.Machine, secret string, cons constraints.Value, includeNetworks, excludeNetworks []string, networkInfo []network.Info, waitInstanceId bool) (inst instance.Instance) { |
1726 | 169 | s.BackingState.StartSync() | 170 | s.BackingState.StartSync() |
1727 | 170 | for { | 171 | for { |
1728 | 171 | select { | 172 | select { |
1729 | @@ -473,20 +474,22 @@ | |||
1730 | 473 | // Add and provision a machine with networks specified. | 474 | // Add and provision a machine with networks specified. |
1731 | 474 | includeNetworks := []string{"net1", "net2"} | 475 | includeNetworks := []string{"net1", "net2"} |
1732 | 475 | excludeNetworks := []string{"net3", "net4"} | 476 | excludeNetworks := []string{"net3", "net4"} |
1734 | 476 | expectNetworkInfo := []environs.NetworkInfo{{ | 477 | expectNetworkInfo := []network.Info{{ |
1735 | 477 | MACAddress: "aa:bb:cc:dd:ee:f0", | 478 | MACAddress: "aa:bb:cc:dd:ee:f0", |
1736 | 478 | InterfaceName: "eth0", | 479 | InterfaceName: "eth0", |
1738 | 479 | NetworkId: "net1", | 480 | ProviderId: "net1", |
1739 | 480 | NetworkName: "net1", | 481 | NetworkName: "net1", |
1740 | 481 | VLANTag: 0, | 482 | VLANTag: 0, |
1741 | 482 | CIDR: "0.1.2.0/24", | 483 | CIDR: "0.1.2.0/24", |
1742 | 484 | IsVirtual: false, | ||
1743 | 483 | }, { | 485 | }, { |
1744 | 484 | MACAddress: "aa:bb:cc:dd:ee:f1", | 486 | MACAddress: "aa:bb:cc:dd:ee:f1", |
1745 | 485 | InterfaceName: "eth1", | 487 | InterfaceName: "eth1", |
1747 | 486 | NetworkId: "net2", | 488 | ProviderId: "net2", |
1748 | 487 | NetworkName: "net2", | 489 | NetworkName: "net2", |
1749 | 488 | VLANTag: 1, | 490 | VLANTag: 1, |
1750 | 489 | CIDR: "0.2.2.0/24", | 491 | CIDR: "0.2.2.0/24", |
1751 | 492 | IsVirtual: true, | ||
1752 | 490 | }} | 493 | }} |
1753 | 491 | m, err := s.addMachineWithRequestedNetworks(includeNetworks, excludeNetworks) | 494 | m, err := s.addMachineWithRequestedNetworks(includeNetworks, excludeNetworks) |
1754 | 492 | c.Assert(err, gc.IsNil) | 495 | c.Assert(err, gc.IsNil) |
1755 | @@ -519,9 +522,9 @@ | |||
1756 | 519 | // Add and provision a machine with networks specified. | 522 | // Add and provision a machine with networks specified. |
1757 | 520 | includeNetworks := []string{"bad-net1"} | 523 | includeNetworks := []string{"bad-net1"} |
1758 | 521 | // "bad-" prefix for networks causes dummy provider to report | 524 | // "bad-" prefix for networks causes dummy provider to report |
1762 | 522 | // invalid NetworkInfo. | 525 | // invalid network.Info. |
1763 | 523 | expectNetworkInfo := []environs.NetworkInfo{ | 526 | expectNetworkInfo := []network.Info{ |
1764 | 524 | {NetworkId: "bad-net1", NetworkName: "bad-net1", CIDR: "invalid"}, | 527 | {ProviderId: "bad-net1", NetworkName: "bad-net1", CIDR: "invalid"}, |
1765 | 525 | } | 528 | } |
1766 | 526 | m, err := s.addMachineWithRequestedNetworks(includeNetworks, nil) | 529 | m, err := s.addMachineWithRequestedNetworks(includeNetworks, nil) |
1767 | 527 | c.Assert(err, gc.IsNil) | 530 | c.Assert(err, gc.IsNil) |
1768 | @@ -924,7 +927,7 @@ | |||
1769 | 924 | retryCount map[string]int | 927 | retryCount map[string]int |
1770 | 925 | } | 928 | } |
1771 | 926 | 929 | ||
1773 | 927 | func (b *mockBroker) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) { | 930 | func (b *mockBroker) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) { |
1774 | 928 | // All machines except machines 3, 4 are provisioned successfully the first time. | 931 | // All machines except machines 3, 4 are provisioned successfully the first time. |
1775 | 929 | // Machines 3 is provisioned after some attempts have been made. | 932 | // Machines 3 is provisioned after some attempts have been made. |
1776 | 930 | // Machine 4 is never provisioned. | 933 | // Machine 4 is never provisioned. |
Reviewers: mp+216453_ code.launchpad. net,
Message:
Please take a look.
Description:
various: Support multiple NICs with the same MAC
Fixes bug #1307513, allowing more than one network
interface with the same MAC address, and introduces
the concept of virtual and physical network and NIC.
This is needed because you can have more than one
network interface with the same MAC address on the
same machine (but it has to be on different networks):
one physical and multiple virtual NICs. Changes were
needed mostly in state to use a different primary
key for networkinterfaces collection. Also added a
unique index on "interfacename" and "networkname",
improved tests.
Fixed the MAAS provider to configure networks properly,
so that you can have more than one VLAN virtual NIC
on the same physical NIC.
In a follow-up, machine addresses and networks will
be integrated, so we can link a network interface's
name and MAC address to its network (IP) address.
Finally, networks and machine interfaces will be
visible in juju status.
https:/ /code.launchpad .net/~dimitern/ juju-core/ 400-lp- 1307513- multiple- nics-same- mac/+merge/ 216453
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/89260044/
Affected files (+408, -180 lines): dummy/environs. go maas/environ. go maas/environ_ test.go params/ internal. go provisioner/ provisioner_ test.go /provisioner/ provisioner. go /provisioner/ provisioner_ test.go test.go terfaces. go terfaces_ test.go test.go provisioner/ provisioner_ task.go provisioner/ provisioner_ test.go
A [revision details]
M environs/broker.go
M provider/
M provider/
M provider/
M state/api/
M state/api/
M state/apiserver
M state/apiserver
M state/machine.go
M state/machine_
M state/networkin
M state/networkin
M state/networks.go
M state/networks_
M state/open.go
M state/state.go
M state/state_test.go
M worker/
M worker/