Join GitHub today
GitHub is home to over 20 million developers working together to host and review code, manage projects, and build software together.
provider/gce: implement Subnets and NetworkInterfaces #7126
Conversation
|
!!build!! |
|
!!build!! |
jameinel
requested changes
Mar 20, 2017
I think the general shape is OK. I'd like to double check what we should be using as a ProviderId as the full URL doesn't quite feel right.
https://cloud.google.com/compute/docs/instances/create-start-instance#creating_an_instance_in_a_custom_subnet_network
seems to say the 'providerID' should be just the tail:
"subnetwork": "regions/[REGION]/subnetworks/[SUBNET_NAME]",
| + googleInst := envInst.base | ||
| + // According to GCE docs, an instance can only have one nic. | ||
| + // https://cloud.google.com/compute/docs/instances/#instances_and_networks | ||
| + if ifaces := len(googleInst.NetworkInterfaces()); ifaces != 1 { |
jameinel
Mar 20, 2017
Owner
Why force it to be just one? It seems like all of this can just iterate over a loop on these objects and build up a list and perhaps only at the end assert that there is 1.
Given the function calls are already returning lists, it seems silly to start failing the moment the list can be >1.
babbageclunk
Mar 20, 2017
Member
My thinking was that it would be a bit of fiddly code that we don't need now - we don't want to do one Subnets call for each interface, so it would be something like:
- collect the subnet ids
- make the call and pull the results into a map
- match each interface up with its subnet
- handle and test for the cases where not all the subnets come back.
But I wasn't super comfortable with that decision - like you say, the source is a list so probably there'll be more things in there at some point. I'll expand it out.
| +} | ||
| + | ||
| +// AllocateContainerAddresses implements environs.NetworkingEnviron. | ||
| +func (e *environ) AllocateContainerAddresses(instance.Id, names.MachineTag, []network.InterfaceInfo) ([]network.InterfaceInfo, error) { |
| + return errors.NotSupportedf("container addresses") | ||
| +} | ||
| + | ||
| +func makeSubnetInfo(subnetId network.Id, cidr string, zones []string) network.SubnetInfo { |
jameinel
Mar 20, 2017
Owner
This seems perfectly fine. You wouldn't be using SpaceProviderID or VLAN as they aren't relevant for these (and should be commented as optional).
Often I've found the Go practice of omitting fields that are 'implicitly' set to the Zero value to not be amazing, because it isn't always clear that the caller knew that they were there and explicitly wanted the zero value, vs didn't know that they were there and thus they accidentally inherited the default value.
so I'd personally be fine with adding an explicit:
VLAN: 0, // No VLANs in GCE
SpaceProviderID: "", // No Spaces defined by GCE
or something to that effect, but I wouldn't mandate it, either.
babbageclunk
Mar 20, 2017
Member
Yeah, I think you're right - I've done that for default-value fields in InterfaceInfo, for example. I'll add those in.
| + return network.SubnetInfo{ | ||
| + ProviderId: subnetId, | ||
| + CIDR: cidr, | ||
| + AvailabilityZones: zonesCopy, |
jameinel
Mar 20, 2017
Owner
Reading through the GCE docs, I'm pretty sure we need to start modeling "networks" sooner rather than later. Can you add a field to SubnetInfo which is NetworkProviderId and populate that field here? Existing Subnets are probably ok, because MAAS doesn't really have the concept yet of disjoint subnets. We should start populating VPC-ID for AWS subnets as well.
But given GCE can have 1 project with multiple disjoint Networks, such that you end up with overlapping Subnet ranges, we really need to start tracking network ids.
If it ends up a huge yak with many layers of tests that start breaking, you can punt, but it is pretty clearly useful to get there, and feels better to start adding them now if we can.
| - c.Check(s.FakeConn.Calls[0].FirewallName, gc.Equals, fwname) | ||
| - c.Check(s.FakeConn.Calls[0].Rules, jc.DeepEquals, s.Rules) | ||
| + c.Assert(subnets, gc.DeepEquals, []network.SubnetInfo{{ | ||
| + ProviderId: "https://www.googleapis.com/compute/v1/projects/sonic-youth/regions/asia-east1/subnetworks/go-team", |
jameinel
Mar 20, 2017
Owner
Is there really no contextual shorter ID for a subnet? Is this the value that you're supposed to pass back to something like StartInstance to get an instance that is using that subnetwork?
It looks more like the ProviderID should be something like "go-team" and the rest of it is inferred, but I could be wrong.
babbageclunk
Mar 20, 2017
Member
Subnetworks have an integer ID which seems like it might be the right thing to use for Provider ID, but a network interface's Subnet field is the link rather than the ID (which I guess makes sense from a REST perspective).
My thinking was that if I use the ID as the subnet ProviderId, then I won't be able to construct a SubnetInfo directly from the NetworkInterface in the instance version of Subnets - I'd need to do an extra call to get the subnets for an instance so I can get the ID.
But as I typed that it sounded wrong, and looking at the code I think it is - if I make the subnet ProviderId the integer ID everything should still work the same. I'll do that. I'd rather use the ID than trying to unpack components out of the URL.
| +// NetworkInterfaces returns the details of the network connection for | ||
| +// this instance. | ||
| +func (gi Instance) NetworkInterfaces() []*compute.NetworkInterface { | ||
| + return gi.InstanceSummary.NetworkInterfaces |
jameinel
Mar 20, 2017
Owner
should this be something that we copy() just in case someone tries to mutate the result value?
babbageclunk
added some commits
Mar 15, 2017
|
!!build!! |
|
!!chittychitty!! |
|
!!build!! |
jameinel
approved these changes
Mar 22, 2017
This feels like its good enough that we can use it for now, and evolve it in the future if we find it needs tweaks.
Ideally we'd make sure that we could provision an instance with the Subnet information that we're storing (can we recreate the URL needed to pass into the instance from the information we are recording).
| + CIDR: subnet.CIDR, | ||
| + // The network interface has no id in GCE so it's | ||
| + // identified by the machine's id + its position. | ||
| + ProviderId: network.Id(fmt.Sprintf("%s/%d", instId, i)), |
jameinel
Mar 22, 2017
Owner
https://cloud.google.com/compute/docs/reference/latest/instances says that network interfaces have a "Name" field. Is that better than index? (if you are ever able to add/remove them it feels slightly better)
babbageclunk
Mar 22, 2017
Member
D'oh, yes, that would be a better thing to use here. Updating it now.
| + if err != nil { | ||
| + return nil, errors.Trace(err) | ||
| + } | ||
| + // We don't want to get all subnets if no urls are passed. |
jameinel
Mar 22, 2017
Owner
You have this comment, but don't seem to be doing:
if len(urls) == 0 {
return nil, nil
}
babbageclunk
Mar 22, 2017
Member
It was meant to explain why I'm not calling something that could return an includeAny, but you're right, doing an early return here makes more sense.
| + subnet.IpCidrRange, | ||
| + zones, | ||
| + ) | ||
| + } |
jameinel
Mar 22, 2017
Owner
Should we do some sort of checking if we got the same SelfLink 2 times? I guess urlSet doesn't let us determine whether it not in the set because we saw it, or whether it is not in the set because we never asked for it.
babbageclunk
Mar 22, 2017
Member
Do you mean a sanity check to make sure GCE aren't breaking their own rules? I could see that being useful if an interface was marked with the wrong CIDR because two subnets had the same URL. But I'm not sure it's worth restructuring the code to check for. What about a sanity check that the ip address is contained in the CIDR higher up?
| jc "github.com/juju/testing/checkers" | ||
| + // "github.com/juju/version" |
|
!!build!! |
|
At the moment the GCE provider doesn't support subnet placement - I'm not going to add that in this PR, but I'll add a card to the board to do it. I'm a bit wary about constructing the URL directly from the project + region + subnet-name though - it means we'll break if they change their format. Rather than constructing the URL we'd find the subnet by name and get the URL from it, maybe? |
|
$$merge$$ |
|
Status: merge request accepted. Url: http://juju-ci.vapour.ws:8080/job/github-merge-juju |
|
Build failed: Tests failed |
|
Seems like a spurious lxd failure, retrying. $$merge$$ |
|
Status: merge request accepted. Url: http://juju-ci.vapour.ws:8080/job/github-merge-juju |
|
Build failed: Tests failed |
|
Seems like another different intermittent failure (StateSuite.TestNoModelDocs). $$retry$$ |
|
Status: merge request accepted. Url: http://juju-ci.vapour.ws:8080/job/github-merge-juju |
jujubot
merged commit 565ce69
into
juju:develop
Mar 23, 2017
1 check failed
babbageclunk
deleted the
babbageclunk:subnets-gce
branch
Mar 23, 2017
|
If we're not comfortable constructing the URL then it seems we should be
saving it. We should have enough context to be able to use the object.
John
=:->
On Mar 23, 2017 02:17, "Christian Muirhead" <notifications@github.com> wrote:
At the moment the GCE provider doesn't support subnet placement - I'm not
going to add that in this PR, but I'll add a card to the board to do it.
I'm a bit wary about constructing the URL directly from the project +
region + subnet-name though - it means we'll break if they change their
format. Rather than constructing the URL we'd find the subnet by name and
get the URL from it, maybe?
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#7126 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAMYfctnBHi8oLNf-_HpOWcPuYayQv1bks5roZ4PgaJpZM4MiKt5>
.
|
babbageclunk commentedMar 20, 2017
Description of change
Implement NetworkingEnviron for the GCE provider. No support for spaces, space discovery or container addressing, just listing subnets and network interfaces at the moment. This enables more fine-grained management of ingress rules for cross-model relations.
QA steps
Bootstrap a controller in GCE, in a project that has some subnets (this will require creating an additional network if the project is using a legacy default network). The controller should bootstrap successfully and running
juju subnetsshould list all of the subnets in the relevant region.