-
Notifications
You must be signed in to change notification settings - Fork 23.7k
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
New module tower_workflow_template. #37520
New module tower_workflow_template. #37520
Conversation
@AlanCoding @ghjm @jlaska @matburt @rooftopcellist @ryanpetrello @simfarm @wwitzel3 As a maintainer of a module in the same namespace this new module has been submitted to, your vote counts for shipits. Please review this module and add |
|
||
if module.params.get('schema'): | ||
wfjt_res.schema( | ||
wfjt_res.get(name=params['name'])['id'], |
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.
nit-picky optimization, but if the prior step was successful then 'id' should already be in result
Also, if the state is "absent", then you need to be sure that you don't hit this code. Either that, or it should throw an error if schema is provided and state is absent.
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.
Ok, I've fixed that.
) | ||
|
||
except (exc.ConnectionError, exc.BadRequest) as excinfo: | ||
module.fail_json(msg='Failed to update inventory source: \ |
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.
failed to update workflow?
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.
Sorry, I've badly copy/paste.
97f7952
to
9022629
Compare
abc774b
to
76892ec
Compare
@ryanpetrello, I've added the required integration test but they fail due to a licence error:
I don't see any way to overcome that inside the CI. |
Ah, you're right 😢 due to licensing restrictions, this may be one we just can't test in our public CI (give me a bit to see what I can do here). |
@fleu42 we're almost there; your test is a little bit unstable (it fails periodically) because it's not giving the Tower VM enough time to finish the workflow job: Let's bump this to a 60 second delay similar to:
...and see if we have better luck: https://github.com/ansible/ansible/pull/37520/files#diff-f8ce5023269e6a4d72463a3582374814R39 |
9654608
to
1cb92df
Compare
@ryanpetrello, I've changed the number of retries as you asked. That should make the testing more stable. |
shipit |
shipit |
state=dict(choices=['present', 'absent'], default='present'), | ||
) | ||
|
||
module = TowerModule(argument_spec=argument_spec, supports_check_mode=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 should be supports_check_mode=False.
organization_res = tower_cli.get_resource('organization') | ||
try: | ||
organization = organization_res.get( | ||
name=module.params.get('organization')) |
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 it okay that the organization can be None 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.
Okay, so alancoding says that this could throw an error that it can't figure out which organization you meant if there is more than one organization.
Perhaps what we need here is:
if organization is not None:
try:
organization = organization_res.get([....]
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.
Isn't that covered by if module.params.get('organization'):
?
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.
Oops, sorry, you are correct.
Okay, I noticed one thing that needs to be changed (check_mode set to False) and one set of related questions. The argument spec and documentation are saying that many of the arguments are not required but they have no explicit default set. This means that if the user does not specify those parameters they will default to None. The None value is then passed into the tower API. Is that what you want or should you either make those a required user parameter (organization may fall in this category?) or set a default (the booleans seem like they might need to be default=True or default=False?), or not include them in the parameters if they're set to None? I don't know the tower API so None may be fine for some or all of these but figured I should check. Last question, does delete() take all the same parameters as modify() or will you end up with an error if the user uses state=absent but fills in the rest of the parameters with values? |
Thank you for reviewing my module.
|
0a6017d
to
3e7aef1
Compare
Manage Tower workflows and their schemas.
Add a test to cover the deletion of a template.
3e7aef1
to
1e32867
Compare
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.
Still what happens if a value is None? The value is left unchanged in tower?
with settings.runtime_values(**tower_auth): | ||
tower_check_mode(module) | ||
wfjt_res = tower_cli.get_resource('workflow') | ||
try: |
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.
Try except blocks souls he as small as possible
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.
Thanks for pointing that out. I've fixed it.
wfjt_res.schema( | ||
result['id'], | ||
module.params.get('schema') | ||
) |
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.
Two things standout to me about this code: (1) merge it into the above if state == "present" block. (2) you should have a check after the ansible module is created that errors if schema is set and state==absent
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 relocated the schema association to the workflow template
- I've added a condition for that
For setting expectations, it should be possible to change a non-null value to a null value. For workflows, this is allowed by the API just fine too. Because we take values as strings, and have to abide by the click library practices, tower-cli introduced "null" to be a keyword
However, this keyword of "null" does not impact the modules, because it is implemented in tower-cli types, which these modules bypass. A null value should be interpreted as setting the organization to null, which is different from the parameter being absent. Granted, this isn't an important use-case, and there may be general Ansible module practices that I am unaware of. |
Alright... then, at least for now, we probably need this module to see that the user did not specify a value for a parameter and not try to forward on None to the API and later, figure out how the user should specify that the value can be nulled by the user? As coded right now, this module will set the optional fields to None if the user didn't specify them. |
On creation, I think that's perfectly fine. If I have a task to create a workflow and no organization specified, I would be happy to see that field is null. It's modification where that becomes more challenging. My gut thinking is that if it's not provided it should not actively remove the organization from the workflow of that name, but I don't know if this is standard behavior. |
Relocate the schema association to the workflow template.
Your gut matches up with the standard behaviour of modules: if an optional field is not specified then we usually do not modify it. |
Errors if state is absent and schema is present.
175e888
to
3f991c3
Compare
I pulled the code, everything looks good. Here is me doing some testing on managing the blank-ness or null-ness of the related organization. https://gist.github.com/AlanCoding/999b415be68f7f419d95ded8c92404f1 The only thing which doesn't work as expected is that there's no real way to remove the organization, see foo4 example. I was talking with @abadger with this, but I'm still not sure what means of specifying null would be expected. |
If there was a very strong desire to address the set-null case, then we could carry through the practice of using "null" string as a keyword, as tower-cli did. diff --git a/lib/ansible/modules/web_infrastructure/ansible_tower/tower_workflow_template.py b/lib/ansible/modules/web_infrastructure/ansible_tower/tower_workflow_template.py
index 3454f432d9..fddead2803 100644
--- a/lib/ansible/modules/web_infrastructure/ansible_tower/tower_workflow_template.py
+++ b/lib/ansible/modules/web_infrastructure/ansible_tower/tower_workflow_template.py
@@ -148,7 +148,9 @@ def main():
if module.params.get('description'):
params['description'] = module.params.get('description')
- if module.params.get('organization'):
+ if module.params.get('organization') == "null":
+ params['organization'] = "null"
+ elif module.params.get('organization'):
organization_res = tower_cli.get_resource('organization')
try:
organization = organization_res.get( Then the tasks - name: remove org from foo4
tower_workflow_template:
name: foo4
organization: "null" Would be able to remove it. This is a very general problem, and I would rather delay addressing it, since I'm not thrilled about the API structure for this. |
@AlanCoding Sounds good. Thanks for also pointing out that |
SUMMARY
There was no way to manage Tower workflow with Ansible so here is that module.
ISSUE TYPE
COMPONENT NAME
ANSIBLE VERSION
ADDITIONAL INFORMATION