-
Notifications
You must be signed in to change notification settings - Fork 163
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
host: add interfaces_attributes parameter #979
Conversation
Thank you for addressing that. |
I think that @evgeni 's comment in #788 also applies to interfaces_attributes:
|
So There is an API for managing interfaces directly (without the Host) as you can see in #792, but doing so we would have the same problem we had with parameters "if we do it after the host creation, it will not propagate to the CR for initial deployment" (see #941). And then the API supports both, managing the interface as the entity in Foreman but also managing the NIC in a virtual system. So I think what we could do here is to take the spec @Fobhep started in #792 and use the "ansible" part of it (as returned by And idempotency is then left as an exercise to the reader |
69042b3
to
43c2a3c
Compare
What if we added the interfaced in the same call for host creation, but in the update case we do it properly, separate and idempotent. |
discussion during triage:
|
example how to do a foreman-ansible-modules/plugins/modules/repository_set.py Lines 252 to 255 in 04a98bc
also needs similar updates to documentation: foreman-ansible-modules/plugins/modules/repository_set.py Lines 46 to 63 in 04a98bc
|
@evgeni thanks for the pointers, I will amend the PR according to the apidoc. |
3aa5df1
to
e993812
Compare
@evgeni I've updated the foreman_spec but those 3 points remain unclear to me:
Any help would be appreciated. |
Thanks @achevalet! For the first question: yes, this looks correct. We do a similar kind of filtering for the top-level parameters automatically here:
But for sub options like in your case, the individual modules have been doing the filtering themself:
I think extending the automation to sub options might be a good idea (:eyes: @mdellweg), but sounds like out-of-scope for the current PR. For the second question: I guess you mean And third: oof, I'll give it a try myself, not sure from just looking at the code. |
Sorry, yes I mean |
Thanks @achevalet! I've finally found some time to look at this. Creating a host with Another thing (but unrelated to the comment above): for subnet, subnet6 and domain you've used the "id", which is correct for the API, but confusing for the user -- they usually want to put the name in there. We should make the module do the lookup for us before merging this. |
Thanks the update.
Tested on ovirt and vmware, same error. For the second point, should we update |
So I took your work here and applied the logic we discussed with @mdellweg above: if we create a host, we pass the interfaces directly, but if we update it, we use the dedicated interfaces api. the code is here: https://github.com/evgeni/foreman-ansible-modules/tree/interfaces -- if you want I can just push it to your fork, which will update this PR and we can discuss further. this also avoid the |
Awesome! Yes please push :) |
We give it a try tomorrow I think |
I think the idea back then was to use a dedicated module for a dedicated resource and avoid the more tough way using the host module :) |
Cool, so you'd say merging this would close #757 ans #792? Oh and note to myself, this needs a changelog entry |
plugins/modules/host.py
Outdated
if 'mac' in interface: | ||
interface['mac'] = interface['mac'].lower() | ||
|
||
existing_interface = next((x for x in current_interfaces if x.get(unique_identifier) == interface[unique_identifier]), None) |
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.
existing_interface = next((x for x in current_interfaces if x.get(unique_identifier) == interface[unique_identifier]), None) | |
existing_interface = next((x for x in current_interfaces if unique_identifier and x.get(unique_identifier) == interface[unique_identifier]), None) |
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.
note: the parameter name
actually defines (or is defined by) the host's FQDN and identifier
is optional.
If those are not specified, it ends up with an empty interface list.
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.
Yeah, so I needed to "find" an existing interface somehow to know if we're updating it or creating a new one. My idea was to look if there is an interface defined with the same identifier, hostname or mac (and I didn't add mac in my code, ups). This behavior is not documented yet.
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 it would make sense for PXE deployment (mac
is probably the best option since it is required) but for image based provisioning the changes won't be propagated to the VM since most compute resources does not manage host update (afaik, same applies to compute_attributes
). Shouldn't we just exclude interfaces_attributes
in this case?
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.
Is there anything that we could ask the user to provide to make the entry unique? If you for example use identifier:fam01 (like I did in the tests), would the interface be properly deployed with that name inside the OS, even if we don't define ip/mac to match on?
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.
So I had a few more thoughts:
- I'll look what hammer does tomorrow
- If both the user and API both provide exactly one interface, that's the one we're updating, no need to match
- In the case we couldn't find an unique identifier, proceed to add a new interface and warn the user that this is probably not what they want
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.
Sounds good! We just need to be careful with Foreman setting ignore_puppet_facts_for_provisioning
, disabled by default. Puppet facts may update some values and/or add new interfaces. If new interfaces are created by puppet facts, we need to match, and if the identifier has changed, we might create a new interface at each run, which is not what we want :)
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've implemented the "only one" and "warning" proposals from above.
Now to hammer:
- Given the non-declarative way hammer is designed, you have individual commands to "add", "update" and "delete" host interfaces.
- Let's ignore adding, that is trivial.
- Deleting an interface requires two inputs: host id (or name) and interface id (which you need to look up manually via
hammer host interfaces list
before) - Updating also (technically) requires host id/name and interface id, but nothing enforces the entry of the ID, and if you don't you get the good old "Interfaces some interfaces are invalid" error because it tries to add an interface with an identifier that's already present.
So, all in all, I'm no way wiser now.
Now the update tries to remove the interface :)
|
Given the fact that our inital plan was anyways to port all features from a standalone module to the host module I would say so, yes. I don't see a lot of people using an extra module to handle interfaces, when really I can also do it via the host-module. But if someone disagrees, I will gladly be persuaded otherwise |
Works for me. Nice will be the lookup for entities e.g. |
okay, so I've pushed some changes that make subnet/domain lookup work, but it's not as pretty as I'd like it to be ping @mdellweg for ideas quick recap of our problem: currently, our lookup code only looks at entity and entity_list elements of the "main" spec, but in this module (and in some other modules before that), we actually have a list of hashes, and some parts of those hashes are entities. 🤯 I've now implemented the lookup specifically for the |
Maybe we can also fix the apidoc to accept the interfaces on host update too... Edit: given that's what hammer does, it probably should work with a small apidoc patch |
But even if we use "same api request", the lookup is needed the same way, so let's not overcomplicate things. Or rather: I needed to apply enough other workarounds to make update work using the "same api request" so that it's not worth 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.
Added my thoughts.
@@ -96,7 +96,7 @@ | |||
|
|||
filter_foreman_spec = dict( | |||
id=dict(invisible=True), | |||
permissions=dict(type='entity_list', required=True), | |||
permissions=dict(type='entity_list', required=True, resolve=False), |
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.
Interesting side effect.
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 left some comments. Nothing that should stop us from merging necessarily.
But consider the doc improvement.
and nested_spec.get('type') in {'entity', 'entity_list'}): | ||
item[nested_key] = self._lookup_entity(item[nested_key], nested_spec) | ||
nested_spec['resolved'] = True | ||
|
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 is not yet fully recursive, right?
Maybe we can incorporate the nested lookup into the _lookup_entity
eventually, in a followup pr...
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.
Yeah. It's not. But I'd also defer that to another PR :)
628556d
to
853fd77
Compare
I've just tested this and it looks to address a part of #757 (via the
host
API). I'm not sure but I think we could not make it idempotent, as for the compute_attributes.