19 June 2013

Grails Project: Using Grails as a UI Wrapper to a CLI like SIPP



For many people this project is going to be Easy.  It's very simple.

The idea for this came from a situation at work.

I am a sole user of a command line SIP/VOIP tool called SIPP.  The tool is incredibly complex. It took me many weeks to get it up and running, but I know it well now and use it often. 

However, other members of the team could also benefit form the use of the tool, but some members of the office may not have a computer background, or SSH access to run the command line tool itself.

You may have command line tools you'd like to offload to others, but don't want them to make mistakes... so maybe using a GUI to wrap up the commands and constrain the options is useful for you as well.

To that end, I came up with an idea to play with a bit of Grails and get a Web Application stood up, that would power the command line tool itself.

The Setup (I wont cover these aspects):

First, in my case the tool (SIPP) needs to be installed
Second, Grails needs to be installed on the same environment

What I'll cover:

Building the Grails app
Making the calls to run the command line tool
Making the calls run in the background using Executor
Daemonize the app so it can run/stop and start on restart.

Pulling in server stats via Cacti will be covered in a different post.

Building the Grails app

This is pretty simple. There's not much difficulty in this task. 
So first things first... we need to know the command line tool parameters.  In my case I'm using SIPP.  The most common parameters I use are:
sipp -s [DNIS] [PROXY] -r [CALLS PER SECOND] -m [MAX CALLS] -sf [SCENARIO FILE] -d [DELAY OF THE CALL]

So I'll need to make a application that has a form with user selects for those items.  The PROXY in my case is going to be hard coded, as I don't want people accidentally sending traffic to the wrong IP/Host. 

In my case I only foresaw the need for one controller and a couple Views.  If you're not familiar with MVC, you might want to read up on it a bit.  Basically the Controller will handle logic, the View will be the display/rendering aspect of the app and the Model is the data handling.

So I'm going to make a super easy app that has one controller, and some views.

So lets start:
  1. Make the grails app.  Go to a folder of your choice, and type grails create-app  At the prompt for a name, give it a name and hit enter.
  2. It will now make a folder with the name of the Grails App that you just created.  Go ahead and enter the folder - cd [APP NAME]
  3. In the app folder create a controller with the command grails create-controller At the prompt for a name, give it a name and hit enter.
Let's launch an IDE to edit this... I  use Spring's Grails Tool Suite.  I love Intellij, but the community (free) edition doesn't currently support Grails.  Only the paid ($500+) version does.

Import the project you just made.  In Grails Tool Suite it's File / Import / Project - Grails.

Once imported, lets edit the controller.


In the Project Tree in your IDE you'll see [web-app name]/controllers/[project-name]/[your-controller]

Go ahead and open that up in the IDE.

You'll have some code with a index action like
class SippcallController {
     def index() {

                    }
  }

I made a action that was more useful for what I'm doing.  So I have:
def callLogic() {
    def sipp = "sipp -s 18008888888 10.98.1.1 -r 1 -m 1 -sf uac.xml -d 1200".execute()
  }

Initially I just put in the actual command to dial a number via SIPP.  Then I tested it... it worked... so at that point I replaced all the parameters with values that will be coming from a user Form.  So the action became:

def callLogic() {
    def sipp = "sipp -s ${params.phoneNumber} 10.98.1.1 -r $(params.Rate} -m ${params.Max} -sf ${params.scenario} -d ${params.delay}".execute()

[view_darta:sipp.text]
  }

That last bit, [view_data:sipp} is a model I can access in a View or web page.  In a webpage of this app, I can just have ${view_data} and it will reference the output of the SIPP sip call itself.


Creating the Web Form for User Input


Now lets go ahead and edit the index.gsp file.  It's listed in the Project Explorer as: Project Name / Views /

Once that's open, you'll notice the basic sample page that Grails creates with each new application.  I removed all the Grails code within the Body Tags and replaced it with a form.... using g tags.

My form is like this ( the Grails tags are highlighted in green):
        <g:form name="callForm" controller="makeCall" action="callLogic">
        <p><h3>Phone number:</h3></p>
        <g:select name="phoneNumber" from = "${['12132830920', '12132830912', '12132830591', '13237549121'] }" value="12132830920" noSelection="['':'-Choose the phone number -']"/>
        <p><h3>Calls Per Second:</h3></p>
        <g:select name="cps" from="${1..30}" value="1"/>
        <p><h3>Max Calls:</h3></p>
        <g:select name="maxCount" from="${['1', '10', '50', '100', '500', '1000', '2000']}" value="1"/>
        <p><h3>How Long to Hold Audio Open (ms):</h3></p>
        <g:select name="delay" from="${['1200', '5000', '10000', '20000', '60000', '120000']}" value="1000"/>
          <p><h3>Scenario:</h3> </p>
          <g:select name="scenario" from ="${['uac.xml', 'codec_speex.xml', 'codec_g729.xml', 'carrier_sprint.xml'] }"
            value = "uac.xml" />

        <g:actionSubmit value="Place Call" action="callLogic"/>
        </g:form>

It's pretty easily readable. A few things to note:
  • To handle multiple selections in a dropdown, you can use a function or just list them out like I did here.  A function is superior, but this was quick and easy to set up a test.  you make the g tag a select and you add from with "${['value1', 'value2']}" and so forth.  
  • Like a regular form, you can set the default value with value="value1"  
  • Make sure the form references your controller and action correctly.
 If done right, this should send the field data to your Controller and Action correctly... which would run the command line with the parameters supplied via this form. 

Creating an Output View

 

In my case I decided to make another page that would handle the output form the controller.  It's the same name as the controller.  So in the [project]/views/[subfolder]/callLogic.gsp page I will put some data from the SIPP tool....

I could add ${view_data}, and it would display the output from the SIPP test into the page itself.

In my case, as you can see in the screenshot, I'm pulling in server stats via Cacti.  It's too much to go into in this blog post, but I set up Cacti on the linux VM here that I'm using, to pull snmp data from the box I'm driving the SIPP load to.

When I first did this, the page loaded fine, but it would wait for SIPP to finish, then output the data to the view.

I now send the call to a background job using the Executor plugin for grails, and using the runAsync closure around the SIPP call in the controller.  This way once a user submits the form they load on the results page.  The data is still being collected and will need to be updated later onto the page (I haven't worked that part out yet.)

Installing Executor (to run background jobs)

In case you need this, here's how it works... you do a grails install-plugin executor
After it installs, you can then see the plugin listed in your IDE's project tree like so: project/plugins.  You can now use the methods the plugin gives access to.

In my case, I just wanted the runAsync method.  so back in my controller I added it like this:

def callLogic() {
    def sipp = "sipp -s ${params.phoneNumber} 10.98.1.1 -r $(params.Rate} -m ${params.Max} -sf ${params.scenario} -d ${params.delay}".execute()

runAsync{
[view_darta:sipp.text]
}
  }

This allows the output to be collected in the background. 

The part I haven't worked out yet, is getting a push or polling mechanism set up to get that data once it's ready.

Daemonizing It
I wanted to be able to start and stop this thing, so I set up a job in the /etc/init.d/ folder and called it sippgui  in that file is a series of commands, such as:

start() {
        cd /sippcall

        /sippcall/grails run-app -Dserver.port=8090 &
        sudo touch /var/lock/subsys/sippgui
        echo

}


You'll want to do something similar to stop it.

At that point it can be added to cron, or run manually with /etc/init.d/sippgui start|stop|restart, etc.

Btw. the -Dserver.port=8090 is how i'm setting the port it's using. 

Opening the Port

That's it... Oh WAIT one more thing...

If you can't get this App to load, you may need to open your firewall to allow traffic to this port (i.e. 8090.)  In my case I couldn't  use 8080, so I used a non standard port. I had to modify the IPTABLES to allow this. 

CENTOS uses IPTABLES so that's my solution. I won't go into details on it, just know that you'll need to open any non standard port and may need to google how to do that on whatever OS you're using. 


02 June 2013

Setting up Raspberry Pi

This is a departure from the main crux of this blog.  But I wanted to gather some notes on my pitfalls I encountered with setting up a Raspberry Pi device.

Hardware and SD Card Set Up


I had the version 2 B 512 version of the Pi.
I used a PNY 16GB class 6 SD card
I used a solar/electric battery to power it
I used a usb keyboard
and a standard hdmi cable

I started this all off by downloading the official Raspberry "wheezy" distro (2013-05-25-wheezy-raspbian) from the direct download link.  However, I couldn't unzip it on windows... although the download was the correct size, windows' default unarcher gave me a "can't read" this file error.  However, 7zip would read it and uncompress it... I figured this was just a problem with Windows.

Butut when I used the img file that it produced to drop on the SD card... it corrupted the SD card.

Again - this was the direct download official link of the "wheezy" distro.  

At this point he SD card would read "18mb left of 56mb" yet this was a 16Gig card.  I freaked out a bit thinking the card was now damaged.  However I read that it only needs to be reformatted....

I tried to reformat using Windows' reformat tool (right click / format)... but the card would always read "56mb avail."

I in fact had to now download the official SD formatter... ugh.  Ok, Now that got me back to 16gigs.

I tried multiple downloads from that direct download link - all with the same problem!

Then I tried the torrent.

They recommend the torrent, but I hate using torrents.  I always end up with spyware from the torrent clients... anyway, I installed bit torrent and downloaded the distro via the torrent, and then uninstalled bit torrent afterwards.

I did get the torrent to download, it was about 10x faster then the direct link.  I also was able to unzip it fine without the error's encountered from the direct link.

I put the SD card back in the Pi, and plugged it back in... It booted up great.

Configuration

When it boots up successfully you'll see something resembling the old PC Bios menu.  This is how you'll configure your Raspberry Pi.

At the configuration screen, you'll want to:
1. set the thing to use the entire space on the SD card, it's the first option in this boot menu.
2. after that, if you want to boot to a desktop, go to that option, if you use a console only, skip it.
3. To turn on SSH (so you can remote into the box via SSH) you need to go to advanced settings and then choose SSH and then Enable.
4. If this is a public facing device, you might want to change the password as well - it's a option on the boot menu.
5. I also changed the hostname (it defaults to 'raspberrypi')

After that I chose to finish and reboot.

From here on out, you'll log in as your user "pi" with the password you picked... or use the default (raspberry.)

SSH

To SSH to this box, first get it's IP by running ifconfig from the command line.  You'll see "eth0" and in there a line inet addr:.  take that address.

From another box, using either terminal on mac, or Putty/supper putty on PC, you can just ssh over to:
ssh [ip]
login as user pi and input your pass.

Installing Software from the Command Line

If you're used to installers in Linux (like Centos' YUM) then you'll get the same thing here, but it's apt-get.  You'll sudo each command like this.  So: sudo apt-get iw tshark would install iw and tshark (for packet sniffing.)

Find the tools you want and they should give you the proper apt-get install commands.

Shutting Down the Raspberry Pi


Also another important thing.  The official site for Raspberry Pi, says to shut it down you just "unplug it" from what I've read this could damage the SD card.  So... you must run an official shutdown:

sudo shutdown -h now
From the UI, you click the red icon and choose shutdown.  Wait for the proper screen statement "system halted," and then remove the power cable.