-
Notifications
You must be signed in to change notification settings - Fork 249
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for the new IPv4Pools and IPv6Pools properties on AutoAssign #223
Conversation
@tomdee I don't think this is a blocker for v2.0.0 since it is a feature add. |
Marking this as WIP because I added support for hooking this into K8s via annotation and I haven't had a chance to test it yet. However, if people could look at the code in k8s/k8s.go to see if it looks right I'd appreciate it. |
ok I think this is ready for some eyes on it |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, looks good to me. We're about to do a calico-CNI release that I don't think can include this, but we should be able to merge soon after.
Ideally, we would have tests covering the k8s code too. I'm working on a framework for the k8s testing, but it's not ready enough to share yet. If I can get it out in the next few days then I might ask you to write tests for the k8s side too.
"ipam": { | ||
"type": "%s", | ||
"assign_ipv4": "true", | ||
"ipv4_pools": [ "192.168.0.0/16" ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Odd indent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
"ipv4_pools": [ "192.168.0.0/16" ] | ||
} | ||
}`, os.Getenv("ETCD_IP"), plugin) | ||
_, _, _, _, _, _, err := CreateContainer(netconf) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should assert on something more than there just not being an error. This test case would have passed before you added any other code so it's not really testing anything.
if err != nil { | ||
fmt.Printf("Session Err: %v\n", string(session.Err.Contents())) | ||
} | ||
Expect(err).ShouldNot(HaveOccurred()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, I would like to see more assertions here
return nil, fmt.Errorf("%q isn't a IPv4 address", ip) | ||
} | ||
if !isv4 && ip.To4() != nil { | ||
return nil, fmt.Errorf("%q isn't a IPv16 address", ip) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
v16? Now there's a very futuristic IP protocol!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's called future proofing. :-)
Fixed.
utils.ReleaseIPAllocation(logger, conf.IPAM.Type, args.StdinData) | ||
return nil, err | ||
} | ||
logger.WithField("labels", labels).Info("Fetched K8s labels") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there are a large number of labels or annotations this could result is many large logs - I wonder if debug would be a better level?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't expect there would be that many to cause an issue, but switched anyway.
I can work with @duglin to write some tests for k8tes if you can share your framework. |
316a9d8
to
13c7e33
Compare
@tomdee comments addressed and rebased |
@duglin / @cmluciano I've just up a PR for an initial k8s test #235 Hopefully I can get it tidied/merged soon, then you'll be able to add test(s) for your new and updated code paths. |
Looks like there are some conflicts in your glide.lock |
hmm, git and github aren't complaining - where are you seeing that? |
Hmmm, maybe I was dreaming it. It looks OK now. |
@duglin / @cmluciano - My k8s test framework changes are merged, so you should be able to add a test for your code now. I expect you to be able to add a test that's similar to this - https://github.com/projectcalico/calico-cni/blob/master/calico_cni_k8s_test.go#L77 - but to vary the annotations on the pod to hit your code. |
@tomdee thanks! Still need to catch-up on the other thread too about possibly changing what's passed in..... |
4557b36
to
bd079d8
Compare
@tomdee I'm running into a problem. I added the start of a k8s test, following your guidance - thanks. But, when trying to test it I'm not seeing what I expected to see. In particular, my annotations seemed to have no effect, so I started to debug it and got to the point where I added a panic() at https://github.com/projectcalico/cni-plugin/pull/223/files#diff-b396ca928d5bd0e161acd283b56ead9fR114 just to see if that if-statement was being called at all - and I don't think it is. In fact, it doesn't look like that code in k8s/k8s.go is called at all. Another interesting thing is that when I print out the Pod we get back from the Pod.Create() call, all of the IP fields are empty. Does the testing infrastructure invoke k8s and the calico stuff or does it fake some of it? |
Oh wait - it could be timing thing.... checking.... |
ok - it may be a timing issue but I never see the Pod leave the "Pending" state. When I look at the docker containers running I see the API server and etcd. Shouldn't there be others running - like the kubelet? |
One thought - Kubernetes best practice indicates that annotations should be part of a domain owned by the project, so this should probably be @tomdee WDYT? |
@duglin The k8s testing that I added is quite "interesting". the kubelet doesn't actually invoke the CNI plugin, we still do that manually. In fact, there's not even a kubelet running. However, the test framework does run a kubernetes API server, and manually injects the podspec into it. I think this shouil dbe enough to still enable some useful testing. It does explain why you see pods stuck in pending state though, since there's nothing to actually run the pod, they'll never move out of pending. |
@caseydavenport do you have a link to the k8s best practices. I can't see anything relevant about annotations in https://kubernetes.io/docs/user-guide/config-best-practices/ In general, I agree with your suggestion of putting the domain in the annotation though. Do you know if it's "normal" to reverse it for k8s annotations though (e.g. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some nits and a hint on why updating the test might not be working.
@@ -53,11 +53,10 @@ var _ = Describe("CalicoCni", func() { | |||
"subnet": "10.0.0.0/8" | |||
}, | |||
"kubernetes": { | |||
"k8s_api_root": "http://127.0.0.1:8080" | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Broken indent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed, I hope. Indentation in backticks is gonna kill me ;-)
}, | ||
"policy": {"type": "k8s"}, | ||
"log_level":"info" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Broken indent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"log_level" looks ok to me, but I'll recheck after the next push
ObjectMeta: v1.ObjectMeta{ | ||
Name: name2, | ||
Annotations: map[string]string{ | ||
"cni.calico/ipv4pools": "192.169.1.0/24", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This annotation won't be used since you're calling CreateContainer below with name
not name2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
@@ -1,5 +1,5 @@ | |||
hash: 1efa10f7d9f9793128d78496760c641fb6ee82b2686a4fd476ba83a624f1506c | |||
updated: 2016-12-13T15:51:57.719804486-08:00 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you really need to update the glide.lock?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I had to update the glide.yaml at one point, which forced the lock file to change. But I think that requirement is now behind me so yea I'll try to remove this from the PR.
@tomdee Interestingly, neither can I. However, this section on label syntax does mention the format that I was thinking of: https://kubernetes.io/docs/user-guide/labels/#syntax-and-character-set It's easy get a picture of the standard notation from other well-known annotations, e.g:
See this comment for the annotation design: https://github.com/projectcalico/cni-plugin/issues/213#issuecomment-272053112 |
Now that projectcalico/libcalico-go#271 is merged. Bump refs to libcalico-go too Signed-off-by: Doug Davis <[email protected]>
Add pod annotations to enable them: ``` spec: template: metadata: annotations: cni.calico/ipv4pools: [<ip-pool-1>, <ip-pool-2>] cni.calico/ipv6pools: [<ip-pool-1>, <ip-pool-2>] ``` Signed-off-by: Doug Davis <[email protected]>
Signed-off-by: Doug Davis <[email protected]>
e8b769d
to
04c2cfb
Compare
re: annotations and forward/reverse : I've seen it both ways in Kube, and been told to do it both ways too. For now I've picked @tomdee do you have some sample code I can use as a guide for how to run the CNI plug-in manually in the k8s testing setup? In the meantime, I've disable the code that waits for the pod to get into the right state, so the test will fail for now. |
Signed-off-by: Doug Davis <[email protected]>
@@ -83,6 +85,7 @@ var _ = Describe("CalicoCni", func() { | |||
panic(err) | |||
} | |||
containerID, netnspath, session, contVeth, contAddresses, contRoutes, err := CreateContainer(netconf, name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tomdee this CreateContainer() call is confusing me. Didn't the call to clientset.Pods().Create() create the Pod and the underlying container already?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clientset.Pods().Create() just creates the API object in the kubernetes API server,
CreateContainer() actually invokes the CNI plugin binary directly. It's NOT the kublet that invokes. This test code invokes it directly passing in similar information to what kubernetes would.
first, let me apologize for this looking like its lingering... I've just been swamped. I think the outstanding issue here is the testing side of things. I think I have the basic structure there, but I've not be able to get the CNI code to be invoked to verify my code works. I'll try to find some time over the next day or so to see if I can push this over the finish line. |
No worries, we're pretty swamped too :) Just want to make sure you're not waiting on us for something and that if you are, we prioritize unblocking you. |
I don't think I'm blocked on anything other than a possible lack of education on how to get the CNI code invoked, but before I cry for more help I feel I need to play around with it some more first. |
Are there any other docs changes planned for this feature besides the ones here: projectcalico/calico#275 Do there need to be? Is there a Kubernetes use case this was added for? |
@djosborne I'm not aware of any plans and I don't think we'd ask @duglin to add any more. I can see that this would be a great feature to add more docs for though so maybe we should raise a docs issue to track doing that? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
few more comments
labels, annot, err = getK8sLabelsAnnotations(client, k8sArgs) | ||
if err != nil { | ||
// Cleanup IP allocation and return the error. | ||
utils.ReleaseIPAllocation(logger, conf.IPAM.Type, args.StdinData) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to ReleaseIP here? ADD
happens later so not sure I see why we need to release IP here.
// if the policy type has been set to "k8s". This allows users to | ||
// run the plugin under Kubernetes without needing it to access the | ||
// Kubernetes API | ||
if conf.Policy.PolicyType == "k8s" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should also add a check conf.IPAM.Type == "calico-ipam"
here to make sure this code only gets called for calico-ipam
so it doesn't set fields that are not relevant to other IPAMs.
if len(v4pools) != 0 || len(v6pools) != 0 { | ||
var stdinData map[string]interface{} | ||
if err := json.Unmarshal(args.StdinData, &stdinData); err != nil { | ||
utils.ReleaseIPAllocation(logger, conf.IPAM.Type, args.StdinData) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above. Not sure if we need to release IP here
} | ||
newData, err := json.Marshal(stdinData) | ||
if err != nil { | ||
utils.ReleaseIPAllocation(logger, conf.IPAM.Type, args.StdinData) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think pools won't get assigned to the right fields in stdinData since the string ID doesn't match the json field ID
utils.ReleaseIPAllocation(logger, conf.IPAM.Type, args.StdinData) | ||
return nil, err | ||
} | ||
stdinData["ipam"].(map[string]interface{})["ipv4pools"] = v4pools |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't this be ipv4_pools
instead of ipv4pools
since NetConf's IPv4Pools
field processes json by the string ipv4_pools
`IPv4Pools []string `json:"ipv4_pools"`
Same with ipv6pools
in the line below.
Changes moved to #260 . Closing this |
Now that projectcalico/libcalico-go#271 is merged.
Bump refs to libcalico-go too
Add pod annotations to enable them:
Signed-off-by: Doug Davis [email protected]