Merge lp:~dimitern/juju-core/400-lp-1307513-multiple-nics-same-mac into lp:~go-bot/juju-core/trunk

Proposed by Dimiter Naydenov
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
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.NetworkInfo to network.Info.

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://codereview.appspot.com/89260044/

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.NetworkInfo to network.Info.

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://codereview.appspot.com/89260044/

To post a comment you must log in.
Revision history for this message
Dimiter Naydenov (dimitern) wrote :

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):
   A [revision details]
   M environs/broker.go
   M provider/dummy/environs.go
   M provider/maas/environ.go
   M provider/maas/environ_test.go
   M state/api/params/internal.go
   M state/api/provisioner/provisioner_test.go
   M state/apiserver/provisioner/provisioner.go
   M state/apiserver/provisioner/provisioner_test.go
   M state/machine.go
   M state/machine_test.go
   M state/networkinterfaces.go
   M state/networkinterfaces_test.go
   M state/networks.go
   M state/networks_test.go
   M state/open.go
   M state/state.go
   M state/state_test.go
   M worker/provisioner/provisioner_task.go
   M worker/provisioner/provisioner_test.go

Revision history for this message
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://codereview.appspot.com/89260044/diff/1/environs/broker.go
File environs/broker.go (right):

https://codereview.appspot.com/89260044/diff/1/environs/broker.go#newcode51
environs/broker.go:51: ProviderId string
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://codereview.appspot.com/89260044/diff/1/state/api/params/internal.go
File state/api/params/internal.go (right):

https://codereview.appspot.com/89260044/diff/1/state/api/params/internal.go#newcode331
state/api/params/internal.go:331: IsVirtual bool
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://codereview.appspot.com/89260044/diff/1/state/machine.go
File state/machine.go (right):

