• Welcome to Overclockers Forums! Join us to reply in threads, receive reduced ads, and to customize your site experience!

/bin

Overclockers is supported by our readers. When you click a link to make a purchase, we may earn a commission. Learn More.
here is another script that i wrote for #idlerpg on synIRC (see http://splat.mine.nu/idlerpg if you don't know what that is). i have two scripts. the first one is to just return the status to the command line. the second will check the status page and see if i am online or not. if i am not, it will email me.

./idlerpg_v1
Code:
#!/bin/bash
## written by mbentley

## set variables
command=$0
username=$1

function check_username {
        if [ -z "${username}" ];
        then
                echo "Usage: $command <username>";
                exit 1
        fi
}

function temp_dir {
        tempdir=/tmp/idlerpg_$username_`date +%N`
        mkdir $tempdir
        if [ ! -d "$tempdir" ]
        then
                exit 1
        fi
}

function query_stats {
        cd $tempdir
        wget -t 1 -T 5 -q http://splat.mine.nu/idlerpg/xml.php?player=$username
}

function verify_download {
        if [ ! -e "$tempdir/xml.php?player=$username" ]
        then
                echo "Error fetching data!  Please check manually:  http://splat.mine.nu/idlerpg/players.php";
                cleanup_tmp
                exit 1
        fi
}

function cleanup_tmp {
        rm -rf $tempdir
}

function validate_user {
        validate=`cat $tempdir/xml.php?player=$username | grep "<online>" | awk -F "[<>]" '{ print $3 }'`
        if [ -z "${validate}" ];
        then
                echo "$username is not a valid user (usernames are case sensitive)";
                cleanup_tmp
                exit 1
        fi
}

function grab_status {
        user_status=$validate
}

function status_check {
        if [ $user_status == 1 ];
        then
                echo "$username is online";
        else
                echo "$username is offline";
        fi
}

## run functions
check_username
temp_dir
query_stats
verify_download
validate_user
grab_status
status_check
cleanup_tmp

example output:

root@athena:~/scripts# ./idlerpg_v1 mbentley
mbentley is online
root@athena:~/scripts# ./idlerpg_v1 Baked
Baked is offline


here is the 2nd one which emails:
./idlerpg_v2
Code:
#!/bin/bash
## written by mbentley

## set variables
command=$0
username=$1

function check_username {
        if [ -z "${username}" ];
        then
                echo "Usage: $command <username>";
                exit 1
        fi
}

function temp_dir {
        tempdir=/tmp/idlerpg_$username_`date +%N`
        mkdir $tempdir
        if [ ! -d "$tempdir" ]
        then
                exit 1
        fi
}

function query_stats {
        cd $tempdir
        wget -t 1 -T 5 -q http://splat.mine.nu/idlerpg/xml.php?player=$username
}

function verify_download {
        if [ ! -e "$tempdir/xml.php?player=$username" ]
        then
                cleanup_tmp
                exit 1
        fi
}

function cleanup_tmp {
        rm -rf $tempdir
}

function validate_user {
        validate=`cat $tempdir/xml.php?player=$username | grep "<online>" | awk -F "[<>]" '{ print $3 }'`
        if [ -z "${validate}" ];
        then
                cleanup_tmp
                exit 1
        fi
}

function grab_status {
        user_status=$validate
}

function status_check {
        if [ $user_status == 0 ];
        then
                email_offline
        fi
}

function email_offline {
        mail=$tempdir/mail_`date +%F`
        touch $mail
        chmod 600 $mail
        echo -e "subject: idleRPG: $username is offline" >> $mail
        echo -e "$username is currently offline!" >> $mail
        /usr/sbin/sendmail -f [email protected] root < $mail
}

## run functions
check_username
temp_dir
query_stats
verify_download
validate_user
grab_status
status_check
cleanup_tmp

with this one, there is no output to the command line but will email me:
Date: Wed, 09 Jun 2010 15:49:47 -0400
From: root <[email protected]>
Subject: idleRPG: Baked is offline

Baked is currently offline!
 
Last edited:
this isn't my script but i have found it to be very helpful when used in a cronjob. it checks to make sure my website is online. it will email me if it does not respond:

Code:
#!/usr/bin/perl

#  ====================================================================
#  Source code from www.blazonry.com/perl/monitor.php
#  Copyright (c) 2000 Astonish Inc. www.astonishinc.com
#  All rights reserved.
#  ====================================================================
#
#################################################################
#
# website_monitor.pl
#
# Perl script to monitor a website
# and e-mail out if it is not available
#
#################################################################

use LWP::Simple;

my $url = "http://www.mbentley.net/alive.html";

# list of e-mails to send out message
@emails = ('<youremail>@<domain>.com');

($min, $hr, $day, $mon) = (localtime)[1,2,3,4];
$qdate = "$mon/$day $hr:$min";

# fetch webpage
my $webpage = get $url;

        # if no page then create message
        # send e-mail out to list
        if (!$webpage) {
        $msg = "ERROR: Could not retrieve $url";

                foreach $email (@emails) {
                        sendmail($email, $msg);
                }
        }
    else {
        # no problems
    }

exit(0);

#-------------------------------------------------------------------------------------
# SUB:  sendmail(email-address, message)
#
# DESC: uses SENDMAIL to send out e-mail
#-------------------------------------------------------------------------------------
sub sendmail {
        my $email = $_[0];
        my $msg = $_[1];

        open (SENDMAIL, "|/usr/sbin/sendmail -oi -t") || die ("No Sendmail: $!\n");
        print SENDMAIL "From: URL-Monitor\@mbentley.net\n";
        print SENDMAIL "To: $email\n";
        print SENDMAIL "Subject: URL Monitor      \n\n";
        print SENDMAIL "$msg";
        close(SENDMAIL);

}

#-------------------------------------------------------------------------------------
 
Last edited:
just made this quick script.

i store my esniper item files in a folder called esniper

all this does it run an instant of esniper in a detached screen for each file in the esniper folder.

Code:
#!/bin/bash

screen -ls > esniper.tmp

for i in $( ls /home/mark/esniper/)
do
        if grep -qw "esniper-$i" esniper.tmp; then
                echo esniper is already running for $i
        else
                echo starting esniper screen session for $i 
                /usr/bin/screen -mSd esniper-$i /usr/bin/esniper /home/mark/esniper/$i

        fi 
done
i set this to run every boot with cron, so that if for any reason my computer has to reboot then esniper will run again.

@reboot ~/scripts/esniperstart.sh


its only small, but it does what i need it to.

edit: just threw in a quick if statement to make sure that it only runs 1 version of esniper per item file.
 
Last edited:
i've been doing some more bash scripting as of late. on my vps which hosts mbentley.net, i use nginx for all of my web serving needs. since my vps is eternally stuck on debian etch, i figured i would compile nginx from source so i could get the latest stable releases. instead of just having to compile it by hand every time there was an update, i figured why not script it?

Code:
#!/bin/bash

function get_version {
        echo -ne "\nplease enter the nginx version number you would like to upgrade to (ex - '0.8.54'):  "
        read version
        version="nginx-$version"
        echo $version

        echo -n "is this the version you would like to download? (y/n):  "
        read response
        if [ "$response" == "n" ] || [ "$response" == "N" ]; then
                echo -e "\n\nplease try again"
                get_version
        else
                nginx_source
        fi
}

function nginx_source {
        cd /opt
        wget http://sysoev.ru/nginx/"$version".tar.gz

        if [ -a "$version".tar.gz ]; then
                tar xvf "$version".tar.gz
                chown -R root:root "$version"
                cd "$version"
                nginx_upgrade
        else
                echo "the file did not download correctly!"
                exit 1
        fi
}

function nginx_upgrade {
        ./configure \
          --sbin-path=/usr/local/sbin \
          --conf-path=/etc/nginx/nginx.conf \
          --error-log-path=/var/log/nginx/error.log \
          --pid-path=/var/run/nginx.pid \
          --lock-path=/var/lock/nginx.lock \
          --http-log-path=/var/log/nginx/access.log \
          --with-http_dav_module \
          --http-client-body-temp-path=/var/lib/nginx/body \
          --with-http_ssl_module \
          --with-http_realip_module \
          --http-proxy-temp-path=/var/lib/nginx/proxy \
          --with-http_stub_status_module \
          --http-fastcgi-temp-path=/var/lib/nginx/fastcgi \
          --with-debug \
          --with-http_flv_module \
          --user=www-data \
          --group=www-data

        make
        echo -e "\n\nplease check for configuration errors (press enter to continue)"
        read
        /etc/init.d/nginx stop
        /etc/init.d/php-fastcgi stop
        make install
        echo -e "\n\nnew version number verification (press enter to continue):"
        echo "$version"
        nginx -v
        read
        /etc/init.d/php-fastcgi start
        /etc/init.d/nginx start
        cd /etc/nginx
        mv *.default backups/
        cd /opt
        rm "$version".tar.gz
}

get_version
 
i also wrote a script which i use to manage my virtual machines on my vmware 2 servers. it is pretty simple but does everything i could possibly want from command line and has a menu:

Code:
#!/bin/bash

## written by mbentley ([email protected])

function get_info {
        read -e -p "server name (localhost): " server_name
        read -e -p "user name (root): " user_name
        read -s -e -p "password: " password

        if [ -z $server_name ]; then server_name="localhost"; fi
        if [ -z $user_name ]; then user_name="root"; fi
        if [ -z $password ]; then echo "you must enter a password!"; echo; get_info; fi
        clear
}

function menu {
        echo; cd /mnt
        find vm/ -name "*.vmx" -print > /tmp/vmware_control.vm
        sed -i 's/vm\// vm   /g' /tmp/vmware_control.vm
        echo "Available Virtual Machines"; echo
        echo " DS   VM Name"
        echo " ==   ===================="
        sort +1 -2 /tmp/vmware_control.vm
        rm /tmp/vmware_control.vm
        echo; read -e -p "choose a command (start|stop|reset|suspend|list|pid|help|quit): " command_to_execute

        case "$command_to_execute" in
                start)
                        read -e -p "Data store name: " data_store
                        read -e -p "VM name: " virtual_machine
                        vmrun -T server -h https://"$server_name":8333/sdk -u "$user_name" -p "$password" $command_to_execute "["$data_store"] "$virtual_machine""; echo
                        ps -ef | grep "$virtual_machine" | grep VMware | awk '{ print $2 " " $19}' | awk -F \/ '{ print $1 $5 "/" $6 }'; echo
                ;;
                stop|reset|suspend)
                        read -e -p "Data store name: " data_store
                        read -e -p "VM name: " virtual_machine
                        vmrun -T server -h https://"$server_name":8333/sdk -u "$user_name" -p "$password" $command_to_execute "["$data_store"] "$virtual_machine"" soft; echo
                ;;
                list)
                        echo; vmrun -T server -h https://"$server_name":8333/sdk -u "$user_name" -p "$password" $command_to_execute; echo
                ;;
                pid)
                        echo; ps -ef | grep vmware-vmx | grep VMware | awk '{ print $2 " " $19}' | awk -F \/ '{ print $1 $NF }' | rev | cut -b 5- | rev | sort -k 2; echo
                ;;
                help)
                        echo
                        echo "start     start a VM"
                        echo "stop      stop a VM"
                        echo "reset     reset a VM"
                        echo "suspend   suspend a VM"
                        echo "pause     pause a VM"
                        echo "unpause   unpause a VM"
                        echo "list      list all running VMs"
                        echo "pid       display PIDs of all running VMs"
                        echo "help      display this help menu"
                        echo "quit      leave this script"
                        echo; read -n 1 -p "press any key to continue..."; clear; menu
                ;;
                exit|quit|q)
                        echo; exit
                ;;
                *)
                        echo "invalid command!"; echo
                ;;
        esac
        read -n 1 -p "press any key to continue..."; clear; menu
}

get_info
menu
 
Little script I wrote to search eBay's Buy It Now for any given product description. It will return up to the first 200 results. The nice thing is that it will also read from stdin, so at work I can dump our inventory to file and search for all of them with a simple redirection (search <file).

Code:
#!/usr/bin/env bash

shopt -s extglob

