Add ValidateForAdmission function#581
Conversation
| var allErrs field.ErrorList | ||
|
|
||
| for _, existingHost := range hostList.Items { | ||
| if host.Spec.BMC.Address == existingHost.Spec.BMC.Address { |
There was a problem hiding this comment.
Do we want to check for .Address == "" earlier? For unmanaged hosts, the BMC address will be optional. If this lands first perhaps we defer adding that check in the unmanaged PR #569
There was a problem hiding this comment.
I'm not sure how think about uniqueness in this context given that multiple fields are nullable. Do we have a list of hard requirements/rules?
There was a problem hiding this comment.
We want the BMC.Address to be unique, if it is set, to avoid having 2 resources managing the same physical host.
We want the BMC.CredentialsName to be unique, if it is set, to avoid having 2 host resources taking ownership of the same Secret resource.
We want the BootMACAddress to be unique to avoid having 2 resources trying to claim the same data for a discovered node. The current draft of the code says the field can be empty, but I don't think we want to support that given that we've seen bugs recently.
There was a problem hiding this comment.
I have added a check for the credentials name field.
| Namespace: host.Namespace, | ||
| } | ||
|
|
||
| err := c.List(ctx, &hostList, opts) |
There was a problem hiding this comment.
Can you use field selectors to do a query for existing BMH with the same MAC or BMC address instead of listing all the hosts (of which there could be thousands) e.g. https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#ListOptions
Not sure if the API tools work that way to allow us to do such a query (or if it's even better), I haven't done anything like this before.
There was a problem hiding this comment.
Can you use field selectors to do a query for existing BMH with the same MAC or BMC address instead of listing all the hosts (of which there could be thousands)?
No. The field selector only operates on a small number of fields, think metadata.name.
There seem to be many fields we need to check, and doing a query for each one seems slow. This way we grab all of the resources at once, and can quickly run through them to validate them.
There was a problem hiding this comment.
Is the client used the same type of caching client that a controller uses?
|
Is it possible to do this as a standalone helper function in its own package or does the web hook framework assume it is a method of the type? Adding it this way is going to cause anything consuming the host resource to pull in all of the new dependencies as well, even if they are not implementing the web hook. |
Yes. The pattern that I have seen is that the webook handler contains a one-liner which is a method call on the resource type. But it's easy to move it to a new package to avoid the dependency problem. I added a new package called |
dhellmann
left a comment
There was a problem hiding this comment.
The implementation looks good. I had one comment on test coverage.
In other cases where we queried the API for all resources of a type we assumed that the caching client would make that operation relatively quick. I wonder if that cache could introduce a race condition that would bypass the admission check, though. What do we know about the concurrency behavior of the admission web hooks?
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: dhellmann, honza The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
/test-integration |
| Namespace: host.Namespace, | ||
| } | ||
|
|
||
| err := c.List(ctx, &hostList, opts) |
There was a problem hiding this comment.
I presume we don't have a cache here, but even so this is still susceptible to race conditions. Are we saying we just don't care about that?
There was a problem hiding this comment.
By default, the runtime creates a caching client.
Do we have any means of performing atomic operations on a set of resources?
There was a problem hiding this comment.
Only using the kubernetes API. So we'd have to have some sort of CRD in which MAC addresses and BMC addresses could be claimed. There's no way that I know of to make that atomic with creating the BareMetalHost though, so I'm not even sure how that would work.
There was a problem hiding this comment.
I removed the client code from the function, and changed it to accept a list of existing resources; we'll leave it up to the caller for now to deal with caching/atomic semantics.
| // ValidateHostForAdmission returns an error if the host fails uniqueness | ||
| // validation, and cannot be added to the cluster. This is ordinarily run by an | ||
| // admission webhook. | ||
| func ValidateHostForAdmission(c client.Client, host metal3v1alpha1.BareMetalHost) error { |
There was a problem hiding this comment.
Once we have a validating webhook we'll almost certainly want to use it for other things that don't involve uniqueness across the whole cluster. It might pay to group this stuff that does in a function with a more specific name.
|
New changes are detected. LGTM label has been removed. |
zaneb
left a comment
There was a problem hiding this comment.
Just realised that I typed a comment on Friday and neglected to hit submit.
| } | ||
|
|
||
| // The BMC address is optional so only validate it if it's set | ||
| if host.Spec.BMC.Address != "" && host.Spec.BMC.Address == existingHost.Spec.BMC.Address { |
There was a problem hiding this comment.
I think we might want to dig down a bit further rather than just comparing strings. e.g. redfish://192.168.122.1 and redfish-ilo5://192.168.122.1 are the same BMC.
I'm not sure how the path components come into it. Is it possible with e.g. redfish that multiple hosts share a BMC with the same IP address but different paths?
There was a problem hiding this comment.
Yes, chassis can have multiple hosts with 1 controller (think blade servers). Each host would have a different path, with (for example) the /Systems/1 part changing based on which host is being used.
There was a problem hiding this comment.
Makes sense, so we should compare the hostname, path (for redfish), and presumably port (for IPMI/iDRAC/iRMC), but not the scheme.
There was a problem hiding this comment.
How much knowledge of that sort of thing do we want to embed here, vs. using the AccessDetails implementations to do the comparison?
This function determines if a new BareMetalHost can be added to the cluster. It's suitable to be run from a `ValidateCreate` admission webhook. Currently, it checks for the uniqueness of the following fields: * BMC address * BMC credentials name * Boot MAC address Uniqueness of a field is only checked if set.
This patch adds a UniqueAccessPath() function to the AccessDetails interface which asks implementers to indicate how the driver implements uniqueness.
e873171 to
6eb5aab
Compare
|
I just reimplemented the logic that performs the uniqueness check. I added a new function to the The unit tests could use some work but I wanted to see first if this was in the general direction we wanted to go in. |
| continue | ||
| } | ||
|
|
||
| // If the two hosts don't share drivers, we can assume that they don't conflict |
There was a problem hiding this comment.
I don't think that's a safe assumption. BMCs can support multiple protocols.
There was a problem hiding this comment.
A safer assumption might be:
- same IP but different driver -> reject
- same IP and same driver -> compare unique access path
- different IP -> accept
This has the advantage of blocking anyone trying to use different drivers for different blades in a blade server :D
We can resolve any hostnames to IP addresses to avoid aliasing at that level. Then the only thing we won't catch is things with multiple IP addresses (dual stack IPv4/IPv6 is probably the only likely one to happen in the real world, I'd expect).
|
I would like to freeze go code changes for a few days to try to land #650 without having to rebase it, because rebasing will mean redoing the work from scratch. /hold |
|
@honza: The following test failed, say
DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
|
#655 has merged /hold cancel |
|
Issues go stale after 90d of inactivity. If this issue is safe to close now please do so with /lifecycle stale |
This function determines if a new BareMetalHost can be added to the
cluster. It's suitable to be run from a
ValidateCreateadmissionwebhook.
Currently, it checks for BMC address uniquess, and BootMACAddress
uniqueness.