https://codereview.appspot.com/89260044/diff/1/state/machine.go#newcode570
state/machine.go:570: var doc networkInterfaceDoc
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://codereview.appspot.com/89260044/diff/1/state/machine.go#newcode1077
state/machine.go:1077: panic("unknown error while adding network
interface")
This is on the state server, let's not panic even if it should never
happen.

https://codereview.appspot.com/89260044/

Revision history for this message
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.

https://codereview.appspot.com/89260044/

Revision history for this message
Dimiter Naydenov (dimitern) wrote :

Please take a look.

https://codereview.appspot.com/89260044/diff/1/environs/broker.go
File environs/broker.go (right):

https://codereview.appspot.com/89260044/diff/1/environs/broker.go#newcode51
environs/broker.go:51: ProviderId string
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://codereview.appspot.com/89260044/diff/1/state/api/params/internal.go
File state/api/params/internal.go (right):

https://codereview.appspot.com/89260044/diff/1/state/api/params/internal.go#newcode331
state/api/params/internal.go:331: IsVirtual bool
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://codereview.appspot.com/89260044/diff/1/state/machine.go
File state/machine.go (right):

https://codereview.appspot.com/89260044/diff/1/state/machine.go#newcode570
state/machine.go:570: var doc networkInterfaceDoc
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://codereview.appspot.com/89260044/diff/1/state/machine.go#newcode1077
state/machine.go:1077: panic("unknown error while adding network
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.

https://codereview.appspot.com/89260044/

Revision history for this message
William Reade (fwereade) wrote :

Thanks, LGTM with trivials.

https://codereview.appspot.com/89260044/diff/1/environs/broker.go
File environs/broker.go (right):

https://codereview.appspot.com/89260044/diff/1/environs/broker.go#newcode51
environs/broker.go:51: ProviderId string
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://codereview.appspot.com/89260044/diff/1/state/machine.go
File state/machine.go (right):

https://codereview.appspot.com/89260044/diff/1/state/machine.go#newcode570
state/machine.go:570: var doc networkInterfaceDoc
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://codereview.appspot.com/89260044/diff/10021/state/api/params/internal.go
File state/api/params/internal.go (right):

https://codereview.appspot.com/89260044/diff/10021/state/api/params/internal.go#newcode320
state/api/params/internal.go:320: ProviderId instance.NetworkId
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://codereview.appspot.com/89260044/diff/10021/state/machine.go
File state/machine.go (right):

https://codereview.appspot.com/89260044/diff/10021/state/machine.go#newcode1063
state/machine.go:1063: if err =
m.st.networkInterfaces.FindId(doc.Id).One(nil); err == nil {
.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.

https://codereview.appspot.com/89260044/

Revision history for this message
Dimiter Naydenov (dimitern) wrote :

Please take a look.

https://codereview.appspot.com/89260044/diff/1/state/machine.go
File state/machine.go (right):

https://codereview.appspot.com/89260044/diff/1/state/machine.go#newcode570
state/machine.go:570: var doc networkInterfaceDoc
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://codereview.appspot.com/89260044/diff/10021/state/api/params/internal.go
File state/api/params/internal.go (right):

https://codereview.appspot.com/89260044/diff/10021/state/api/params/internal.go#newcode320
state/api/params/internal.go:320: ProviderId instance.NetworkId
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.NetworkInfo there.

https://codereview.appspot.com/89260044/diff/10021/state/machine.go
File state/machine.go (right):

https://codereview.appspot.com/89260044/diff/10021/state/machine.go#newcode1063
state/machine.go:1063: if err =
m.st.networkInterfaces.FindId(doc.Id).One(nil); err == nil {
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.

https://codereview.appspot.com/89260044/

Revision history for this message
Dimiter Naydenov (dimitern) wrote :

Please take a look.

https://codereview.appspot.com/89260044/diff/1/state/machine.go
File state/machine.go (right):

https://codereview.appspot.com/89260044/diff/1/state/machine.go#newcode570
state/machine.go:570: var doc networkInterfaceDoc
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://codereview.appspot.com/89260044/diff/10021/state/api/params/internal.go
File state/api/params/internal.go (right):

https://codereview.appspot.com/89260044/diff/10021/state/api/params/internal.go#newcode320
state/api/params/internal.go:320: ProviderId instance.NetworkId
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.NetworkInfo there.

https://codereview.appspot.com/89260044/diff/10021/state/machine.go
File state/machine.go (right):

https://codereview.appspot.com/89260044/diff/10021/state/machine.go#newcode1063
state/machine.go:1063: if err =
m.st.networkInterfaces.FindId(doc.Id).One(nil); err == nil {
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.

https://codereview.appspot.com/89260044/

Revision history for this message
Go Bot (go-bot) wrote :
Download full text (181.6 KiB)

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.net/juju-core 0.014s
ok launchpad.net/juju-core/agent 1.193s
ok launchpad.net/juju-core/agent/mongo 1.308s
ok launchpad.net/juju-core/agent/tools 0.217s
ok launchpad.net/juju-core/bzr 5.105s
ok launchpad.net/juju-core/cert 2.137s
ok launchpad.net/juju-core/charm 0.357s
? launchpad.net/juju-core/charm/hooks [no test files]
? launchpad.net/juju-core/charm/testing [no test files]
ok launchpad.net/juju-core/cloudinit 0.030s
ok launchpad.net/juju-core/cloudinit/sshinit 0.772s
ok launchpad.net/juju-core/cmd 0.177s
ok launchpad.net/juju-core/cmd/charm-admin 0.849s
? launchpad.net/juju-core/cmd/charmd [no test files]
? launchpad.net/juju-core/cmd/charmload [no test files]
ok launchpad.net/juju-core/cmd/envcmd 0.163s
ok launchpad.net/juju-core/cmd/juju 228.831s
ok launchpad.net/juju-core/cmd/jujud 76.425s
ok launchpad.net/juju-core/cmd/plugins/juju-metadata 6.412s
? launchpad.net/juju-core/cmd/plugins/juju-restore [no test files]
ok launchpad.net/juju-core/cmd/plugins/local 0.164s
? launchpad.net/juju-core/cmd/plugins/local/juju-local [no test files]
ok launchpad.net/juju-core/constraints 0.021s
ok launchpad.net/juju-core/container 0.037s
ok launchpad.net/juju-core/container/factory 0.043s
ok launchpad.net/juju-core/container/kvm 0.230s
ok launchpad.net/juju-core/container/kvm/mock 0.040s
? launchpad.net/juju-core/container/kvm/testing [no test files]
ok launchpad.net/juju-core/container/lxc 4.326s
? launchpad.net/juju-core/container/lxc/mock [no test files]
? launchpad.net/juju-core/container/lxc/testing [no test files]
? launchpad.net/juju-core/container/testing [no test files]
ok launchpad.net/juju-core/downloader 5.245s
ok launchpad.net/juju-core/environs 2.474s
ok launchpad.net/juju-core/environs/bootstrap 12.744s
ok launchpad.net/juju-core/environs/cloudinit 0.446s
ok launchpad.net/juju-core/environs/config 2.050s
ok launchpad.net/juju-core/environs/configstore 0.032s
ok launchpad.net/juju-core/environs/filestorage 0.026s
ok launchpad.net/juju-core/environs/httpstorage 0.651s
ok launchpad.net/juju-core/environs/imagemetadata 0.488s
? launchpad.net/juju-core/environs/imagemetadata/testing [no test files]
ok launchpad.net/juju-core/environs/instances 0.041s
ok launchpad.net/juju-core/environs/jujutest 0.187s
ok launchpad.net/juju-core/environs/manual 10.221s
? launchpad.net/juju-core/environs/network [no test files]
ok launchpad.net/juju-core/environs/simplestreams 0.235s
? launchpad.net/juju-core/environs/simplestreams/testing [no test files]
ok launchpad.net/juju-core/environs/sshstorage 0.918s
ok launchpad.net/juju-core/environs/storage 0.861s
ok launchpad.net/juju-core/environs/sync 49.998s
ok launchpad.net/juju-core/environs/testing 0.140s
ok launchpad.net/juju-core/environs/tools 4.487s
? launchpad.net/juju-core/environs/tools/testing [no test files]
ok launchpad.net/juju-core/errors 0.018s
ok launchpad.net/juju-core/instance 0.020s
? launchpad.net/juju...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'environs/broker.go'
--- environs/broker.go 2014-04-11 13:54:51 +0000
+++ environs/broker.go 2014-04-18 16:46:53 +0000
@@ -6,6 +6,7 @@
6import (6import (
7 "launchpad.net/juju-core/constraints"7 "launchpad.net/juju-core/constraints"
8 "launchpad.net/juju-core/environs/cloudinit"8 "launchpad.net/juju-core/environs/cloudinit"
9 "launchpad.net/juju-core/environs/network"
9 "launchpad.net/juju-core/instance"10 "launchpad.net/juju-core/instance"
10 "launchpad.net/juju-core/tools"11 "launchpad.net/juju-core/tools"
11)12)
@@ -33,32 +34,6 @@
33 DistributionGroup func() ([]instance.Id, error)34 DistributionGroup func() ([]instance.Id, error)
34}35}
3536
36// NetworkInfo describes a single network interface available on an
37// instance. For providers that support networks, this will be
38// available at StartInstance() time.
39type NetworkInfo struct {
40 // MACAddress is the network interface's hardware MAC address
41 // (e.g. "aa:bb:cc:dd:ee:ff").
42 MACAddress string
43
44 // CIDR of the network, in 123.45.67.89/24 format.
45 CIDR string
46
47 // NetworkName is juju-internal name of the network.
48 NetworkName string
49
50 // NetworkId is a provider-specific network id.
51 NetworkId string
52
53 // VLANTag needs to be between 1 and 4094 for VLANs and 0 for
54 // normal networks. It's defined by IEEE 802.1Q standard.
55 VLANTag int
56
57 // InterfaceName is the OS-specific network device name (e.g.
58 // "eth0" or "eth1.42" for a VLAN virtual interface).
59 InterfaceName string
60}
61
62// TODO(wallyworld) - we want this in the environs/instance package but import loops37// TODO(wallyworld) - we want this in the environs/instance package but import loops
63// stop that from being possible right now.38// stop that from being possible right now.
64type InstanceBroker interface {39type InstanceBroker interface {
@@ -68,7 +43,7 @@
68 // unique within an environment, is used by juju to protect against the43 // unique within an environment, is used by juju to protect against the
69 // consequences of multiple instances being started with the same machine44 // consequences of multiple instances being started with the same machine
70 // id.45 // id.
71 StartInstance(args StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []NetworkInfo, error)46 StartInstance(args StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error)
7247
73 // StopInstances shuts down the given instances.48 // StopInstances shuts down the given instances.
74 StopInstances([]instance.Instance) error49 StopInstances([]instance.Instance) error
7550
=== added directory 'environs/network'
=== added file 'environs/network/network.go'
--- environs/network/network.go 1970-01-01 00:00:00 +0000
+++ environs/network/network.go 2014-04-18 16:46:53 +0000
@@ -0,0 +1,37 @@
1// Copyright 2014 Canonical Ltd.
2// Licensed under the AGPLv3, see LICENCE file for details.
3
4package network
5
6// Id defines a provider-specific network id.
7type Id string
8
9// Info describes a single network interface available on an instance.
10// For providers that support networks, this will be available at
11// StartInstance() time.
12type Info struct {
13 // MACAddress is the network interface's hardware MAC address
14 // (e.g. "aa:bb:cc:dd:ee:ff").
15 MACAddress string
16
17 // CIDR of the network, in 123.45.67.89/24 format.
18 CIDR string
19
20 // NetworkName is juju-internal name of the network.
21 NetworkName string
22
23 // ProviderId is a provider-specific network id.
24 ProviderId Id
25
26 // VLANTag needs to be between 1 and 4094 for VLANs and 0 for
27 // normal networks. It's defined by IEEE 802.1Q standard.
28 VLANTag int
29
30 // InterfaceName is the OS-specific network device name (e.g.
31 // "eth0" or "eth1.42" for a VLAN virtual interface).
32 InterfaceName string
33
34 // IsVirtual is true when the interface is a virtual device, as
35 // opposed to a physical device.
36 IsVirtual bool
37}
038
=== modified file 'juju/testing/instance.go'
--- juju/testing/instance.go 2014-04-14 16:41:28 +0000
+++ juju/testing/instance.go 2014-04-18 16:46:53 +0000
@@ -11,6 +11,7 @@
11 "launchpad.net/juju-core/constraints"11 "launchpad.net/juju-core/constraints"
12 "launchpad.net/juju-core/environs"12 "launchpad.net/juju-core/environs"
13 "launchpad.net/juju-core/environs/config"13 "launchpad.net/juju-core/environs/config"
14 "launchpad.net/juju-core/environs/network"
14 "launchpad.net/juju-core/environs/tools"15 "launchpad.net/juju-core/environs/tools"
15 "launchpad.net/juju-core/instance"16 "launchpad.net/juju-core/instance"
16 "launchpad.net/juju-core/names"17 "launchpad.net/juju-core/names"
@@ -60,7 +61,7 @@
60func StartInstance(61func StartInstance(
61 env environs.Environ, machineId string,62 env environs.Environ, machineId string,
62) (63) (
63 instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error,64 instance.Instance, *instance.HardwareCharacteristics, []network.Info, error,
64) {65) {
65 return StartInstanceWithConstraints(env, machineId, constraints.Value{})66 return StartInstanceWithConstraints(env, machineId, constraints.Value{})
66}67}
@@ -84,7 +85,7 @@
84func StartInstanceWithConstraints(85func StartInstanceWithConstraints(
85 env environs.Environ, machineId string, cons constraints.Value,86 env environs.Environ, machineId string, cons constraints.Value,
86) (87) (
87 instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error,88 instance.Instance, *instance.HardwareCharacteristics, []network.Info, error,
88) {89) {
89 return StartInstanceWithConstraintsAndNetworks(env, machineId, cons, nil, nil)90 return StartInstanceWithConstraintsAndNetworks(env, machineId, cons, nil, nil)
90}91}
@@ -111,7 +112,7 @@
111 env environs.Environ, machineId string, cons constraints.Value,112 env environs.Environ, machineId string, cons constraints.Value,
112 includeNetworks, excludeNetworks []string,113 includeNetworks, excludeNetworks []string,
113) (114) (
114 instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error,115 instance.Instance, *instance.HardwareCharacteristics, []network.Info, error,
115) {116) {
116 series := config.PreferredSeries(env.Config())117 series := config.PreferredSeries(env.Config())
117 agentVersion, ok := env.Config().AgentVersion()118 agentVersion, ok := env.Config().AgentVersion()
118119
=== modified file 'provider/azure/environ.go'
--- provider/azure/environ.go 2014-04-04 15:55:19 +0000
+++ provider/azure/environ.go 2014-04-18 16:46:53 +0000
@@ -19,6 +19,7 @@
19 "launchpad.net/juju-core/environs/config"19 "launchpad.net/juju-core/environs/config"
20 "launchpad.net/juju-core/environs/imagemetadata"20 "launchpad.net/juju-core/environs/imagemetadata"
21 "launchpad.net/juju-core/environs/instances"21 "launchpad.net/juju-core/environs/instances"
22 "launchpad.net/juju-core/environs/network"
22 "launchpad.net/juju-core/environs/simplestreams"23 "launchpad.net/juju-core/environs/simplestreams"
23 "launchpad.net/juju-core/environs/storage"24 "launchpad.net/juju-core/environs/storage"
24 envtools "launchpad.net/juju-core/environs/tools"25 envtools "launchpad.net/juju-core/environs/tools"
@@ -508,7 +509,7 @@
508}509}
509510
510// StartInstance is specified in the InstanceBroker interface.511// StartInstance is specified in the InstanceBroker interface.
511func (env *azureEnviron) StartInstance(args environs.StartInstanceParams) (_ instance.Instance, _ *instance.HardwareCharacteristics, _ []environs.NetworkInfo, err error) {512func (env *azureEnviron) StartInstance(args environs.StartInstanceParams) (_ instance.Instance, _ *instance.HardwareCharacteristics, _ []network.Info, err error) {
512 if args.MachineConfig.HasNetworks() {513 if args.MachineConfig.HasNetworks() {
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.")
514 }515 }
515516
=== modified file 'provider/common/bootstrap_test.go'
--- provider/common/bootstrap_test.go 2014-04-11 10:12:20 +0000
+++ provider/common/bootstrap_test.go 2014-04-18 16:46:53 +0000
@@ -17,6 +17,7 @@
17 "launchpad.net/juju-core/environs"17 "launchpad.net/juju-core/environs"
18 "launchpad.net/juju-core/environs/cloudinit"18 "launchpad.net/juju-core/environs/cloudinit"
19 "launchpad.net/juju-core/environs/config"19 "launchpad.net/juju-core/environs/config"
20 "launchpad.net/juju-core/environs/network"
20 "launchpad.net/juju-core/environs/storage"21 "launchpad.net/juju-core/environs/storage"
21 envtesting "launchpad.net/juju-core/environs/testing"22 envtesting "launchpad.net/juju-core/environs/testing"
22 "launchpad.net/juju-core/instance"23 "launchpad.net/juju-core/instance"
@@ -80,7 +81,7 @@
80 startInstance := func(81 startInstance := func(
81 cons constraints.Value, _, _ []string, possibleTools tools.List, mcfg *cloudinit.MachineConfig,82 cons constraints.Value, _, _ []string, possibleTools tools.List, mcfg *cloudinit.MachineConfig,
82 ) (83 ) (
83 instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error,84 instance.Instance, *instance.HardwareCharacteristics, []network.Info, error,
84 ) {85 ) {
85 c.Assert(cons, gc.DeepEquals, checkCons)86 c.Assert(cons, gc.DeepEquals, checkCons)
86 c.Assert(mcfg, gc.DeepEquals, environs.NewBootstrapMachineConfig(mcfg.SystemPrivateSSHKey))87 c.Assert(mcfg, gc.DeepEquals, environs.NewBootstrapMachineConfig(mcfg.SystemPrivateSSHKey))
@@ -105,7 +106,7 @@
105 startInstance := func(106 startInstance := func(
106 _ constraints.Value, _, _ []string, _ tools.List, _ *cloudinit.MachineConfig,107 _ constraints.Value, _, _ []string, _ tools.List, _ *cloudinit.MachineConfig,
107 ) (108 ) (
108 instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error,109 instance.Instance, *instance.HardwareCharacteristics, []network.Info, error,
109 ) {110 ) {
110 stor.putErr = fmt.Errorf("suddenly a wild blah")111 stor.putErr = fmt.Errorf("suddenly a wild blah")
111 return &mockInstance{id: "i-blah"}, nil, nil, nil112 return &mockInstance{id: "i-blah"}, nil, nil, nil
@@ -138,7 +139,7 @@
138 startInstance := func(139 startInstance := func(
139 _ constraints.Value, _, _ []string, _ tools.List, _ *cloudinit.MachineConfig,140 _ constraints.Value, _, _ []string, _ tools.List, _ *cloudinit.MachineConfig,
140 ) (141 ) (
141 instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error,142 instance.Instance, *instance.HardwareCharacteristics, []network.Info, error,
142 ) {143 ) {
143 stor.putErr = fmt.Errorf("suddenly a wild blah")144 stor.putErr = fmt.Errorf("suddenly a wild blah")
144 return &mockInstance{id: "i-blah"}, nil, nil, nil145 return &mockInstance{id: "i-blah"}, nil, nil, nil
@@ -179,7 +180,7 @@
179 startInstance := func(180 startInstance := func(
180 _ constraints.Value, _, _ []string, _ tools.List, mcfg *cloudinit.MachineConfig,181 _ constraints.Value, _, _ []string, _ tools.List, mcfg *cloudinit.MachineConfig,
181 ) (182 ) (
182 instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error,183 instance.Instance, *instance.HardwareCharacteristics, []network.Info, error,
183 ) {184 ) {
184 return &mockInstance{id: checkInstanceId}, &checkHardware, nil, nil185 return &mockInstance{id: checkInstanceId}, &checkHardware, nil, nil
185 }186 }
186187
=== modified file 'provider/common/mock_test.go'
--- provider/common/mock_test.go 2014-04-04 15:55:19 +0000
+++ provider/common/mock_test.go 2014-04-18 16:46:53 +0000
@@ -10,6 +10,7 @@
10 "launchpad.net/juju-core/environs"10 "launchpad.net/juju-core/environs"
11 "launchpad.net/juju-core/environs/cloudinit"11 "launchpad.net/juju-core/environs/cloudinit"
12 "launchpad.net/juju-core/environs/config"12 "launchpad.net/juju-core/environs/config"
13 "launchpad.net/juju-core/environs/network"
13 "launchpad.net/juju-core/environs/simplestreams"14 "launchpad.net/juju-core/environs/simplestreams"
14 "launchpad.net/juju-core/environs/storage"15 "launchpad.net/juju-core/environs/storage"
15 "launchpad.net/juju-core/instance"16 "launchpad.net/juju-core/instance"
@@ -17,7 +18,7 @@
17)18)
1819
19type allInstancesFunc func() ([]instance.Instance, error)20type allInstancesFunc func() ([]instance.Instance, error)
20type startInstanceFunc func(constraints.Value, []string, []string, tools.List, *cloudinit.MachineConfig) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error)21type startInstanceFunc func(constraints.Value, []string, []string, tools.List, *cloudinit.MachineConfig) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error)
21type stopInstancesFunc func([]instance.Instance) error22type stopInstancesFunc func([]instance.Instance) error
22type getToolsSourcesFunc func() ([]simplestreams.DataSource, error)23type getToolsSourcesFunc func() ([]simplestreams.DataSource, error)
23type configFunc func() *config.Config24type configFunc func() *config.Config
@@ -49,7 +50,7 @@
49func (env *mockEnviron) AllInstances() ([]instance.Instance, error) {50func (env *mockEnviron) AllInstances() ([]instance.Instance, error) {
50 return env.allInstances()51 return env.allInstances()
51}52}
52func (env *mockEnviron) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) {53func (env *mockEnviron) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) {
53 return env.startInstance(54 return env.startInstance(
54 args.Constraints,55 args.Constraints,
55 args.MachineConfig.IncludeNetworks,56 args.MachineConfig.IncludeNetworks,
5657
=== modified file 'provider/dummy/environs.go'
--- provider/dummy/environs.go 2014-04-14 16:41:28 +0000
+++ provider/dummy/environs.go 2014-04-18 16:46:53 +0000
@@ -40,6 +40,7 @@
40 "launchpad.net/juju-core/environs/bootstrap"40 "launchpad.net/juju-core/environs/bootstrap"
41 "launchpad.net/juju-core/environs/config"41 "launchpad.net/juju-core/environs/config"
42 "launchpad.net/juju-core/environs/imagemetadata"42 "launchpad.net/juju-core/environs/imagemetadata"
43 "launchpad.net/juju-core/environs/network"
43 "launchpad.net/juju-core/environs/simplestreams"44 "launchpad.net/juju-core/environs/simplestreams"
44 "launchpad.net/juju-core/environs/storage"45 "launchpad.net/juju-core/environs/storage"
45 "launchpad.net/juju-core/environs/tools"46 "launchpad.net/juju-core/environs/tools"
@@ -115,7 +116,7 @@
115 Constraints constraints.Value116 Constraints constraints.Value
116 IncludeNetworks []string117 IncludeNetworks []string
117 ExcludeNetworks []string118 ExcludeNetworks []string
118 NetworkInfo []environs.NetworkInfo119 NetworkInfo []network.Info
119 Info *state.Info120 Info *state.Info
120 APIInfo *api.Info121 APIInfo *api.Info
121 Secret string122 Secret string
@@ -693,7 +694,7 @@
693}694}
694695
695// StartInstance is specified in the InstanceBroker interface.696// StartInstance is specified in the InstanceBroker interface.
696func (e *environ) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) {697func (e *environ) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) {
697698
698 defer delay()699 defer delay()
699 machineId := args.MachineConfig.MachineId700 machineId := args.MachineConfig.MachineId
@@ -766,23 +767,24 @@
766 }767 }
767 }768 }
768 // Simulate networks added when requested.769 // Simulate networks added when requested.
769 networkInfo := make([]environs.NetworkInfo, len(args.MachineConfig.IncludeNetworks))770 networkInfo := make([]network.Info, len(args.MachineConfig.IncludeNetworks))
770 for i, network := range args.MachineConfig.IncludeNetworks {771 for i, netName := range args.MachineConfig.IncludeNetworks {
771 if strings.HasPrefix(network, "bad-") {772 if strings.HasPrefix(netName, "bad-") {
772 // Simulate we didn't get correct information for the network.773 // Simulate we didn't get correct information for the network.
773 networkInfo[i] = environs.NetworkInfo{774 networkInfo[i] = network.Info{
774 NetworkId: network,775 ProviderId: network.Id(netName),
775 NetworkName: network,776 NetworkName: netName,
776 CIDR: "invalid",777 CIDR: "invalid",
777 }778 }
778 } else {779 } else {
779 networkInfo[i] = environs.NetworkInfo{780 networkInfo[i] = network.Info{
780 NetworkId: network,781 ProviderId: network.Id(netName),
781 NetworkName: network,782 NetworkName: netName,
782 CIDR: fmt.Sprintf("0.%d.2.0/24", i+1),783 CIDR: fmt.Sprintf("0.%d.2.0/24", i+1),
783 InterfaceName: fmt.Sprintf("eth%d", i),784 InterfaceName: fmt.Sprintf("eth%d", i),
784 VLANTag: i,785 VLANTag: i,
785 MACAddress: fmt.Sprintf("aa:bb:cc:dd:ee:f%d", i),786 MACAddress: fmt.Sprintf("aa:bb:cc:dd:ee:f%d", i),
787 IsVirtual: i > 0,
786 }788 }
787 }789 }
788 }790 }
789791
=== modified file 'provider/ec2/ec2.go'
--- provider/ec2/ec2.go 2014-04-09 16:36:12 +0000
+++ provider/ec2/ec2.go 2014-04-18 16:46:53 +0000
@@ -18,6 +18,7 @@
18 "launchpad.net/juju-core/environs/config"18 "launchpad.net/juju-core/environs/config"
19 "launchpad.net/juju-core/environs/imagemetadata"19 "launchpad.net/juju-core/environs/imagemetadata"
20 "launchpad.net/juju-core/environs/instances"20 "launchpad.net/juju-core/environs/instances"
21 "launchpad.net/juju-core/environs/network"
21 "launchpad.net/juju-core/environs/simplestreams"22 "launchpad.net/juju-core/environs/simplestreams"
22 "launchpad.net/juju-core/environs/storage"23 "launchpad.net/juju-core/environs/storage"
23 envtools "launchpad.net/juju-core/environs/tools"24 envtools "launchpad.net/juju-core/environs/tools"
@@ -393,7 +394,7 @@
393const ebsStorage = "ebs"394const ebsStorage = "ebs"
394395
395// StartInstance is specified in the InstanceBroker interface.396// StartInstance is specified in the InstanceBroker interface.
396func (e *environ) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) {397func (e *environ) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) {
397 if args.MachineConfig.HasNetworks() {398 if args.MachineConfig.HasNetworks() {
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.")
399 }400 }
400401
=== modified file 'provider/joyent/environ_instance.go'
--- provider/joyent/environ_instance.go 2014-04-04 15:55:19 +0000
+++ provider/joyent/environ_instance.go 2014-04-18 16:46:53 +0000
@@ -15,6 +15,7 @@
15 "launchpad.net/juju-core/environs"15 "launchpad.net/juju-core/environs"
16 "launchpad.net/juju-core/environs/imagemetadata"16 "launchpad.net/juju-core/environs/imagemetadata"
17 "launchpad.net/juju-core/environs/instances"17 "launchpad.net/juju-core/environs/instances"
18 "launchpad.net/juju-core/environs/network"
18 "launchpad.net/juju-core/environs/simplestreams"19 "launchpad.net/juju-core/environs/simplestreams"
19 "launchpad.net/juju-core/instance"20 "launchpad.net/juju-core/instance"
20 "launchpad.net/juju-core/names"21 "launchpad.net/juju-core/names"
@@ -50,7 +51,7 @@
50 return fmt.Sprintf("juju-%s-%s", env.Name(), names.MachineTag(machineId))51 return fmt.Sprintf("juju-%s-%s", env.Name(), names.MachineTag(machineId))
51}52}
5253
53func (env *joyentEnviron) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) {54func (env *joyentEnviron) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) {
5455
55 if args.MachineConfig.HasNetworks() {56 if args.MachineConfig.HasNetworks() {
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.")
5758
=== modified file 'provider/local/environ.go'
--- provider/local/environ.go 2014-04-14 16:41:28 +0000
+++ provider/local/environ.go 2014-04-18 16:46:53 +0000
@@ -30,6 +30,7 @@
30 "launchpad.net/juju-core/environs/config"30 "launchpad.net/juju-core/environs/config"
31 "launchpad.net/juju-core/environs/filestorage"31 "launchpad.net/juju-core/environs/filestorage"
32 "launchpad.net/juju-core/environs/httpstorage"32 "launchpad.net/juju-core/environs/httpstorage"
33 "launchpad.net/juju-core/environs/network"
33 "launchpad.net/juju-core/environs/simplestreams"34 "launchpad.net/juju-core/environs/simplestreams"
34 "launchpad.net/juju-core/environs/storage"35 "launchpad.net/juju-core/environs/storage"
35 envtools "launchpad.net/juju-core/environs/tools"36 envtools "launchpad.net/juju-core/environs/tools"
@@ -301,7 +302,7 @@
301}302}
302303
303// StartInstance is specified in the InstanceBroker interface.304// StartInstance is specified in the InstanceBroker interface.
304func (env *localEnviron) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) {305func (env *localEnviron) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) {
305 if args.MachineConfig.HasNetworks() {306 if args.MachineConfig.HasNetworks() {
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.")
307 }308 }
308309
=== modified file 'provider/maas/environ.go'
--- provider/maas/environ.go 2014-04-11 15:20:32 +0000
+++ provider/maas/environ.go 2014-04-18 16:46:53 +0000
@@ -22,6 +22,7 @@
22 "launchpad.net/juju-core/environs"22 "launchpad.net/juju-core/environs"
23 "launchpad.net/juju-core/environs/config"23 "launchpad.net/juju-core/environs/config"
24 "launchpad.net/juju-core/environs/imagemetadata"24 "launchpad.net/juju-core/environs/imagemetadata"
25 "launchpad.net/juju-core/environs/network"
25 "launchpad.net/juju-core/environs/simplestreams"26 "launchpad.net/juju-core/environs/simplestreams"
26 "launchpad.net/juju-core/environs/storage"27 "launchpad.net/juju-core/environs/storage"
27 envtools "launchpad.net/juju-core/environs/tools"28 envtools "launchpad.net/juju-core/environs/tools"
@@ -331,56 +332,54 @@
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`
332}333}
333334
334// setupNetworks prepares a []environs.NetworkInfo for the given instance.335// setupNetworks prepares a []network.Info for the given instance.
335func (environ *maasEnviron) setupNetworks(inst instance.Instance) ([]environs.NetworkInfo, error) {336func (environ *maasEnviron) setupNetworks(inst instance.Instance) ([]network.Info, error) {
336 // Get the instance network interfaces first.337 // Get the instance network interfaces first.
337 interfaces, err := environ.getInstanceNetworkInterfaces(inst)338 interfaces, err := environ.getInstanceNetworkInterfaces(inst)
338 if err != nil {339 if err != nil {
339 return nil, fmt.Errorf("getInstanceNetworkInterfaces failed: %v", err)340 return nil, fmt.Errorf("getInstanceNetworkInterfaces failed: %v", err)
340 }341 }
341 logger.Debugf("node %q has network interfaces %v", inst.Id(), interfaces)342 logger.Debugf("node %q has network interfaces %v", inst.Id(), interfaces)
342 networkInfoMap := make(map[string]environs.NetworkInfo)
343 for macAddress, interfaceName := range interfaces {
344 networkInfoMap[macAddress] = environs.NetworkInfo{
345 MACAddress: macAddress,
346 InterfaceName: interfaceName,
347 }
348 }
349 networks, err := environ.getInstanceNetworks(inst)343 networks, err := environ.getInstanceNetworks(inst)
350 if err != nil {344 if err != nil {
351 return nil, fmt.Errorf("getInstanceNetworks failed: %v", err)345 return nil, fmt.Errorf("getInstanceNetworks failed: %v", err)
352 }346 }
353 logger.Debugf("node %q has networks %v", inst.Id(), networks)347 logger.Debugf("node %q has networks %v", inst.Id(), networks)
354 for _, network := range networks {348 var tempNetworkInfo []network.Info
349 for _, netw := range networks {
355 netCIDR := &net.IPNet{350 netCIDR := &net.IPNet{
356 IP: net.ParseIP(network.IP),351 IP: net.ParseIP(netw.IP),
357 Mask: net.IPMask(net.ParseIP(network.Mask)),352 Mask: net.IPMask(net.ParseIP(netw.Mask)),
358 }353 }
359 macs, err := environ.getNetworkMACs(network.Name)354 macs, err := environ.getNetworkMACs(netw.Name)
360 if err != nil {355 if err != nil {
361 return nil, fmt.Errorf("getNetworkMACs failed: %v", err)356 return nil, fmt.Errorf("getNetworkMACs failed: %v", err)
362 }357 }
358 logger.Debugf("network %q has MACs: %v", netw.Name, macs)
363 for _, mac := range macs {359 for _, mac := range macs {
364 if _, ok := interfaces[mac]; ok {360 if interfaceName, ok := interfaces[mac]; ok {
365 info := networkInfoMap[mac]361 tempNetworkInfo = append(tempNetworkInfo, network.Info{
366 info.CIDR = netCIDR.String()362 MACAddress: mac,
367 info.VLANTag = network.VLANTag363 InterfaceName: interfaceName,
368 info.NetworkId = network.Name364 CIDR: netCIDR.String(),
369 info.NetworkName = network.Name365 VLANTag: netw.VLANTag,
370 networkInfoMap[mac] = info366 ProviderId: network.Id(netw.Name),
367 NetworkName: netw.Name,
368 IsVirtual: netw.VLANTag > 0,
369 })
371 }370 }
372 }371 }
373 }372 }
374 // Verify we filled-in everything for all networks/interfaces373 // Verify we filled-in everything for all networks/interfaces
375 // and drop incomplete records.374 // and drop incomplete records.
376 var networkInfo []environs.NetworkInfo375 var networkInfo []network.Info
377 for _, info := range networkInfoMap {376 for _, info := range tempNetworkInfo {
378 if info.NetworkId == "" || info.NetworkName == "" || info.CIDR == "" {377 if info.ProviderId == "" || info.NetworkName == "" || info.CIDR == "" {
379 logger.Warningf("ignoring network interface %q: missing network information", info.InterfaceName)378 logger.Warningf("ignoring network interface %q: missing network information", info.InterfaceName)
380 continue379 continue
381 }380 }
382 if info.MACAddress == "" || info.InterfaceName == "" {381 if info.MACAddress == "" || info.InterfaceName == "" {
383 logger.Warningf("ignoring network %q: missing network interface information", info.NetworkId)382 logger.Warningf("ignoring network %q: missing network interface information", info.ProviderId)
384 continue383 continue
385 }384 }
386 networkInfo = append(networkInfo, info)385 networkInfo = append(networkInfo, info)
@@ -391,7 +390,7 @@
391390
392// StartInstance is specified in the InstanceBroker interface.391// StartInstance is specified in the InstanceBroker interface.
393func (environ *maasEnviron) StartInstance(args environs.StartInstanceParams) (392func (environ *maasEnviron) StartInstance(args environs.StartInstanceParams) (
394 instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error,393 instance.Instance, *instance.HardwareCharacteristics, []network.Info, error,
395) {394) {
396 var inst *maasInstance395 var inst *maasInstance
397 var err error396 var err error
@@ -413,7 +412,7 @@
413 }412 }
414 }413 }
415 }()414 }()
416 var networkInfo []environs.NetworkInfo415 var networkInfo []network.Info
417 if args.MachineConfig.HasNetworks() {416 if args.MachineConfig.HasNetworks() {
418 networkInfo, err = environ.setupNetworks(inst)417 networkInfo, err = environ.setupNetworks(inst)
419 if err != nil {418 if err != nil {
@@ -454,7 +453,7 @@
454453
455// newCloudinitConfig creates a cloudinit.Config structure454// newCloudinitConfig creates a cloudinit.Config structure
456// suitable as a base for initialising a MAAS node.455// suitable as a base for initialising a MAAS node.
457func newCloudinitConfig(hostname string, networkInfo []environs.NetworkInfo) (*cloudinit.Config, error) {456func newCloudinitConfig(hostname string, networkInfo []network.Info) (*cloudinit.Config, error) {
458 info := machineInfo{hostname}457 info := machineInfo{hostname}
459 runCmd, err := info.cloudinitRunCmd()458 runCmd, err := info.cloudinitRunCmd()
460 if err != nil {459 if err != nil {
@@ -477,11 +476,7 @@
477476
478// setupNetworksOnBoot prepares a script to enable and start all given477// setupNetworksOnBoot prepares a script to enable and start all given
479// networks on boot.478// networks on boot.
480//479func setupNetworksOnBoot(cloudcfg *cloudinit.Config, networkInfo []network.Info) {
481// TODO(dimitern) To support more than one VLAN on the same physical
482// interface, we need model changes to allow muliple NICs with the
483// same MAC address, but different network name.
484func setupNetworksOnBoot(cloudcfg *cloudinit.Config, networkInfo []environs.NetworkInfo) {
485 const ifaceConfig = `cat >> /etc/network/interfaces << EOF480 const ifaceConfig = `cat >> /etc/network/interfaces << EOF
486481
487auto %s482auto %s
@@ -494,6 +489,10 @@
494 script := func(line string, args ...interface{}) {489 script := func(line string, args ...interface{}) {
495 cloudcfg.AddScripts(fmt.Sprintf(line, args...))490 cloudcfg.AddScripts(fmt.Sprintf(line, args...))
496 }491 }
492 // Because eth0 is already configured in the br0 bridge, we
493 // don't want to break that.
494 configured := set.NewStrings("eth0")
495
497 // In order to support VLANs, we need to include 8021q module496 // In order to support VLANs, we need to include 8021q module
498 // configure vconfig's set_name_type497 // configure vconfig's set_name_type
499 script("modprobe 8021q")498 script("modprobe 8021q")
@@ -501,14 +500,12 @@
501 script("vconfig set_name_type DEV_PLUS_VID_NO_PAD")500 script("vconfig set_name_type DEV_PLUS_VID_NO_PAD")
502 // Now prepare each interface configuration501 // Now prepare each interface configuration
503 for _, info := range networkInfo {502 for _, info := range networkInfo {
504 // Because eth0 is already configured in the br0 bridge, we503 if !configured.Contains(info.InterfaceName) {
505 // don't want to break that.504 // Register and bring up the physical interface.
506 if info.InterfaceName == "eth0" {505 script(ifaceConfig, info.InterfaceName, info.InterfaceName)
507 continue506 script("ifup %s", info.InterfaceName)
507 configured.Add(info.InterfaceName)
508 }508 }
509 // Register and bring up the interface.
510 script(ifaceConfig, info.InterfaceName, info.InterfaceName)
511 script("ifup %s", info.InterfaceName)
512 if info.VLANTag > 0 {509 if info.VLANTag > 0 {
513 // We have a VLAN and need to create and register it after510 // We have a VLAN and need to create and register it after
514 // its parent interface was brought up.511 // its parent interface was brought up.
515512
=== modified file 'provider/maas/environ_test.go'
--- provider/maas/environ_test.go 2014-04-10 17:46:52 +0000
+++ provider/maas/environ_test.go 2014-04-18 16:46:53 +0000
@@ -10,8 +10,8 @@
10 gc "launchpad.net/gocheck"10 gc "launchpad.net/gocheck"
11 "launchpad.net/gomaasapi"11 "launchpad.net/gomaasapi"
1212
13 "launchpad.net/juju-core/environs"
14 "launchpad.net/juju-core/environs/config"13 "launchpad.net/juju-core/environs/config"
14 "launchpad.net/juju-core/environs/network"
15 envtesting "launchpad.net/juju-core/environs/testing"15 envtesting "launchpad.net/juju-core/environs/testing"
16 "launchpad.net/juju-core/provider/maas"16 "launchpad.net/juju-core/provider/maas"
17 coretesting "launchpad.net/juju-core/testing"17 coretesting "launchpad.net/juju-core/testing"
@@ -197,10 +197,17 @@
197}197}
198198
199func (*environSuite) TestNewCloudinitConfig(c *gc.C) {199func (*environSuite) TestNewCloudinitConfig(c *gc.C) {
200 nwInfo := []environs.NetworkInfo{200 nwInfo := []network.Info{
201 // physical eth0 won't be touched, but it can have VLANs on it.
201 {InterfaceName: "eth0", VLANTag: 0},202 {InterfaceName: "eth0", VLANTag: 0},
203 {InterfaceName: "eth0", VLANTag: 99},
204 // physical NIC given explicitly, then a couple of virtual ones using it.
205 {InterfaceName: "eth1", VLANTag: 0},
202 {InterfaceName: "eth1", VLANTag: 42},206 {InterfaceName: "eth1", VLANTag: 42},
207 {InterfaceName: "eth1", VLANTag: 69},
203 {InterfaceName: "eth2", VLANTag: 0},208 {InterfaceName: "eth2", VLANTag: 0},
209 // physical NIC not given, ensure it gets brought up first, before the virtual one.
210 {InterfaceName: "eth3", VLANTag: 123},
204 }211 }
205 cloudcfg, err := maas.NewCloudinitConfig("testing.invalid", nwInfo)212 cloudcfg, err := maas.NewCloudinitConfig("testing.invalid", nwInfo)
206 c.Assert(err, gc.IsNil)213 c.Assert(err, gc.IsNil)
@@ -216,12 +223,23 @@
216 "modprobe 8021q",223 "modprobe 8021q",
217 "sh -c 'grep -q 8021q /etc/modules || echo 8021q >> /etc/modules'",224 "sh -c 'grep -q 8021q /etc/modules || echo 8021q >> /etc/modules'",
218 "vconfig set_name_type DEV_PLUS_VID_NO_PAD",225 "vconfig set_name_type DEV_PLUS_VID_NO_PAD",
226 "vconfig add eth0 99",
227 "cat >> /etc/network/interfaces << EOF\n\nauto eth0.99\niface eth0.99 inet dhcp\nEOF\n",
228 "ifup eth0.99",
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",
220 "ifup eth1",230 "ifup eth1",
221 "vconfig add eth1 42",231 "vconfig add eth1 42",
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",
223 "ifup eth1.42",233 "ifup eth1.42",
234 "vconfig add eth1 69",
235 "cat >> /etc/network/interfaces << EOF\n\nauto eth1.69\niface eth1.69 inet dhcp\nEOF\n",
236 "ifup eth1.69",
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",
225 "ifup eth2",238 "ifup eth2",
239 "cat >> /etc/network/interfaces << EOF\n\nauto eth3\niface eth3 inet dhcp\nEOF\n",
240 "ifup eth3",
241 "vconfig add eth3 123",
242 "cat >> /etc/network/interfaces << EOF\n\nauto eth3.123\niface eth3.123 inet dhcp\nEOF\n",
243 "ifup eth3.123",
226 })244 })
227}245}
228246
=== modified file 'provider/manual/environ.go'
--- provider/manual/environ.go 2014-04-11 17:51:58 +0000
+++ provider/manual/environ.go 2014-04-18 16:46:53 +0000
@@ -21,6 +21,7 @@
21 "launchpad.net/juju-core/environs/config"21 "launchpad.net/juju-core/environs/config"
22 "launchpad.net/juju-core/environs/httpstorage"22 "launchpad.net/juju-core/environs/httpstorage"
23 "launchpad.net/juju-core/environs/manual"23 "launchpad.net/juju-core/environs/manual"
24 "launchpad.net/juju-core/environs/network"
24 "launchpad.net/juju-core/environs/simplestreams"25 "launchpad.net/juju-core/environs/simplestreams"
25 "launchpad.net/juju-core/environs/sshstorage"26 "launchpad.net/juju-core/environs/sshstorage"
26 "launchpad.net/juju-core/environs/storage"27 "launchpad.net/juju-core/environs/storage"
@@ -65,7 +66,7 @@
65var errNoStartInstance = errors.New("manual provider cannot start instances")66var errNoStartInstance = errors.New("manual provider cannot start instances")
66var errNoStopInstance = errors.New("manual provider cannot stop instances")67var errNoStopInstance = errors.New("manual provider cannot stop instances")
6768
68func (*manualEnviron) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) {69func (*manualEnviron) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) {
69 return nil, nil, nil, errNoStartInstance70 return nil, nil, nil, errNoStartInstance
70}71}
7172
7273
=== modified file 'provider/openstack/provider.go'
--- provider/openstack/provider.go 2014-04-12 05:53:58 +0000
+++ provider/openstack/provider.go 2014-04-18 16:46:53 +0000
@@ -27,6 +27,7 @@
27 "launchpad.net/juju-core/environs/config"27 "launchpad.net/juju-core/environs/config"
28 "launchpad.net/juju-core/environs/imagemetadata"28 "launchpad.net/juju-core/environs/imagemetadata"
29 "launchpad.net/juju-core/environs/instances"29 "launchpad.net/juju-core/environs/instances"
30 "launchpad.net/juju-core/environs/network"
30 "launchpad.net/juju-core/environs/simplestreams"31 "launchpad.net/juju-core/environs/simplestreams"
31 "launchpad.net/juju-core/environs/storage"32 "launchpad.net/juju-core/environs/storage"
32 envtools "launchpad.net/juju-core/environs/tools"33 envtools "launchpad.net/juju-core/environs/tools"
@@ -745,7 +746,7 @@
745}746}
746747
747// StartInstance is specified in the InstanceBroker interface.748// StartInstance is specified in the InstanceBroker interface.
748func (e *environ) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) {749func (e *environ) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) {
749750
750 if args.MachineConfig.HasNetworks() {751 if args.MachineConfig.HasNetworks() {
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.")
752753
=== modified file 'state/api/params/internal.go'
--- state/api/params/internal.go 2014-04-11 15:16:00 +0000
+++ state/api/params/internal.go 2014-04-18 16:46:53 +0000
@@ -7,6 +7,7 @@
7 "time"7 "time"
88
9 "launchpad.net/juju-core/constraints"9 "launchpad.net/juju-core/constraints"
10 "launchpad.net/juju-core/environs/network"
10 "launchpad.net/juju-core/instance"11 "launchpad.net/juju-core/instance"
11 "launchpad.net/juju-core/tools"12 "launchpad.net/juju-core/tools"
12 "launchpad.net/juju-core/utils/exec"13 "launchpad.net/juju-core/utils/exec"
@@ -317,7 +318,7 @@
317 Tag string318 Tag string
318319
319 // ProviderId is the provider-specific network id.320 // ProviderId is the provider-specific network id.
320 ProviderId string321 ProviderId network.Id
321322
322 // CIDR of the network, in "123.45.67.89/12" format.323 // CIDR of the network, in "123.45.67.89/12" format.
323 CIDR string324 CIDR string
@@ -340,6 +341,10 @@
340341
341 // NetworkTag is this interface's network tag.342 // NetworkTag is this interface's network tag.
342 NetworkTag string343 NetworkTag string
344
345 // IsVirtual is true when the interface is a virtual device, as
346 // opposed to a physical device.
347 IsVirtual bool
343}348}
344349
345// InstanceInfo holds a machine tag, provider-specific instance id, a350// InstanceInfo holds a machine tag, provider-specific instance id, a
346351
=== modified file 'state/api/provisioner/provisioner_test.go'
--- state/api/provisioner/provisioner_test.go 2014-04-14 12:36:13 +0000
+++ state/api/provisioner/provisioner_test.go 2014-04-18 16:46:53 +0000
@@ -230,6 +230,11 @@
230 CIDR: "0.2.2.0/24",230 CIDR: "0.2.2.0/24",
231 VLANTag: 42,231 VLANTag: 42,
232 }, {232 }, {
233 Tag: "network-vlan69",
234 ProviderId: "vlan69",
235 CIDR: "0.3.2.0/24",
236 VLANTag: 69,
237 }, {
233 Tag: "network-vlan42", // duplicated; ignored238 Tag: "network-vlan42", // duplicated; ignored
234 ProviderId: "vlan42",239 ProviderId: "vlan42",
235 CIDR: "0.2.2.0/24",240 CIDR: "0.2.2.0/24",
@@ -239,18 +244,32 @@
239 MACAddress: "aa:bb:cc:dd:ee:f0",244 MACAddress: "aa:bb:cc:dd:ee:f0",
240 NetworkTag: "network-net1",245 NetworkTag: "network-net1",
241 InterfaceName: "eth0",246 InterfaceName: "eth0",
247 IsVirtual: false,
242 }, {248 }, {
243 MACAddress: "aa:bb:cc:dd:ee:f1",249 MACAddress: "aa:bb:cc:dd:ee:f1",
244 NetworkTag: "network-net1",250 NetworkTag: "network-net1",
245 InterfaceName: "eth1",251 InterfaceName: "eth1",
246 }, {252 IsVirtual: false,
247 MACAddress: "aa:bb:cc:dd:ee:f2",253 }, {
248 NetworkTag: "network-vlan42",254 MACAddress: "aa:bb:cc:dd:ee:f1",
249 InterfaceName: "eth2",255 NetworkTag: "network-vlan42",
250 }, {256 InterfaceName: "eth1.42",
251 MACAddress: "aa:bb:cc:dd:ee:f2", // duplicated; ignored257 IsVirtual: true,
252 NetworkTag: "network-vlan42",258 }, {
253 InterfaceName: "eth2",259 MACAddress: "aa:bb:cc:dd:ee:f1",
260 NetworkTag: "network-vlan69",
261 InterfaceName: "eth1.69",
262 IsVirtual: true,
263 }, {
264 MACAddress: "aa:bb:cc:dd:ee:f1", // duplicated mac+net; ignored
265 NetworkTag: "network-vlan42",
266 InterfaceName: "eth2",
267 IsVirtual: true,
268 }, {
269 MACAddress: "aa:bb:cc:dd:ee:f4",
270 NetworkTag: "network-net1",
271 InterfaceName: "eth1", // duplicated name+machine id; ignored
272 IsVirtual: false,
254 }}273 }}
255274
256 err = apiMachine.SetInstanceInfo("i-will", "fake_nonce", &hwChars, networks, ifaces)275 err = apiMachine.SetInstanceInfo("i-will", "fake_nonce", &hwChars, networks, ifaces)
@@ -273,7 +292,7 @@
273292
274 // Check the networks are created.293 // Check the networks are created.
275 for i, _ := range networks {294 for i, _ := range networks {
276 if i == 2 {295 if i == 3 {
277 // Last one was ignored, so skip it.296 // Last one was ignored, so skip it.
278 break297 break
279 }298 }
@@ -291,16 +310,17 @@
291 // And the network interfaces as well.310 // And the network interfaces as well.
292 ifacesMachine, err = notProvisionedMachine.NetworkInterfaces()311 ifacesMachine, err = notProvisionedMachine.NetworkInterfaces()
293 c.Assert(err, gc.IsNil)312 c.Assert(err, gc.IsNil)
294 c.Assert(ifacesMachine, gc.HasLen, 3)313 c.Assert(ifacesMachine, gc.HasLen, 4)
295 actual := make([]params.NetworkInterface, len(ifacesMachine))314 actual := make([]params.NetworkInterface, len(ifacesMachine))
296 for i, iface := range ifacesMachine {315 for i, iface := range ifacesMachine {
297 actual[i].InterfaceName = iface.InterfaceName()316 actual[i].InterfaceName = iface.InterfaceName()
298 actual[i].NetworkTag = iface.NetworkTag()317 actual[i].NetworkTag = iface.NetworkTag()
299 actual[i].MACAddress = iface.MACAddress()318 actual[i].MACAddress = iface.MACAddress()
319 actual[i].IsVirtual = iface.IsVirtual()
300 c.Check(iface.MachineTag(), gc.Equals, notProvisionedMachine.Tag())320 c.Check(iface.MachineTag(), gc.Equals, notProvisionedMachine.Tag())
301 c.Check(iface.MachineId(), gc.Equals, notProvisionedMachine.Id())321 c.Check(iface.MachineId(), gc.Equals, notProvisionedMachine.Id())
302 }322 }
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.
304}324}
305325
306func (s *provisionerSuite) TestSeries(c *gc.C) {326func (s *provisionerSuite) TestSeries(c *gc.C) {
307327
=== modified file 'state/apiserver/provisioner/provisioner.go'
--- state/apiserver/provisioner/provisioner.go 2014-04-11 15:10:48 +0000
+++ state/apiserver/provisioner/provisioner.go 2014-04-18 16:46:53 +0000
@@ -435,6 +435,7 @@
435 MACAddress: iface.MACAddress,435 MACAddress: iface.MACAddress,
436 NetworkName: networkName,436 NetworkName: networkName,
437 InterfaceName: iface.InterfaceName,437 InterfaceName: iface.InterfaceName,
438 IsVirtual: iface.IsVirtual,
438 }439 }
439 }440 }
440 return stateNetworks, stateInterfaces, nil441 return stateNetworks, stateInterfaces, nil
441442
=== modified file 'state/apiserver/provisioner/provisioner_test.go'
--- state/apiserver/provisioner/provisioner_test.go 2014-04-17 12:53:23 +0000
+++ state/apiserver/provisioner/provisioner_test.go 2014-04-18 16:46:53 +0000
@@ -862,6 +862,11 @@
862 CIDR: "0.2.2.0/24",862 CIDR: "0.2.2.0/24",
863 VLANTag: 42,863 VLANTag: 42,
864 }, {864 }, {
865 Tag: "network-vlan69",
866 ProviderId: "vlan69",
867 CIDR: "0.3.2.0/24",
868 VLANTag: 69,
869 }, {
865 Tag: "network-vlan42", // duplicated; ignored870 Tag: "network-vlan42", // duplicated; ignored
866 ProviderId: "vlan42",871 ProviderId: "vlan42",
867 CIDR: "0.2.2.0/24",872 CIDR: "0.2.2.0/24",
@@ -871,18 +876,32 @@
871 MACAddress: "aa:bb:cc:dd:ee:f0",876 MACAddress: "aa:bb:cc:dd:ee:f0",
872 NetworkTag: "network-net1",877 NetworkTag: "network-net1",
873 InterfaceName: "eth0",878 InterfaceName: "eth0",
879 IsVirtual: false,
874 }, {880 }, {
875 MACAddress: "aa:bb:cc:dd:ee:f1",881 MACAddress: "aa:bb:cc:dd:ee:f1",
876 NetworkTag: "network-net1",882 NetworkTag: "network-net1",
877 InterfaceName: "eth1",883 InterfaceName: "eth1",
884 IsVirtual: false,
885 }, {
886 MACAddress: "aa:bb:cc:dd:ee:f1",
887 NetworkTag: "network-vlan42",
888 InterfaceName: "eth1.42",
889 IsVirtual: true,
890 }, {
891 MACAddress: "aa:bb:cc:dd:ee:f0",
892 NetworkTag: "network-vlan69",
893 InterfaceName: "eth0.69",
894 IsVirtual: true,
895 }, {
896 MACAddress: "aa:bb:cc:dd:ee:f1", // duplicated mac+net; ignored
897 NetworkTag: "network-vlan42",
898 InterfaceName: "eth2",
899 IsVirtual: true,
878 }, {900 }, {
879 MACAddress: "aa:bb:cc:dd:ee:f2",901 MACAddress: "aa:bb:cc:dd:ee:f2",
880 NetworkTag: "network-vlan42",902 NetworkTag: "network-net1",
881 InterfaceName: "eth2",903 InterfaceName: "eth1", // duplicated name+machine id; ignored for machine 1.
882 }, {904 IsVirtual: false,
883 MACAddress: "aa:bb:cc:dd:ee:f2", // duplicated; ignored
884 NetworkTag: "network-vlan42",
885 InterfaceName: "eth2",
886 }}905 }}
887 args := params.InstancesInfo{Machines: []params.InstanceInfo{{906 args := params.InstancesInfo{Machines: []params.InstanceInfo{{
888 Tag: s.machines[0].Tag(),907 Tag: s.machines[0].Tag(),
@@ -939,21 +958,26 @@
939 c.Check(gotHardware, gc.DeepEquals, &hwChars)958 c.Check(gotHardware, gc.DeepEquals, &hwChars)
940 ifacesMachine1, err := s.machines[1].NetworkInterfaces()959 ifacesMachine1, err := s.machines[1].NetworkInterfaces()
941 c.Assert(err, gc.IsNil)960 c.Assert(err, gc.IsNil)
942 c.Assert(ifacesMachine1, gc.HasLen, 3)961 c.Assert(ifacesMachine1, gc.HasLen, 4)
943 actual := make([]params.NetworkInterface, len(ifacesMachine1))962 actual := make([]params.NetworkInterface, len(ifacesMachine1))
944 for i, iface := range ifacesMachine1 {963 for i, iface := range ifacesMachine1 {
945 actual[i].InterfaceName = iface.InterfaceName()964 actual[i].InterfaceName = iface.InterfaceName()
946 actual[i].NetworkTag = iface.NetworkTag()965 actual[i].NetworkTag = iface.NetworkTag()
947 actual[i].MACAddress = iface.MACAddress()966 actual[i].MACAddress = iface.MACAddress()
967 actual[i].IsVirtual = iface.IsVirtual()
948 c.Check(iface.MachineId(), gc.Equals, s.machines[1].Id())968 c.Check(iface.MachineId(), gc.Equals, s.machines[1].Id())
949 c.Check(iface.MachineTag(), gc.Equals, s.machines[1].Tag())969 c.Check(iface.MachineTag(), gc.Equals, s.machines[1].Tag())
950 }970 }
951 c.Assert(actual, jc.SameContents, ifaces[:3])971 c.Assert(actual, jc.SameContents, ifaces[:4])
952 ifacesMachine2, err := s.machines[2].NetworkInterfaces()972 ifacesMachine2, err := s.machines[2].NetworkInterfaces()
953 c.Assert(err, gc.IsNil)973 c.Assert(err, gc.IsNil)
954 c.Assert(ifacesMachine2, gc.HasLen, 0)974 c.Assert(ifacesMachine2, gc.HasLen, 1)
975 c.Assert(ifacesMachine2[0].InterfaceName(), gc.Equals, ifaces[5].InterfaceName)
976 c.Assert(ifacesMachine2[0].MACAddress(), gc.Equals, ifaces[5].MACAddress)
977 c.Assert(ifacesMachine2[0].NetworkTag(), gc.Equals, ifaces[5].NetworkTag)
978 c.Assert(ifacesMachine2[0].MachineId(), gc.Equals, s.machines[2].Id())
955 for i, _ := range networks {979 for i, _ := range networks {
956 if i == 2 {980 if i == 3 {
957 // Last one was ignored, so don't check.981 // Last one was ignored, so don't check.
958 break982 break
959 }983 }
960984
=== modified file 'state/machine.go'
--- state/machine.go 2014-04-17 16:18:46 +0000
+++ state/machine.go 2014-04-18 16:46:53 +0000
@@ -567,16 +567,21 @@
567}567}
568568
569func (m *Machine) removeNetworkInterfacesOps() ([]txn.Op, error) {569func (m *Machine) removeNetworkInterfacesOps() ([]txn.Op, error) {
570 var doc struct {570 if m.doc.Life != Dead {
571 MACAddress string `bson:"_id"`571 return nil, fmt.Errorf("machine is not dead")
572 }572 }
573 ops := []txn.Op{}573 var doc networkInterfaceDoc
574 ops := []txn.Op{{
575 C: m.st.machines.Name,
576 Id: m.doc.Id,
577 Assert: isDeadDoc,
578 }}
574 sel := bson.D{{"machineid", m.doc.Id}}579 sel := bson.D{{"machineid", m.doc.Id}}
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()
576 for iter.Next(&doc) {581 for iter.Next(&doc) {
577 ops = append(ops, txn.Op{582 ops = append(ops, txn.Op{
578 C: m.st.networkInterfaces.Name,583 C: m.st.networkInterfaces.Name,
579 Id: doc.MACAddress,584 Id: doc.Id,
580 Remove: true,585 Remove: true,
581 })586 })
582 }587 }
@@ -842,7 +847,7 @@
842847
843 // Add the networks and interfaces first.848 // Add the networks and interfaces first.
844 for _, network := range networks {849 for _, network := range networks {
845 _, err := m.st.AddNetwork(network.Name, network.ProviderId, network.CIDR, network.VLANTag)850 _, err := m.st.AddNetwork(network)
846 if err != nil && errors.IsAlreadyExists(err) {851 if err != nil && errors.IsAlreadyExists(err) {
847 // Ignore already existing networks.852 // Ignore already existing networks.
848 continue853 continue
@@ -851,7 +856,7 @@
851 }856 }
852 }857 }
853 for _, iface := range interfaces {858 for _, iface := range interfaces {
854 _, err := m.AddNetworkInterface(iface.MACAddress, iface.InterfaceName, iface.NetworkName)859 _, err := m.AddNetworkInterface(iface)
855 if err != nil && errors.IsAlreadyExists(err) {860 if err != nil && errors.IsAlreadyExists(err) {
856 // Ignore already existing network interfaces.861 // Ignore already existing network interfaces.
857 continue862 continue
@@ -996,34 +1001,31 @@
996 return ifaces, nil1001 return ifaces, nil
997}1002}
9981003
999// AddNetworkInterface creates a new network interface on the given1004// AddNetworkInterface creates a new network interface with the given
1000// network for the machine. The machine must be alive and not yet1005// args for this machine. The machine must be alive and not yet
1001// provisioned, and there must be no other interface with the same MAC1006// provisioned, and there must be no other interface with the same MAC
1002// address or the same name on that machine for this to succeed. If a1007// address on the same network, or the same name on that machine for
1003// network interface already exists, the returned error satisfies1008// this to succeed. If a network interface already exists, the
1004// errors.IsAlreadyExists.1009// returned error satisfies errors.IsAlreadyExists.
1005func (m *Machine) AddNetworkInterface(macAddress, interfaceName, networkName string) (iface *NetworkInterface, err error) {1010func (m *Machine) AddNetworkInterface(args NetworkInterfaceInfo) (iface *NetworkInterface, err error) {
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)
10071012
1008 if macAddress == "" {1013 if args.MACAddress == "" {
1009 return nil, fmt.Errorf("MAC address must be not empty")1014 return nil, fmt.Errorf("MAC address must be not empty")
1010 }1015 }
1011 if _, err = net.ParseMAC(macAddress); err != nil {1016 if _, err = net.ParseMAC(args.MACAddress); err != nil {
1012 return nil, err1017 return nil, err
1013 }1018 }
1014 if interfaceName == "" {1019 if args.InterfaceName == "" {
1015 return nil, fmt.Errorf("interface name must be not empty")1020 return nil, fmt.Errorf("interface name must be not empty")
1016 }1021 }
1017 aliveAndNotProvisioned := append(isAliveDoc, bson.D{{"nonce", ""}}...)1022 aliveAndNotProvisioned := append(isAliveDoc, bson.D{{"nonce", ""}}...)
1018 doc := &networkInterfaceDoc{1023 doc := newNetworkInterfaceDoc(args)
1019 MACAddress: macAddress,1024 doc.MachineId = m.doc.Id
1020 InterfaceName: interfaceName,1025 doc.Id = bson.NewObjectId()
1021 NetworkName: networkName,
1022 MachineId: m.doc.Id,
1023 }
1024 ops := []txn.Op{{1026 ops := []txn.Op{{
1025 C: m.st.networks.Name,1027 C: m.st.networks.Name,
1026 Id: networkName,1028 Id: args.NetworkName,
1027 Assert: txn.DocExists,1029 Assert: txn.DocExists,
1028 }, {1030 }, {
1029 C: m.st.machines.Name,1031 C: m.st.machines.Name,
@@ -1031,7 +1033,7 @@
1031 Assert: aliveAndNotProvisioned,1033 Assert: aliveAndNotProvisioned,
1032 }, {1034 }, {
1033 C: m.st.networkInterfaces.Name,1035 C: m.st.networkInterfaces.Name,
1034 Id: macAddress,1036 Id: doc.Id,
1035 Assert: txn.DocMissing,1037 Assert: txn.DocMissing,
1036 Insert: doc,1038 Insert: doc,
1037 }}1039 }}
@@ -1039,10 +1041,7 @@
1039 err = m.st.runTransaction(ops)1041 err = m.st.runTransaction(ops)
1040 switch err {1042 switch err {
1041 case txn.ErrAborted:1043 case txn.ErrAborted:
1042 if err = m.st.networkInterfaces.FindId(macAddress).One(nil); err == nil {1044 if _, err = m.st.Network(args.NetworkName); err != nil {
1043 return nil, errors.AlreadyExistsf("interface with MAC address %q", macAddress)
1044 }
1045 if _, err = m.st.Network(networkName); err != nil {
1046 return nil, err1045 return nil, err
1047 }1046 }
1048 if err = m.Refresh(); err != nil {1047 if err = m.Refresh(); err != nil {
@@ -1053,17 +1052,30 @@
1053 msg := "machine already provisioned: dynamic network interfaces not currently supported"1052 msg := "machine already provisioned: dynamic network interfaces not currently supported"
1054 return nil, fmt.Errorf(msg)1053 return nil, fmt.Errorf(msg)
1055 }1054 }
1055 // Should never happen.
1056 logger.Errorf("unhandled assert while adding network interface doc %#v", doc)
1056 case nil:1057 case nil:
1057 // We have a unique key restriction on the InterfaceName1058 // We have a unique key restrictions on the following fields:
1058 // field, which will cause the insert to fail if there is1059 // - InterfaceName, MachineId
1059 // another record with the same interface name in the table.1060 // - MACAddress, NetworkName
1061 // These will cause the insert to fail if there is another record
1062 // with the same combination of values in the table.
1060 // The txn logic does not report insertion errors, so we check1063 // The txn logic does not report insertion errors, so we check
1061 // that the record has actually been inserted correctly before1064 // that the record has actually been inserted correctly before
1062 // reporting success.1065 // reporting success.
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 {
1064 return nil, errors.AlreadyExistsf("%q on machine %q", interfaceName, m.doc.Id)1067 return newNetworkInterface(m.st, doc), nil
1065 }1068 }
1066 return newNetworkInterface(m.st, doc), nil1069 sel := bson.D{{"interfacename", args.InterfaceName}, {"machineid", m.doc.Id}}
1070 if err = m.st.networkInterfaces.Find(sel).One(nil); err == nil {
1071 return nil, errors.AlreadyExistsf("%q on machine %q", args.InterfaceName, m.doc.Id)
1072 }
1073 sel = bson.D{{"macaddress", args.MACAddress}, {"networkname", args.NetworkName}}
1074 if err = m.st.networkInterfaces.Find(sel).One(nil); err == nil {
1075 return nil, errors.AlreadyExistsf("MAC address %q on network %q", args.MACAddress, args.NetworkName)
1076 }
1077 // Should never happen.
1078 logger.Errorf("unknown error while adding network interface doc %#v", doc)
1067 }1079 }
1068 return nil, err1080 return nil, err
1069}1081}
10701082
=== modified file 'state/machine_test.go'
--- state/machine_test.go 2014-04-14 12:36:13 +0000
+++ state/machine_test.go 2014-04-18 16:46:53 +0000
@@ -12,6 +12,7 @@
12 gc "launchpad.net/gocheck"12 gc "launchpad.net/gocheck"
1313
14 "launchpad.net/juju-core/constraints"14 "launchpad.net/juju-core/constraints"
15 "launchpad.net/juju-core/environs/network"
15 "launchpad.net/juju-core/errors"16 "launchpad.net/juju-core/errors"
16 "launchpad.net/juju-core/instance"17 "launchpad.net/juju-core/instance"
17 "launchpad.net/juju-core/state"18 "launchpad.net/juju-core/state"
@@ -389,12 +390,22 @@
389}390}
390391
391func addNetworkAndInterface(c *gc.C, st *state.State, machine *state.Machine,392func addNetworkAndInterface(c *gc.C, st *state.State, machine *state.Machine,
392 networkName, providerId, cidr string, vlanTag int,393 networkName, providerId, cidr string, vlanTag int, isVirtual bool,
393 mac, ifaceName string,394 mac, ifaceName string,
394) (*state.Network, *state.NetworkInterface) {395) (*state.Network, *state.NetworkInterface) {
395 net, err := st.AddNetwork(networkName, providerId, cidr, vlanTag)396 net, err := st.AddNetwork(state.NetworkInfo{
397 Name: networkName,
398 ProviderId: network.Id(providerId),
399 CIDR: cidr,
400 VLANTag: vlanTag,
401 })
396 c.Assert(err, gc.IsNil)402 c.Assert(err, gc.IsNil)
397 iface, err := machine.AddNetworkInterface(mac, ifaceName, networkName)403 iface, err := machine.AddNetworkInterface(state.NetworkInterfaceInfo{
404 MACAddress: mac,
405 InterfaceName: ifaceName,
406 NetworkName: networkName,
407 IsVirtual: isVirtual,
408 })
398 c.Assert(err, gc.IsNil)409 c.Assert(err, gc.IsNil)
399 return net, iface410 return net, iface
400}411}
@@ -419,11 +430,11 @@
419430
420 net1, _ := addNetworkAndInterface(431 net1, _ := addNetworkAndInterface(
421 c, s.State, machine,432 c, s.State, machine,
422 "net1", "net1", "0.1.2.0/24", 0,433 "net1", "net1", "0.1.2.0/24", 0, false,
423 "aa:bb:cc:dd:ee:f0", "eth0")434 "aa:bb:cc:dd:ee:f0", "eth0")
424 net2, _ := addNetworkAndInterface(435 net2, _ := addNetworkAndInterface(
425 c, s.State, machine,436 c, s.State, machine,
426 "net2", "net2", "0.2.2.0/24", 0,437 "net2", "net2", "0.2.2.0/24", 0, false,
427 "aa:bb:cc:dd:ee:f1", "eth1")438 "aa:bb:cc:dd:ee:f1", "eth1")
428439
429 nets, err = machine.Networks()440 nets, err = machine.Networks()
@@ -448,15 +459,15 @@
448 // And a few networks and NICs.459 // And a few networks and NICs.
449 _, iface0 := addNetworkAndInterface(460 _, iface0 := addNetworkAndInterface(
450 c, s.State, machine,461 c, s.State, machine,
451 "net1", "net1", "0.1.2.0/24", 0,462 "net1", "net1", "0.1.2.0/24", 0, false,
452 "aa:bb:cc:dd:ee:f0", "eth0")463 "aa:bb:cc:dd:ee:f0", "eth0")
453 _, iface1 := addNetworkAndInterface(464 _, iface1 := addNetworkAndInterface(
454 c, s.State, machine,465 c, s.State, machine,
455 "vlan42", "vlan42", "0.1.2.0/30", 42,466 "vlan42", "vlan42", "0.1.2.0/30", 42, true,
456 "aa:bb:cc:dd:ee:f1", "eth0.42")467 "aa:bb:cc:dd:ee:f1", "eth0.42")
457 _, iface2 := addNetworkAndInterface(468 _, iface2 := addNetworkAndInterface(
458 c, s.State, machine,469 c, s.State, machine,
459 "net2", "net2", "0.2.2.0/24", 0,470 "net2", "net2", "0.2.2.0/24", 0, false,
460 "aa:bb:cc:dd:ee:f2", "eth1")471 "aa:bb:cc:dd:ee:f2", "eth1")
461472
462 ifaces, err = machine.NetworkInterfaces()473 ifaces, err = machine.NetworkInterfaces()
@@ -476,49 +487,47 @@
476}487}
477488
478var addNetworkInterfaceErrorsTests = []struct {489var addNetworkInterfaceErrorsTests = []struct {
479 macAddress string490 args state.NetworkInterfaceInfo
480 interfaceName string491 beforeAdding func(*gc.C, *state.Machine)
481 networkName string492 expectErr string
482 beforeAdding func(*gc.C, *state.Machine)
483 expectErr string
484}{{493}{{
485 "", "eth1", "net1",494 state.NetworkInterfaceInfo{"", "eth1", "net1", false},
486 nil,495 nil,
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`,
488}, {497}, {
489 "invalid", "eth1", "net1",498 state.NetworkInterfaceInfo{"invalid", "eth1", "net1", false},
490 nil,499 nil,
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`,
492}, {501}, {
493 "aa:bb:cc:dd:ee:f0", "eth1", "net1",502 state.NetworkInterfaceInfo{"aa:bb:cc:dd:ee:f0", "eth1", "net1", false},
494 nil,503 nil,
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`,
496}, {505}, {
497 "aa:bb:cc:dd:ee:ff", "", "net1",506 state.NetworkInterfaceInfo{"aa:bb:cc:dd:ee:ff", "", "net1", false},
498 nil,507 nil,
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`,
500}, {509}, {
501 "aa:bb:cc:dd:ee:ff", "eth0", "net1",510 state.NetworkInterfaceInfo{"aa:bb:cc:dd:ee:ff", "eth0", "net1", false},
502 nil,511 nil,
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`,
504}, {513}, {
505 "aa:bb:cc:dd:ee:ff", "eth1", "missing",514 state.NetworkInterfaceInfo{"aa:bb:cc:dd:ee:ff", "eth1", "missing", false},
506 nil,515 nil,
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`,
508}, {517}, {
509 "aa:bb:cc:dd:ee:f1", "eth1", "net1",518 state.NetworkInterfaceInfo{"aa:bb:cc:dd:ee:f1", "eth1", "net1", false},
510 func(c *gc.C, m *state.Machine) {519 func(c *gc.C, m *state.Machine) {
511 c.Check(m.SetProvisioned("i-am", "fake_nonce", nil), gc.IsNil)520 c.Check(m.SetProvisioned("i-am", "fake_nonce", nil), gc.IsNil)
512 },521 },
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`,
514}, {523}, {
515 "aa:bb:cc:dd:ee:f1", "eth1", "net1",524 state.NetworkInterfaceInfo{"aa:bb:cc:dd:ee:f1", "eth1", "net1", false},
516 func(c *gc.C, m *state.Machine) {525 func(c *gc.C, m *state.Machine) {
517 c.Check(m.EnsureDead(), gc.IsNil)526 c.Check(m.EnsureDead(), gc.IsNil)
518 },527 },
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`,
520}, {529}, {
521 "aa:bb:cc:dd:ee:f1", "eth1", "net1",530 state.NetworkInterfaceInfo{"aa:bb:cc:dd:ee:f1", "eth1", "net1", false},
522 func(c *gc.C, m *state.Machine) {531 func(c *gc.C, m *state.Machine) {
523 c.Check(m.Remove(), gc.IsNil)532 c.Check(m.Remove(), gc.IsNil)
524 },533 },
@@ -534,18 +543,20 @@
534 c.Assert(err, gc.IsNil)543 c.Assert(err, gc.IsNil)
535 addNetworkAndInterface(544 addNetworkAndInterface(
536 c, s.State, machine,545 c, s.State, machine,
537 "net1", "provider-net1", "0.1.2.0/24", 0,546 "net1", "provider-net1", "0.1.2.0/24", 0, false,
538 "aa:bb:cc:dd:ee:f0", "eth0")547 "aa:bb:cc:dd:ee:f0", "eth0")
548 ifaces, err := machine.NetworkInterfaces()
549 c.Assert(err, gc.IsNil)
550 c.Assert(ifaces, gc.HasLen, 1)
539551
540 for i, test := range addNetworkInterfaceErrorsTests {552 for i, test := range addNetworkInterfaceErrorsTests {
541 c.Logf("test %d: mac=%q, name=%q, network=%q",553 c.Logf("test %d: %#v", i, test.args)
542 i, test.macAddress, test.interfaceName, test.networkName)
543554
544 if test.beforeAdding != nil {555 if test.beforeAdding != nil {
545 test.beforeAdding(c, machine)556 test.beforeAdding(c, machine)
546 }557 }
547558
548 _, err = machine.AddNetworkInterface(test.macAddress, test.interfaceName, test.networkName)559 _, err = machine.AddNetworkInterface(test.args)
549 c.Check(err, gc.ErrorMatches, test.expectErr)560 c.Check(err, gc.ErrorMatches, test.expectErr)
550 if strings.Contains(test.expectErr, "not found") {561 if strings.Contains(test.expectErr, "not found") {
551 c.Check(err, jc.Satisfies, errors.IsNotFound)562 c.Check(err, jc.Satisfies, errors.IsNotFound)
@@ -685,9 +696,11 @@
685696
686func (s *MachineSuite) TestMachineSetInstanceInfoSuccess(c *gc.C) {697func (s *MachineSuite) TestMachineSetInstanceInfoSuccess(c *gc.C) {
687 c.Assert(s.machine.CheckProvisioned("fake_nonce"), gc.Equals, false)698 c.Assert(s.machine.CheckProvisioned("fake_nonce"), gc.Equals, false)
688 networks := []state.NetworkInfo{{Name: "net1", ProviderId: "net1", CIDR: "0.1.2.0/24", VLANTag: 0}}699 networks := []state.NetworkInfo{
700 {Name: "net1", ProviderId: "net1", CIDR: "0.1.2.0/24", VLANTag: 0},
701 }
689 interfaces := []state.NetworkInterfaceInfo{702 interfaces := []state.NetworkInterfaceInfo{
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},
691 }704 }
692 err := s.machine.SetInstanceInfo("umbrella/0", "fake_nonce", nil, networks, interfaces)705 err := s.machine.SetInstanceInfo("umbrella/0", "fake_nonce", nil, networks, interfaces)
693 c.Assert(err, gc.IsNil)706 c.Assert(err, gc.IsNil)
@@ -705,6 +718,7 @@
705 c.Check(ifaces[0].NetworkName(), gc.Equals, interfaces[0].NetworkName)718 c.Check(ifaces[0].NetworkName(), gc.Equals, interfaces[0].NetworkName)
706 c.Check(ifaces[0].MACAddress(), gc.Equals, interfaces[0].MACAddress)719 c.Check(ifaces[0].MACAddress(), gc.Equals, interfaces[0].MACAddress)
707 c.Check(ifaces[0].MachineTag(), gc.Equals, s.machine.Tag())720 c.Check(ifaces[0].MachineTag(), gc.Equals, s.machine.Tag())
721 c.Check(ifaces[0].IsVirtual(), gc.Equals, interfaces[0].IsVirtual)
708}722}
709723
710func (s *MachineSuite) TestMachineSetProvisionedWhenNotAlive(c *gc.C) {724func (s *MachineSuite) TestMachineSetProvisionedWhenNotAlive(c *gc.C) {
711725
=== modified file 'state/networkinterfaces.go'
--- state/networkinterfaces.go 2014-04-11 15:10:48 +0000
+++ state/networkinterfaces.go 2014-04-18 16:46:53 +0000
@@ -4,6 +4,10 @@
4package state4package state
55
6import (6import (
7 "fmt"
8
9 "labix.org/v2/mgo/bson"
10
7 "launchpad.net/juju-core/names"11 "launchpad.net/juju-core/names"
8)12)
913
@@ -27,25 +31,49 @@
2731
28 // NetworkName is this interface's network name.32 // NetworkName is this interface's network name.
29 NetworkName string33 NetworkName string
34
35 // IsVirtual is true when the interface is a virtual device, as
36 // opposed to a physical device.
37 IsVirtual bool
30}38}
3139
32// networkInterfaceDoc represents a network interface for a machine on40// networkInterfaceDoc represents a network interface for a machine on
33// a given network.41// a given network.
34//
35// TODO(dimitern) To allow multiple virtual (e.g. VLAN) interfaces on
36// the same MAC address, we need to change the key and uniqueness
37// constraints.
38type networkInterfaceDoc struct {42type networkInterfaceDoc struct {
39 MACAddress string `bson:"_id"`43 Id bson.ObjectId `bson:"_id"`
44 MACAddress string
40 InterfaceName string45 InterfaceName string
41 NetworkName string46 NetworkName string
42 MachineId string47 MachineId string
48 IsVirtual bool
43}49}
4450
45func newNetworkInterface(st *State, doc *networkInterfaceDoc) *NetworkInterface {51func newNetworkInterface(st *State, doc *networkInterfaceDoc) *NetworkInterface {
46 return &NetworkInterface{st, *doc}52 return &NetworkInterface{st, *doc}
47}53}
4854
55func newNetworkInterfaceDoc(args NetworkInterfaceInfo) *networkInterfaceDoc {
56 // This does not set the machine id.
57 return &networkInterfaceDoc{
58 MACAddress: args.MACAddress,
59 InterfaceName: args.InterfaceName,
60 NetworkName: args.NetworkName,
61 IsVirtual: args.IsVirtual,
62 }
63}
64
65// GoString implements fmt.GoStringer.
66func (ni *NetworkInterface) GoString() string {
67 return fmt.Sprintf(
68 "&state.NetworkInterface{machineId: %q, mac: %q, name: %q, networkName: %q, isVirtual: %v}",
69 ni.MachineId(), ni.MACAddress(), ni.InterfaceName(), ni.NetworkName(), ni.IsVirtual())
70}
71
72// Id returns the internal juju-specific id of the interface.
73func (ni *NetworkInterface) Id() string {
74 return ni.doc.Id.String()
75}
76
49// MACAddress returns the MAC address of the interface.77// MACAddress returns the MAC address of the interface.
50func (ni *NetworkInterface) MACAddress() string {78func (ni *NetworkInterface) MACAddress() string {
51 return ni.doc.MACAddress79 return ni.doc.MACAddress
@@ -56,7 +84,7 @@
56 return ni.doc.InterfaceName84 return ni.doc.InterfaceName
57}85}
5886
59// NetworkId returns the network name of the interface.87// NetworkName returns the network name of the interface.
60func (ni *NetworkInterface) NetworkName() string {88func (ni *NetworkInterface) NetworkName() string {
61 return ni.doc.NetworkName89 return ni.doc.NetworkName
62}90}
@@ -75,3 +103,15 @@
75func (ni *NetworkInterface) MachineTag() string {103func (ni *NetworkInterface) MachineTag() string {
76 return names.MachineTag(ni.doc.MachineId)104 return names.MachineTag(ni.doc.MachineId)
77}105}
106
107// IsVirtual returns whether the interface represents a virtual
108// device.
109func (ni *NetworkInterface) IsVirtual() bool {
110 return ni.doc.IsVirtual
111}
112
113// IsPhysical returns whether the interface represents a physical
114// device.
115func (ni *NetworkInterface) IsPhysical() bool {
116 return !ni.doc.IsVirtual
117}
78118
=== modified file 'state/networkinterfaces_test.go'
--- state/networkinterfaces_test.go 2014-04-10 14:40:34 +0000
+++ state/networkinterfaces_test.go 2014-04-18 16:46:53 +0000
@@ -4,6 +4,7 @@
4package state_test4package state_test
55
6import (6import (
7 jc "github.com/juju/testing/checkers"
7 gc "launchpad.net/gocheck"8 gc "launchpad.net/gocheck"
89
9 "launchpad.net/juju-core/state"10 "launchpad.net/juju-core/state"
@@ -23,17 +24,25 @@
23 var err error24 var err error
24 s.machine, err = s.State.AddMachine("quantal", state.JobHostUnits)25 s.machine, err = s.State.AddMachine("quantal", state.JobHostUnits)
25 c.Assert(err, gc.IsNil)26 c.Assert(err, gc.IsNil)
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})
27 c.Assert(err, gc.IsNil)28 c.Assert(err, gc.IsNil)
28 s.iface, err = s.machine.AddNetworkInterface("aa:bb:cc:dd:ee:ff", "eth0", "net1")29 s.iface, err = s.machine.AddNetworkInterface(state.NetworkInterfaceInfo{
30 MACAddress: "aa:bb:cc:dd:ee:ff",
31 InterfaceName: "eth0",
32 NetworkName: "net1",
33 IsVirtual: true,
34 })
29 c.Assert(err, gc.IsNil)35 c.Assert(err, gc.IsNil)
30}36}
3137
32func (s *NetworkInterfaceSuite) TestGetterMethods(c *gc.C) {38func (s *NetworkInterfaceSuite) TestGetterMethods(c *gc.C) {
39 c.Assert(s.iface.Id(), gc.Not(gc.Equals), "")
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")
34 c.Assert(s.iface.InterfaceName(), gc.Equals, "eth0")41 c.Assert(s.iface.InterfaceName(), gc.Equals, "eth0")
35 c.Assert(s.iface.NetworkName(), gc.Equals, s.network.Name())42 c.Assert(s.iface.NetworkName(), gc.Equals, s.network.Name())
36 c.Assert(s.iface.NetworkTag(), gc.Equals, s.network.Tag())43 c.Assert(s.iface.NetworkTag(), gc.Equals, s.network.Tag())
37 c.Assert(s.iface.MachineId(), gc.Equals, s.machine.Id())44 c.Assert(s.iface.MachineId(), gc.Equals, s.machine.Id())
38 c.Assert(s.iface.MachineTag(), gc.Equals, s.machine.Tag())45 c.Assert(s.iface.MachineTag(), gc.Equals, s.machine.Tag())
46 c.Assert(s.iface.IsVirtual(), jc.IsTrue)
47 c.Assert(s.iface.IsPhysical(), jc.IsFalse)
39}48}
4049
=== modified file 'state/networks.go'
--- state/networks.go 2014-04-11 15:10:48 +0000
+++ state/networks.go 2014-04-18 16:46:53 +0000
@@ -4,8 +4,11 @@
4package state4package state
55
6import (6import (
7 "fmt"
8
7 "labix.org/v2/mgo/bson"9 "labix.org/v2/mgo/bson"
810
11 "launchpad.net/juju-core/environs/network"
9 "launchpad.net/juju-core/names"12 "launchpad.net/juju-core/names"
10)13)
1114
@@ -21,7 +24,7 @@
21 Name string24 Name string
2225
23 // ProviderId is a provider-specific network id.26 // ProviderId is a provider-specific network id.
24 ProviderId string27 ProviderId network.Id
2528
26 // CIDR of the network, in 123.45.67.89/24 format.29 // CIDR of the network, in 123.45.67.89/24 format.
27 CIDR string30 CIDR string
@@ -38,7 +41,7 @@
38 // included networks.41 // included networks.
39 Name string `bson:"_id"`42 Name string `bson:"_id"`
4043
41 ProviderId string44 ProviderId network.Id
42 CIDR string45 CIDR string
43 VLANTag int46 VLANTag int
44}47}
@@ -47,13 +50,29 @@
47 return &Network{st, *doc}50 return &Network{st, *doc}
48}51}
4952
53func newNetworkDoc(args NetworkInfo) *networkDoc {
54 return &networkDoc{
55 Name: args.Name,
56 ProviderId: args.ProviderId,
57 CIDR: args.CIDR,
58 VLANTag: args.VLANTag,
59 }
60}
61
62// GoString implements fmt.GoStringer.
63func (n *Network) GoString() string {
64 return fmt.Sprintf(
65 "&state.Network{name: %q, providerId: %q, cidr: %q, vlanTag: %v}",
66 n.Name(), n.ProviderId(), n.CIDR(), n.VLANTag())
67}
68
50// Name returns the network name.69// Name returns the network name.
51func (n *Network) Name() string {70func (n *Network) Name() string {
52 return n.doc.Name71 return n.doc.Name
53}72}
5473
55// ProviderId returns the provider-specific id of the network.74// ProviderId returns the provider-specific id of the network.
56func (n *Network) ProviderId() string {75func (n *Network) ProviderId() network.Id {
57 return n.doc.ProviderId76 return n.doc.ProviderId
58}77}
5978
6079
=== modified file 'state/networks_test.go'
--- state/networks_test.go 2014-04-10 14:40:34 +0000
+++ state/networks_test.go 2014-04-18 16:46:53 +0000
@@ -24,15 +24,15 @@
24 var err error24 var err error
25 s.machine, err = s.State.AddMachine("quantal", state.JobHostUnits)25 s.machine, err = s.State.AddMachine("quantal", state.JobHostUnits)
26 c.Assert(err, gc.IsNil)26 c.Assert(err, gc.IsNil)
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})
28 c.Assert(err, gc.IsNil)28 c.Assert(err, gc.IsNil)
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})
30 c.Assert(err, gc.IsNil)30 c.Assert(err, gc.IsNil)
31}31}
3232
33func (s *NetworkSuite) TestGetterMethods(c *gc.C) {33func (s *NetworkSuite) TestGetterMethods(c *gc.C) {
34 c.Assert(s.network.Name(), gc.Equals, "net1")34 c.Assert(s.network.Name(), gc.Equals, "net1")
35 c.Assert(s.network.ProviderId(), gc.Equals, "net1")35 c.Assert(string(s.network.ProviderId()), gc.Equals, "net1")
36 c.Assert(s.network.Tag(), gc.Equals, "network-net1")36 c.Assert(s.network.Tag(), gc.Equals, "network-net1")
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")
38 c.Assert(s.network.VLANTag(), gc.Equals, 0)38 c.Assert(s.network.VLANTag(), gc.Equals, 0)
@@ -46,9 +46,19 @@
46 c.Assert(err, gc.IsNil)46 c.Assert(err, gc.IsNil)
47 c.Assert(ifaces, gc.HasLen, 0)47 c.Assert(ifaces, gc.HasLen, 0)
4848
49 iface0, err := s.machine.AddNetworkInterface("aa:bb:cc:dd:ee:f0", "eth0", "net1")49 iface0, err := s.machine.AddNetworkInterface(state.NetworkInterfaceInfo{
50 MACAddress: "aa:bb:cc:dd:ee:f0",
51 InterfaceName: "eth0",
52 NetworkName: "net1",
53 IsVirtual: false,
54 })
50 c.Assert(err, gc.IsNil)55 c.Assert(err, gc.IsNil)
51 iface1, err := s.machine.AddNetworkInterface("aa:bb:cc:dd:ee:f1", "eth1", "net1")56 iface1, err := s.machine.AddNetworkInterface(state.NetworkInterfaceInfo{
57 MACAddress: "aa:bb:cc:dd:ee:f1",
58 InterfaceName: "eth1",
59 NetworkName: "net1",
60 IsVirtual: false,
61 })
52 c.Assert(err, gc.IsNil)62 c.Assert(err, gc.IsNil)
5363
54 ifaces, err = s.network.Interfaces()64 ifaces, err = s.network.Interfaces()
5565
=== modified file 'state/open.go'
--- state/open.go 2014-04-17 17:30:48 +0000
+++ state/open.go 2014-04-18 16:46:53 +0000
@@ -209,6 +209,7 @@
209 {"users", []string{"name"}, false},209 {"users", []string{"name"}, false},
210 {"networks", []string{"providerid"}, true},210 {"networks", []string{"providerid"}, true},
211 {"networkinterfaces", []string{"interfacename", "machineid"}, true},211 {"networkinterfaces", []string{"interfacename", "machineid"}, true},
212 {"networkinterfaces", []string{"macaddress", "networkname"}, true},
212 {"networkinterfaces", []string{"networkname"}, false},213 {"networkinterfaces", []string{"networkname"}, false},
213 {"networkinterfaces", []string{"machineid"}, false},214 {"networkinterfaces", []string{"machineid"}, false},
214}215}
215216
=== modified file 'state/state.go'
--- state/state.go 2014-04-17 16:18:46 +0000
+++ state/state.go 2014-04-18 16:46:53 +0000
@@ -1014,47 +1014,41 @@
1014 return svc, nil1014 return svc, nil
1015}1015}
10161016
1017// AddNetwork creates a new network with the given name,1017// AddNetwork creates a new network with the given params. If a
1018// provider-specific id, CIDR and VLAN tag. If a network with the same1018// network with the same name or provider id already exists in state,
1019// name or provider id already exists in state, an error satisfying1019// an error satisfying errors.IsAlreadyExists is returned.
1020// errors.IsAlreadyExists is returned.1020func (st *State) AddNetwork(args NetworkInfo) (n *Network, err error) {
1021func (st *State) AddNetwork(name, providerId, cidr string, vlanTag int) (n *Network, err error) {1021 defer errors.Contextf(&err, "cannot add network %q", args.Name)
1022 defer errors.Contextf(&err, "cannot add network %q", name)1022 if args.CIDR != "" {
1023 if cidr != "" {1023 _, _, err := net.ParseCIDR(args.CIDR)
1024 _, _, err := net.ParseCIDR(cidr)
1025 if err != nil {1024 if err != nil {
1026 return nil, err1025 return nil, err
1027 }1026 }
1028 }1027 }
1029 if name == "" {1028 if args.Name == "" {
1030 return nil, fmt.Errorf("name must be not empty")1029 return nil, fmt.Errorf("name must be not empty")
1031 }1030 }
1032 if !names.IsNetwork(name) {1031 if !names.IsNetwork(args.Name) {
1033 return nil, fmt.Errorf("invalid name")1032 return nil, fmt.Errorf("invalid name")
1034 }1033 }
1035 if providerId == "" {1034 if args.ProviderId == "" {
1036 return nil, fmt.Errorf("provider id must be not empty")1035 return nil, fmt.Errorf("provider id must be not empty")
1037 }1036 }
1038 if vlanTag < 0 || vlanTag > 4094 {1037 if args.VLANTag < 0 || args.VLANTag > 4094 {
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)
1040 }1039 }
1041 doc := &networkDoc{1040 doc := newNetworkDoc(args)
1042 Name: name,
1043 ProviderId: providerId,
1044 CIDR: cidr,
1045 VLANTag: vlanTag,
1046 }
1047 ops := []txn.Op{{1041 ops := []txn.Op{{
1048 C: st.networks.Name,1042 C: st.networks.Name,
1049 Id: name,1043 Id: args.Name,
1050 Assert: txn.DocMissing,1044 Assert: txn.DocMissing,
1051 Insert: doc,1045 Insert: doc,
1052 }}1046 }}
1053 err = st.runTransaction(ops)1047 err = st.runTransaction(ops)
1054 switch err {1048 switch err {
1055 case txn.ErrAborted:1049 case txn.ErrAborted:
1056 if _, err = st.Network(name); err == nil {1050 if _, err = st.Network(args.Name); err == nil {
1057 return nil, errors.AlreadyExistsf("network %q", name)1051 return nil, errors.AlreadyExistsf("network %q", args.Name)
1058 } else if err != nil {1052 } else if err != nil {
1059 return nil, err1053 return nil, err
1060 }1054 }
@@ -1065,8 +1059,8 @@
1065 // logic does not report insertion errors, so we check that1059 // logic does not report insertion errors, so we check that
1066 // the record has actually been inserted correctly before1060 // the record has actually been inserted correctly before
1067 // reporting success.1061 // reporting success.
1068 if _, err = st.Network(name); err != nil {1062 if _, err = st.Network(args.Name); err != nil {
1069 return nil, errors.AlreadyExistsf("network with provider id %q", providerId)1063 return nil, errors.AlreadyExistsf("network with provider id %q", args.ProviderId)
1070 }1064 }
1071 return newNetwork(st, doc), nil1065 return newNetwork(st, doc), nil
1072 }1066 }
10731067
=== modified file 'state/state_test.go'
--- state/state_test.go 2014-04-17 15:32:49 +0000
+++ state/state_test.go 2014-04-18 16:46:53 +0000
@@ -963,34 +963,31 @@
963}963}
964964
965var addNetworkErrorsTests = []struct {965var addNetworkErrorsTests = []struct {
966 name string966 args state.NetworkInfo
967 providerId string967 expectErr string
968 cidr string
969 vlanTag int
970 expectErr string
971}{{968}{{
972 "", "provider-id", "0.3.1.0/24", 0,969 state.NetworkInfo{"", "provider-id", "0.3.1.0/24", 0},
973 `cannot add network "": name must be not empty`,970 `cannot add network "": name must be not empty`,
974}, {971}, {
975 "-invalid-", "provider-id", "0.3.1.0/24", 0,972 state.NetworkInfo{"-invalid-", "provider-id", "0.3.1.0/24", 0},
976 `cannot add network "-invalid-": invalid name`,973 `cannot add network "-invalid-": invalid name`,
977}, {974}, {
978 "net2", "", "0.3.1.0/24", 0,975 state.NetworkInfo{"net2", "", "0.3.1.0/24", 0},
979 `cannot add network "net2": provider id must be not empty`,976 `cannot add network "net2": provider id must be not empty`,
980}, {977}, {
981 "net2", "provider-id", "invalid", 0,978 state.NetworkInfo{"net2", "provider-id", "invalid", 0},
982 `cannot add network "net2": invalid CIDR address: invalid`,979 `cannot add network "net2": invalid CIDR address: invalid`,
983}, {980}, {
984 "net2", "provider-id", "0.3.1.0/24", -1,981 state.NetworkInfo{"net2", "provider-id", "0.3.1.0/24", -1},
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`,
986}, {983}, {
987 "net2", "provider-id", "0.3.1.0/24", 9999,984 state.NetworkInfo{"net2", "provider-id", "0.3.1.0/24", 9999},
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`,
989}, {986}, {
990 "net1", "provider-id", "0.3.1.0/24", 0,987 state.NetworkInfo{"net1", "provider-id", "0.3.1.0/24", 0},
991 `cannot add network "net1": network "net1" already exists`,988 `cannot add network "net1": network "net1" already exists`,
992}, {989}, {
993 "net2", "provider-net1", "0.3.1.0/24", 0,990 state.NetworkInfo{"net2", "provider-net1", "0.3.1.0/24", 0},
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`,
995}}992}}
996993
@@ -1005,22 +1002,21 @@
10051002
1006 net1, _ := addNetworkAndInterface(1003 net1, _ := addNetworkAndInterface(
1007 c, s.State, machine,1004 c, s.State, machine,
1008 "net1", "provider-net1", "0.1.2.0/24", 0,1005 "net1", "provider-net1", "0.1.2.0/24", 0, false,
1009 "aa:bb:cc:dd:ee:f0", "eth0")1006 "aa:bb:cc:dd:ee:f0", "eth0")
10101007
1011 net, err := s.State.Network("net1")1008 net, err := s.State.Network("net1")
1012 c.Assert(err, gc.IsNil)1009 c.Assert(err, gc.IsNil)
1013 c.Assert(net, gc.DeepEquals, net1)1010 c.Assert(net, gc.DeepEquals, net1)
1014 c.Assert(net.Name(), gc.Equals, "net1")1011 c.Assert(net.Name(), gc.Equals, "net1")
1015 c.Assert(net.ProviderId(), gc.Equals, "provider-net1")1012 c.Assert(string(net.ProviderId()), gc.Equals, "provider-net1")
1016 _, err = s.State.Network("missing")1013 _, err = s.State.Network("missing")
1017 c.Assert(err, jc.Satisfies, errors.IsNotFound)1014 c.Assert(err, jc.Satisfies, errors.IsNotFound)
1018 c.Assert(err, gc.ErrorMatches, `network "missing" not found`)1015 c.Assert(err, gc.ErrorMatches, `network "missing" not found`)
10191016
1020 for i, test := range addNetworkErrorsTests {1017 for i, test := range addNetworkErrorsTests {
1021 c.Logf("test %d: name=%q, providerId=%q, cidr=%q, vlanTag=%d",1018 c.Logf("test %d: %#v", i, test.args)
1022 i, test.name, test.providerId, test.cidr, test.vlanTag)1019 _, err := s.State.AddNetwork(test.args)
1023 _, err := s.State.AddNetwork(test.name, test.providerId, test.cidr, test.vlanTag)
1024 c.Check(err, gc.ErrorMatches, test.expectErr)1020 c.Check(err, gc.ErrorMatches, test.expectErr)
1025 if strings.Contains(test.expectErr, "already exists") {1021 if strings.Contains(test.expectErr, "already exists") {
1026 c.Check(err, jc.Satisfies, errors.IsAlreadyExists)1022 c.Check(err, jc.Satisfies, errors.IsAlreadyExists)
@@ -2280,10 +2276,15 @@
2280 rel, err := s.State.AddRelation(eps...)2276 rel, err := s.State.AddRelation(eps...)
2281 c.Assert(err, gc.IsNil)2277 c.Assert(err, gc.IsNil)
2282 c.Assert(rel.String(), gc.Equals, "wordpress:db ser-vice2:server")2278 c.Assert(rel.String(), gc.Equals, "wordpress:db ser-vice2:server")
2283 net1, err := s.State.AddNetwork("net1", "provider-id", "0.1.2.0/24", 0)2279 net1, err := s.State.AddNetwork(state.NetworkInfo{
2280 Name: "net1",
2281 ProviderId: "provider-id",
2282 CIDR: "0.1.2.0/24",
2283 VLANTag: 0,
2284 })
2284 c.Assert(err, gc.IsNil)2285 c.Assert(err, gc.IsNil)
2285 c.Assert(net1.Tag(), gc.Equals, "network-net1")2286 c.Assert(net1.Tag(), gc.Equals, "network-net1")
2286 c.Assert(net1.ProviderId(), gc.Equals, "provider-id")2287 c.Assert(string(net1.ProviderId()), gc.Equals, "provider-id")
22872288
2288 // environment tag is dynamically generated2289 // environment tag is dynamically generated
2289 env, err := s.State.Environment()2290 env, err := s.State.Environment()
@@ -2375,7 +2376,12 @@
2375 c.Assert(err, gc.IsNil)2376 c.Assert(err, gc.IsNil)
23762377
2377 // Parse a network name.2378 // Parse a network name.
2378 net1, err := s.State.AddNetwork("net1", "provider-id", "0.1.2.0/24", 0)2379 net1, err := s.State.AddNetwork(state.NetworkInfo{
2380 Name: "net1",
2381 ProviderId: "provider-id",
2382 CIDR: "0.1.2.0/24",
2383 VLANTag: 0,
2384 })
2379 c.Assert(err, gc.IsNil)2385 c.Assert(err, gc.IsNil)
2380 coll, id, err = state.ParseTag(s.State, net1.Tag())2386 coll, id, err = state.ParseTag(s.State, net1.Tag())
2381 c.Assert(coll, gc.Equals, "networks")2387 c.Assert(coll, gc.Equals, "networks")
23822388
=== modified file 'worker/provisioner/kvm-broker.go'
--- worker/provisioner/kvm-broker.go 2014-04-08 03:37:14 +0000
+++ worker/provisioner/kvm-broker.go 2014-04-18 16:46:53 +0000
@@ -12,6 +12,7 @@
12 "launchpad.net/juju-core/container"12 "launchpad.net/juju-core/container"
13 "launchpad.net/juju-core/container/kvm"13 "launchpad.net/juju-core/container/kvm"
14 "launchpad.net/juju-core/environs"14 "launchpad.net/juju-core/environs"
15 "launchpad.net/juju-core/environs/network"
15 "launchpad.net/juju-core/instance"16 "launchpad.net/juju-core/instance"
16 "launchpad.net/juju-core/tools"17 "launchpad.net/juju-core/tools"
17)18)
@@ -54,7 +55,7 @@
54}55}
5556
56// StartInstance is specified in the Broker interface.57// StartInstance is specified in the Broker interface.
57func (broker *kvmBroker) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) {58func (broker *kvmBroker) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) {
58 if args.MachineConfig.HasNetworks() {59 if args.MachineConfig.HasNetworks() {
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.")
60 }61 }
6162
=== modified file 'worker/provisioner/lxc-broker.go'
--- worker/provisioner/lxc-broker.go 2014-04-08 03:37:14 +0000
+++ worker/provisioner/lxc-broker.go 2014-04-18 16:46:53 +0000
@@ -12,6 +12,7 @@
12 "launchpad.net/juju-core/container"12 "launchpad.net/juju-core/container"
13 "launchpad.net/juju-core/container/lxc"13 "launchpad.net/juju-core/container/lxc"
14 "launchpad.net/juju-core/environs"14 "launchpad.net/juju-core/environs"
15 "launchpad.net/juju-core/environs/network"
15 "launchpad.net/juju-core/instance"16 "launchpad.net/juju-core/instance"
16 "launchpad.net/juju-core/state/api/params"17 "launchpad.net/juju-core/state/api/params"
17 "launchpad.net/juju-core/tools"18 "launchpad.net/juju-core/tools"
@@ -55,7 +56,7 @@
55}56}
5657
57// StartInstance is specified in the Broker interface.58// StartInstance is specified in the Broker interface.
58func (broker *lxcBroker) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) {59func (broker *lxcBroker) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) {
59 if args.MachineConfig.HasNetworks() {60 if args.MachineConfig.HasNetworks() {
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.")
61 }62 }
6263
=== modified file 'worker/provisioner/provisioner_task.go'
--- worker/provisioner/provisioner_task.go 2014-04-17 13:21:44 +0000
+++ worker/provisioner/provisioner_task.go 2014-04-18 16:46:53 +0000
@@ -11,6 +11,7 @@
11 "launchpad.net/juju-core/constraints"11 "launchpad.net/juju-core/constraints"
12 "launchpad.net/juju-core/environs"12 "launchpad.net/juju-core/environs"
13 "launchpad.net/juju-core/environs/cloudinit"13 "launchpad.net/juju-core/environs/cloudinit"
14 "launchpad.net/juju-core/environs/network"
14 "launchpad.net/juju-core/environs/tools"15 "launchpad.net/juju-core/environs/tools"
15 "launchpad.net/juju-core/instance"16 "launchpad.net/juju-core/instance"
16 "launchpad.net/juju-core/names"17 "launchpad.net/juju-core/names"
@@ -421,7 +422,7 @@
421 return nil422 return nil
422}423}
423424
424func (task *provisionerTask) prepareNetworkAndInterfaces(networkInfo []environs.NetworkInfo) (425func (task *provisionerTask) prepareNetworkAndInterfaces(networkInfo []network.Info) (
425 networks []params.Network, ifaces []params.NetworkInterface) {426 networks []params.Network, ifaces []params.NetworkInterface) {
426 if len(networkInfo) == 0 {427 if len(networkInfo) == 0 {
427 return nil, nil428 return nil, nil
@@ -429,19 +430,20 @@
429 visitedNetworks := set.NewStrings()430 visitedNetworks := set.NewStrings()
430 for _, info := range networkInfo {431 for _, info := range networkInfo {
431 networkTag := names.NetworkTag(info.NetworkName)432 networkTag := names.NetworkTag(info.NetworkName)
432 if !visitedNetworks.Contains(info.NetworkId) {433 if !visitedNetworks.Contains(networkTag) {
433 networks = append(networks, params.Network{434 networks = append(networks, params.Network{
434 Tag: networkTag,435 Tag: networkTag,
435 ProviderId: info.NetworkId,436 ProviderId: info.ProviderId,
436 CIDR: info.CIDR,437 CIDR: info.CIDR,
437 VLANTag: info.VLANTag,438 VLANTag: info.VLANTag,
438 })439 })
439 visitedNetworks.Add(info.NetworkId)440 visitedNetworks.Add(networkTag)
440 }441 }
441 ifaces = append(ifaces, params.NetworkInterface{442 ifaces = append(ifaces, params.NetworkInterface{
442 InterfaceName: info.InterfaceName,443 InterfaceName: info.InterfaceName,
443 MACAddress: info.MACAddress,444 MACAddress: info.MACAddress,
444 NetworkTag: networkTag,445 NetworkTag: networkTag,
446 IsVirtual: info.IsVirtual,
445 })447 })
446 }448 }
447 return networks, ifaces449 return networks, ifaces
448450
=== modified file 'worker/provisioner/provisioner_test.go'
--- worker/provisioner/provisioner_test.go 2014-04-14 12:36:13 +0000
+++ worker/provisioner/provisioner_test.go 2014-04-18 16:46:53 +0000
@@ -14,6 +14,7 @@
14 "launchpad.net/juju-core/constraints"14 "launchpad.net/juju-core/constraints"
15 "launchpad.net/juju-core/environs"15 "launchpad.net/juju-core/environs"
16 "launchpad.net/juju-core/environs/config"16 "launchpad.net/juju-core/environs/config"
17 "launchpad.net/juju-core/environs/network"
17 "launchpad.net/juju-core/environs/simplestreams"18 "launchpad.net/juju-core/environs/simplestreams"
18 "launchpad.net/juju-core/environs/tools"19 "launchpad.net/juju-core/environs/tools"
19 "launchpad.net/juju-core/errors"20 "launchpad.net/juju-core/errors"
@@ -165,7 +166,7 @@
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)
166}167}
167168
168func (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) {169func (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) {
169 s.BackingState.StartSync()170 s.BackingState.StartSync()
170 for {171 for {
171 select {172 select {
@@ -473,20 +474,22 @@
473 // Add and provision a machine with networks specified.474 // Add and provision a machine with networks specified.
474 includeNetworks := []string{"net1", "net2"}475 includeNetworks := []string{"net1", "net2"}
475 excludeNetworks := []string{"net3", "net4"}476 excludeNetworks := []string{"net3", "net4"}
476 expectNetworkInfo := []environs.NetworkInfo{{477 expectNetworkInfo := []network.Info{{
477 MACAddress: "aa:bb:cc:dd:ee:f0",478 MACAddress: "aa:bb:cc:dd:ee:f0",
478 InterfaceName: "eth0",479 InterfaceName: "eth0",
479 NetworkId: "net1",480 ProviderId: "net1",
480 NetworkName: "net1",481 NetworkName: "net1",
481 VLANTag: 0,482 VLANTag: 0,
482 CIDR: "0.1.2.0/24",483 CIDR: "0.1.2.0/24",
484 IsVirtual: false,
483 }, {485 }, {
484 MACAddress: "aa:bb:cc:dd:ee:f1",486 MACAddress: "aa:bb:cc:dd:ee:f1",
485 InterfaceName: "eth1",487 InterfaceName: "eth1",
486 NetworkId: "net2",488 ProviderId: "net2",
487 NetworkName: "net2",489 NetworkName: "net2",
488 VLANTag: 1,490 VLANTag: 1,
489 CIDR: "0.2.2.0/24",491 CIDR: "0.2.2.0/24",
492 IsVirtual: true,
490 }}493 }}
491 m, err := s.addMachineWithRequestedNetworks(includeNetworks, excludeNetworks)494 m, err := s.addMachineWithRequestedNetworks(includeNetworks, excludeNetworks)
492 c.Assert(err, gc.IsNil)495 c.Assert(err, gc.IsNil)
@@ -519,9 +522,9 @@
519 // Add and provision a machine with networks specified.522 // Add and provision a machine with networks specified.
520 includeNetworks := []string{"bad-net1"}523 includeNetworks := []string{"bad-net1"}
521 // "bad-" prefix for networks causes dummy provider to report524 // "bad-" prefix for networks causes dummy provider to report
522 // invalid NetworkInfo.525 // invalid network.Info.
523 expectNetworkInfo := []environs.NetworkInfo{526 expectNetworkInfo := []network.Info{
524 {NetworkId: "bad-net1", NetworkName: "bad-net1", CIDR: "invalid"},527 {ProviderId: "bad-net1", NetworkName: "bad-net1", CIDR: "invalid"},
525 }528 }
526 m, err := s.addMachineWithRequestedNetworks(includeNetworks, nil)529 m, err := s.addMachineWithRequestedNetworks(includeNetworks, nil)
527 c.Assert(err, gc.IsNil)530 c.Assert(err, gc.IsNil)
@@ -924,7 +927,7 @@
924 retryCount map[string]int927 retryCount map[string]int
925}928}
926929
927func (b *mockBroker) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []environs.NetworkInfo, error) {930func (b *mockBroker) StartInstance(args environs.StartInstanceParams) (instance.Instance, *instance.HardwareCharacteristics, []network.Info, error) {
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.
929 // Machines 3 is provisioned after some attempts have been made.932 // Machines 3 is provisioned after some attempts have been made.
930 // Machine 4 is never provisioned.933 // Machine 4 is never provisioned.

Subscribers

People subscribed via source and target branches

to status/vote changes: