Skip to content

Commit 6cd8740

Browse files
committed
Transormation to pip package
1 parent 2940ee1 commit 6cd8740

36 files changed

+587
-778
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
cotea.egg-info/
2+
__pycache__/
3+
dist/
4+

pyproject.toml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[build-system]
2+
requires = ["setuptools>=42"]
3+
build-backend = "setuptools.build_meta"

setup.cfg

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[metadata]
2+
name = cotea
3+
version = 1.3
4+
author = David Badalyan
5+
author_email = [email protected]
6+
description = Tool that provides Python API to run Ansible programmatically.
7+
long_description = file: README.md
8+
long_description_content_type = text/markdown
9+
url = https://github.com/ispras/cotea
10+
project_urls =
11+
Bug Tracker = https://github.com/ispras/cotea/issues
12+
classifiers =
13+
Programming Language :: Python :: 3
14+
License :: OSI Approved :: Apache Software License
15+
Operating System :: OS Independent
16+
17+
[options]
18+
package_dir =
19+
= src
20+
packages = find:
21+
python_requires = >=3.6
22+
23+
[options.packages.find]
24+
where = src
25+
Binary file not shown.
-635 Bytes
Binary file not shown.

src/__pycache__/runner.cpython-38.pyc

-9.96 KB
Binary file not shown.

src/cotea/__init__.py

Whitespace-only changes.

src/ansible_execution_sync.py renamed to src/cotea/ansible_execution_sync.py

+12-10
Original file line numberDiff line numberDiff line change
@@ -6,39 +6,41 @@ def __init__(self, logger):
66
self.runner_event = threading.Event()
77
self.ansible_event = threading.Event()
88
self.logger = logger
9+
self.curr_breakpoint_label = None
910

