1+ #!/usr/bin/python
2+ # -*- coding: utf-8 -*-
3+
4+ DOCUMENTATION = '''
5+ lookup: awx_templates_with_enabled_notifications
6+ short_description: Find AWX job templates with notifications
7+ description:
8+ - This lookup returns all AWX job templates that have notification templates configured
9+ options:
10+ host:
11+ description: The AWX host URL
12+ required: True
13+ username:
14+ description: The AWX username
15+ required: True
16+ password:
17+ description: The AWX password
18+ required: True
19+ max_workers:
20+ description: Maximum number of concurrent workers
21+ required: False
22+ default: 30
23+ type: int
24+ page_size:
25+ description: Number of items to fetch per page
26+ required: False
27+ default: 400
28+ type: int
29+ verify_ssl:
30+ description:
31+ - Whether to verify SSL certificates or not
32+ - Useful for environments with self-signed certificates or corporate proxies
33+ - Setting to false also disables SSL warnings
34+ required: False
35+ default: True
36+ type: bool
37+ notes:
38+ - Returns a dictionary with template information, detailed notification data, and performance metrics
39+ '''
40+
41+ EXAMPLES = '''
42+ - name: Show job templates with notifications
43+ debug:
44+ msg: "{{ lookup('awx_notification_templates', host='https://awx.example.com', username='admin', password='password') }}"
45+
46+ - name: Get job templates with notifications using 10 workers
47+ set_fact:
48+ notification_data: "{{ lookup('awx_notification_templates', host=awx_host, username=awx_username, password=awx_password, max_workers=10)[0] }}"
49+
50+ - name: Use specific parts of the results
51+ debug:
52+ msg: "Found {{ notification_data.count }} templates with notifications"
53+
54+ - name: Loop through templates with notifications
55+ debug:
56+ msg: "Template {{ item.name }} (ID: {{ item.id }}) has {{ item.notification_types | join(', ') }} notifications"
57+ loop: "{{ notification_data.job_templates }}"
58+
59+ - name: Use with SSL verification disabled
60+ debug:
61+ msg: "{{ lookup('awx_notification_templates', host='https://awx.example.com', username='admin', password='password', verify_ssl=false) }}"
62+ '''
63+
64+ RETURN = '''
65+ _list:
66+ description:
67+ - List containing a single dictionary with job template notification information
68+ type: list
69+ elements: dict
70+ contains:
71+ job_templates:
72+ description: List of dictionaries with template id, name, and notification types
73+ type: list
74+ returned: always
75+ count:
76+ description: Count of templates with notifications
77+ type: int
78+ returned: always
79+ total_templates:
80+ description: Total number of job templates in AWX
81+ type: int
82+ returned: always
83+ execution_time_seconds:
84+ description: Time taken to execute the lookup in seconds
85+ type: float
86+ returned: always
87+ workers_used:
88+ description: Number of concurrent workers used
89+ type: int
90+ returned: always
91+ '''
92+
93+ from ansible .plugins .lookup import LookupBase
94+ from ansible .errors import AnsibleError , AnsibleParserError
95+ from ansible .utils .display import Display
96+ from ansible .module_utils .parsing .convert_bool import boolean
97+
98+ import requests
99+ import json
100+ import time
101+ from urllib3 .exceptions import InsecureRequestWarning
102+ from concurrent .futures import ThreadPoolExecutor
103+ import threading
104+
105+ display = Display ()
106+
107+ class LookupModule (LookupBase ):
108+
109+ def run (self , terms , variables = None , ** kwargs ):
110+ start_time = time .time ()
111+
112+ self .set_options (var_options = variables , direct = kwargs )
113+
114+ # Get parameters
115+ host = self .get_option ('host' )
116+ username = self .get_option ('username' )
117+ password = self .get_option ('password' )
118+ max_workers = self .get_option ('max_workers' , 30 )
119+ page_size = self .get_option ('page_size' , 400 )
120+ verify_ssl = self .get_option ('verify_ssl' , True )
121+
122+ # Convert verify_ssl to boolean if it's not already
123+ if not isinstance (verify_ssl , bool ):
124+ verify_ssl = boolean (verify_ssl )
125+
126+ # Disable SSL warnings if verify_ssl is False
127+ if not verify_ssl :
128+ requests .packages .urllib3 .disable_warnings (InsecureRequestWarning )
129+
130+ if not all ([host , username , password ]):
131+ raise AnsibleError ("Missing required parameters: host, username, and password are required" )
132+
133+ try :
134+ # Setup authentication
135+ auth = (username , password )
136+ headers = {'Content-Type' : 'application/json' }
137+
138+ display .vvv (f"Fetching job templates from { host } with page size { page_size } " )
139+
140+ # Get all job templates with pagination
141+ template_info = [] # Store both id and name
142+ next_url = f"{ host } /api/v2/job_templates/?page_size={ page_size } "
143+
144+ while next_url :
145+ templates_response = requests .get (next_url , auth = auth , headers = headers , verify = verify_ssl )
146+
147+ if templates_response .status_code != 200 :
148+ raise AnsibleError (f"Failed to get job templates: { templates_response .status_code } " )
149+
150+ templates_data = templates_response .json ()
151+ # Store both id and name for each template
152+ template_info .extend ([{'id' : template ['id' ], 'name' : template ['name' ]} for template in templates_data .get ('results' , [])])
153+
154+ # Get next page URL
155+ next_url = templates_data .get ('next' )
156+ if next_url and not next_url .startswith ('http' ):
157+ next_url = f"{ host } { next_url } "
158+
159+ display .vvv (f"Found { len (template_info )} total job templates, checking for notifications with { max_workers } workers" )
160+
161+ # Templates with notifications
162+ templates_with_notifications = []
163+ lock = threading .Lock ()
164+
165+ # Create a session for connection pooling
166+ session = requests .Session ()
167+
168+ def check_template (template_data ):
169+ template_id = template_data ['id' ]
170+ template_name = template_data ['name' ]
171+ template_info = {'id' : template_id , 'name' : template_name , 'notification_types' : []}
172+ has_notifications = False
173+
174+ # Check each notification type
175+ for notification_type in ['started' , 'success' , 'error' ]:
176+ url = f"{ host } /api/v2/job_templates/{ template_id } /notification_templates_{ notification_type } /"
177+ response = session .get (url , auth = auth , headers = headers , verify = verify_ssl )
178+
179+ if response .status_code == 200 :
180+ data = response .json ()
181+ count = data .get ('count' , 0 )
182+
183+ if count > 0 :
184+ has_notifications = True
185+ template_info ['notification_types' ].append (notification_type )
186+
187+ if has_notifications :
188+ with lock :
189+ templates_with_notifications .append (template_info )
190+
191+ # Use ThreadPoolExecutor for concurrent processing
192+ with ThreadPoolExecutor (max_workers = max_workers ) as executor :
193+ executor .map (check_template , template_info )
194+
195+ elapsed_time = time .time () - start_time
196+
197+ # Return with enhanced information
198+ return [{
199+ "job_templates" : templates_with_notifications ,
200+ "count" : len (templates_with_notifications ),
201+ "total_templates" : len (template_info ),
202+ "execution_time_seconds" : round (elapsed_time , 2 ),
203+ "workers_used" : max_workers
204+ }]
205+
206+ except Exception as e :
207+ raise AnsibleError (f"Error in awx_notification_templates lookup: { str (e )} " )
0 commit comments