Wednesday, April 11, 2012

Calling Mail from command line - What works and doesn't

I had some trouble recently calling /bin/mail with -s for subject, quoting the actual subject in single or double quotes, and passing in the destination addresses in a shell / environment variable. So, here's the truth table of what works and what doesn't.
# Explanation of what works and doesn't when calling mail with various params:

#[krice@test1 krice]$ EMDEST="Kevin@justanyone.com"
#[krice@test1 krice]$ ps | mail -s 1132 $EMDEST          OK
#[krice@test1 krice]$ ps | mail -s 1132A "$EMDEST"       OK
#[krice@test1 krice]$ ps | mail -s "1132B" "$EMDEST"     OK
#[krice@test1 krice]$ ps | mail -s "1132C" '$EMDEST'     BAD
#[krice@test1 krice]$ EMDEST="Kevin\@justanyone.COM"
#[krice@test1 krice]$ ps | mail -s "1132D" '$EMDEST'     BAD
#[krice@test1 krice]$ ps | mail -s "1132E" $EMDEST       BAD
#[krice@test1 krice]$ EMDEST="Kevin@justanyone.COM"
#[krice@test1 krice]$ ps | mail -s "1132F" $EMDEST       OK

Thursday, April 05, 2012

How to Pretty Print json.dumps() with indent, compactly

I'm working in Python and trying to pretty print some JSON objects. The trouble is, they print all weird. Indentation really messes up with TOO MANY LINES of data, one number per line. In other words, when I do this:
out = json.dumps(tfarray, sort_keys = True, indent = 2)
the indent=2 line causes each array element (in my case, a number) to be printed on its own line. This sucks and takes lots of space. Here's my program to pretty print the json.dumps result into something nicer:
#!/usr/bin/python
import re
instr = """    
       {
          "abbbb": 52,
          "acccc": 32220,
          "asdfasdfasfd": 32220,
          "asdfasdf": [
            0,
            1,
            2,
            3
            ],
          "somethingElse": 13,
          "asdfasdfasfd": [
            10,
            11,
            12,
            13
            ],
        }
"""
y = re.sub(r'\s\s+(\d+)', lambda match: r' {}'.format(match.group(1), instr), instr)
print "Y=%s" % (y)
the instr is the input string as pretty printed. The same sort of thing happens when I call pprint() or pformat() on a complex data structure - the result is hard to read. With the above re:sub, I get:
[krice@loadtest1 HD]$ python test_resub.py
Y=
       {
          "abbbb": 52,
          "acccc": 32220,
          "asdfasdfasfd": 32220,
          "asdfasdf": [ 0, 1, 2, 3
            ],
          "somethingElse": 13,
          "asdfasdfasfd": [ 10, 11, 12, 13
            ],
        }
Lots nicer, eh? Certainly more compact. Hurray for re.sub regex substitutions and lambda functions.

Wednesday, February 01, 2012

Python Robot Framework "FOR loop contains no keywords"

I've just been having a spot of trouble with Robot Framework and :FOR loops. The darn thing wouldn't recognize that the loop contained anything. Turns out, the problem is due to my using a .TXT file (text file with space delimited format). The :FOR loop didn't know how to parse the leading spaces into two empty columns. It had to presume there was one. With only one, the FOR loop contents were empty. This always leads to an error: "FOR loop contains no keywords". The solution for this is to just use pipe delimiters for that keyword. For instance, consider:
| Then I should see that it is below "${critical_value}" |
|   | Log               | In ThenIShouldSeethatItIsBelow keyword now.  | 
|   | ${table_lines}=   | Get Lines Containing String | ${full_output} | Table ${table} is served by  |
|   | Should Not Be Empty | ${table_lines} |
|   | @{lines}= | Split To Lines | ${table_lines}   |
|   | :FOR      | ${line} | IN | @{lines} |
|   |           | Log | havealine ${line} now. |
|   |           | ${value}=  | Fetch From Right | ${line} | ${SPACE} |
|   |           | Convert To Integer | ${value}                         |
|   |           | Should Be True     | ${value} <= ${critical_value}    |
|   | Log       | ending ThenIShouldSeethatItIsBelow now.  |
This allows the pipe delimiter to do its work. A more succinct example is:
| *Setting*  |     *Value*     |
| Library    | OperatingSystem |

| *Variable* |     *Value*     |
| ${MESSAGE} | Hello, world!   |

| *Test Case*  | *Action*        | *Argument*   |
| My Test      | [Documentation] | Example test |
|              | Log             | ${MESSAGE}   |
|              | My Keyword      | /tmp         |
| Another Test | Should Be Equal | ${MESSAGE}   | Hello, world! |
| TestTwo      |
|              | Log             | \nStarting   | WARN |
|              | MyForLoop       |
|              | Log             | \nEnding     | WARN |

| *Keyword*     |
| My Keyword    | [Arguments] | ${path}
|               | Directory Should Exist | ${path}
| MyForLoop     |
|               | Log | In myforloop now. | WARN |
|               | @{gvar}=  | Create List | a | b | c |
|               | Log | gvar is @{gvar} now. | WARN |
|               | :FOR  | ${x} | in | @{gvar} |
|               |       | Log | havealine ${x} now. | WARN |
|               | Log | ending myforloop now.  | WARN |
Enjoy your newfound power and use it responsibly. Or not.

Wednesday, November 30, 2011

I've recently run into the need to create a simple StatefulTelnetProtocol Telnet server. But, most of the examples have lots of extra cruft in the way. So, here's what I came up with by removing some extras from a post I found online: --> Note: I don't know the difference (yet) between doing a self.sendLine() and a self.transport.write() call. Feel free to comment if you know the distinction.
from twisted.internet.protocol import ServerFactory, Protocol
from twisted.conch.telnet import StatefulTelnetProtocol
from twisted.internet import reactor
from time import sleep

class MyProtocol(StatefulTelnetProtocol):
    
    def connectionMade(self):
        print "DEBUG: connectionMade called"
        self.sendLine("***************************************\r\n")
        self.sendLine("Welcome to the Simplified Telnet Server\r\n")
        self.sendLine("***************************************\r\n")
        sleep(2)
        self.transport.write("Can also send a line this way.\r\n")
        self.clearLineBuffer()
     
    def lineReceived(self, line):
        print "DEBUG: lineReceived called with %s" % line.strip()
        if line.strip() != "exit":
            self.sendLine("***************************************\r\n")
            #self.transport.write("TRANSPORT_WRITE: GOT LINE='%s'\n" % (str(line.strip())))
        else:
            print "telnet killed in line: %s" % str(line.strip())
            self.sendLine("TelnetShell killed. Bye Bye ...")
            self.transport.loseConnection()
            self.clearLineBuffer()
     
    def connectionLost(self, reason):
        print "DEBUG: connectionLost called with: %s" % str(reason)
     
def CreateMyFactory():
    factory = ServerFactory()
    factory.protocol = MyProtocol
    return factory
 
if __name__ == "__main__":
    MaFactory = CreateMyFactory()
    reactor.listenTCP(8023, MaFactory)
    reactor.run()

Monday, October 31, 2011

Python sdist package directory not found: Solved

Just was trying to create a new Python module and submit it to PyPi. Trouble was, when I was doing the standard:
me@mybox ~/myusername/blah
$ python setup.py sdist --formats=gztar,zip,bztar,ztar,tar
running sdist
error: package directory 'filenameX' does not exist
turns out the problem was, my setup.py had the following line:
py_modules = ['filenameX.py'],
This should be:
py_modules = ['filenameX'],
FIXED IT! Yay! Now it proceeds nicely.

Friday, October 14, 2011

Using ssh id_rsa without password - another username

Just had to login to another box via ssh, but the other account has a different username than my current one. Further, had to use a different id_dsa / id_dsa.pub set of files. I couldn't figure this out for a while. Turns out, the right way to do this is:
  • generate the keys
  • copy the pub key into authorized_keys2 on the remote box
  • ssh -i ~/.ssh/privateKeyFileName otheruser@remoteboxname
Pretty straightforward, found out. Kinda cool - didn't know about the -i parameter.

Wednesday, October 05, 2011

SSH Slow password prompt

Just had a problem with my vmware player install of Ubuntu Natty. Doing SSH takes a long, long time to come back with a password prompt. This is really aggravating.

Solved it by finding the following info:

1. Edit the /etc/ssh/ssh_config file using the following command

sudo vi /etc/ssh/ssh_config

Commentout the following lines

GSSAPIAuthentication yes
GSSAPIDelegateCredentials no

save the file and exit

2. Test it with ssh to another box, should be very fast now!