Bug 878986

Summary: column restriction is too agressive AND it causes "stty: standard input: Invalid argument"
Product: Red Hat Enterprise Linux 6 Reporter: John Sefler <jsefler>
Component: subscription-managerAssignee: Bryan Kearney <bkearney>
Status: CLOSED ERRATA QA Contact: IDM QE LIST <seceng-idm-qe-list>
Severity: high Docs Contact:
Priority: unspecified    
Version: 6.4CC: alikins, bkearney, tlavigne
Target Milestone: rcKeywords: TestBlocker
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: subscription-manager-1.1.11-1 Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2013-02-21 09:01:27 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 771481    

Description John Sefler 2012-11-21 17:40:17 UTC
Description of problem:
Unfortunately there is a TestBlocker side affect from the fix for bug 864177.

In commit 6a3facb1ad01f224d04d9a5e6d3430319eb9bf67 there is a new function called get_terminal_width() that assumes an artificial column width of 80 when the try block fails.  This is causing problems for automated tests that are running through ssh where there is no stty.

Ideally, if no stty exists, then there is no reason to impose an artifitial column restriction.


SOLUTION A:
src/subscription-manager/utils.py
>def get_terminal_width():
>    # TODO:  Something about these magic numbers!
>    columns = 80
               ^^ CHANGE THIS TO SOME REALLY LARGE VALUE LIKE 800
>    try:
>        rows, columns = os.popen('stty size', 'r').read().split()
>    except:
>        pass
>
>    return int(columns)


SOLUTION B:
src/subscription-manager/utils.py
>def get_terminal_width():
>    # TODO:  Something about these magic numbers!
>    columns = 80
               ^^ CHANGE THIS TO none
>    try:
>        rows, columns = os.popen('stty size', 'r').read().split()
>    except:
>        pass
>
>    return int(columns)

src/subscription-manager/managercli.py
>         # Split here and build it back up by word, this way we get word wrapping
>         for word in words:
>             if current + len(word) < max_length:
  CHANGE THIS ^ LINE TO: if (max_length and (current + len(word) < max_length)):
>                 current += len(word) + 1  # Have to account for the extra space
>                 line.append(word)
>             else:
>                 add_line()
>                 line = [' ' * (indent - 1), word]
>                 current = indent + len(word) + 1


Version-Release number of selected component (if applicable):
[jsefler@jseflerT5400 subscription_manager]$ git log | head -1
commit c29e8ac7a83d51d1a174d2a7b60b6676ae3bd52b
[root@jsefler-6 ~]# rpm -q subscription-manager
subscription-manager-1.1.10-1.el6.x86_64







Additional info:

Something else that is bad about the above implementation of get_terminal_width() is that it encounters "stty: standard input: Invalid argument".  For example:

[jsefler@jseflerT5400 ~]$ ssh root.redhat.com "subscription-manager list --consumed"
reverse mapping checking getaddrinfo for unused [10.16.120.157] failed - POSSIBLE BREAK-IN ATTEMPT!
root.redhat.com's password: 
stty: standard input: Invalid argument         <=========== COMES FROM try BLOCK
No consumed subscription pools to list

Comment 2 J.C. Molet 2012-11-21 18:00:52 UTC
This is a slightly more robust version of get_terminal_size() that doesn't throw a traceback in the event of no stty.  It was modified from console.py which is apparently included in another version of python:


def getTerminalSize():
    import os
    env = os.environ
    def ioctl_GWINSZ(fd):
        try:
            import fcntl, termios, struct
            cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,
        '1234'))
            print cr
        except:
            return
        return cr
    cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
    if not cr:
        try:
            fd = os.open(os.ctermid(), os.O_RDONLY)
            cr = ioctl_GWINSZ(fd)
            os.close(fd)
        except:
            pass
    if not cr:
        #defaults would go here, currently 25 and 80
        cr = (env.get('LINES', 25), env.get('COLUMNS', 80))

    return int(cr[0]), int(cr[1])


For option B above, we would set the defaults to None (which I like better anyway).  The return statement here could be minimally modified to behave the same way as the existing function.

Comment 4 Bryan Kearney 2012-11-28 16:44:13 UTC
commit 4ed8da58cfa992e0a01b04523c084da193d7a59e
Author: Bryan Kearney <bkearney>
Date:   Mon Nov 26 14:18:49 2012 -0500

    878986: Default to no line breaking if no stty is available


Cherry pick request has been put in.

Comment 7 John Sefler 2012-12-03 19:31:16 UTC
Version...
[root@jsefler-6workstation ~]# rpm -q subscription-manager
subscription-manager-1.1.10-1.git.3.26d45eb.el6.x86_64


