Skip to content
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

Support Pod /32 IP request via k8s annotation (ipAddrsNoIpam) #264

Merged
merged 1 commit into from Feb 9, 2017

Conversation

gunjan5
Copy link
Contributor

@gunjan5 gunjan5 commented Feb 7, 2017

Part of issue #258


cni.projectcalico.org/ipAddrsNoIpam: "[\"10.0.0.1\"]"

If specified, this annotation ignores all other IPAM settings and will be stored in the Calico WorkloadEndpoint without calling any IPAM plugin, no questions asked. This allows non-CNI things to be the source of truth for IPAM.


_, _, _, _, contAddresses, _, err := CreateContainer(netconfCalicoIPAM, name)
Expect(err).NotTo(HaveOccurred())

podIP := contAddresses[0].IP
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about checking what IP was stored in the workload endpoint in etcd?

k8s/k8s.go Outdated
if visited6 >= 1 {
logger.Fatal("Can not have more than one IPv6 addresses in ipAddrsNoIpam annotation")
} else {
result.IP6.IP.IP = ipAddr
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you really need the visited stuff? Why not just checkout result.IPx.IP or whatever?

k8s/k8s.go Outdated
logger.WithField("annotation", ipAddrsNoIpam).Fatal("Invalid JSON")
}

result := types.Result{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you really need all of this for creating the Result?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I understand what you mean here. Can you elaborate?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I get what you're saying now. Done!

k8s/k8s.go Outdated
// We also make sure there is only one IPv4 and/or one IPv6 passed in,
// since CNI spec only supports one of each right now.
for _, ip := range ips {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra blank line

k8s/k8s.go Outdated
}
logger.Debugf("IPAM plugin returned: %+v", result)
} else {
// ipAddrsNoIpam annotation is set so bypass IPMA, and set the IPs manually.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: IPMA

k8s/k8s.go Outdated
} else {
// ipAddrsNoIpam annotation is set so bypass IPMA, and set the IPs manually.
result = overrideIPAMResult(ipAddrsNoIpam, logger)
logger.Debugf("Bypassing IPAM to set the IP config to: %+v", result)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IP config -> result to be consistent.

k8s/k8s.go Outdated

err := json.Unmarshal([]byte(ipAddrsNoIpam), &ips)
if err != nil {
logger.WithField("annotation", ipAddrsNoIpam).Fatal("Invalid JSON")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you make the error here more descriptive? It's user facing, so something like "failed to parse ipAddrsNoIpam as json"

utils/types.go Outdated
AssignIpv6 *string `json:"assign_ipv6"`
IPv4Pools []string `json:"ipv4_pools,omitempty"`
IPv6Pools []string `json:"ipv6_pools,omitempty"`
IPAddrsNoIpam []string `json:"ip_addrs_noipam,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this needs to be part of the CNI config file.

k8s/k8s.go Outdated
// overrideIPAMResult generates types.Result like the one produced by IPAM plugin,
// but sets IP field manually since IPAM is bypassed with this annotation.
// Example annotation:
// cni.projectcalico.org/ipAddrsNoIpam: "[\"10.0.0.1\", \"2001:db8::1\"]"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole annotation isn't passed to this function, right? We should document the format of the string that gets passed to this function.

return nil, err
}
logger.Debugf("IPAM plugin returned: %+v", result)
} else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we worried about the fact that we do IPAM related stuff up above even when this annotation is specified?

e.g https://github.com/projectcalico/cni-plugin/pull/264/files#diff-b396ca928d5bd0e161acd283b56ead9fR84

and https://github.com/projectcalico/cni-plugin/pull/264/files#diff-b396ca928d5bd0e161acd283b56ead9fR124?

Probably not because it's a kinda weird case, but it does mean we'll be doing more work than we need to.

Copy link
Contributor Author

@gunjan5 gunjan5 Feb 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(discussed this offline. Going to leave this as it is for now. Will need to refactor how we call k8s APIs at some point. )

@ozdanborne ozdanborne changed the title Support for annotation ipAddrsNoIpam to assign IP to pod bypassing IPAM Support Pod /32 IP request via k8s annotation (ipAddrsNoIpam) Feb 7, 2017
@gunjan5
Copy link
Contributor Author

gunjan5 commented Feb 7, 2017

@tomdee @caseydavenport addressed your comments. PTAL

k8s/k8s.go Outdated

err := json.Unmarshal([]byte(ipAddrsNoIpam), &ips)
if err != nil {
logger.WithField("annotation", ipAddrsNoIpam).Fatal("Failed to parse ipAddrsNoIpam as json")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be doing a log.Fatal here? Shouldn't this function return an error so we can pass back an error over CNI?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same below.

k8s/k8s.go Outdated

// annotation value can't be empty.
if len(ips) == 0 {
logger.WithField("annotation", "cni.projectcalico.org/ipAddrsNoIpam").Fatal("No IPs specified")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I always forget... should this actually be ipAddrsNoIPAM?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's what you and @lxpollitt decided, but then later you had a suggestion of using ipAddrsSkipIPAM which I personally like better

k8s/k8s.go Outdated
err := json.Unmarshal([]byte(ipAddrsNoIpam), &ips)
if err != nil {
logger.WithField("annotation", ipAddrsNoIpam).Error("Failed to parse ipAddrsNoIpam as json")
return nil, err
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to wrap these errors with context before returning - remember they all end up in the user's eyes via kubectl describe pod

e.g return nil, fmt.Errorf("Failed to parse ipAddrsNoIpam: %s", err)

Same goes for other returned errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done! BTW, this is why I think we should be using https://github.com/pkg/errors 🙂

k8s/k8s.go Outdated
ipAddr := net.ParseIP(ip)
if ipAddr == nil {
logger.WithField("IP", ip).Error("Invalid IP format")
return nil, fmt.Errorf("Invalid IP format: %s", err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's this line that should include the IP in the returned error so that it's clear what the misconfig is.

k8s/k8s.go Outdated
// If/when CNI spec supports more than one IP, we can loosen this requirement.
if result.IP6 != nil {
logger.Error("Can not have more than one IPv6 addresses in ipAddrsNoIpam annotation")
return nil, fmt.Errorf("Can not have more than one IPv6 addresses in ipAddrsNoIpam annotation")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: more than one IPv6 addresses

k8s/k8s.go Outdated
// It's an IPv4 address.
if result.IP4 != nil {
logger.Error("Can not have more than one IPv4 addresses in ipAddrsNoIpam annotation")
return nil, fmt.Errorf("Can not have more than one IPv4 addresses in ipAddrsNoIpam annotation")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

more than one IPv4 addresses (shouldn't be plural)

@gunjan5 gunjan5 merged commit 701df28 into projectcalico:master Feb 9, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants