cli2 4.2.5__tar.gz → 4.2.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cli2-4.2.5/cli2.egg-info → cli2-4.2.7}/PKG-INFO +1 -1
- {cli2-4.2.5 → cli2-4.2.7}/cli2/ansible/action.py +43 -4
- {cli2-4.2.5 → cli2-4.2.7/cli2.egg-info}/PKG-INFO +1 -1
- {cli2-4.2.5 → cli2-4.2.7}/setup.py +1 -1
- {cli2-4.2.5 → cli2-4.2.7}/tests/test_ansible.py +19 -0
- {cli2-4.2.5 → cli2-4.2.7}/MANIFEST.in +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/README.rst +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/classifiers.txt +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/__init__.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/ansible/__init__.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/ansible/playbook.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/ansible/variables.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/asyncio.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/cli.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/cli2.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/client.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/colors.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/configuration.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/decorators.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/display.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/examples/__init__.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/examples/client.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/examples/conf.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/examples/example.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/examples/example_obj.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/examples/nesting.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/examples/obj.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/examples/obj2.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/examples/test.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/lock.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/log.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/node.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/sphinx.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/table.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2/test.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2.egg-info/SOURCES.txt +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2.egg-info/dependency_links.txt +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2.egg-info/entry_points.txt +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2.egg-info/requires.txt +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/cli2.egg-info/top_level.txt +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/setup.cfg +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/tests/test_ansible_variables.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/tests/test_asyncio.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/tests/test_cli.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/tests/test_client.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/tests/test_command.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/tests/test_configuration.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/tests/test_decorators.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/tests/test_display.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/tests/test_entry_point.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/tests/test_group.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/tests/test_inject.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/tests/test_lock.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/tests/test_node.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/tests/test_restful.py +0 -0
- {cli2-4.2.5 → cli2-4.2.7}/tests/test_table.py +0 -0
|
@@ -9,6 +9,7 @@ import os
|
|
|
9
9
|
import re
|
|
10
10
|
import traceback
|
|
11
11
|
|
|
12
|
+
from ansible.parsing.yaml.objects import AnsibleUnicode
|
|
12
13
|
from ansible.plugins.action import ActionBase
|
|
13
14
|
|
|
14
15
|
# colors:
|
|
@@ -126,7 +127,15 @@ class ActionBase(ActionBase):
|
|
|
126
127
|
|
|
127
128
|
The client object generated by :py:meth:`client_factory` if you
|
|
128
129
|
implement it.
|
|
130
|
+
|
|
131
|
+
.. py:attribute:: mask
|
|
132
|
+
|
|
133
|
+
List of result keys to mask, if set, this module will print the result
|
|
134
|
+
with masked values, so you can set no_log: True for the task and still
|
|
135
|
+
see most of the result.
|
|
129
136
|
"""
|
|
137
|
+
mask = None
|
|
138
|
+
|
|
130
139
|
def get(self, arg_name=None, fact_name=None, default=UNSET_DEFAULT):
|
|
131
140
|
if arg_name and arg_name in self._task.args:
|
|
132
141
|
return self._task.args[arg_name]
|
|
@@ -165,6 +174,9 @@ class ActionBase(ActionBase):
|
|
|
165
174
|
except Exception as exc:
|
|
166
175
|
self.result['failed'] = True
|
|
167
176
|
|
|
177
|
+
if self.verbosity:
|
|
178
|
+
traceback.print_exc()
|
|
179
|
+
|
|
168
180
|
if isinstance(exc, AnsibleError):
|
|
169
181
|
self.result['error'] = exc.message
|
|
170
182
|
elif isinstance(exc, cli2.ResponseError):
|
|
@@ -179,12 +191,14 @@ class ActionBase(ActionBase):
|
|
|
179
191
|
key, value = self.client.request_log_data(exc.request)
|
|
180
192
|
if key:
|
|
181
193
|
self.result[f'request_{key}'] = value
|
|
182
|
-
elif self.verbosity:
|
|
183
|
-
traceback.print_exc()
|
|
184
194
|
|
|
185
195
|
# for pytest to raise
|
|
186
196
|
self.exc = exc
|
|
187
197
|
finally:
|
|
198
|
+
if self.mask and self.verbosity:
|
|
199
|
+
print('\nResult:')
|
|
200
|
+
cli2.print(self.masked_result())
|
|
201
|
+
|
|
188
202
|
if (
|
|
189
203
|
self._before_data != UNSET_DEFAULT
|
|
190
204
|
and self._after_data != UNSET_DEFAULT
|
|
@@ -208,6 +222,31 @@ class ActionBase(ActionBase):
|
|
|
208
222
|
else:
|
|
209
223
|
cli2.diff(diff)
|
|
210
224
|
|
|
225
|
+
def native(self, data):
|
|
226
|
+
def _native(data):
|
|
227
|
+
for key, value in data.items():
|
|
228
|
+
if isinstance(value, AnsibleUnicode):
|
|
229
|
+
data[key] = str(value)
|
|
230
|
+
elif isinstance(value, dict):
|
|
231
|
+
data[key] = _native(value)
|
|
232
|
+
elif isinstance(value, list):
|
|
233
|
+
data[key] = [_native(item) for item in value]
|
|
234
|
+
return data
|
|
235
|
+
return _native(copy.deepcopy(data))
|
|
236
|
+
|
|
237
|
+
def masked_result(self):
|
|
238
|
+
def _mask(data):
|
|
239
|
+
if isinstance(data, dict):
|
|
240
|
+
for key, value in data.items():
|
|
241
|
+
if key in self.mask:
|
|
242
|
+
data[key] = '***MASKED***'
|
|
243
|
+
else:
|
|
244
|
+
data[key] = _mask(value)
|
|
245
|
+
elif isinstance(data, list):
|
|
246
|
+
return [_mask(item) for item in data]
|
|
247
|
+
return data
|
|
248
|
+
return _mask(self.native(self.result))
|
|
249
|
+
|
|
211
250
|
async def run_async(self):
|
|
212
251
|
"""
|
|
213
252
|
The method you are supposed to implement.
|
|
@@ -276,7 +315,7 @@ class ActionBase(ActionBase):
|
|
|
276
315
|
:param data: Dictionnary of data
|
|
277
316
|
:param label: Label to show in diff
|
|
278
317
|
"""
|
|
279
|
-
self._before_data =
|
|
318
|
+
self._before_data = self.native(data)
|
|
280
319
|
self._before_label = label
|
|
281
320
|
|
|
282
321
|
def after_set(self, data, label='after'):
|
|
@@ -286,5 +325,5 @@ class ActionBase(ActionBase):
|
|
|
286
325
|
:param data: Dictionnary of data
|
|
287
326
|
:param label: Label to show in diff
|
|
288
327
|
"""
|
|
289
|
-
self._after_data =
|
|
328
|
+
self._after_data = self.native(data)
|
|
290
329
|
self._after_label = label
|
|
@@ -8,6 +8,25 @@ import yaml
|
|
|
8
8
|
from cli2 import ansible
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
class ActionModule(ansible.ActionBase):
|
|
12
|
+
mask = ['a']
|
|
13
|
+
|
|
14
|
+
async def run_async(self):
|
|
15
|
+
self.result['x'] = dict(a='a', b='b')
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@pytest.mark.asyncio
|
|
19
|
+
async def test_mask(monkeypatch):
|
|
20
|
+
printer = mock.Mock()
|
|
21
|
+
from cli2.ansible import action
|
|
22
|
+
monkeypatch.setattr(action.cli2, 'print', printer)
|
|
23
|
+
module = await ActionModule.run_test_async()
|
|
24
|
+
assert module.result == dict(x=dict(a='a', b='b'))
|
|
25
|
+
printer.assert_called_once_with(
|
|
26
|
+
dict(x=dict(a='***MASKED***', b='b'))
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
11
30
|
@pytest.mark.asyncio
|
|
12
31
|
async def test_response_error(httpx_mock):
|
|
13
32
|
class Client(cli2.Client):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|