Skip to content
This repository has been archived by the owner on Jun 29, 2022. It is now read-only.

Commit

Permalink
Add truncating output on tailing data based on verbosity. Closes #154. (
Browse files Browse the repository at this point in the history
#231)

* Add truncating output on tailing data based on verbosity. Closes #154.

* code review comment updates.
  • Loading branch information
chambridge committed Aug 28, 2017
1 parent 3279ac5 commit ec859b5
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 4 deletions.
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
ansible
pexpect
future
sh

# These requirements are for DEVELOPMENT ONLY!
-r dev-requirements.txt
Expand Down
1 change: 1 addition & 0 deletions rho.spec
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Requires: python-enum34
Requires: python-yaml
Requires: epel-release
Requires: python2-future
Requires: python2-sh

%description
Rho is a tool for scanning your network, logging into systems via SSH, and
Expand Down
5 changes: 1 addition & 4 deletions rho/scancommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import re
import time
import json
import subprocess
from collections import defaultdict
import pexpect
import yaml
Expand Down Expand Up @@ -304,8 +303,7 @@ def run_ansible_with_vault(cmd_string, vault_pass, ssh_key_passphrase=None,
env=env)

if log_to_stdout:
tail = subprocess.Popen(['tail', '-f', '-n', '+0',
log_path])
utilities.threaded_tailing(log_path, ansible_verbosity)

result = child.expect('Vault password:')
child.sendline(vault_pass)
Expand All @@ -324,7 +322,6 @@ def run_ansible_with_vault(cmd_string, vault_pass, ssh_key_passphrase=None,
child.wait()
if log_to_stdout:
time.sleep(2)
tail.terminate()

return child
except pexpect.EOF:
Expand Down
51 changes: 51 additions & 0 deletions rho/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,15 @@
import csv
import tempfile
from shutil import move
import sh
from rho.translation import _

if sys.version_info > (3,):
import _thread
else:
import thread as _thread # pylint: disable=import-error


CREDENTIALS_PATH = 'data/credentials'
PROFILES_PATH = 'data/profiles'

Expand Down Expand Up @@ -118,6 +125,50 @@
+ CONNECTION_FACTS_TUPLE


def threaded_tailing(path, ansible_verbosity=0):
"""Follow and provide output using a thread
:param path: path to file to follow
:param ansible_verbosity: the verbosity level
"""

_thread.start_new_thread(tail_and_follow, (path, ansible_verbosity))


def tail_and_follow(path, ansible_verbosity):
"""Follow and provide output
:param path: tuple containing thepath to file to follow
:param ansible_verbosity: the verbosity level
"""
if len(path) > 0: # pylint: disable=len-as-condition
truncate = 1
if ansible_verbosity:
truncate = ansible_verbosity

print_line = truncate
plabook_started = False
truncated = False

# pylint: disable=no-member
for line in sh.tail('-f', '-n', '+0', path, _iter=True):
line = line.strip('\n')
if line.startswith('TASK') or line.startswith('PLAY'):
print(line)
print_line = truncate
plabook_started = True
truncated = False
elif print_line > 0:
line_len = len(line)
char_truncate = truncate * 100
if line_len > char_truncate:
print(line[0:char_truncate] + '...')
else:
print(line)
print_line = print_line - 1
elif print_line == 0 and not truncated and plabook_started:
print(_('-- output truncated --'))
truncated = True


def ensure_config_dir_exists():
"""Ensure the Rho configuration directory exists."""

Expand Down
31 changes: 31 additions & 0 deletions test/test_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,37 @@

"""Unit tests for rho/utilities.py."""

import contextlib
import sys
import os
import time
import unittest
import six
from rho import utilities

# pylint: disable=missing-docstring
TMP_FOLLOW = "/tmp/follow.txt"


@contextlib.contextmanager
def redirect_stdout(stream):
"""Run a code block, capturing stdout to the given stream"""

old_stdout = sys.stdout
try:
sys.stdout = stream
yield
finally:
sys.stdout = old_stdout


class TestValidatePort(unittest.TestCase):
def setUp(self):
if os.path.isfile(TMP_FOLLOW):
os.remove(TMP_FOLLOW)
with open(TMP_FOLLOW, 'w') as follow_file:
follow_file.write('follow\n')

def test_wrong_type(self):
with self.assertRaises(ValueError):
utilities.validate_port([1, 2, 3])
Expand All @@ -37,3 +61,10 @@ def test_valid_string_port(self):

def test_valid_int_port(self):
self.assertEqual(utilities.validate_port(123), 123)

def test_threaded_tailing(self):
follow_list_out = six.StringIO()
with redirect_stdout(follow_list_out):
utilities.threaded_tailing(TMP_FOLLOW, 3)
time.sleep(2)
self.assertEqual(follow_list_out.getvalue(), 'follow\n')

0 comments on commit ec859b5

Please sign in to comment.