usage() {
fold -sw $(tput cols) <<EOF >&2
usage: search [product descriptions]
    
Will return the current price list on ebay for the given product description.

This script can also read from stdin, treating every line as a seperate product description, when passed the single argument `-'.
EOF
}

search() {
  local desc
  desc=${1//+([![:alnum:]])/+}
  wget -q -O "$tmp" "http://shop.ebay.com/i.html?LH_BIN=1&_nkw=${desc}&_ipg=200" || exit
}

parse() {
  local name price match
  local -a fields
  IFS='<' read -rd '' -a fields < <(grep 'g-b"' "$tmp")
  for field in "${fields[@]}"; do
    if [[ $field = *class=*vip* && -z $match ]]; then
      printf "%s\t" "${field##*>}:" >> "$output"
      match=1
    elif [[ $field = *class=*g-b* && $match ]]; then
      printf "%s\n" "${field##*>}" >> "$output"
      unset match
    fi  
  done
}

main() {
  tmp=$(mktemp) && output=$(mktemp) || exit
  trap "rm '$tmp' '$output'" 0
  search "$1"
  parse
  if [[ -s $output ]]; then
    column -s $'\t' -t "$output" 2>/dev/null || cat "$output" 
  else
    echo "No matches found in Buy It Now"
  fi  
}

if [[ -t 0 ]]; then
  if (($#)) && [[ $1 != -* ]]; then
    for string in "$@"; do
      (($# > 1)) && printf "\n%s\n\n" "$string"
      main "$string"
      echo
    done
  else
    usage
    [[ $1 = @(-h|--help|-\?) ]]
    exit
  fi  
else
  if [[ $1 = - ]]; then
    while read -r input; do
      printf "\n%s\n\n" "$input"
      main "$input"
      echo
    done
  else
    usage
    [[ $1 = @(-h|--help|-\?) ]]
    exit
  fi
fi
 
Last edited:
just made this quick script.

i store my esniper item files in a folder called esniper

all this does it run an instant of esniper in a detached screen for each file in the esniper folder.

Code:
#!/bin/bash

screen -ls > esniper.tmp

for i in $( ls /home/mark/esniper/)
do
        if grep -qw "esniper-$i" esniper.tmp; then
                echo esniper is already running for $i
        else
                echo starting esniper screen session for $i 
                /usr/bin/screen -mSd esniper-$i /usr/bin/esniper /home/mark/esniper/$i

        fi 
done
i set this to run every boot with cron, so that if for any reason my computer has to reboot then esniper will run again.

@reboot ~/scripts/esniperstart.sh


its only small, but it does what i need it to.

edit: just threw in a quick if statement to make sure that it only runs 1 version of esniper per item file.

I would just like to point out the danger of parsing ls(1), this script will break for any file with whitespace in it. In fact, for should not be used for iterating through the output of a command at all. Use while read for that. But a simple glob will suffice for this purpose

Code:
#!/bin/bash

temp=$(mktemp) || exit
screen -ls > "$temp"

for f in /home/mark/esniper/*; do
  if grep -qw "esniper-$f" "$temp"; then
    echo "esniper is already running for $f"
  else
    echo "starting esniper for $f"
    /usr/bin/screen -mSd "esniper-$f" /usr/bin/esniper "/home/mark/esniper/$f"
  fi
done
 
I would just like to point out the danger of parsing ls(1), this script will break for any file with whitespace in it. In fact, for should not be used for iterating through the output of a command at all. Use while read for that. But a simple glob will suffice for this purpose

Code:
#!/bin/bash

temp=$(mktemp) || exit
screen -ls > "$temp"

for f in /home/mark/esniper/*; do
  if grep -qw "esniper-$f" "$temp"; then
    echo "esniper is already running for $f"
  else
    echo "starting esniper for $f"
    /usr/bin/screen -mSd "esniper-$f" /usr/bin/esniper "/home/mark/esniper/$f"
  fi
done

Thanks for replying, didnt see that post till toda

since i posted that script, I have updated it similar to how you described.

I appreciate the advice :)






just made this (Very Small) script, requires a postfix or other mail server to be running on your machine.


Code:
#!/bin/bash

##Author: markp1989
##version 2011.03.18 

##small email script
##usage
##mail.sh "recipent" "subject" "body"
## eg mail.sh "[email protected],[email protected]" "Just saying hi" "hey \n\n just emailing you to give you this notification" 

##currently does no error checking, will run even if the user doesnt provide needed parameters 

recipent=$1
subject=$2
body=$3


echo -e "$(date) \n\n $body" | mail -s "$subject" $recipent

just made this a few minutes ago, I used to have the "echo -e "$(date) \n\n $body" | mail -s "$subject" $recipent" line in a lot of my scripts to email me the output, but I was sick of writing it every time I needed it so I just made it its own script.

current issues:
it doesnt check user input, will run even if the required information is not parsed in, this will be changed late tonight.
 
Last edited:
i wrote a script today that will check to see if your wan ip has changed. if it has, it will email you the new ip address assuming you have sendmail setup properly. this script requires that you have curl installed. you may need to run this as root if sendmail requires root privileges. just customize the variables in the 'load_variables' function to fit your needs.

Code:
#!/bin/bash

function load_variables {
        ip_file=/tmp/current.ip # set the ip storage location
        sender="[email protected]" # set the sender of the email
        recipient="[email protected]" # set the recipient of the email
        sm="/usr/sbin/sendmail" # set the location of sendmail
        current_ip=`curl -s http://automation.whatismyip.com/n09230945.asp` # set current ip

        check_for_errors
}

function check_for_errors {
        if [[ ${current_ip} == *Error* ]]
        then
                echo "server side error";
                exit 1
        fi

        if [[ ${current_ip} == *Unavailable* ]]
        then
                echo "service unavailable";
                exit 1
        fi

        if [ -z ${current_ip} ]
        then
                echo "failed to find server";
                exit 1
        fi

        file_check
}

function file_check {
        if [ -f ${ip_file} ]
        then
                last_ip=`cat ${ip_file}` # retreive last known ip from file
                compare_ips # execute compare function
        else
                echo "no ip on file.  writing current ip to file";
                write_ip_to_file # write current ip to file
                exit 0
        fi
}

function compare_ips {
        if [ "${last_ip}" = "${current_ip}" ]
        then
                echo "ip has not changed";
                exit 0
        else
                echo "ip has changed from ${last_ip} to ${current_ip}";
                email_new_ip
                write_ip_to_file
                exit 0
        fi
}

function write_ip_to_file {
        echo ${current_ip} > ${ip_file}
}

function email_new_ip {
        tmp=/tmp/ipcheck.mail`date +%F`
        touch ${tmp}; chmod 600 ${tmp}
        echo -e "subject: IP address has changed\n" > ${tmp}
        echo -e "your IP address has changed from ${last_ip} to ${current_ip}" >> ${tmp}
        ${sm} -f ${sender} ${recipient} < ${tmp}
        rm ${tmp}
}

load_variables

this script was a bit of a quick hack job of a script but works fine for a cronjob :)
 
Last edited:
i made an update to my ipcheck script as i found a bug where if the service returned a 'service unavailable', it would mess up. i just added a value check for that message.
 
I just finished this script for sending push notifications to my android phone using Notify My Androids API
https://nma.usk.bz/api.php

Code:
#!/bin/sh
#########################################################################################
### androidNotifty.sh									#
### Script for sending notifications using "Notify My Androids" API https://nma.usk.bz/ #
### Author : [email protected]							#
### Version: 08JULY2011									#
#########################################################################################
## Requirements:									#
##		curl 									#
##		which									#
#########################################################################################
## Usage:										#
##	androidNotify.sh "Application Name" "Event Name" "Some Details" 		#
#########################################################################################
## API Documentation:									#
##	see https://nma.usk.bz/api.php 							#
#########################################################################################

##checking curl is installed
which  curl >/dev/null  || { printf '%s\n' "curl is required but it's not installed, exiting."; exit 1; }
##checking that the machine can connect to the internet
ping -c 5 -w 5  "google.com" >/dev/null || { printf '%s\n' "internet connection is required but not connected, exiting." ; exit 1; }

## API Key must me set here, go to http://nma.usk.bz/ to get a member ship.
APIkey=""

#checking that the apikey provided was valid using nmas' API
curl --data-ascii "apikey=$APIkey" https://nma.usk.bz/publicapi/verify -o /tmp/verify
##api returns 200 if the api key was valid
if [ -z "$APIkey" ] ; then
	printf '%s\n' "[error] API key not set"
	exit 1
elif grep -q 200 /tmp/verify ; then
	printf '%s\n' "[info] APIkey: $APIkey is valid"
	rm /tmp/verify
else
        printf '%s\n' "[error] API key is invalid "
	printf '%s\n' "[error] $(cut -f4 -d'>' /tmp/verify | cut -f1 -d'<')" ##outputs the error received from the server
	rm /tmp/verify
	exit 1
fi


##this section checks weather all expected parameters have been provided.
#checking thats the first 3 parameters were set.
if [ -z "$1" ] ; then
	printf '%s\n\t%s\n' "[error] one or more parameters are missing:" '3 parameters are expected, eg: androidNotify "application" "event" "description"'
	exit 1
elif [ -z "$2" ] ; then
        printf '%s\n\t%s\n' "[error] one or more parameters are missing:" '3 parameters are expected, eg: androidNotify "application" "event" "description"'
        exit 1
elif [ -z "$3" ] ; then
        printf '%s\n\t%s\n' "[error] one or more parameters are missing:" '3 parameters are expected, eg: androidNotify "application" "event" "description"'
        exit 1
#checking weather a 4th parameter has been set
elif [ -n "$4" ] ; then
	printf '%s\n\t%s\n' "[error] too many parameters have been provided:" '3 parameters are expected, eg: androidNotify "application" "event" "description"'
        exit 1
fi

##sending the notification using curl 
curl --data-ascii "apikey=$APIkey" --data-ascii "application=$1" --data-ascii "event=$2" --data-asci "description=$3" https://nma.usk.bz/publicapi/notify -o /tmp/notify

##checking that the notification was sent.
##api returns message 200 if the notification was sent 
if grep -q 200 /tmp/notify ; then
	printf '%s\n' "[info] Notification sent"
	rm /tmp/notify 
	exit 0
else
	printf '%s\n' "[error] Notification failed:"
        printf '%s\n' "[error] $(cut -f4 -d'>' /tmp/notify | cut -f1 -d'<') " ##outputs the error received from the server 
	rm /tmp/notify
	exit 1
fi

any recommended changes?
 
Last edited:
I just finished this script for sending push notifications to my android phone using Notify My Androids API
https://nma.usk.bz/api.php

made a few changes
Code:
#!/bin/bash
#########################################################################################
### androidNotifty.sh									#
### Script for sending notifications using "Notify My Androids" API 			#
### 			Author : [email protected]	 Version: 20JULY2011		#
#########################################################################################
## Requirements:	curl 								#
#########################################################################################
## Usage:		androidNotify.sh "Application Name" "Event Name" "Some Details" #
#########################################################################################
## API Documentation:	https://nma.usk.bz/api.php 					#
#########################################################################################

## API Key must me set here, go to http://nma.usk.bz/ to get one
APIkey=""
verifyurl="https://nma.usk.bz/publicapi/verify"
posturl="https://nma.usk.bz/publicapi/notify"
pinghost="google.com"

command=$0 
application=$1
event=$2
description=$3

##choosing a unique temp file based on the time, to avoid concurent usage interfering with each other
notifyout=/tmp/notify$(date '+%H%M%N')

function error_exit {
        printf '%s\n\t%s\n\t\t%s\n' "[ Error ] Notification not sent:" "$errormessage" "Usage: $0 Application Event Description"
        exit 1
}

function clean_exit {
        printf '%s\n' "[ info ] Notification sent" 
        rm "$notifyout" 
        exit 0
}

##checking curl is installed
which  curl >/dev/null  || { errormessage="curl is required but it's not installed, exiting."; error_exit; }
##checking that the machine can connect to the internet by pinging the host defined in $pinghost
ping -c 5 -w 10  "$pinghost" >/dev/null || { errormessage="internet connection is required but not connected, exiting." ; error_exit; }

##this section checks that the parameters are an acceptable length if any of these tests fail then the program exits.
##the API will send an error back if the data sent is invalid, but no point in knowingly sending incorrect information.
#API key must be 48 characters long, just because the APIkey is the right length doesnt mean its valid,the API will complain if it is invalid.
if [ "${#APIkey}" -ne "48" ] ; then
	errormessage="APIkey must be 48 characters long, you gave me ${#APIkey}"
        error_exit
#application must be between 1 and 256 characters long
elif [ "${#application}" -gt "256" ] || [ "${#application}" -lt "1" ] ; then
        errormessage="[ error ] the application parameter is invalid or missing"
	error_exit
#event must be between 1 and 1000 characters long
elif [ "${#event}" -gt "1000" ] || [ "${#event}" -lt "1" ] ; then
        errormessage="[ error ] the event parameter is invalid or missing"
	error_exit
#description must be between 1 and 1000 characters long
elif [ "${#description}" -gt "1000" ] || [ "${#description}" -lt "1" ] ; then
	errormessage="[ error ] the description parameter is invalid or missing"
	error_exit
elif [ -n "$4" ] ; then
	errormessage="[ error ] too many parameters have been provided:"
	error_exit
fi

##sending the notification using curl
curl --data-ascii "apikey=$APIkey" --data-ascii "application=$application" --data-ascii "event=$event" --data-asci "description=$description" $posturl -o $notifyout

##checking that the notification was sent ok.
##api returns message 200 if the notification was sent
if grep -q 200 $notifyout ; then
	clean_exit
else
	errormessage="$(cut -f4 -d'>' $notifyout | cut -f1 -d'<')"
	rm "$notifyout"
	error_exit

fi
 
Last edited:
I put together a python script to manage the archiving of VMWare Server VMs.

I know parts of it seem a little strange (especially moving and deleting of files) we have limited storage so I have to do some "voodoo" to keep files for the specified time period. NOTE that any company identification has been removed so the script may be incomplete(ish)

*Also of note, I was doing a bash -> python translation so some of the methods used may not be "pythonic" and that is either due to my own lack of understanding or a specific requirement.
** import smtp was not functioning properly on this old box so the mail utility in linux is a workaround

*** I updated the script so that it now writes stdout and stderr to a logfile instead of having to redirect from the CLI


Code:
#!/usr/bin/env python
#This program will first go through a cleaning process.
#It will discover files older than 12 days and move them to /archive2
#it will then search /archive2 for files older than 30 days and delete them
#after that, it will attempt to get the list of running vms and then suspend them
#After they are suspended, it will tar up those vms
#Finally it will run a check on the tars and email alerts based on the results
"""

Error checking is done by initializing the error variable to ""
in order to check it later. If there is an exception thrown,
the error variable gets reassigned to the thrown error
"""
#Lets setup the modules we will be using
import sys
import os
import re
import datetime
import tarfile
import time
import fnmatch
import shutil
import subprocess

email_addresses = "[email protected]"
#Set the time variables. These will be used to determine which files to clean up
#Since time is measured in seconds, we have to do the convertion 
#The number of days held is directly related to the available storage space in /archive. If more VMs get added, 
#the number of days a file can be held will have to be decreased.
#Archive2 is a secondary archive which allows us to hold onto files for an additional 8 days
seconds_per_day = 86400
number_of_days = 12
days_to_keep_files = seconds_per_day * number_of_days
current_date = time.time()

archive_path = '/archive/vms/'
move_to_archive2 = '/archive2/weekly'
clean_archive2 = '/archive2/'

#The following creates a new directory in /archive/vms with today's date
todays_date = datetime.datetime.now().strftime("%Y-%m-%d")
todays_directory = archive_path + todays_date

logfile = "/var/log/virtual_machine_logs/vm_backup_",todays_date,".log"
logfile = "".join([str(x) for x in logfile])

old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = open(logfile, "w")
sys.stderr = open(logfile, "a")
print "---------------------Starting backup processes on this date: --------->", datetime.datetime.now().strftime("%Y-%m-%d-%H:%M"), "<----------"

#Get a list of the running vms and store it in a temporary file

os.system("/usr/bin/vmrun -h https://vm-server:8333/sdk -T server -u root -p `cat /root/.gnupg/pass` list |grep -v Total > /root/vm_list.tmp")

vmlist = "/root/vm_list.tmp"    
 

#This function reads the vm list from the top. Putting this as a function avoids "cut-and-paste" programming
def read_vm_list():
    vm_list = open(vmlist, 'r')
    return vm_list


################################################cleanup section ##############################################
#This function crawls through directories as specied. It is used to recursively search
#through the directories in archive2
def find_files(directory, pattern):
    for root, dirs, files in os.walk(directory):
        for basename in files:
            #the fnmatch module is required (import fnmatch) for this section
            #after finding the file, os.path is used to create an absolute path
            #to the files. The filenames are then returned as a generator
            if fnmatch.fnmatch(basename, pattern):
                filename = os.path.join(root, basename)
                yield filename
try:
    
    print "The current disk usage is "
    p = os.popen('df -h |grep -v usr |grep -v tmp |grep -v udev |grep -v var |grep -v home').read()
    print p
    print "Beginning the cleaning process of /archive2"
    print "Attempting to remove files from /archive2 which are older than ", ((days_to_keep_files + (10 * 86400))/86400), " days"

    for file in find_files(clean_archive2, '*.gz'):
        #days_to_keep_files + 8 indicates the base number of days to keep a file in /archive and
        #The additional number of days it will be kept in /archive2
        if os.stat(file).st_ctime < current_date - (days_to_keep_files + (5 * 86400)):
            #os.path.basename strips the absolute path of the file away
            #for example /tmp/test.file is turned into test.file
            #this is done so that tarballs can be created in specific directories
            #instead of in the directory where the original file was (which is default action)
            try:
                print "removing the following file:", file, "--> it is older than ",((days_to_keep_files + (10 * 86400))/86400), "days"
                os.remove(file)
                error_archive2 = ""
            except Exception, error_archive2:
                print error_archive2
    #create folders required for backup. This is done after the removal process but before the
    #moving section in order to ensure the folders exist if they are removed from the folder removal
    try: 
        os.makedirs(todays_directory)
        os.makedirs(move_to_archive2)
    except Exception, e:
        pass    

    print "--------------------------------------------------------------"
    print "Beginning the cleaning of /archive"
    print "--------------------------------------------------------------"  
    print "Attempting to move old files to /archive2"
    #This for-loop only does a surface scan meaning that it scans only the directories inside of
    #the directory specified. IE. It scans only folders in /archive/vms and NOT any subfolders
    #Thus it will not scan /archive/vms/xxx/somefolder.
    #The for-loop relies upon modified times of the folder which it is assumed will not change after
    #their initial creation
    for item in os.listdir(archive_path):
        #searched_dir joins both the folders found and the absolute path
        #without the os.path.join, operations will atempt to interact with the files
        #as if they were in the relative path. I.E. if it finds /archive/somefile.txt
        #os.listdir returns only somefile.txt and therefore if trying to tar it
        #you will receive a 'file not found' error
        searched_dir = os.path.join(archive_path, item)
        if os.path.isdir(searched_dir):
            if os.stat(searched_dir).st_mtime < current_date - days_to_keep_files:
                try:
                    print "Moving ", searched_dir, "---> ", move_to_archive2
                    #The line below moves /archive/vms/$item to /archive2/weekly/$item
                    #where $item is any folder which is older than the specified time
                    shutil.move(searched_dir, (os.path.join(move_to_archive2, (os.path.basename(searched_dir))))) 
                    error_archive1 = ""
                except Exception, error_archive1:
                    print error_archive1
                   
    print "The cleanup is complete and the disk usage is now: "
    print os.popen("df -h |grep -v usr |grep -v tmp |grep -v udev |grep -v var |grep -v home").read()
    print "-----------------------------------------------------------"
###############################################end cleanup ######################################################
    

####################################backup procedures ########################################
    #This section is a sanity check to make sure there is enough space to complete the backups  
    free_space = os.popen("df -h |grep archive |grep -v archive2 |awk '{print $4}'").read().rstrip()
    #We are going to assume that the free space will be displayed in Gb so we must strip off the "G" in order to evaluate
    #if there is not enough space after the cleaning, abort the program. Based on current backup sizes
    #The backups require approximately 200G to complete so we will use 210 as a buffer
    free_space = free_space.replace("G", "")
      
    if int(free_space) < 210:
        print "Error: there is not enough space on /archive to continue...ABORTING"
        #Change stdout back
        sys.stdout = old_stdout 
        sys.stderr = old_stderr
        #mail the error message
        mail_mes = 'mail -s "Not enough space for backup" %s < %s' % (email_addresses, logfile)
        os.system(mail_mes)
        sys.exit()
    else:
        print "/archive has at least 210G of free space. Commencing backup."
    #Open the list for reading and begin suspending the vms
        
    vm_list = read_vm_list()
    
    for suspend_vm in vm_list:
        try:
            #vm_basename = suspend_vm.replace("[standard] ", "").split("/")            
            print ""
            print "Suspending ", suspend_vm,
            #vmrun requires quotation marks be placed around the vm to be suspended. single_vm covers that
            single_vm = '"%s"' % suspend_vm.rstrip()
            #Results variable puts the required parameters into a variable which can be passed into os.system command
            results = "/usr/bin/vmrun -h https://vm-server:8333/sdk -T server -u root -p `cat /root/.gnupg/pass` suspend", single_vm
            #the way results variable is declared creates a tuple. It must be joined and made into a string in order for it to be processed properly
            results = " ".join([str(x) for x in results])
            os.system(results)
            error_suspend = ""
        except Exception, error_suspend:
            print "The following errors occured: "
            print error_suspend

    print " "        
    print "VMs have been suspended successfully. Starting the backup process"
    
    #Change to the directory where the files should be dumped
    os.chdir(todays_directory)

    #This function returns the total number of tar processes running
    def getProcesses(search_process):
        number_of_processes = subprocess.Popen("ps aux | grep '%s' |grep -v grep |grep -v .vmx|grep -v .tar.gz |wc -l" % search_process, shell=True, stdout=subprocess.PIPE)
        output = number_of_processes.stdout.read()
        number_of_processes.stdout.close()
        number_of_processes.wait()
        return output

    counter = 1
    vm_list = read_vm_list()
    for vms in vm_list:
      try:
        #This section gets the number of processes so that we know how many tar processes are running at a time
        output = getProcesses("tar_vms.py")
        print output
        ####begin parsing vm list#####
        vms = vms.replace("[standard] ", "")
        vms = os.path.dirname(vms)  
        print "tarring: ", vms
        ####end parsing ####
        
        os.system("python /root/virtual_machine_python_scripts/tar_vms.py %s &" % vms)

        time.sleep(10)
        #Since vm-server has 8 cores, we are going to set the thread to 7
        #We will then ask the computer to wait 10 minutes before attempting another backup process 
        while int(output) > 7:
            output = getProcesses("tar_vms.py")      
            time.sleep(600)
        print "Loop %s completed" % counter
        counter += 1
        error_tar = ""
      except Exception, error_tar:
        print "The following errors occured: "
        print error_tar  
    vm_list = read_vm_list()
    for start_vms in vm_list:
        try:
            #Strip the vm list of any junk that will confuse grep
            vm_basename = start_vms.replace("[standard] ", "").split("/")
            #pass the first element of the vm_basename to grep for the vm name   
            running_processes = getProcesses(vm_basename[0])

            #If the vm name is found in the process list the script will sleep for 5 minutes
            #This is to avoid starting a vm before the tarring has been completed
            while int(running_processes) != 0:
                running_processes = getProcesses(vm_basename[0])
                print "sleeping because there are processes running %s" % vm_basename[0]
                time.sleep(300)

            print ""
            print "Restarting ", start_vms,
            #vmrun requires quotation marks be placed around the vm to be suspended. single_vm covers that
            single_vm = '"%s"' % start_vms.rstrip()
            #Results variable puts the required parameters into a variable which can be passed into os.system command
            results = "/usr/bin/vmrun -h https://vm-server:8333/sdk -T server -u root -p `cat /root/.gnupg/pass` start", single_vm, " &"
           #the way results variable is declared creates a tuple. It must be joined and made into a string in order for it to be   processed properly
            results = " ".join([str(x) for x in results])
            os.system(results)
            time.sleep(10)
            error_resume = ""
        except Exception, error_resume:
                print "The following errors occured: "
                print error_resume

    print " "        
    print "VMs have been restarted successfully. Backup process is complete"
    print "-------------------------------------------------------------------------"
#####################backup complete#####################

####################check the tar files ###############

#The following is a function which uses the module 'fnmatch' and os.walk to crawl through the root directory fed into the program.
    print " "
    print "Beginning tar checks"
    print " "
    def find_files(directory, pattern):
        for root, dirs, files in os.walk(directory):
            for basename in files:
                if fnmatch.fnmatch(basename, pattern):
                    filename = os.path.join(root, basename)
                    yield filename
    #The tar check follows the same methodoly as the tarring. It spawns subprocesses
    #In order to complete more quickly. As the checks may run into business hours
    #The number of concurrent checks is limited to 5 

    for tar_file in find_files(todays_directory, '*.gz'):
        try:
            output = getProcesses("tar_vms.py")
            while int(output) !=0:
                print "there are files still being tarred"      
                time.sleep(600)
            print "checking ", tar_file    
            os.system("python /root/virtual_machine_python_scripts/check_tars.py %s &" % tar_file)
            time.sleep(5)
            running_tar_checks = getProcesses("check_tars.py")
            while int(running_tar_checks) > 5: 
                running_tar_checks = getProcesses("check_tars.py")    
                time.sleep(600)
            error_tar_check = ""            
        except Exception, error_tar_check:
            print error_tar_check
except Exception, e:
    e = str(e)
    print e

print "---------------------Backup processes is completed on this date: --------->", datetime.datetime.now().strftime("%Y-%m-%d-%H:%M"), "<----------"
print os.popen("df -h |grep -v usr |grep -v tmp |grep -v udev |grep -v var |grep -v home").read()
sys.stdout = old_stdout
######send mail ########
counter = 0

email_errors = []

if error_archive2 != "":
   email_errors.append("Error cleaning /archive2")

if error_archive1 != "":
    email_errors.append("Error moving old files to /archive2")

if error_suspend != "":
    email_errors.append("Error suspending vms")

if error_tar != "":
    email_errors.append("Error while attempting to tar suspended vms")

if error_resume != "":
    email_errors.append("Error attempting to resume VMs")

if error_tar_check != "":
    email_errors.append("Error while testing tar archives")

os.system("echo 'The following error(s) was ecounter: '%s'.' > /root/mail.txt" % (email_errors)

#In python a list which is not empty considered true, therefore if email_errors evaluates to true, run the error messages
if email_errors:
    mail_mes = "mutt -s 'Problems with vm backups' -a '%s' '%s' < /root/mail.txt" % (logfile, email_addresses)
    os.system(mail_mes)
#If the list is blank email no problems
else:
    mail_mes = "echo 'The logs can be found at '%s'' |mail -s 'No problems with VM-weekly backup' %s " % (logfile, email_addresses)
    os.system(mail_mes)

os.system("rm -rf /root/mail.txt")
 
Last edited:
Just had to split apart some ics files because I haven't figured out how to make my web server (nginx) and PHP (php-fpm) cooperate for uploads larger than a couple MB :( So, I wrote up a small C++ program during class :)

https://github.com/petteyg/icalsplit

The .cpp file is the code, the file with no extension is the amd64 Linux executable, and the .exe file is the Win32 executable. I've tested it with files downloaded from Yahoo! calendar. It splits based on line count, and on average my files turned out to be around 1MB each. If you attach a lot of extra data (locations, comments, etc.) to your events, or use really really long event names, your files might be larger.
 
Last edited:
here is a bit of code that will take input from a file.
It assumes you have made images in VMWare server and that those files were the default SCSI interface.

Code:
#!/usr/bin/python
#written by Stratus_ss
#This script assumes there is a file called "vm_list" in the current directory.
#The template file has the following format "Name_of_vm" "/path/to/disk_image" (seperated by a whitespace)
# Sept 2011
 
import os
import sys
import fnmatch
import string

#create the vm_list list
vm_list = []

#Open the list for reading
files = open("vm_list").readlines()

#create a list to hold the path to the disk images
path = []
for line in files:
    #split the text file at the path /vm
    columns = line.split("/vm")
    path1 = "/vm", columns[1]
    path1 = "".join([str(x) for x in path1])
    path.append(path1)
    vm_list.append(columns[0])   

#This element tracks the iteration of the loop so that the correct element of the path array lines up with the proper vm

element = 0
for vm in vm_list:
    #the following two variables adds double quotes so that the vbox command will be recognized
    single_vm = '"%s"' % vm.rstrip()
    path[element] = '"%s"' % path[element].rstrip()
    #due to the way the variables are created, python interprets them as a list
    #In order to use this in a command we have to make the list into a single string which is accomplished by the join command
    createvms = 'vboxmanage createvm --name ', single_vm, ' --ostype Windows2003 --register'
    createvms = "".join([str(x) for x in createvms])
    
    add_scsi = 'vboxmanage storagectl ', single_vm, ' --name "SCSI Controller" --add scsi --controller LSILogic'
    add_scsi = "".join([str(x) for x in add_scsi])
   
    add_storage = 'vboxmanage storageattach ', single_vm,  ' --storagectl "SCSI Controller" --port 0 --device 0 --type hdd --medium ', path[element]
    add_storage = "".join([str(x) for x in add_storage])
    print 'I am creating ----> %-20s  with the following hard drive ---->' % (vm), path[element]
    #create the vm
    os.system(createvms)
    #add the scsi controller since virtualbox assumes you will be using SATA controllers
    os.system(add_scsi)
    #add the vmdk file (or vdi file)
    os.system(add_storage)
    element +=1
print "Virtual Machines have been successfully added to Virtualbox"
 
Last edited:
We had a need to know which subdirectories some html files were in. I figured I would post up the script for others to use

Code:
#!/bin/sh
#This file searches folders and its subdirectories and reports
#which (sub)directory the files are found in
START=.
 
# change your directory to command line if passed
# otherwise use home directory
[ $# -eq 1 ] && START=$1 || :
 
if [ ! -d $START ]
then
	echo "$START not a directory!"
	exit 1
fi
 
# use find command to get all subdirs name in DIRS variable
DIRS=$(find "$START" -type d)
 
# loop thought each dir to get the number of files in each of subdir
for d in $DIRS
do
   [ "$d" != "." -a "$d" != ".." ] &&  echo "looking for html files in $d  " && echo "found  $(ls -l $d | grep htm| wc -l)"
done
 
This program requires the PyGTK and MySQLdb modules for python
It is cross platform so Windows users will be required to install GTK+, python 2.2 or higher and MySQLdb

Currently my table layout is as follows
Code:
-- phpMyAdmin SQL Dump
-- version 3.3.10deb1
-- http://www.phpmyadmin.net
--
-- Host: localhost
-- Generation Time: Sep 24, 2011 at 09:11 PM
-- Server version: 5.1.54
-- PHP Version: 5.3.5-1ubuntu7.2

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

--
-- Database: `nmap`
--

-- --------------------------------------------------------

--
-- Table structure for table `Computer_Info`
--

CREATE TABLE IF NOT EXISTS `Computer_Info` (
  `Computer_ID` int(11) NOT NULL,
  `DNS_Name` varchar(50) NOT NULL,
  `Computer_IP_Address` varchar(15) NOT NULL,
  `OS_ID` int(11) NOT NULL,
  PRIMARY KEY (`Computer_ID`),
  UNIQUE KEY `Computer_IP_Address` (`Computer_IP_Address`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

--
-- Dumping data for table `Computer_Info`
--


-- --------------------------------------------------------

--
-- Table structure for table `Computer_Ports`
--

CREATE TABLE IF NOT EXISTS `Computer_Ports` (
  `Computer_ID` int(11) NOT NULL,
  `Port_ID` int(11) NOT NULL,
  PRIMARY KEY (`Computer_ID`,`Port_ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

--
-- Dumping data for table `Computer_Ports`
--


-- --------------------------------------------------------

--
-- Table structure for table `OS_Table`
--

CREATE TABLE IF NOT EXISTS `OS_Table` (
  `OS_ID` int(11) NOT NULL AUTO_INCREMENT,
  `OS_Name` varchar(100) NOT NULL,
  PRIMARY KEY (`OS_ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

--
-- Dumping data for table `OS_Table`
--


-- --------------------------------------------------------

--
-- Table structure for table `Ports_Table`
--

CREATE TABLE IF NOT EXISTS `Ports_Table` (
  `Port_ID` int(11) NOT NULL,
  `Port_Number` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

--
-- Dumping data for table `Ports_Table`
--


-- --------------------------------------------------------

--
-- Table structure for table `Port_Description`
--

CREATE TABLE IF NOT EXISTS `Port_Description` (
  `Port_Number` varchar(50) NOT NULL,
  `Port_Description` varchar(100) NOT NULL,
  `Port_Protocol` varchar(3) NOT NULL,
  PRIMARY KEY (`Port_Number`),
  UNIQUE KEY `Port_Number` (`Port_Number`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

--
-- Dumping data for table `Port_Description`
--

Currently you have to edit the script to tell nmap where to scan. Eventually it will take user input. The script which puts the information into mysql is as follows

Code:
#!/usr/bin/python
#This script is being designed to cleanup an NMAP produced text file and insert it into mysql

import sys, os
import re
import MySQLdb
from BeautifulSoup import BeautifulSoup, NavigableString


#####Global variables

last_line = '---'  #if you reach this line, treat previous lines as a single block
scratch_file = "sit_new"
#nmap_output is the file which nmap will be piped to
nmap_output = "SIT_nmap"

#When the flag is set to 0 the script will begin to read
#When the flag is set to 1, the script knows that this is being designated as the last line
flag = 1

# Open the connection to the database
database_connection = MySQLdb.connect('192.168.89.22', 'root', '', 'nmap');
cursor = database_connection.cursor()
##########################################################################
def createNmap():
    
    
    #Run the nmap command with the option to querry the host OS
    #os.system("sudo nmap -O 192.168.88.0/24 > '%s'" % str(nmap_output))    
    nmap_unformatted = open(nmap_output, "r").readlines()
    #Words to exclude
    word1 = "up"
    word3 = "Starting"
    word4 = "done"
    word5 = "Not"
    word6 = "MAC"
    word7 = "Device"
    word8 = "Network"
    word9 = "detection"

#Here I am redirecting standard out to the scratch file
#So that the info can be more easily managed
    old_stdout = sys.stdout
    sys.stdout = open(scratch_file, "w")
    for line in nmap_unformatted:
        if word1 not in line and word3 not in line and word5 not in line and word6 not in line and word7 not in line and word8 not in line and word9 not in line:
     #replace the blank lines with dashes so that they are easier to parse
            if line.isspace():
                print "---"
            else:
                print line.strip()
    #Put the stardard out back to normal
    sys.stdout = old_stdout
##########################################################################    
def parse_dns():

    text = open(scratch_file, "r").readlines()
    #filter out the hostname expecting user.company.com
    hostname = re.compile(r'[\w\-][\w\-\.]+.com')
    #filter out the IP, expecting a 192 address
    ip = re.compile(r'192.\d+.\d+.\d+')
    
    computer_id = 1
    #go through the text line by line
    ip_address_list = []
    host_name_list = []
    for word in text:        
        find_ip = ip.findall(word)
        find_ip = " ".join(find_ip)   
        find_hostname = hostname.findall(word)
        find_hostname = " ".join(find_hostname)
        #if the hostname and the IP are blank pass
        if str(find_hostname) == "" and find_ip == "":
            pass
        #If the hostname is not in dns but it has an ip, insert the information into the ip table    
        elif find_hostname == "" and find_ip != "":
            computer_id +=1 
            print "inserting :", find_ip         
            ip_address_list.append(find_ip)
            host_name_list.append("Not Available")
        #This statement assumes that both the dns name and ip are parsed properly and it adds this information to the proper table
        else:
            print "inserting :", find_hostname
            host_name_list.append(find_hostname)
            ip_address_list.append(find_ip)
            computer_id +=1
    
    counter = 0
    #Use the length of the ip_address_list to determine the number of loops to run to add to database
    while counter < len(ip_address_list):
        ID = counter + 1
        print "Adding OS ID: ", ID, " IP Address: ", ip_address_list[counter], " and Host Name: ", host_name_list[counter]
        cursor.execute("INSERT ignore INTO Computer_Info(Computer_ID, DNS_Name,Computer_IP_Address,OS_ID) values('%s','%s','%s', '%s')" % (ID, host_name_list[counter], ip_address_list[counter], ID))
        cursor.execute("INSERT ignore INTO Computer_Ports(Computer_ID, Port_ID) values('%s', '%s')" % (ID, ID))
        counter +=1
        
#########################################################################    
def parse_ports():
    
        ###############Parse known ports from the IANA list ####################
    #open the xml file for reading
    ports_xml = open("port_numbers.xml", "r")
    search_xml = BeautifulSoup(ports_xml) 

    #This tells beautiful soup to pull out only the name tag 
    search_unassigned_numbers = search_xml.findAll('record')
    #The file contains stuff we dont want (unassined and reserved ports)
    #This list contains the known ports that we want
    filtered_entries = []

    #append the appropriate ports to the filtered_entries list
    for entries in search_unassigned_numbers:
        entries = str(entries)
        if "Unassigned" in entries or "Reserved" in entries:
            pass
        else:
            filtered_entries.append(entries)

    #Turn the list into text so that Beautiful soup can use it
    filtered_entries = "".join([x for x in filtered_entries])

    #Change the soup tags so that it is searching for the 'name' html tag
    search_xml = BeautifulSoup(filtered_entries)
    search_port_names = search_xml.findAll('name')

    #set the list for the port_descriptions
    port_description = []

    for port_names in search_port_names:
        port_names = str(port_names)
        #It is best to avoid 'strip' method as I don't know all of the 
        #items being entered into the database. Using replace is safer
        port_names = port_names.replace("<name>", "").replace("</name>", "")
        port_description.append(port_names)
        
    search_port_numbers = search_xml.findAll('number')

    #set the list for the port_descriptions
    port_number = []
    #remove the tags and leave only the port numbers going into the list
    for ports in search_port_numbers:
        ports = str(ports)
        ports = ports.replace("<number>", "").replace("</number>", "")
        port_number.append(ports)

    search_protocol = search_xml.findAll('protocol')

    #set the list for the port_descriptions
    protocol_name = []

    #remove the tags and leave only the protocol names going into the list
    for protocol in search_protocol:
        protocol = str(protocol)
        protocol = protocol.replace("<protocol>", "").replace("</protocol>", "")
        protocol_name.append(protocol)
    
        #############Begin parsing nmap###################
    port_list = []
    nmap_file = open(scratch_file)
    for line in nmap_file:
        if line.startswith('Nmap'):
            flag = 0
        if last_line in line:
            flag = 1
        if not flag and not last_line in line:
            #append the line to the list and strip the dashes away
            port_list.append(line.strip('---').rstrip())
    
    #set the computer_id to 0. The computer_id represents the ID of the computer
    #each port can have the same ID. In this way ports 80, 22, 443 etc all reference computer by ID
    computer_id = 0
    existing_ports = []
    for ports_open in port_list:
        starts_with_digit = re.match(r"[0-9]", ports_open) is not None
        #For the ports section we dont want anything that starts with a letter
        #If the line starts with a digit, parse out only the port number
        if starts_with_digit == True:
            ports_open = ports_open.split('/')[0]
            print "Inserting: ", ports_open
            existing_ports.append(ports_open)
            cursor.execute("INSERT ignore INTO Ports_Table(Port_ID, Port_Number) values('%s','%s')" % (computer_id, ports_open))
            continue
        #If the line starts with Port, increase the computer_id. Nmap lists the PORT heading only once per computer
        #Therefore it is a reliable way to indicate the ID of a new computer
        elif starts_with_digit == False and "Nmap" in ports_open:
            computer_id +=1
        elif "All 1000" in ports_open:
            print "no ports open at ID ", computer_id
            ports_open = 0
            cursor.execute("INSERT ignore INTO Ports_Table(Port_ID, Port_Number) values('%s','%s')" % (computer_id, ports_open))
    #Loop through the open ports on your network and only add port descriptions of ports which exist on your network
    #This was done to reduce querry time against the list of known ports
    x = 0
    while x < len(port_number):
        if port_number[x] in existing_ports:
            print "adding ", port_number[x], port_description[x], protocol_name[x], " to the database"
            cursor.execute("INSERT ignore INTO Port_Description(Port_Number, Port_Description, Port_Protocol) values('%s', '%s', '%s')" % (port_number[x], port_description[x], protocol_name[x]))
        else:
            print "This port is not found among the open ports on your network.... OMITTING"
        x +=1
#######################################################################   
def parse_os():
    OS_list = []
    nmap_file = open(scratch_file)
    for line in nmap_file:
        if line.startswith('Nmap'):
            flag = 0
        if last_line in line:
            flag = 1
        if not flag and not last_line  in line:
            #append the line to the list and strip the dashes away
            OS_list.append(line.strip('---').rstrip())
    #set the computer_id to 0. The computer_id represents the ID of the computer
    #Each computer will only have a single OS at the time of scanning. Link the ID to the OS
    computer_id = 0
    for host_os in OS_list:
        starts_with_digit = re.match(r"[0-9]", host_os) is not None
        #If the line starts with a digit, skip it and look for the OS information
        if starts_with_digit == True:
            continue
        #If the line starts with Port, increase the computer_id. Nmap lists the PORT heading only once per computer
        #Therefore it is a reliable way to indicate the ID of a new computer
        elif "Nmap" in host_os:
            computer_id +=1
        elif "OS" in host_os and "OS:" not in host_os and "Warn" not in host_os and "Running"not in host_os and "Agg" not in host_os and "Microsoft" not in host_os :
            host_os = host_os.strip("OS details: ")
            if "No" in host_os or "Too many" in host_os:
                host_os = "Not available"
                print "Not available"
                cursor.execute("INSERT ignore INTO OS_Table(OS_Name) values('%s')" % (host_os))
            else:
                host_os = host_os.split(",")
                print "Inserting: ", host_os[0]
                cursor.execute("INSERT ignore INTO OS_Table(OS_Name) values('%s')" % (host_os[0]))
        elif "Microsoft" in host_os and "OS" not in host_os and "JUST" not in host_os:
            host_os = host_os.split("Running: ") 
            print "Inserting: ", host_os[1]
            cursor.execute("INSERT ignore INTO OS_Table(OS_Name) values('%s')" % (host_os[1]))
##############################################################################
createNmap()

parse_ports()
parse_dns()
parse_os()
#close the database connection
database_connection.commit()
cursor.close()
database_connection.close()
#clean up after yourself
os.remove(scratch_file)
#os.remove(nmap_output)

Here is a down and dirty UI:

Code:
#!/usr/bin/python
#This program is being designed to be a front end for mysql


from Tkinter import *
import MySQLdb
import struct
import os
import re

#This is where the bulk of the decision making is made
#This class is used to turn the checkbox input into meaning database parameters
#In ddition, it does some error checking by making sure all of the input boxes
#have text in them, as well as making sure that only 1 very ending is checked        

class getResults:
    
        
    def __init__(self, parent):
       
        def formatListbox(msg, listbox_height):
            fetch_results = cursor.fetchall()

            global top
            #top = Frame(root)
            top = Toplevel()
            #top.pack()
            
            #top.title("Information retrieved")
            msg_title = Message (top, text="The following computers are running '%s'" % msg, width=80)
            msg_title.pack(pady=5)
            scrollbar = Scrollbar(top)
            scrollbar.pack(side=RIGHT, fill=Y)
            listbox = Listbox(top, yscrollcommand=scrollbar.set, width=100, height=listbox_height)
            listbox.pack(pady=15, padx=50)
            
            #This sets the spacing for the listbox it explicitely tells the program to print each element, one at a time, to the list box
                        
            for single_result in fetch_results:
                character_count = 0
                #set the first spacing
            #we know that in the quad octet of ips, 15 characters are the maximum there will ever be
            #Therefore set the spacing 
                first_spacing = " "
                spacing = " "
                #print len(single_result[0]), len(single_result[1]), len(single_result[2])
                
                if (15 - len(single_result[0])) > 2:               
                    first_spacing = (first_spacing * 9)
                elif (15 - len(single_result[0])) > 1:
                    first_spacing = (first_spacing * 7)                                    
                elif (15 - len(single_result[0])) == 1:
                    first_spacing = (first_spacing * 5)
                
                if "Linux 2.6.13 - 2.6.28" in single_result[1] or "Linux 2.6.18 - 2.6.28" in single_result[1] or "Linux 2.6.24 - 2.6.31" in single_result[1] or "Linux 2.6.19 - 2.6.31" in single_result[1]:
                    spacing = (spacing * 45)
                elif "Microsoft Windows XP" in single_result[1]:
                    spacing = (spacing * 44)
                elif "Microsoft Windows Vista|2008|7" in single_result[1]:
                    spacing = (spacing * 29)
                    print "Found Vista|2008|7"
                elif "Microsoft Windows 2003" in single_result[1]:
                    spacing = (spacing * 40)
                elif "Not available" in single_result[1]:
                    spacing = (spacing * 58)
                elif "Linux 2.4.20" in single_result[1]:
                    spacing = (spacing * 58)
                elif "IBM InfoPrint 1140 printer" in single_result[1]:
                    spacing = (spacing * 37)
                elif "Linux 2.4.18 - 2.4.35 (likely embedded)" in single_result[1]:
                    spacing = (spacing * 17)
                elif "Dell 5210n or Lexmark C534dn" in single_result[1]:
                    spacing = (spacing * 29)
                elif "HP LaserJet 4250 printer (J7949E)" in single_result[1]:
                    spacing = (spacing * 25)
                elif "Microsoft Windows Vista" in single_result[1]:
                    spacing = (spacing * 41) 
                elif "APC AP7851 power distribution unit (AOS 2.7.0)" in single_result[1]:
                    spacing = (spacing * 4) 
                elif "WatchGuard FireBox 700 or X700 firew" in single_result[1]:
                    spacing = (spacing * 18) 
                elif "HP InkJet 2300" in single_result[1]:
                    spacing = (spacing * 54)
                elif "FreeBSD 4.3-RELEASE or IBM AIX 5.3 - 6.1" in single_result[1]:
                    spacing = (spacing * 13) 
                elif "Netgear GSM7224 switch" in single_result[1]:
                    spacing = (spacing * 39)                
                   
                single_result = single_result[0] + first_spacing + single_result[1] + spacing + single_result[2]             
                listbox.insert(END, single_result)
            scrollbar.config(command=listbox.yview)

        oper_sys = OS.get()
        ip_get = IP.get()
        database_connection = MySQLdb.connect('localhost', 'root', '', 'nmap');
        cursor = database_connection.cursor()
        starts_with_digit = re.match(r"[0-9]", ip_get) is not None
        
        #display_all_ports = display_ports.get()
        #if display_all_ports 
        
        if  oper_sys == "" and ip_get != "":
                starts_with_digit = re.match(r"[0-9]", ip_get) is not None
                if starts_with_digit == True:
                    #cursor.execute("SELECT Computer_Info.Computer_IP_Address,OS_Table.OS_Name FROM Computer_Info, OS_Table WHERE Computer_Info.Computer_ID=OS_Table.OS_ID AND Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton(Computer_IP_Address)" % ip_get)
                    
                    cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Port_Number = PS.Port_Number ) \
                    WHERE Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % ip_get)
                    
                    #we get the number of rows in order to set the height of the listbox (it gets passed to the function)                    
                    number_of_rows = int(cursor.rowcount) /4  
                    if number_of_rows < 6:
                        number_of_rows = 8
                    formatListbox(ip_get, number_of_rows)
                else:
                    print "you did not enter a valid IP!!!"
        elif oper_sys != "" and ip_get == "":
            starts_with_digit = re.match(r"[0-9]", oper_sys) is not None
            if starts_with_digit == False:
                    cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Port_Number = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % oper_sys)
                    #we get the number of rows in order to set the height of the listbox (it gets passed to the function)                    
                    number_of_rows = int(cursor.rowcount) /4  
                    if number_of_rows < 6:
                        number_of_rows = 8
                    formatListbox(oper_sys, number_of_rows)
            else:
                    print "you did not enter a valid Operating system!!!"
        else:
            #print "please enter ONLY the OS or the IP address!!!"
            cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name \
            FROM Computer_Ports AS CP \
            JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
            JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
            JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
            JOIN Port_Description AS PS ON ( PT.Port_Number = PS.Port_Number ) \
            WHERE Computer_IP_Address LIKE '%%%s%%' and OS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % (ip_get, oper_sys))
            #we get the number of rows in order to set the height of the listbox (it gets passed to the function)                    
            number_of_rows = int(cursor.rowcount) /4  
            if number_of_rows < 6:
                number_of_rows = 8
            formatListbox(oper_sys, number_of_rows)
#This class designs the UI and the button placement
#This class has a mix of local and global variables. Local variables are designated by the self.xxx
#Any UI element that must return a result has a seperate .pack() lines. This is because having checkButton(xxx text=xxx).pack() returns an error
#when attempting to extract a value            
class createUI:
    def __init__(self, parent):
        #export variables from this class so they are available in other classes
        
        global OS, IP, counter
    
        self.panel1 = Frame(parent.title("main window"))
        self.panel1.pack()
        self.frame1 = Frame(self.panel1)
        #in the first frame, create the directions and the input boxes
        self.OS_label = Message(self.frame1, text="Search by operating system", justify=LEFT, width=180).pack(pady=2)
        OS = Entry(self.frame1)
        OS.pack()
        OS.focus_set()
        self.IP_label = Message(self.frame1, text="Search by IP", justify=LEFT, width=180).pack(pady=3)
        IP = Entry(self.frame1)
        IP.pack(pady=14, padx=60)    
        self.frame1.pack()

        self.frame5 = Frame(self.panel1)
        #set the variables used by the checkboxes to an IntVar so that they can be evaluated as off or on
        display_ports = IntVar()
        ports_checkbutton = Checkbutton(self.frame5, text='Display Ports', onvalue = 1, offvalue = 0, variable=display_ports, width=10)
        ports_checkbutton.pack(side=LEFT)
        self.frame5.pack()

        self.frame6 = Frame(self.panel1)
        #lambda was used so that the button does not execute the addToDB class before click. addToDB requires an argument and self.database_button didn't work
        self.database_button = Button(self.frame6, text="Get results!")
        self.database_button.pack()
        self.database_button.configure(command=lambda btn = self.database_button: getResults(btn))
        self.quit_button = Button(self.frame6, text="Get me outta here", command=self.panel1.quit).pack()             
        self.frame6.pack()
  
######main loop #########  

root = Tk()

ui = createUI(root)
ui.panel1.mainloop()

Added a better secondary GUI, though I am leaving the first one in place for reference

Code:
#!/usr/bin/python
import pygtk
pygtk.require('2.0')
import gtk
import os
import sys
import MySQLdb
from Tkinter import *

database_connection = MySQLdb.connect('localhost', 'root', '', 'nmap');
cursor = database_connection.cursor()
class Table_GUI:
    cells = {}
    columns = {}
    sort_order = gtk.SORT_ASCENDING
	
    def delete_event(self, widget, event, data=None):
		return False

    def destroy(self, widget, data=None):
		gtk.main_quit()
		
    def __init__(self):
     
		# create a new window
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_geometry_hints(min_width=400, min_height=200)

        self.window.connect("delete_event", self.delete_event)
        self.window.connect("destroy", self.destroy)
        
        self.vbox = gtk.VBox(False, 0)
        self.window.add(self.vbox)
        
        self.vbox.show()
		#For some reason I can't get the scrolled window to work...
        self.scrolledwindow = gtk.ScrolledWindow()
        self.scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)

        self.vbox.pack_start(self.scrolledwindow)
		
        self.frm_table = gtk.Frame()
        self.frm_table.set_shadow_type(gtk.SHADOW_NONE)
        self.frm_table.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#fff'))
        self.show_Table(oper_sys, ip_get)
        self.frm_table.show()
        self.vbox.pack_start(self.frm_table, True, True, 0)

        self.window.show()
    
    def show_Table(self, search_os, search_ip):

        ### Create the table
        # List of items to display which represent IP, OS, DNS, Port number and Port description
        self.liststore = gtk.ListStore(str, str, str, str, str)
        
          
        if search_os != "" and search_ip !="":
        #Set up the querries. If the user has activted the checkbox, we need to include the ports in the querry
            if ports_check == 1:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' and Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % (search_os, search_ip))
        #Otherwise just return the relevent data
            else:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' and Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % (search_os, search_ip))
        elif search_os != "" and search_ip == "":
            if ports_check == 1:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % search_os)
            else:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % search_os)
        elif search_os =="" and search_ip != "":
            if ports_check == 1:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % search_ip)
            else:
                  cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % search_ip)
        #get the results and prepare to put them inside of lists
        fetch_results = cursor.fetchall()
        host_name_list = []
        operating_list = []
        ip_list = []
        ports = []
        #The element chosen to append to each list based on the order of retrieval in the mysql querry
        for individual_result in fetch_results:
            ip_list.append(individual_result[0])
            operating_list.append(individual_result[1])    
            host_name_list.append(individual_result[2])
            if ports_check == 1:    
                ports.append(individual_result[3])
        
        cleaned_host =[]
        cleaned_ip = []
        cleaned_os_list = []
        
        index_counter = 0
        print len(operating_list)
        
        while index_counter < len(host_name_list):
            if host_name_list[index_counter] in cleaned_host:
              print "found a duplicate in HOST....OMITTING"
              cleaned_host.append("")
            else:
                print "adding ", host_name_list[index_counter]  
                cleaned_host.append(host_name_list[index_counter])
                
            if operating_list[index_counter] in cleaned_os_list:
                print "found a duplicate in OPERATING....OMITTING"
                cleaned_os_list.append("")
            else:
                print "adding ", operating_list[index_counter]     
                cleaned_os_list.append(operating_list[index_counter])
                
            if ip_list[index_counter] in cleaned_ip:
                print "Found a duplicate in IP.... OMITTING "
                cleaned_ip.append("")
            else:
                print "adding ", ip_list[index_counter]     
                cleaned_ip.append(ip_list[index_counter])
            index_counter +=1  
        counter = 0
        for single_result in fetch_results:
            if ports_check == 1:
                self.liststore.append(
            [ cleaned_host[counter], cleaned_ip[counter], cleaned_os_list[counter], single_result[4], single_result[3] ]
			)
            else:
                self.liststore.append(
            [ single_result[0], single_result[1], single_result[2], "" , "" ]
			)
            counter +=1
        # Treeview
        self.treeview = gtk.TreeView()
      	self.treeview.set_property("fixed-height-mode", False)
        
        # Columns
        self.newColumn("IP Address", 0)
        self.newColumn("Operating System", 1)
        self.newColumn("Hostname",2)
        if ports_check == 1:
            self.newColumn("Ports", 3)
            self.newColumn("Protocol name", 4)
            
        self.treeview.set_model(self.liststore)
        self.treeview.set_headers_clickable(True)

        self.frm_table.add(self.treeview)
        self.treeview.show()

		

    def on_column_clicked(self, tc, user_data):
		self.liststore.set_sort_column_id(user_data, self.sort_order)

		if self.sort_order == gtk.SORT_ASCENDING:
			self.sort_order = gtk.SORT_DESCENDING
		else:
			self.sort_order = gtk.SORT_ASCENDING

		tc.set_sort_order(self.sort_order)

    def newColumn(self, title, index):
		self.cells[index] = gtk.CellRendererText()
		self.cells[index].set_property('cell-background-gdk', gtk.gdk.color_parse("#FFF"))
		
		self.columns[index] = gtk.TreeViewColumn(title, self.cells[index], text=index)
		self.columns[index].set_resizable(True)
		self.columns[index].set_reorderable(True)
		self.columns[index].set_sort_indicator(True)
		if(index == 2 or index == 3 or index == 4): self.columns[index].set_min_width(90)
		
		self.columns[index].connect("clicked", self.on_column_clicked, index)
		self.treeview.insert_column(self.columns[index], -1)
		
	# The main function
    def main(self):
		gtk.main()
        
class createUI:
    def pushButton(self, parent):
        global ports_check, oper_sys, ip_get
        ports_check = display_ports.get()
        oper_sys = OS.get()
        ip_get = IP.get()
        gui = Table_GUI()
        gui.main()
        
    def __init__(self, parent):
        #export variables from this class so they are available in other classes
        
        global OS, IP, counter, display_ports
    
        self.panel1 = Frame(parent.title("main window"))
        self.panel1.pack()
        self.frame1 = Frame(self.panel1)
        #in the first frame, create the directions and the input boxes
        self.OS_label = Message(self.frame1, text="Search by operating system", justify=LEFT, width=180).pack(pady=2)
        OS = Entry(self.frame1)
        OS.pack()
        OS.focus_set()
        self.IP_label = Message(self.frame1, text="Search by IP", justify=LEFT, width=180).pack(pady=3)
        IP = Entry(self.frame1)
        IP.pack(pady=14, padx=60)    
        self.frame1.pack()

        self.frame5 = Frame(self.panel1)
        #set the variables used by the checkboxes to an IntVar so that they can be evaluated as off or on
        display_ports = IntVar()
        ports_checkbutton = Checkbutton(self.frame5, text='Display Ports', onvalue = 1, offvalue = 0, variable=display_ports, width=10)
        ports_checkbutton.pack(side=LEFT)
        self.frame5.pack()

        self.frame6 = Frame(self.panel1)
        #lambda was used so that the button does not execute the addToDB class before click. addToDB requires an argument and self.database_button didn't work
        self.database_button = Button(self.frame6, text="Get results!")
        self.database_button.pack()
        
    
        self.database_button.configure(command=lambda btn = self.database_button: self.pushButton(btn))
        
        self.quit_button = Button(self.frame6, text="Get me outta here", command=self.panel1.quit).pack()             
        self.frame6.pack()





if __name__ == "__main__":
    root = Tk()

    ui = createUI(root)
    ui.panel1.mainloop()

Added a completely GTK interface... its kinda rough but its functional. Added scrollbars and changed the liststore to the treestore

Code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pygtk
import gtk
import os
import sys
import MySQLdb

database_connection = MySQLdb.connect('localhost', 'root', '', 'nmap');
cursor = database_connection.cursor()

class Application(gtk.Window):
    cells = {}
    columns = {}
    sort_order = gtk.SORT_ASCENDING
####################
    def __init__(self):
        gtk.Window.__init__( self )
        self.set_title("Netowrk Scanner")
        self.set_position(gtk.WIN_POS_CENTER)
        self.create_widgets()
        self.connect_signals()

        #self.window.show_all()
        self.show_all()
        gtk.main()
##################        
    def create_widgets(self):
        #Ask the user to search by operating system
        self.vbox = gtk.VBox(spacing=10)
        self.operating_system_label_hbox_1 = gtk.HBox(spacing=10)
        self.label = gtk.Label("Search by Operating System :")
        self.operating_system_label_hbox_1.pack_start(self.label)

        #Set a check box so the user can choose to display ports
        self.ports_hbox_8 = gtk.HBox(spacing=10)
        self.ports_check = gtk.CheckButton("Display Ports")
        self.ports_hbox_8.pack_start(self.ports_check)
        self.halign_ports = gtk.Alignment(0,1,1,0)
        self.halign_ports.add(self.ports_hbox_8)

        self.os_entry_hbox_2 = gtk.HBox(spacing=10)
        self.OS = gtk.Entry()
        self.os_entry_hbox_2.pack_start(self.OS)

        self.hostname_label_hbox_3 = gtk.HBox(spacing=10)
        self.label = gtk.Label("Search by Hostname:")
        self.hostname_label_hbox_3.pack_start(self.label)

        self.hostname_entry_hbox_4 = gtk.HBox(spacing=10)
        self.HOSTNAME = gtk.Entry()
        self.hostname_entry_hbox_4.pack_start(self.HOSTNAME)

        self.ip_label_hbox_5 = gtk.HBox(spacing=10)
        self.label = gtk.Label("Search by IP:")
        self.ip_label_hbox_5.pack_start(self.label)

        self.ip_entry_hbox_6 = gtk.HBox(spacing=10)
        self.IP = gtk.Entry()
        self.ip_entry_hbox_6.pack_start(self.IP)

        self.buttons_hbox_7 = gtk.HBox(spacing=10)
        self.button_ok = gtk.Button("Get Results!")
        self.buttons_hbox_7.pack_start(self.button_ok)
        self.button_exit = gtk.Button("Get me Outta Here!")
        self.buttons_hbox_7.pack_start(self.button_exit)

        #The order in which you pack_start a widget is the order in which it is displayed on the screen
        self.vbox.pack_start(self.operating_system_label_hbox_1)
        self.vbox.pack_start(self.os_entry_hbox_2)
        self.vbox.pack_start(self.hostname_label_hbox_3)
        self.vbox.pack_start(self.hostname_entry_hbox_4)
        self.vbox.pack_start(self.ip_label_hbox_5)
        self.vbox.pack_start(self.ip_entry_hbox_6)
        self.vbox.pack_start(self.halign_ports, False, False, 3)
        self.vbox.pack_start(self.buttons_hbox_7)

        self.add(self.vbox)
##########################
    def connect_signals(self):
        #Have the buttons start 'listening' for user interaction
        self.button_ok.connect("clicked", self.button_click)
        self.button_exit.connect("clicked", self.exit_program)
########################
    def button_click(self, clicked):
        #This function gets the values of the input boxes as well as the check box
        #And then passes them to the show_table function so it can get the correct results from the database
        global ports_check, os, ip, hostname
        os = self.OS.get_text()
        ip = self.IP.get_text()
        hostname = self.HOSTNAME.get_text()
        ports_check = self.ports_check.get_active()
        if hostname != "" and (os != "" or ip != ""):
            error_message = gtk.MessageDialog(self, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, "If you know the hostname why are you searching with other options? Please search by hostname only")
            error_message.run()
            error_message.destroy()
            self.OS.set_text("")
            self.IP.set_text("")
            self.HOSTNAME.set_text("")
        else:
            self.show_Table(os, ip, hostname)
##############        
    def show_Table(self, search_os, search_ip, search_hostname):
    ### Create the table
        # List of items to display which represent IP, OS, DNS, Port number and Port description
         # Columns
        if ports_check == True:
            cols = ['IP Address', 'Operating System', 'Hostname', 'Ports', 'Protocol Name']
        else:
            cols = ['IP Address', 'Operating System', 'Hostname']
        """    
        self.newColumn("IP Address", 0)
        self.newColumn("Operating System", 1)
        self.newColumn("Hostname",2)
        #I only want the ports columns to show if the user requests it because this calls different mysql querries
        if ports_check == True:
            self.newColumn("Ports", 3)
            self.newColumn("Protocol name", 4)
        """
        
        sequence = [str] * len(cols)
        self.treestore = gtk.TreeStore( * sequence)
        self.treestore.connect("rows-reordered", self.on_column_clicked)
        self.treeview = gtk.TreeView(self.treestore)
        self.treeview.cell = [None] * len(cols)
        self.treeview_column = [None] * len(cols)
        
        for column_number, col in enumerate(cols):
            self.treeview.cell[column_number] = gtk.CellRendererText()
            self.treeview_column[column_number] = gtk.TreeViewColumn(col, self.treeview.cell[column_number])
            self.treeview_column[column_number].add_attribute(self.treeview.cell[column_number], 'text', column_number)
            self.treeview_column[column_number].set_resizable(True)
            self.treeview_column[column_number].set_reorderable(True)
            self.treeview_column[column_number].set_sort_indicator(True)
            self.treeview_column[column_number].set_sort_column_id(column_number)
            self.treeview.append_column(self.treeview_column[column_number])
        
        self.scrollTree = gtk.ScrolledWindow()
        self.scrollTree.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        self.scrollTree.add(self.treeview)
        
        #If the user is running a search on the hostname run these querries
        if search_hostname != "":
            if ports_check == True:
                    cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                        JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                        JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                        JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                        JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                        WHERE DNS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % (search_hostname))
            #Otherwise just return the relevent data
            else:
                    cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                        JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                        JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                        JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                        JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                        WHERE DNS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % (search_hostname))
        
        
        #If the user has specified the IP and the OS to search, run this querry  
        if search_os != "" and search_ip !="":
        #Set up the querries. If the user has activted the checkbox, we need to include the ports in the querry
            if ports_check == True:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' and Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % (search_os, search_ip))
        #Otherwise just return the relevent data
            else:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' and Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % (search_os, search_ip))
        #If the user has specified an OS but not an IP run this
        elif search_os != "" and search_ip == "":
            if ports_check == True:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % search_os)
            else:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % search_os)
        #If the user has specified an IP but not an OS run this
        elif search_os =="" and search_ip != "":
            if ports_check == True:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % search_ip)
            else:
                 cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % search_ip)

        #get the results and prepare to put them inside of lists
        fetch_results = cursor.fetchall()
        host_name_list = []
        operating_list = []
        ip_list = []
        ports = []
        #The element chosen to append to each list based on the order of retrieval in the mysql querry
        for individual_result in fetch_results:
            ip_list.append(individual_result[0])
            operating_list.append(individual_result[1])    
            host_name_list.append(individual_result[2])
            if ports_check == True:    
                ports.append(individual_result[3])
        #we are going to add blanks to the files in order to help readability
        #when putting this into the chart
        cleaned_host =[]
        cleaned_ip = []
        cleaned_os_list = []

        index_counter = 0
        #this loop will check to see if the entry already exists in the cleaned variables. If it does, it 'omitts' them by inserting a blank line
        while index_counter < len(host_name_list):
            if host_name_list[index_counter] in cleaned_host:
              #print "found a duplicate in HOST....OMITTING"
              cleaned_host.append("")
            else:
                #print "adding ", host_name_list[index_counter]  
                cleaned_host.append(host_name_list[index_counter])

            if operating_list[index_counter] in cleaned_os_list and ip_list[index_counter] in cleaned_ip:
                #print "found a duplicate in OPERATING....OMITTING"
                cleaned_os_list.append("")
            else:
                #print "adding ", operating_list[index_counter]     
                cleaned_os_list.append(operating_list[index_counter])

            if ip_list[index_counter] in cleaned_ip:
                #print "Found a duplicate in IP.... OMITTING "
                cleaned_ip.append("")
            else:
                #print "adding ", ip_list[index_counter]     
                cleaned_ip.append(ip_list[index_counter])
            index_counter +=1  

        #this section appends to the list store depending on whether the user wants to see the ports or not
        counter = 0
        for single_result in fetch_results:
            if ports_check == True:
                self.treestore.append( None,
            [ cleaned_ip[counter], cleaned_os_list[counter], cleaned_host[counter], single_result[4], single_result[3] ]
            )

            else:

                self.treestore.append(None,
            [ single_result[0], single_result[1], single_result[2] ]
            )
            counter +=1
        
        
        self.frm_table = gtk.Window()
        self.frm_table.set_default_size(600, 800)
        self.frm_table.set_title("Network scan results")
        #Change the background to white instead of grey
        self.frm_table.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#fff'))
        self.frm_table.add(self.scrollTree)
        self.frm_table.show_all()
###################### 
    def on_column_clicked(self, col1, col2, col3, col4 ):
        #This function allows the columns to be resorted upon click

        if self.sort_order == gtk.SORT_ASCENDING:
            self.sort_order = gtk.SORT_DESCENDING
        else:
            self.sort_order = gtk.SORT_ASCENDING

        #tc.set_sort_order(self.sort_order) 
###############        
    def exit_program(self, widget, callback_data=None):
        gtk.main_quit()
#---------------------------------------------
if __name__ == "__main__":
    app = Application() 
    database_connection.commit()
    cursor.close()
    database_connection.close()
 
Last edited:
For anyone who ever needs to install the Progress/OpenEdge database I wrote a python script to help the process along. Hopefully the comments will help fill in the gaps in understanding of what the script is doing

Code:
#!/usr/bin/python
#This script will attempt to create a blank response.ini for progress
#it assumes it is running on a unix-like system

import os
import sys
import fileinput

company_name = raw_input("Enter the company name: ")
number_of_products = raw_input("Enter the number of products to install:   ")
counter = 0

list_of_serial_numbers = []
control_codes = []


#This section will ask the users for the relevent information and produce proper output
#provided that the user entered the correct number of products to install
while counter < int(number_of_products):
    list_of_serial_numbers.append(raw_input("Enter a serial number for product %s: " % (counter + 1)))
    control_codes.append(raw_input("Enter a control code for product %s: " % (counter + 1)))
    counter += 1

#capture standard output into an ini file
old_stdout = sys.stdout
sys.stdout = open("response1.ini", "w")
###################Configuration Count Section

print "[Configuration Count]"
print "NumberofConfigurations=%s" % number_of_products
print ""

######################Product configuration Section

#get the java path from the OS
java_path = os.popen("which java").read()
java_path = java_path.split("/bin")
java_path = java_path[0]

#get the hostname
hostname = os.popen("hostname").read()
hostname = hostname.rstrip()
hostname = hostname, "Container"
hostname = "".join(hostname)

counter = 0
#raw_input takes in strings, we need to turn that into an integer
while counter < int(number_of_products):
    #set the headings
    #The product section will have to loop until counter == number_of_products in order to create enough product ini sections
    #Since the only section that requires duplication is the Product Configuration, we don't need variables
    #for the other sections. This may help improve readbility
    product_configuration_heading = "[Product Configuration %s]" % (counter + 1)
    print product_configuration_heading
    print "name=%s" % company_name
    print "serial=00%s" % list_of_serial_numbers[counter]
    #print "version=10.2B"
    print "control=%s" % control_codes[counter]
    print ""
    counter +=1

#The print statement below provides the default answers that we would like to standardize on
#The java path, the hostname and the number of products are the only 'variable' answers in this section
print """
[OpenEdge Explorer]
enable=yes


[Java]
jdkHomePath=%s
jvmAllowUnsupported=yes

[Type and Destination]
type=COMPLETE
path=/u/DLC/dlcv102b
workpath=/u/pmwork
oem_path=/u/DLC/oemgmt
oem_workpath=/u/wrk_oemgmt

[Server Engine]
UseSqlServerEngine=1

[SonicEsbAdapter]
esbcontainername=%s
esbdomain=Domain1
esburl=tcp://localhost:2506
esbusername=Administrator
esbpassword=Administrator
esbpath=empty

[Language Default]
DefaultLanguage=English - American

[Language Choice]
lang1=English - American

[International Settings]
cpinternal=ISO8859-1
cpcollation=Basic
cpcase=Basic
dateformat=mdy
numsep=44
numdec=46


[Installed Products]
ProductCount=%s
""" % (java_path, hostname, number_of_products)

NOTE: I have left out the final section of the INI file as I am not sure whether they are needed or not. I will investigate further

the section that was left out looks like the following

Code:
[Product 113]
__xxx Options=1
 
Last edited:
I am posting up the source code for aptitude front end I created

Code:
#!/usr/bin/python
import gtk
import pygtk
import os
import sys
import re

class createUI:
####################   
    def on_column_clicked(self, col1, col2, col3, col4 ):
            #This function allows the columns to be resorted upon click

            if sort_order == gtk.SORT_ASCENDING:
               sort_order = gtk.SORT_DESCENDING
            else:
               sort_order = gtk.SORT_ASCENDING
####################               
    def install_selected(self, option):
            #This function determines which field has been selected
            #Then it picks the package name from the second column 
            self.selection = self.treeview.get_selection()
            self.selection.set_mode(gtk.SELECTION_SINGLE)
            #We only want the user to be able to select one file
            tree_model, tree_iter = self.selection.get_selected()
            #The line below is the line which determines which column is passed to the installer
            self.selected_program = tree_model.get_value(tree_iter, 1)    
            print self.selected_program
            os.system("gksudo 'aptitude install %s -y'" % self.selected_program)
##################
    def search_packages(self, clicked):
        #this is the function which searches for the packages and stores the list in a file
        #for easier manipulation. It starts by trying to remove any temp files in case there was not a clean shutdown
        #previously
        try:
            os.system('rm -rf somefile')
        except:
            pass
        search = self.search_package.get_text()
        os.system("aptitude search %s> somefile" % search )
        if search != "":
            #Call the results        
            self.createTable()
            #destroy the search window
            self.window.destroy()
        else:
            pass    
#############
    def kill_program(self, click):
        #attempt to clean up before quitting
        os.system("rm -rf somefile")
        gtk.main_quit()
#####################    
    def uninstall_program(self, click):
        #this section functions in the same way as the install package except it purges files instead of installs them
        self.selection = self.treeview.get_selection()
        self.selection.set_mode(gtk.SELECTION_SINGLE)
        tree_model, tree_iter = self.selection.get_selected()
        self.selected_program = tree_model.get_value(tree_iter, 1)    
        os.system("gksudo 'aptitude --purge remove %s -y'" % self.selected_program)
####################            
    def __init__(self):
        self.create_search(None)
##################        
    def create_search(self, dummy):
        try:
            self.aptitude_results.destroy()
        except:
            pass
        #create the initial search window
        self.window = gtk.Window()
        #centre the window
        self.window.set_position(gtk.WIN_POS_CENTER)
        #We set the default because otherwise the dialogue box looks disproportionate
        self.window.set_default_size(300,150)
        self.window.set_title("Search for a Package")
        
        #Deal with the search label. It goes inside of an Hbox for horizontal positioning
        self.vbox = gtk.VBox(spacing=10)
        self.search_label_hbox_1 = gtk.HBox(spacing=10)
        self.label = gtk.Label("Please enter a program to search for :")
        self.search_label_hbox_1.pack_start(self.label)
        
        #Add the entry box for user input, again in an Hbox
        self.search_entry_hbox_2 = gtk.HBox(spacing=10)
        self.search_package = gtk.Entry()
        self.search_entry_hbox_2.pack_start(self.search_package)
        
        #add the buttons
        self.buttons_hbox_3 = gtk.HBox(spacing=10)
        self.button_ok = gtk.Button("Get Results!")
        #the results button calls the 'search_packages' function
        self.button_ok.connect("clicked", self.search_packages)
        
        self.buttons_hbox_3.pack_start(self.button_ok)
        self.button_exit = gtk.Button("Get me Outta Here!")
        self.buttons_hbox_3.pack_start(self.button_exit)
        self.button_exit.connect("clicked", gtk.main_quit)
        
        #here we put the hboxes inside of the vbox (verticle box)
        self.vbox.pack_start(self.search_label_hbox_1)
        self.vbox.pack_start(self.search_entry_hbox_2)
        self.vbox.pack_start(self.buttons_hbox_3)
        
        #add everything to the main window and display it       
        self.window.add(self.vbox)
        self.window.show_all()
        gtk.main()
#####################3        
    def createTable(self):
        
        builder = gtk.Builder()
        builder.add_from_file('aptitude_frontend.glade')
        builder.connect_signals(self)
        self.aptitude_results = builder.get_object('window')
        treeview = builder.get_object('treeview')
        table_vbox = builder.get_object('vbox')

        treestore = builder.get_object('liststore1')
        
        cols = ["Installed?", "Package Name", "Description"]
        treeview.cell = [None] * len(cols)
        treeview_column = [None] * len(cols)

        for column_number, col in enumerate(cols):
            treeview.cell[column_number] = gtk.CellRendererText()
            treeview_column[column_number] = gtk.TreeViewColumn(col, treeview.cell[column_number])
            treeview_column[column_number].add_attribute(treeview.cell[column_number], 'text', column_number)
            treeview_column[column_number].set_resizable(True)
            treeview_column[column_number].set_reorderable(True)
            treeview_column[column_number].set_sort_indicator(True)
            treeview_column[column_number].set_sort_column_id(column_number)
            treeview.append_column(treeview_column[column_number])
        
        #read the output from aptitude
        fetch_results = open("somefile").readlines()
        #A results list is required to get rid of all the wierd spaces that aptitude produces for terminal output
        results_list = []


        for single_result in fetch_results:
            #turn the results into a tuple by splitting at the spaces
            #this allows us to get rid of the spaces
            single_result = single_result.split(" ")
            counter = 0
            place_holder = []
            while counter < len(single_result):
                #here we are checking to see if a line starts with a space/tab/new line and has nothing else
                if re.match(r'^\s*$', single_result[counter]):
                    #we dont want to append these so instead we will just pass over them
                    pass
                else:
                    place_holder.append(single_result[counter])                    
                counter +=1
            #the place holder is required so that we can turn each tuple back into a string so that it can be appended to the actual results list
            place_holder = " ".join(place_holder)
            #get rid of the new line characters if they exist
            place_holder = place_holder.rstrip()
            results_list.append(place_holder)
            
        for column_contents in results_list:
            column_contents = column_contents.split(" ")
            #since the information was entered into the list in the following way "i eog - <package_description>"
            #we want to put all the descriptive words into a single element so they can be placed into
            #a column. We can also tell that the descriptions start at the 4th element
            element = 3
            package_description = []
            while element < len(column_contents):
                package_description.append(column_contents[element])
                element +=1
            package_description = " ".join(package_description)

            #This section translates the 
            if column_contents[0] == "i":
                column_contents[0] = "y"
                treestore.append(
                    [ column_contents[0], column_contents[1], package_description ]
                    )
            
            elif column_contents[0] == "v":
                #skip the meta package information
                pass
            else:
                column_contents[0] = "n"    
                treestore.append(
                    [ column_contents[0], column_contents[1], package_description ]
                    )
            
        
        #add the tool bar for 'nice' buttons
		toolbar = builder.get_object('toolbar')
		
		#quit button
        quit_icon = gtk.Image()
        quit_icon.set_from_file("quit.png")
        quit_button = gtk.ToolButton(label="Quit!", icon_widget=quit_icon)
        toolbar.insert(quit_button, 0)
        quit_button.connect("clicked", self.kill_program)
        
        #uninstall button
        uninstall_icon = gtk.Image()
        uninstall_icon.set_from_file("uninstall.png")
        uninstall_button = gtk.ToolButton(label="Uninstall!", icon_widget=uninstall_icon)
        toolbar.insert(uninstall_button, 0)
        uninstall_button.connect("clicked", self.uninstall_program)
        
        #install button
        install_icon = gtk.Image()
        install_icon.set_from_file("working_tux.png")
        install_button = gtk.ToolButton(label="Install", icon_widget=install_icon)
        toolbar.insert(install_button, 1)
        install_button.connect("clicked", self.install_selected)	
        toolbar.show()
        
        #search button
        search_icon = gtk.Image()
        search_icon.set_from_file("tux_search.png")
        search_button = gtk.ToolButton(label="Search Again", icon_widget=search_icon)
        toolbar.insert(search_button, 2)
        search_button.connect("clicked", self.create_search)
        
        table_vbox.show()
        self.aptitude_results.connect("destroy", lambda w: gtk.main_quit())
        self.aptitude_results.set_default_size(600, 800)
        self.aptitude_results.set_position(gtk.WIN_POS_CENTER)
        self.aptitude_results.show_all()
        
if __name__ == "__main__":
    createUI()

and the glade file

Code:
<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <requires lib="gtk+" version="2.24"/>
  <!-- interface-naming-policy project-wide -->
  <object class="GtkAdjustment" id="adjustment1">
    <property name="upper">100</property>
    <property name="step_increment">1</property>
    <property name="page_increment">10</property>
  </object>
  <object class="GtkListStore" id="liststore1">
    <columns>
      <!-- column-name Installed? -->
      <column type="gchararray"/>
      <!-- column-name Package Name -->
      <column type="gchararray"/>
      <!-- column-name Description -->
      <column type="gchararray"/>
    </columns>
  </object>
  <object class="GtkWindow" id="window">
    <property name="can_focus">False</property>
    <child>
      <object class="GtkVBox" id="vbox">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <child>
          <object class="GtkToolbar" id="toolbar">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkScrolledWindow" id="scrolledwindow">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="vadjustment">adjustment1</property>
            <property name="hscrollbar_policy">automatic</property>
            <property name="vscrollbar_policy">automatic</property>
            <child>
              <object class="GtkTreeView" id="treeview">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="model">liststore1</property>
              </object>
            </child>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>



I am also added the shred program update as of Sept 21, 2012

Code:
#!/usr/bin/env python
import gtk
import pygtk
import gobject
import os
import sys
import re
import getpass
import gtk.glade
import time

#Get the list of available drives even if they are not mounted
os.popen("fdisk -l |grep sd > /tmp/somefile").read()
#If there is an lvm, we assume its going to be at /dev/mapper so lets add those to the devices to check
if "LVM" in open("/tmp/somefile").read():
    os.popen("ls /dev/mapper/* |grep -v control |grep -v grep |grep -v swap >> /tmp/somefile").read()
    
drive_list = open("/tmp/somefile").readlines()
#We initialize the lists so that we can link them together later
#in the liststore
filesystem = []
device = []
used = []
total = []
free = []

class createUI:
####################               
    #This function is linked to the timer. It updates the progress bar based on the interval
    #specified as a parameter of the timer variable
    def progress_timeout(self):
            global percent 
            #Tail the file and start parsing out the percentage complete
            shredding_progress = os.popen("tail -n 1 /tmp/shred.txt").read()
            try:
                shredding_progress = shredding_progress.split(" ")
                drive = shredding_progress[1].rstrip()
                shredding_progress = shredding_progress[5].replace("%", "")
                
                percent_text = shredding_progress.rstrip()
                shredding_progress = float(shredding_progress)/100
                #Percentages are float point integers so anything over than 1
                # will reset the bar
                if shredding_progress >= 1.0:
                    self.progress.set_text(" %s has been completely shredded" % (drive,))
                    self.progress.set_fraction(0.0)
                    return False
                else:
                    self.progress.set_fraction(shredding_progress)
                    self.progress.set_text(" %s is  %s %s shredded" % (drive, percent_text, "%"))
                    return True
            except:
                return True
####################### 
    def shred_selected(self):
            #This function determines which field has been selected
            #Then it picks the package name from the second column 
            self.selection = treeview.get_selection()
            self.selection.set_mode(gtk.SELECTION_SINGLE)
            tree_model, tree_iter = self.selection.get_selected()
            #The line below is the line which determines which column is passed to the installer
            selected_program = tree_model.get_value(tree_iter, 0)    
            os.system("/opt/shred/shred_test %s &" % selected_program)
            time.sleep(0.3)
########################
    #This is the event which is called from the button click
    #It launches the timer and starts the shredding process            
    def launch(self, click):
        self.shred_selected()
        timer = gobject.timeout_add(300, self.progress_timeout)

##################################
    def kill_program(self, click):
        #attempt to clean up before quitting
        os.system('rm -rf /tmp/shred.txt')
        gtk.main_quit()
#################################
    def __init__(self):
        self.createTable(None)
#################################
    #This function gets the disk usage by mounting disks, getting df output and then unmounting the disks
    def get_disk_usage(self, disk):
        disk = disk[0]
        #If we encounter an LVM, it has slightly different output so it must be handled seperately
        if "mapper" in disk:
            os.popen("mount %s /mnt" % disk.strip()).read()
            total.append(os.popen("df -H |grep 'mnt' | awk '{print $3}'").read().strip())
            used.append(os.popen("df -H |grep 'mnt' |awk '{print $2}'").read().strip())
            free.append(os.popen("df -H |grep 'mnt' |awk '{print $1}'").read().strip())
        else:
            os.popen("mount %s /mnt" % disk).read()
            total.append(os.popen("df -H |grep 'mnt' | awk '{print $2}'").read().strip())
            used.append(os.popen("df -H |grep 'mnt' |awk '{print $3}'").read().strip())
            free.append(os.popen("df -H |grep 'mnt' |awk '{print $4}'").read().strip())
        #Get the filesystem type from the mount command
        filesystem.append(os.popen("mount |grep mnt |awk '{print $5}'").read().strip())
        os.system("umount /mnt")
#############################
    #This makes sure that all of the list elements line up properly
    #by adding blanks for information which cannot be gathered
    def append_blank(self):
        total.append("")
        used.append("")
        free.append("")
############################
    def disk_indenting(self,disk):
        disk = disk[0]
        print disk
        if "mapper" in disk:
            disk_indent = "              ", disk
        else:
            disk_indent = "       ", disk
        disk_indent = "".join(disk_indent)
        device.append(disk_indent)
###########################

    def get_disk_info(self):
        #step through the drive list
        for line in drive_list:
            #If we find an LVM, we skip this and dig up info on /dev/mapper
            disk = line.split()
            if "Disk" in line:
                disk = disk[1]
                device.append(disk)
                filesystem.append("")
                self.append_blank()
            elif "LVM" in line:
                pass
            elif "Extended" in line:
                self.disk_indenting(disk)
                filesystem.append("Extended Partition")
                self.append_blank()
            #Extended partitions also through off the parsing so handle them seperately    
            #Note the swap space
            elif "swap" in line:
                filesystem.append("Swap space")
                self.append_blank()
            #If there are Windows partitions on the drive find them
            #Their drive information is at different element locations than the linux drives
            elif "NTFS" in line:
                   line = line.split(" ")
                   line = line[8].replace('"', "")
                   filesystem.append(line)
                   self.get_disk_usage(disk)
            
            #This is to handle misc filesystems such as DOS executable (device driver)
            #else:
            #    filesystem.append("???") 
            #    self.append_blank()
            else:
                self.disk_indenting(disk) 
                #disk = disk[0]
                self.get_disk_usage(disk) 
        counter = 0
        #This loop matches all of the lists together
        while counter < len(device):
            self.treestore.append(
                            [ device[counter], filesystem[counter], used[counter], free[counter],total[counter], "" ]
                            )
            counter +=1

#####################3        
    def createTable(self, blank):
        #Most of this work was done inside of glade
        global treeview
        #get the builder object so that we can interact with the glade component
        self.builder = gtk.Builder()
        self.builder.add_from_file('/opt/shred/shred_ui.glade')
        self.builder.connect_signals(self)
        self.progress = self.builder.get_object('progress')
        self.aptitude_results = self.builder.get_object('window')
        treeview = self.builder.get_object('treeview')
        table_vbox = self.builder.get_object('vbox')

        self.treestore = self.builder.get_object('liststore')
        
        cols = ["Device","Filesystem Type","Used","Free", "Total"]
        treeview.cell = [None] * len(cols)
        treeview_column = [None] * len(cols)

        for column_number, col in enumerate(cols):
            treeview.cell[column_number] = gtk.CellRendererText()
            treeview_column[column_number] = gtk.TreeViewColumn(col, treeview.cell[column_number])
            treeview_column[column_number].add_attribute(treeview.cell[column_number], 'text', column_number)
            treeview_column[column_number].set_resizable(True)
            treeview_column[column_number].set_reorderable(True)
            treeview_column[column_number].set_sort_indicator(True)
            treeview_column[column_number].set_sort_column_id(column_number)
            treeview.append_column(treeview_column[column_number])
        
        self.get_disk_info()
       
        #add the tool bar for 'nice' buttons
        toolbar = self.builder.get_object('toolbar')
		
		#quit button
        quit_icon = gtk.Image()
        quit_icon.set_from_file("/opt/shred/quit.png")
        quit_button = gtk.ToolButton(label="Quit!", icon_widget=quit_icon)
        toolbar.insert(quit_button, 0)
        quit_button.connect("clicked", self.kill_program)
        
        #uninstall button
        shred_icon = gtk.Image()
        shred_icon.set_from_file("/opt/shred/uninstall.png")
        shred_button = gtk.ToolButton(label="Shred!", icon_widget=shred_icon)
        toolbar.insert(shred_button, 0)
        shred_button.connect("clicked", self.launch)
        
        toolbar.show()

        table_vbox.show()
        self.aptitude_results.connect("destroy", lambda w: gtk.main_quit())
        self.aptitude_results.set_default_size(600, 500)
        self.aptitude_results.set_position(gtk.WIN_POS_CENTER)
        self.aptitude_results.show_all()
        gtk.main()
if __name__ == "__main__":
    createUI()
    #cleanup the temp files
    os.system("rm -rf /tmp/somefile")
    os.system("rm -rf /tmp/shred.txt")

And the glade file (I think its current)

Code:
<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <requires lib="gtk+" version="2.24"/>
  <!-- interface-naming-policy project-wide -->
  <object class="GtkAdjustment" id="adjustment1">
    <property name="upper">100</property>
    <property name="step_increment">1</property>
    <property name="page_increment">10</property>
  </object>
  <object class="GtkListStore" id="liststore">
    <columns>
      <!-- column-name Device -->
      <column type="gchararray"/>
      <!-- column-name Filesystem -->
      <column type="gchararray"/>
      <!-- column-name Mount -->
      <column type="gchararray"/>
      <!-- column-name Used -->
      <column type="gchararray"/>
      <!-- column-name Free -->
      <column type="gchararray"/>
      <!-- column-name gchararray1 -->
      <column type="gchararray"/>
    </columns>
  </object>
  <object class="GtkWindow" id="window">
    <property name="can_focus">False</property>
    <child>
      <object class="GtkVBox" id="vbox">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="homogeneous">True</property>
        <child>
          <object class="GtkToolbar" id="toolbar">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="toolbar_style">both</property>
            <property name="icon_size">2</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkScrolledWindow" id="scrolledwindow">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="hscrollbar_policy">automatic</property>
            <property name="vscrollbar_policy">automatic</property>
            <property name="shadow_type">etched-in</property>
            <child>
              <object class="GtkTreeView" id="treeview">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="model">liststore</property>
                <property name="vadjustment">adjustment1</property>
              </object>
            </child>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <object class="GtkProgressBar" id="progress">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">2</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>
 

Attachments

  • Screenshot-1.png
    Screenshot-1.png
    49.1 KB · Views: 196
Last edited:
Back