Skip to content

Commit

Permalink
fix completeness
Browse files Browse the repository at this point in the history
  • Loading branch information
sean-m-sullivan committed Apr 23, 2021
1 parent 4cd4845 commit ec31235
Show file tree
Hide file tree
Showing 5 changed files with 513 additions and 146 deletions.
34 changes: 34 additions & 0 deletions awx_collection/plugins/module_utils/tower_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -740,3 +740,37 @@ def wait_on_url(self, url, object_name, object_type, timeout=30, interval=10):
def wait_output(self, response):
for k in ('id', 'status', 'elapsed', 'started', 'finished'):
self.json_output[k] = response['json'].get(k)

def wait_on_workflow_node_url(self, url, object_name, object_type, timeout=30, interval=10, **kwargs):
# Grab our start time to compare against for the timeout
start = time.time()
result = self.get_endpoint(url, **kwargs)

while result["json"]["count"] == 0:
# If we are past our time out fail with a message
if timeout and timeout < time.time() - start:
# Account for Legacy messages
self.json_output["msg"] = "Monitoring of {0} - {1} aborted due to timeout, {2}".format(object_type, object_name, url)
self.wait_output(result)
self.fail_json(**self.json_output)

# Put the process to sleep for our interval
time.sleep(interval)
result = self.get_endpoint(url, **kwargs)

if object_type == "Workflow Approval":
# Approval jobs have no elapsed time so return
return result["json"]["results"][0]
else:
# Removed time so far from timeout.
revised_timeout = timeout - (time.time() - start)
# Now that Job has been found, wait for it to finish
result = self.wait_on_url(
url=result["json"]["results"][0]["related"]["job"],
object_name=object_name,
object_type=object_type,
timeout=revised_timeout,
interval=interval,
)
self.json_output["job_data"] = result["json"]
return result
125 changes: 125 additions & 0 deletions awx_collection/plugins/modules/tower_workflow_approval.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#!/usr/bin/python
# coding: utf-8 -*-

# (c) 2021, Sean Sullivan
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function

__metaclass__ = type


ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}


DOCUMENTATION = """
---
module: tower_workflow_approval
author: "Sean Sullivan (@sean-m-sullivan)"
short_description: Approve an approval node in a workflow job.
description:
- Approve an approval node in a workflow job. See
U(https://www.ansible.com/tower) for an overview.
options:
workflow_job_id:
description:
- ID of the workflow job to monitor for approval.
required: True
type: int
name:
description:
- Name of the Approval node to approve or deny.
required: True
type: str
action:
description:
- Type of action to take.
choices: ["approve", "deny"]
default: "approve"
type: str
interval:
description:
- The interval in sections, to request an update from Tower.
required: False
default: 1
type: float
timeout:
description:
- Maximum time in seconds to wait for a workflow job to to reach approval node.
default: 10
type: int
extends_documentation_fragment: awx.awx.auth
"""


EXAMPLES = """
- name: Launch a workflow with a timeout of 10 seconds
tower_workflow_launch:
workflow_template: "Test Workflow"
wait: False
register: workflow
- name: Wait for approval node to activate and approve
tower_workflow_approval:
workflow_job_id: "{{ workflow.id }}"
name: Approve Me
interval: 10
timeout: 20
action: deny
"""

RETURN = """
"""


from ..module_utils.tower_api import TowerAPIModule


def main():
# Any additional arguments that are not fields of the item can be added here
argument_spec = dict(
workflow_job_id=dict(type="int", required=True),
name=dict(required=True),
action=dict(choices=["approve", "deny"], default="approve"),
timeout=dict(type="int", default=10),
interval=dict(type="float", default=1),
)

# Create a module for ourselves
module = TowerAPIModule(argument_spec=argument_spec)

# Extract our parameters
workflow_job_id = module.params.get("workflow_job_id")
name = module.params.get("name")
action = module.params.get("action")
timeout = module.params.get("timeout")
interval = module.params.get("interval")