1011
def status(self):
11-
self.logger.info("Runner event status: %s", self.runner_event.is_set())
12-
self.logger.info("Ansible event status: %s",
12+
self.logger.debug("Runner event status: %s", self.runner_event.is_set())
13+
self.logger.debug("Ansible event status: %s",
1314
self.ansible_event.is_set())
1415

1516
def runner_just_wait(self):
16-
self.logger.info("runner: waiting...")
17+
#self.logger.debug("runner: waiting...")
1718
self.runner_event.wait()
1819
self.runner_event.clear()
1920

2021
def ansible_just_wait(self):
21-
self.logger.info("ansible: waiting...")
22+
#self.logger.debug("ansible: waiting...")
2223
self.ansible_event.wait()
2324
self.ansible_event.clear()
2425

25-
def continue_runner_with_stop(self):
26-
self.logger.info("ansible: resume runner work and wait")
26+
def continue_runner_with_stop(self, curr_breakpoint_label):
27+
#self.logger.debug("ansible: resume runner work and wait")
28+
self.curr_breakpoint_label = curr_breakpoint_label
2729
self.runner_event.set()
2830
self.ansible_event.wait()
2931
self.ansible_event.clear()
3032

3133
def continue_ansible_with_stop(self):
32-
self.logger.info("runner: resume ansible work and wait")
34+
#self.logger.debug("runner: resume ansible work and wait")
3335
self.ansible_event.set()
3436
self.runner_event.wait()
3537
self.runner_event.clear()
36-
self.logger.debug("runner: ANSIBLE WAKED ME UP")
38+
#self.logger.debug("runner: ANSIBLE WAKED ME UP")
3739

3840
def continue_runner(self):
39-
self.logger.info("ansible: resume runner work")
41+
#self.logger.debug("ansible: resume runner work")
4042
self.runner_event.set()
4143

4244
def continue_ansible(self):
43-
self.logger.info("runner: resume ansible work")
45+
#self.logger.debug("runner: resume ansible work")
4446
self.ansible_event.set()
File renamed without changes.

src/cotea/runner.py

+290
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
import logging
2+
import threading
3+
4+
from ansible.cli import CLI
5+
from ansible.plugins.strategy.linear import StrategyModule
6+
from ansible.plugins.strategy import StrategyBase
7+
from ansible.cli.playbook import PlaybookCLI
8+
from ansible.parsing.yaml.objects import AnsibleUnicode
9+
10+
from cotea.ansible_execution_sync import ans_sync
11+
from cotea.task_result import TaskResult
12+
from cotea.wrappers.pbcli_run_wrapper import pbcli_run_wrapper
13+
from cotea.wrappers.strategy_run_wrapper import strategy_run_wrapper
14+
from cotea.wrappers.get_next_task_wrapper import get_next_task_wrapper
15+
from cotea.wrappers.update_active_conn_wrapper import update_active_conn_wrapper
16+
from cotea.wrappers.play_prereqs_wrapper import play_prereqs_wrapper
17+
18+
19+
class runner:
20+
def __init__(self, pb_path, arg_maker, debug_mod=None):
21+
logging_lvl = logging.INFO
22+
if debug_mod:
23+
logging_lvl= logging.DEBUG
24+
25+
logging.basicConfig(format="%(name)s %(asctime)s %(message)s", \
26+
datefmt="%H:%M:%S", level=logging_lvl)
27+
28+
self.pb_path = pb_path
29+
self.arg_maker = arg_maker
30+
31+
self.logger = logging.getLogger("RUNNER")
32+
33+
log_sync = logging.getLogger("SYNC")
34+
self.sync_obj = ans_sync(log_sync)
35+
36+
self.breakpoint_labeles = {}
37+
self.breakpoint_labeles["before_playbook"] = "before_playbook_run"
38+
self.breakpoint_labeles["after_playbook"] = "after_playbook_run"
39+
self.breakpoint_labeles["before_play"] = "before_play_run"
40+
self.breakpoint_labeles["after_play"] = "after_play_run"
41+
self.breakpoint_labeles["before_task"] = "before_task_run"
42+
self.breakpoint_labeles["after_task"] = "after_task_run"
43+
44+
self._set_wrappers()
45+
start_ok = self._start_ansible()
46+
self.logger.debug("Ansible start ok: %s", start_ok)
47+
48+
49+
def _set_wrappers(self):
50+
wrp_lgr = logging.getLogger("WRPR")
51+
52+
self.pbcli_run_wrp = pbcli_run_wrapper(PlaybookCLI.run, self.sync_obj, wrp_lgr,
53+
self.breakpoint_labeles["before_playbook"],
54+
self.breakpoint_labeles["after_playbook"])
55+
PlaybookCLI.run = self.pbcli_run_wrp
56+
57+
self.play_wrp = strategy_run_wrapper(StrategyModule.run, self.sync_obj, wrp_lgr,
58+
self.breakpoint_labeles["before_play"],
59+
self.breakpoint_labeles["after_play"])
60+
StrategyModule.run = self.play_wrp
61+
62+
self.task_wrp = get_next_task_wrapper(StrategyModule._get_next_task_lockstep,
63+
self.sync_obj, wrp_lgr,
64+
self.breakpoint_labeles["before_task"])
65+
StrategyModule._get_next_task_lockstep = self.task_wrp
66+
67+
self.update_conn_wrapper = update_active_conn_wrapper(StrategyBase.update_active_connections,
68+
self.sync_obj, wrp_lgr,
69+
self.breakpoint_labeles["after_task"])
70+
StrategyBase.update_active_connections = self.update_conn_wrapper
71+
72+
self.play_prereqs_wrp = play_prereqs_wrapper(CLI._play_prereqs,
73+
self.sync_obj, wrp_lgr)
74+
CLI._play_prereqs = self.play_prereqs_wrp
75+
76+
77+
def _start_ansible(self):
78+
args = self.arg_maker.args
79+
args.insert(0, "/usr/local/bin/ansible-playbook")
80+
args.insert(1, self.pb_path)
81+
82+
self.pbCLI = PlaybookCLI(args)
83+
84+
self.ansible_thread = threading.Thread(target=self.pbCLI.run)
85+
self.ansible_thread.start()
86+
self.sync_obj.runner_just_wait()
87+
88+
if self.sync_obj.curr_breakpoint_label == self.breakpoint_labeles["before_playbook"]:
89+
return True
90+
91+
return False
92+
93+
94+
def has_next_play(self):
95+
if self.sync_obj.curr_breakpoint_label == self.breakpoint_labeles["after_playbook"]:
96+
return False
97+
98+
self.sync_obj.continue_ansible_with_stop()
99+
current_bp_label = self.sync_obj.curr_breakpoint_label
100+
self.logger.debug("has_next_play: %s", current_bp_label)
101+
102+
if current_bp_label == self.breakpoint_labeles["before_play"]:
103+
return True
104+
105+
return False
106+
107+
108+
def has_next_task(self):
109+
if self.sync_obj.curr_breakpoint_label == self.breakpoint_labeles["after_playbook"]:
110+
return False
111+
112+
self.sync_obj.continue_ansible_with_stop()
113+
current_bp_label = self.sync_obj.curr_breakpoint_label
114+
self.logger.debug("has_next_task: %s", current_bp_label)
115+
116+
if current_bp_label == self.breakpoint_labeles["before_task"]:
117+
return True
118+
119+
return False
120+
121+
122+
def run_next_task(self):
123+
res = []
124+
125+
if self.sync_obj.curr_breakpoint_label == self.breakpoint_labeles["after_playbook"]:
126+
return res
127+
128+
self.sync_obj.continue_ansible_with_stop()
129+
current_bp_label = self.sync_obj.curr_breakpoint_label
130+
self.logger.debug("run_next_task: %s", current_bp_label)
131+
132+
if current_bp_label != self.breakpoint_labeles["after_task"]:
133+
self.logger.debug("run_next_task() has come not in to the 'after_task'")
134+
135+
for task_result_ansible_obj in self.update_conn_wrapper.current_results:
136+
res.append(TaskResult(task_result_ansible_obj))
137+
138+
return res
139+
140+
141+
def schedule_last_task_again(self):
142+
self.task_wrp.run_last_one = True
143+
144+
145+
def finish_ansible(self):
146+
while self.sync_obj.curr_breakpoint_label != self.breakpoint_labeles["after_playbook"]:
147+
self.sync_obj.continue_ansible_with_stop()
148+
149+
self.sync_obj.continue_ansible()
150+
151+
152+
def get_cur_play_name(self):
153+
return self.play_wrp.current_play_name
154+
155+
156+
def get_next_task(self):
157+
return self.task_wrp.get_next_task()
158+
159+
160+
def get_next_task_name(self):
161+
return self.task_wrp.get_next_task_name()
162+
163+
164+
def get_prev_task(self):
165+
return self.task_wrp.get_prev_task()
166+
167+
168+
def get_prev_task_name(self):
169+
return self.task_wrp.get_prev_task_name()
170+
171+
172+
def get_last_task_result(self):
173+
res = []
174+
175+
for task_result_ansible_obj in self.update_conn_wrapper.current_results:
176+
res.append(TaskResult(task_result_ansible_obj))
177+
178+
return res
179+
180+
181+
# returns True if there was an non ignored error
182+
def was_error(self):
183+
return self.play_wrp.was_error
184+
185+
186+
# returns list with all errors, including the ignored ones
187+
def get_all_error_msgs(self):
188+
return self.update_conn_wrapper.error_msgs
189+
190+
191+
# returns last error msg that wasn't ignored
192+
def get_error_msg(self):
193+
res = ""
194+
195+
# the errors didn't have 'ignore_errors'
196+
if self.was_error():
197+
errors_count = len(self.update_conn_wrapper.error_msgs)
198+
199+
if errors_count > 0:
200+
res = self.update_conn_wrapper.error_msgs[errors_count - 1]
201+
202+
return res
203+
204+
205+
def get_all_vars(self):
206+
variable_manager = self.play_wrp.variable_manager
207+
cur_play = self.play_wrp.iterator._play
208+
hosts = self.play_wrp.hosts
209+
hosts_all = self.play_wrp.hosts_all
210+
211+
res = variable_manager.get_vars(play=cur_play,
212+
_hosts=hosts,
213+
_hosts_all=hosts_all)
214+
215+
return res
216+
217+
218+
def get_all_facts(self):
219+
return self.play_prereqs_wrp.variable_manager._fact_cache.copy()
220+
221+
222+
def get_variable(self, var_name):
223+
if var_name == "ansible_facts":
224+
return self.get_all_facts()
225+
226+
all_vars = self.get_all_vars()
227+
228+
if var_name in all_vars:
229+
return all_vars[var_name]
230+
231+
# check groups
232+
if "groups" in all_vars:
233+
if var_name in all_vars["groups"]:
234+
return all_vars["groups"][var_name]
235+
236+
result = {}
237+
238+
# check hostvars
239+
if "hostvars" in all_vars:
240+
for host in all_vars["hostvars"]:
241+
for key in all_vars["hostvars"][host]:
242+
if key == var_name:
243+
result[host] = {key: all_vars["hostvars"][host][key]}
244+
245+
if result:
246+
return result
247+
248+
facts = self.get_all_facts()
249+
for host_key in facts:
250+
if var_name in facts[host_key]:
251+
result[host_key] = facts[host_key][var_name]
252+
253+
if result:
254+
return result
255+
256+
self.logger.info("There is no variable with name %s", var_name)
257+
258+
return None
259+
260+
261+
def add_var_as_extra_var(self, new_var_name, value):
262+
variable_manager = self.play_wrp.variable_manager
263+
264+
ansible_way_var = AnsibleUnicode(new_var_name)
265+
variable_manager._extra_vars[ansible_way_var] = value
266+
267+
268+
def _getIP(self):
269+
var_name = "openstack_servers"
270+
host_name = "localhost"
271+
ip1_field_name = "interface_ip"
272+
ip2_field_name = "private_v4"
273+
274+
res = ""
275+
ostack_var = self.get_variable(var_name)
276+
277+
try:
278+
if ip1_field_name in ostack_var[host_name][0]:
279+
res = str(ostack_var[host_name][0][ip1_field_name])
280+
elif ip2_field_name in ostack_var[host_name][0]:
281+
res = str(ostack_var[host_name][0][ip2_field_name])
282+
except Exception as e:
283+
self.logger.info("During runner._getIP() call error was occured. We skipped it.")
284+
self.logger.info("Error is:\n%s", e)
285+
286+
self.logger.debug("get_ip res = %s", res)
287+
self.logger.debug(type(res))
288+
289+
return res
290+

src/cotea/task_result.py

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from ansible.executor.task_result import TaskResult as TR
2+
3+
4+
class TaskResult:
5+
def __init__(self, ansible_task_result: TR):
6+
self.result = ansible_task_result._result.copy()
7+
self.task_name = ansible_task_result.task_name
8+
self.task_ansible_object = ansible_task_result._task.copy()
9+
self.task_fields = ansible_task_result._task_fields.copy()
10+
11+
self.is_changed = ansible_task_result.is_changed()
12+
self.is_failed = ansible_task_result.is_failed()
13+
self.is_skipped = ansible_task_result.is_skipped()
14+
self.is_unreachable = ansible_task_result.is_unreachable()

src/cotea/wrappers/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)