Not sure what was actually implemented for this bug.
Unfortunately side affects are occuring that block our automated tests...


I am getting the following traceback in rhsm.log...
2012-12-03 14:08:05,692 [ERROR]  @managercli.py:115 - exception caught in subscription-manager
2012-12-03 14:08:05,692 [ERROR]  @managercli.py:116 - setupterm: could not find terminfo database
Traceback (most recent call last):
  File "/usr/sbin/subscription-manager", line 78, in <module>
    sys.exit(abs(main() or 0))
  File "/usr/sbin/subscription-manager", line 69, in main
    return managercli.ManagerCLI().main()
  File "/usr/share/rhsm/subscription_manager/managercli.py", line 2042, in __init__
    CLI.__init__(self, command_classes=commands)
  File "/usr/share/rhsm/subscription_manager/cli.py", line 77, in __init__
    cmd = clazz()
  File "/usr/share/rhsm/subscription_manager/managercli.py", line 847, in __init__
    ent_dir, prod_dir)
  File "/usr/share/rhsm/subscription_manager/managercli.py", line 443, in __init__
    prod_dir)
  File "/usr/share/rhsm/subscription_manager/managercli.py", line 195, in __init__
    self.columns = get_terminal_width()
  File "/usr/share/rhsm/subscription_manager/utils.py", line 299, in get_terminal_width
    curses.setupterm()
error: setupterm: could not find terminfo database


Here is a one liner to reproduce the error...
> [root@jsefler-6server ~]# ssh root.redhat.com "expect -c \"spawn subscription-manager register --username=testuser1 --org=admin; expect \"*Password:\"; send foobar\r ; expect eof; catch wait reason; exit [lindex \$reason 3]\""
> root.redhat.com's password: 
> spawn subscription-manager register --username=testuser1 --org=admin
> setupterm: could not find terminfo database
> send: spawn id exp3 not open
>     while executing
> "send foobar\r "
> [root@jsefler-6server ~]# 


Moving status back to ASSIGNED

Comment 8 Adrian Likins 2012-12-04 18:30:13 UTC
I'm going to revert 0eebba0ab85c2aa3905e60a38e6368b24f718a52, that
should fix the formatting, and get rid of the terminfo problem when ran under expect.

Comment 9 Adrian Likins 2012-12-04 19:36:42 UTC
0eebba0ab85c2aa3905e60a38e6368b24f718a52 reverted,

in master:

commit fef10129c2e84a09cfc9ee071b3ca1049ddbe0b3
Author: Adrian Likins <alikins>
Date:   Tue Dec 4 13:19:38 2012 -0500

    Revert "878986: refactor to use curses/textwrap for format"
    
    This reverts commit 0eebba0ab85c2aa3905e60a38e6368b24f718a52.
    
    expect driven scripts dont seem to setup a term in
    a way that curses will work, so revert this.


in rhel-64:

commit d679cb276386a9de4560e6279e04b5027b4a2438
Author: Adrian Likins <alikins>
Date:   Tue Dec 4 13:19:38 2012 -0500

    Revert "878986: refactor to use curses/textwrap for format"
    
    This reverts commit 0eebba0ab85c2aa3905e60a38e6368b24f718a52.
    
    expect driven scripts dont seem to setup a term in
    a way that curses will work, so revert this.

Should land in 1.1.11

Comment 11 John Sefler 2012-12-06 21:51:10 UTC
Verifying Version....
[root@jsefler-6 ~]# rpm -q subscription-manager
subscription-manager-1.1.11-1.el6.x86_64

> [root@jsefler-6 ~]# ssh root.redhat.com "expect -c \"spawn subscription-manager register --username=testuser1 --org=admin; expect \"*Password:\"; send foobar\r ; expect eof; catch wait reason; exit [lindex \$reason 3]\""
> root.redhat.com's password: 
> spawn subscription-manager register --username=testuser1 --org=admin
> Password: 
> Invalid Credentials
> [root@jsefler-6 ~]# 

^ VERIFIED: no longer encounters "setupterm: could not find terminfo database"


> [root@jsefler-6 ~]# ssh root.redhat.com "subscription-manager list --consumed"
> root.redhat.com's password: 
> No consumed subscription pools to list
> [root@jsefler-6 ~]# 

^ VERIFIED: no longer encounters "stty: standard input: Invalid argument"


Moving this bugzilla status to VERIFIED.

Comment 13 errata-xmlrpc 2013-02-21 09:01:27 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

http://rhn.redhat.com/errata/RHBA-2013-0350.html