# Attempt to look up workflow job based on the provided id
approval_job = module.wait_on_workflow_node_url(
url="workflow_jobs/{0}/workflow_nodes/".format(workflow_job_id),
object_name=name,
object_type="Workflow Approval",
timeout=timeout,
interval=interval,
**{
"data": {
"job__name": name,
}
}
)
response = module.post_endpoint("{0}{1}".format(approval_job["related"]["job"], action))
if response["status_code"] == 204:
module.json_output["changed"] = True

# Attempt to look up jobs based on the status
module.exit_json(**module.json_output)


if __name__ == "__main__":
main()
115 changes: 115 additions & 0 deletions awx_collection/plugins/modules/tower_workflow_node_wait.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#!/usr/bin/python
# coding: utf-8 -*-

# (c) 2021, Sean Sullivan
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function

__metaclass__ = type


ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}


DOCUMENTATION = """
---
module: tower_workflow_node_wait
author: "Sean Sullivan (@sean-m-sullivan)"
short_description: Approve an approval node in a workflow job.
description:
- Approve an approval node in a workflow job. See
U(https://www.ansible.com/tower) for an overview.
options:
workflow_job_id:
description:
- ID of the workflow job to monitor for node.
required: True
type: int
name:
description:
- Name of the workflow node to wait on.
required: True
type: str
interval:
description:
- The interval in sections, to request an update from Tower.
required: False
default: 1
type: float
timeout:
description:
- Maximum time in seconds to wait for a workflow job to to reach approval node.
default: 10
type: int
extends_documentation_fragment: awx.awx.auth
"""


EXAMPLES = """
- name: Launch a workflow with a timeout of 10 seconds
tower_workflow_launch:
workflow_template: "Test Workflow"
wait: False
register: workflow
- name: Wait for a workflow node to finish
tower_workflow_node_wait:
workflow_job_id: "{{ workflow.id }}"
name: Approval Data Step
timeout: 120
"""

RETURN = """
"""


from ..module_utils.tower_api import TowerAPIModule
import time


def main():
# Any additional arguments that are not fields of the item can be added here
argument_spec = dict(
workflow_job_id=dict(type="int", required=True),
name=dict(required=True),
timeout=dict(type="int", default=10),
interval=dict(type="float", default=1),
)

# Create a module for ourselves
module = TowerAPIModule(argument_spec=argument_spec)

# Extract our parameters
workflow_job_id = module.params.get("workflow_job_id")
name = module.params.get("name")
timeout = module.params.get("timeout")
interval = module.params.get("interval")

node_url = "workflow_jobs/{0}/workflow_nodes/?job__name={1}".format(workflow_job_id, name)
# Attempt to look up workflow job node based on the provided id

result = module.wait_on_workflow_node_url(
url="workflow_jobs/{0}/workflow_nodes/".format(workflow_job_id),
object_name=name,
object_type="Workflow Node",
timeout=timeout,
interval=interval,
**{
"data": {
"job__name": name,
}
}
)

# Attempt to look up jobs based on the status
module.exit_json(**module.json_output)


if __name__ == "__main__":
main()
8 changes: 5 additions & 3 deletions awx_collection/test/awx/test_completeness.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
'tower_receive',
'tower_send',
'tower_workflow_launch',
'tower_workflow_node_wait',
'tower_job_cancel',
'tower_workflow_template',
'tower_ad_hoc_command_wait',
Expand Down Expand Up @@ -64,16 +65,17 @@
'tower_ad_hoc_command': ['interval', 'timeout', 'wait'],
# tower_group parameters to perserve hosts and children.
'tower_group': ['preserve_existing_children', 'preserve_existing_hosts'],
# tower_workflow_approval parameters that do not apply when approving an approval node.
'tower_workflow_approval': ['action', 'interval', 'timeout', 'workflow_job_id'],
}

# When this tool was created we were not feature complete. Adding something in here indicates a module
# that needs to be developed. If the module is found on the file system it will auto-detect that the
# work is being done and will bypass this check. At some point this module should be removed from this list.
needs_development = [
'tower_workflow_approval',
]
needs_development = ['tower_inventory_script']
needs_param_development = {
'tower_host': ['instance_id'],
'tower_workflow_approval': ['description', 'execution_environment'],
}
# -----------------------------------------------------------------------------------------------------------

Expand Down
Loading

0 comments on commit ec31235

Please sign in to comment.