Commit 7c37d8eb authored by Luke Sneeringer's avatar Luke Sneeringer

More debug logging!

parent a336b25e
......@@ -72,6 +72,16 @@ class Client(Session):
headers.setdefault('Content-Type', 'application/json')
kwargs['headers'] = headers
# If debugging is on, print the URL and data being sent.
debug.log('%s %s' % (method, url), fg='blue', bold=True)
if method in ('POST', 'PUT', 'PATCH'):
debug.log('Data: %s' % kwargs.get('data', {}),
fg='blue', bold=True)
if method == 'GET' or kwargs.get('params', None):
debug.log('Params: %s' % kwargs.get('params', {}),
fg='blue', bold=True)
# If this is a JSON request, encode the data value.
if headers.get('Content-Type', '') == 'application/json':
kwargs['data'] = json.dumps(kwargs.get('data', {}))
......@@ -430,11 +430,6 @@ class Resource(BaseResource):
raise exc.BadRequest('Attempted to set %s twice.' % query[0])
kwargs[query[0]] = query[1]
# If debugging is on, print the URL and data being sent.
debug.log('GET %s' % url, fg='blue', bold=True)
debug.log('Params: %s' % kwargs, fg='blue', bold=True)
# Make the request to the Ansible Tower API.
r = client.get(url, params=kwargs)
resp = r.json()
......@@ -505,6 +500,7 @@ class Resource(BaseResource):
existing_data = self._lookup(
fail_on_missing=not create_on_missing,
if existing_data:
......@@ -559,9 +555,6 @@ class Resource(BaseResource):
# If debugging is on, print the URL and data being sent.
debug.log('Writing the record.', header='details')
debug.log('%s %s' % (method, url), fg='blue', bold=True)
debug.log('Data: %s' % kwargs, fg='blue', bold=True)
# Actually perform the write.
r = getattr(client, method.lower())(url, data=kwargs)
......@@ -618,7 +611,8 @@ class Resource(BaseResource):
If the number of results does not equal one, raise an exception.
debug.log('Getting the record.', header='details')
if kwargs.pop('include_debug_header', True):
debug.log('Getting the record.', header='details')
response =, fail_on_no_results=True,
fail_on_multiple_results=True, **kwargs)
return response['results'][0]
......@@ -744,7 +738,8 @@ class Resource(BaseResource):
r =, data={'disassociate': True, 'id': other})
return {'changed': True}
def _lookup(self, fail_on_missing=False, fail_on_found=False, **kwargs):
def _lookup(self, fail_on_missing=False, fail_on_found=False,
include_debug_header=True, **kwargs):
"""Attempt to perform a lookup that is expected to return a single
result, and return the record.
......@@ -767,7 +762,8 @@ class Resource(BaseResource):
# Get the record to write.
existing_data = self.get(**read_params)
existing_data = self.get(include_debug_header=include_debug_header,
if fail_on_found:
raise exc.Found('A record matching %s already exists, and '
'you requested a failure in that case.')
......@@ -28,7 +28,8 @@ from sdict import adict
from tower_cli import models, get_resource, resources
from tower_cli.api import client
from tower_cli.utils import exceptions as exc, types
from tower_cli.conf import settings
from tower_cli.utils import debug, exceptions as exc, types
class Resource(models.BaseResource):
......@@ -87,6 +88,7 @@ class Resource(models.BaseResource):
data['extra_vars'] = extra_vars
# Create the new job in Ansible Tower.
debug.log('Creating the job.', header='details')
job ='/jobs/', data=data).json()
# There's a non-trivial chance that we are going to need some
......@@ -94,12 +96,15 @@ class Resource(models.BaseResource):
# rely on passwords entered at run-time.
# If there are any such passwords on this job, ask for them now.
debug.log('Asking for information necessary to start the job.',
job_start_info = client.get('/jobs/%d/start/' % job['id']).json()
start_data = {}
for password in job_start_info.get('passwords_needed_to_start', []):
start_data[password] = getpass('Password for %s: ' % password)
# Actually start the job.
debug.log('Launching the job.', header='details')
result ='/jobs/%d/start/' % job['id'], start_data)
# If we were told to monitor the job once it started, then call
......@@ -150,7 +155,7 @@ class Resource(models.BaseResource):
# If the job has failed, we want to raise an Exception for that
# so we get a non-zero response.
if job['failed']:
if is_tty(outfile):
if is_tty(outfile) and not settings.verbose:
click.secho('\r' + ' ' * longest_string + '\n',
raise exc.JobFailure('Job failed.')
......@@ -169,7 +174,7 @@ class Resource(models.BaseResource):
output += ' ' * (longest_string - len(output))
longest_string = len(output)
if is_tty(outfile):
if is_tty(outfile) and not settings.verbose:
click.secho(output, nl=False, file=outfile)
# Put the process to sleep briefly.
......@@ -202,12 +207,12 @@ class Resource(models.BaseResource):
# If the outfile is *not* a TTY, print a status update
# when and only when we make an actual check to job status.
if not is_tty(outfile):
if not is_tty(outfile) or settings.verbose:
click.echo('Current status: %s' % job['status'],
# Wipe out the previous output
if is_tty(outfile):
if is_tty(outfile) and not settings.verbose:
click.secho('\r' + ' ' * longest_string,
file=outfile, nl=False)
click.secho('\r', file=outfile, nl=False)
......@@ -221,6 +226,7 @@ class Resource(models.BaseResource):
def status(self, pk, detail=False):
"""Print the current job status."""
# Get the job from Ansible Tower.
debug.log('Asking for job status.', header='details')
job = client.get('/jobs/%d/' % pk).json()
# In most cases, we probably only want to know the status of the job
......@@ -101,7 +101,7 @@ class ClientTests(unittest.TestCase):
with mock.patch.object(debug, 'log') as dlog:
with self.assertRaises(exc.ConnectionError):
r = client.get('/ping/')
self.assertEqual(dlog.call_count, 2)
self.assertEqual(dlog.call_count, 5)
def test_server_error(self):
"""Establish that server errors raise the ServerError
......@@ -26,7 +26,7 @@ import click
from tower_cli import models, resources
from tower_cli.api import client
from tower_cli.conf import settings
from tower_cli.utils import exceptions as exc
from tower_cli.utils import debug, exceptions as exc
from tests.compat import unittest, mock
......@@ -504,6 +504,17 @@ class ResourceTests(unittest.TestCase):
with self.assertRaises(exc.NotFound):
result = self.res.get(name='spam')
def test_get_no_debug_header(self):
"""Establish that if get is called with include_debug_header=False,
no debug header is issued.
with mock.patch.object(type(self.res), 'read') as read:
with mock.patch.object(debug, 'log') as dlog:
read.return_value = {'results': [True]}
result = self.res.get(42, include_debug_header=False)
self.assertEqual(dlog.call_count, 0)
def test_get_unexpected_multiple_results(self):
"""Establish that if a read method gets more than one result when
it should have gotten one and exactly one, that it raises
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment