Penesive Random Experiments

Deploying app to heroku with mongodb - Part 1

As part of the mongodb course, one of the assignment required to complete the backend of the blog.I wanted to get my hands a bit more dirty and so i decided to deploy the entire application to heroku with mongolab as the backend.The following are the steps that i followed to make the site work in heroku and mongolab.

Deploying the site to Heroku

Heroku has build packs which are essentially set of language tools that are needed for deploying your application. Since in heroku we deploy application by pushing code, build packs provide the basic infrastructure thats needed to compile/interpret your code.

  1. Install the heroku toolbet as it provides a set of command line tools for deploying application easily to heroku.

  2. login to heroku using the following

        $ heroku login
         Enter your Heroku credentials.
         Email: adam@example.com
         Password (typing will be hidden):
         Authentication successful.
    
    
  3. Create a new application using ** heroku create ** .This creates a dyno that can be used to deploy your application.

        Pradheep (master #) hw4-3 $ heroku create
        Creating infinite-shore-9738... done, stack is cedar-14
        https://infinite-shore-9738.herokuapp.com/ | https://git.heroku.com/infinite-shore-9738.git
        Git remote heroku added
    
  4. Now build your application and test it in your local box to make sure that its working as expected and commit all the changes to master.

  5. Push the changes changes to heroku using the command

         Pradheep (master) hw4-3 $ git push heroku master
         Counting objects: 44, done.
         Delta compression using up to 4 threads.
         Compressing objects: 100% (41/41), done.
         Writing objects: 100% (44/44), 4.39 MiB | 664.00 KiB/s, done.
         Total 44 (delta 8), reused 0 (delta 0)
         remote: Compressing source files... done.
         remote: Building source:
         remote: 
         remote: -----> Python app detected
         remote: -----> Installing runtime (python-2.7.10)
         remote: -----> Installing dependencies with pip
         remote:        Collecting bottle (from -r requirements.txt (line 1))
         remote:          Downloading bottle-0.12.9.tar.gz (69kB)
         remote:        Collecting pymongo (from -r requirements.txt (line 2))
         remote:          Downloading pymongo-3.1.1.tar.gz (462kB)
         remote:        Installing collected packages: bottle, pymongo
         remote:          Running setup.py install for bottle
         remote:          Running setup.py install for pymongo
         remote:        Successfully installed bottle-0.12.9 pymongo-3.1.1
         remote: 
         remote: -----> Discovering process types
         remote:        Procfile declares types -> web
         remote: 
         remote: -----> Compressing... done, 40.3MB
         remote: -----> Launching... done, v3
         remote:        https://infinite-shore-9738.herokuapp.com/ deployed to Heroku
         remote: 
         remote: Verifying deploy.... done.
         To https://git.heroku.com/infinite-shore-9738.git
          * [new branch]      master -> master
    
  6. Now the application is deployed to heroku, we need to make sure that its working and we can open the application using

    Pradheep (master) hw4-3 $ heroku open
    Opening infinite-shore-9738... done

7.When i opened the application page it was throwing page not found error.So in order to figure out the error we can see the logs by using command


Pradheep (master) hw4-3 $ heroku logs
2015-12-01T18:54:17.334789+00:00 heroku[web.1]: Starting process with command `python ./blog.py`
2015-12-01T18:54:19.342818+00:00 app[web.1]: Bottle v0.12.9 server starting up (using WSGIRefServer())...
2015-12-01T18:54:19.342862+00:00 app[web.1]: Listening on http://localhost:8082/
2015-12-01T18:54:19.342874+00:00 app[web.1]: Hit Ctrl-C to quit.
2015-12-01T18:54:19.342876+00:00 app[web.1]: 
2015-12-01T18:55:17.799116+00:00 heroku[web.1]: Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch  <--------------- This is error 
2015-12-01T18:55:17.799116+00:00 heroku[web.1]: Stopping process with SIGKILL
2015-12-01T18:55:18.475966+00:00 heroku[web.1]: State changed from starting to crashed
2015-12-01T18:55:18.458035+00:00 heroku[web.1]: Process exited with status 137
2015-12-01T18:55:19.155515+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=infinite-shore-9738.herokuapp.com request_id=79d4746f-8a61-409e-b970-49c99f7ef3c3 fwd="72.177.207.73" dyno= connect= service= status=503 bytes=
2015-12-01T18:55:19.701594+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=infinite-shore-9738.herokuapp.com request_id=a38c3ce7-eb7e-4b88-ad3d-a79eabbe0b61 fwd="72.177.207.73" dyno= connect= service= status=503 bytes=

  1. Looking at the logs above its clear that we are not binding to the correct port. Revel applications must bind to the port that the heroku application specify using the enviornment variable $PORT. So we modify the application to make it listen to the $PORT.
bottle.run(host='0.0.0.0', port=int(os.environ['PORT']))  # Start the webserver running and wait for requests                                                                                                  

In the above example, as the default application used bottle i modified the application a bit to use the enviornment variable $PORT

  1. Heroku also needs a Procfile to help it understand how it needs to start the application.

     Pradheep (master *) hw4-3 $ cat Procfile 
     web: python ./blog.py 
    

In the above, the * web * specifies that the application needs to accept traffic from outside.

  1. The application must also have a * requirements.txt * to specify the files that are needed to deploy the application.

    ``` Pradheep (master *) hw4-3 $ cat requirements.txt bottle pymongo

Now push the changes again using git push and look at the heroku logs to see what went wrong and fix it untill the application is running properly. 

Also make sure that you are trying to access a page that is doesnot use database query as we have not yet connected a mongodb to the application yet.

11. To open the heroku application logs or login to the application use * heroku run bash* command as below 

Pradheep (master *) hw4-3 $ heroku run bash Running bash on infinite-shore-9738… up, run.5908


12. If you application has crashed and you need to start it again then use the * ps:webscale * option

heroku ps:scale web=1

``` The default free tier provides only 1 tier so set the value is set to 1 above.

In the next post i will discuss how i hooked up mongolab to our blog application.

Addding Travis for CI of redis

For those people who don’t know what CI is, continue reading this paragraph . The general way most development team used to work earlier was , team members develop their code in isolation in separate branches and after everyone is done , the integration team would pull all the changes and integrate everything.This is a hard process, as there are merge conflicts due to overlapping changes,memory leaks detection becomes hard as loads of changes, bug isolation is hard as no one is sure which code introduced it and so on. In general, significant dev team was spent on integration and testing.However,CI makes all these process simple by automating tests with unit tests, integration tests so that bugs are detected early and in isolation.More on CI here

But running Continuous integration, for developers of open source was bit difficult.One has to setup a Jenkins server locally and run it for every merge. It would be better, if we are able to run CI on each pull requests that others send. The solution is Travis and it works with all github projects out of the box.

I was excited to see Travis support by default in github and free for all projects that are open sourced. I decided to give it a shot. Though i could have done a small code to test its no fun but nothing beats automating a full project.So looking around i found redis has not updated itself with travis support. Redis in fact runs all the tests in http://ci.redis.io/ .I felt running these tests as part of the each pull requests to redis would be awesome. So here is how i got the basic travis setup to work.

Adding travis to any project in github is easy. Just add .travis.yml in the top directory of your repo and you are done.

So the first step in .travis.yml file is to define the language and the compiler you want the project to compile. Natively travis support gcc and clang. So i added the below lines .travis.yml

language: c 

compiler:
  - clang
  - gcc

Travis provides travis-lint that can check for errors in travis.yml file . You can install travis-lint using the following command

gem install travis-lint

And then you can check .yml file using the command

travis-lint [path to your .travis.yml]

Adding the above changes to the repo and pushing it to the github was all the basic configuration that was needed.Then i had to add my repo to travis.The steps to add a repo into travis is very straight forward and step by step instructions can be found in this site

The travis.yml file has different sections similar to rpm packaging to control the build, test and deployment. To build and test your application the script sections must contain your application specific build and test specification.So i added the below lines to .travis.yml

script:
  - make
  - make test

Pushing the above to github automatically triggers travis to run the test.Result of one such build is here.Travis was reporting error and looking at the logs it was clear that the setup needed tcl and it was not available causing the test to fail.So the next step was to add tcl package.

Travis tests all the applications on top of Ubuntu and installs some of language specfic packages.But not all packages are installed and one can install any package by using the apt-get command.Since the packages must be added before the make test, i added install tcl 8.5 in before_script section to .travis.yml

 before_script:
 - sudo apt-get install -qq tcl8.5

The before_script section, as you might have guessed, is executed before the script section.This installs tcl and since there was no dependency problem anymore tests ran successfully.If you look at the link you will see tha the tests are run both in clang and gcc. This is because we had asked for clang and gcc as compilers in the compiler section.

The next step was to make the code run in both in OSX and linux.Currently travis only supports 64 bit OS Linux and support for OSX is in beta. There is plans to add support for FreeBSD.Back to what I was doing, to add OS support i added the following lines

os:
   - linux
   - osx

But there was one more thing, i need to install tcl for OSX. So i ended up modifying the before_script with the following lines

 before_script:
    - if [ "$TRAVIS_OS_NAME" == "linux" ]; then  sudo apt-get install -qq tcl8.5; fi
    - if [ "$TRAVIS_OS_NAME" == "osx" ] ; then brew update; brew tap homebrew/dupes; brew install tcl-tk;fi

Brew is the unofficial package manager for OSX.

Cautious readers would notice that i added brew tap homebrew/dupes.This is because OSX comes preloaded with tcl and in order to make sure that users dont override the default package, brew uses the dupes to make sure that people who are installing knows what they are doing.

Finally i sent a pull request to redis and i am currently not sure when it will get integrated.The entire pull request is here.The changes are the basic and if the pull request is accepted i am planning to add matrix build and also move the changes to new test infrastructure.

The entire .travis.yml that was pulled

language: c 
os:
   - linux
   - osx

compiler:
  - clang
  - gcc

before_script:
    - if [ "$TRAVIS_OS_NAME" == "linux" ]; then  sudo apt-get install -qq tcl8.5; fi
    - if [ "$TRAVIS_OS_NAME" == "osx" ] ; then brew update; brew tap homebrew/dupes; brew install tcl-tk;fi

script:
  - make
  - make test

Useful links

  1. Travis ci
  2. Travis Documentation

go installation in mac using brew

I wnated to get my hands dirty with go and so i thought i would install it in mac.So as usual i was trying to install using brew.The installation went smooth but whenever i was trying to install a package i was thrown an error as below

Pradheep ~ $ go get gopkg.in/mgo.v2
package gopkg.in/mgo.v2
	imports bytes: unrecognized import path "bytes"
package gopkg.in/mgo.v2
	imports crypto/hmac: unrecognized import path "crypto/hmac"
package gopkg.in/mgo.v2
	imports crypto/md5: unrecognized import path "crypto/md5"
package gopkg.in/mgo.v2
	imports crypto/rand: unrecognized import path "crypto/rand"
package gopkg.in/mgo.v2
	imports crypto/sha1: unrecognized import path "crypto/sha1"
package gopkg.in/mgo.v2
	imports encoding/base64: unrecognized import path "encoding/base64"
package gopkg.in/mgo.v2
	imports encoding/binary: unrecognized import path "encoding/binary"
package gopkg.in/mgo.v2
	imports encoding/hex: unrecognized import path "encoding/hex"
package gopkg.in/mgo.v2
	imports encoding/json: unrecognized import path "encoding/json"
package gopkg.in/mgo.v2
	imports errors: unrecognized import path "errors"
package gopkg.in/mgo.v2
	imports fmt: unrecognized import path "fmt"
package gopkg.in/mgo.v2
	imports io: unrecognized import path "io"
package gopkg.in/mgo.v2
	imports math: unrecognized import path "math"
package gopkg.in/mgo.v2
	imports net/url: unrecognized import path "net/url"
package gopkg.in
.....

The problem is that both the GOPATH and GOROOT was not set properly and PATH was not updated correctly.After several trial and error methods and of course at last google to the rescue i was able to finally get it working

For bash put the below in ~/.bashrc

# don't forget to change your path correctly!

export GOPATH=$HOME/golang
export GOROOT=/usr/local/opt/go/libexec
export PATH=$PATH:$GOPATH/bin
export PATH=$PATH:$GOROOT/bin

For zsh which is the default shell in mac (~/.zshrc)


# don't forget to change your path correctly!

export GOPATH=$HOME/golang
export GOROOT=/usr/local/opt/go/libexec
export PATH=$PATH:$GOPATH/bin
export PATH=$PATH:$GOROOT/bin

You can of course change the GOPATH to any of your project specific workspace.Just update the corresponding path in your folder you are interested.

Just make sure that there is no space in the folder path as i find it causes too much problem :(. The easier way to get around is by soft linking the destination path to the one which has no space :)

I found the above solution in this gist