Skip to content

Latest commit

 

History

History
executable file
·
506 lines (401 loc) · 13.5 KB

index.org

File metadata and controls

executable file
·
506 lines (401 loc) · 13.5 KB

Deploying the application on a server

Introduction

This document will illustrate installation of all the dependencies required for setting up the application.

Utility to install dependendent python packages

Here we use the setuptools module from the standard lib, to make a setup.py file, which will install all the python library dependencies.

from setuptools import setup

requires = [
    'Flask',
    'Flask-SQLAlchemy',
    'oursql',
    'Flask-cors',
    'Flask-testing',
    'requests',
    'pyyaml'
]

setup(
    name='feedback',
    version='2.0.0',
    install_requires=requires
)

Program to populate initial data in the database

This is used to run the service in developer’s environment. Otherwise, mostly the database on production is updated from a dump of previous instance.

from runtime.rest.app import create_app
from runtime.config import flask_app_config as config
from runtime.utils.class_persistence_template import db
from runtime.system.system import System

def populate():
    q_type = "radio"

    question_cls = System.delegate.entities['question']

    question1 = question_cls(name="Did you attempt the experiment?",
			     question_type=q_type)

    question2 = question_cls(name="Did the experiment work?",
			     question_type=q_type)

    question3 = question_cls(name="Did you find any bugs in the experiment?",
			     question_type=q_type)

    question4 = question_cls(name="How much did you know about the experiment before doing it in Virtual Labs?",
			     question_type=q_type)

    question5 = question_cls(name="Is this experiment part of your curriculum?",
			     question_type=q_type)

    question6 = question_cls(name="Did this experiment help you understand the concept better?",
			     question_type=q_type)

    question7 = question_cls(name="Will you recommend this experiment to others?",
			     question_type=q_type)

    
    q_type = "textarea"
    question8 = question_cls(name="Please provide any other feedback about this experiment",
			     question_type=q_type)
    
    question9 = question_cls(name="feedback_about_experiment",
			     question_type=q_type)
    question10 = question_cls(name="feedback_about_lab",
			      question_type=q_type)
    question11 = question_cls(name="how_useful_are_labs",
			      question_type=q_type)
    question12 = question_cls(name="suggestions_about_experiment",
			      question_type=q_type)
    question13 = question_cls(name="suggestions_about_lab",
			      question_type=q_type)
    question14 = question_cls(name="suggestions_in_general",
			      question_type=q_type)
    q_type = "radio"
    question15 = question_cls(name="How much did you know about the lab?",
			      question_type=q_type)
    question16 = question_cls(name="Is this lab part of your curriculum?",
			      question_type=q_type)
    question17 = question_cls(name="Did this lab help you understand the concept better?",
			      question_type=q_type)
    
    question19 = question_cls(name="Will you recommend this lab to others?",
			      question_type=q_type)
    question20 = question_cls(name="Did you find any bugs in the lab?",
			      question_type=q_type)
    q_type = "textarea"

    question21 = question_cls(name="Please provide any other feedback about this lab",
			      question_type=q_type)
    question22 = question_cls(name="Please provide any other feedback about Virtual Labs",
			      question_type=q_type)
    q_type = "radio"
    question23 = question_cls(name="Designation",
			      question_type=q_type)
    question24 = question_cls(name="Did you attempt any experiments ?",
			      question_type=q_type)
    question25 = question_cls(name="Please rate your experience",
			      question_type=q_type)
    
    
    question1.save()
    question2.save()
    question3.save()
    question4.save()
    question5.save()
    question6.save()
    question7.save()
    question8.save()
    question9.save()
    question10.save()
    question11.save()
    question12.save()
    question13.save()
    question14.save()
    question15.save()
    question16.save()
    question17.save()
    question19.save()
    question20.save()
    question21.save()
    question22.save()
    question23.save()
    question24.save()
    question25.save()

if __name__ == "__main__":
    db.create_all(app=create_app(config))
    populate()

Program to migrate the data

import requests
import json
import yaml

data_url = "http://data.vlabs.ac.in/feedback"
data_by_id = data_url+"/"
fb_url = "http://localhost:5000/feedback"

fbs = requests.get(data_url).json()
questions = ['feedback_about_experiment', 'feedback_about_lab',
             'how_useful_are_labs', 'suggestions_about_experiment',
             'suggestions_about_lab', 'suggestions_in_general']

for index in range(1, len(fbs)):
     a_url = data_by_id + str(index)
     fb = requests.get(a_url).json()
     fb_x = yaml.safe_load(json.dumps(fb))
     gateway_ip = fb_x['ip']
     user_id = fb_x['user_name']
     print index
     if fb_x['lab'] is None:
        lab_name = "Null"
     else:
        lab_name = fb_x['lab']['name']

     if fb_x['experiment'] is None:
        exp_name = "Null"
     else:
        exp_name = fb_x['experiment']['name']
        print exp_name

     responses = []
     for question in questions:
         if fb_x[question] is None or\
           fb_x[question] is '':
             answer = "Null"
             response = {'name': question,
                           'answers':[answer] }
             responses.append(response)
         else:
            answer = fb_x[question]
            response = {'name': question,
                        'answers':[answer] }
            responses.append(response)

     version = "virtual-labs-feedback-v1.0"
     payload = {'lab_name': lab_name,
                'exp_name': exp_name,
                'key' : 'defaultkey',
                'responses': responses,
                'gateway_ip': gateway_ip,
                'user_id': user_id,
                'version': version
               }

     print payload

     headers = {'Content-Type': 'application/json'}

     response = requests.post(fb_url, data=json.dumps(payload),
                                  headers=headers)
     print response.status_code

Install mysql db, dependencies and python packages

Install OS related Packages

Install pre-requsite dependencies: python-dev, libmysqld-dev, python-setuptools, apache2, libapache2-mod-wsgi

echo "Updating package cache.."
apt-get -y update
if [ $? -ne 0 ]; then
  echo "Updating package cache failed!"
  exit 1;
fi

echo "Installing pre-requisite dependencies.."

apt-get install -y python-dev libmysqld-dev python-setuptools apache2 libapache2-mod-wsgi python-mysqldb

if [ $? -ne 0 ]; then
  echo "FATAL: Installing os-related packages failed!"
  exit 1;
fi

Enable mod wsgi

WSGI mode is needed for one web server to talk to another. In our case, Flask and Apache2 need to communicate. To make this happen, wsgi is enabled.

echo "Enabling the mod WSGI on apache"
a2enmod wsgi
if [ $? -ne 0 ]; then
  echo "FATAL: Unable to enable mod wsgi!"
  exit 1;
fi

Install mysql db

Install mysql db. The idea to generate a random password while installaing the mysql. This same password that is stored in a file is used by the application to connect to the database. Currently, this is not implemented, instead the password is set to root. The database can only be installed by a super user.

DB_PASS_FILE="db_pass.txt"

if [ `id -u` -ne 0 ]; then
  echo "You have to execute this script as super user!"
  exit 1;
fi

echo "Installing MySQL database.."

DBPASS="root"
# Install MySQL Server in a Non-Interactive mode.
echo "mysql-server mysql-server/root_password password $DBPASS" | debconf-set-selections
echo "mysql-server mysql-server/root_password_again password $DBPASS" | debconf-set-selections
apt-get install -y mysql-server

if [ $? -ne 0 ]; then
  echo "FATAL: MySQL installation failed!"
  exit 1;
fi

echo $DBPASS > $DB_PASS_FILE

Install Pip

pip is python package insaller.

echo "Installing PIP"
apt-get remove -y python-pip
apt-get purge python-pip
mkdir -p build/pip
cd build/pip
wget https://pypi.python.org/packages/11/b6/abcb525026a4be042b486df43905d6893fb04f05aac21c32c638e939e447/pip-9.0.1.tar.gz
tar xvf pip-9.0.1.tar.gz
cd pip-9.0.1
python setup.py install
if [ $? -ne 0 ]; then
  echo "FATAL: PIP installation failed!"
  exit 1;
fi

Install Python packages

The flask application needs the following python packages. oursql package is installed from sources. Others are installed using pip package manager.

echo "Installing dependencies.."

mkdir -p build/oursql
cd build/oursql
wget https://pypi.python.org/packages/8c/88/9f53a314a2af6f56c0a1249c5673ee384b85dc791bac5c1228772ced3502/oursql-0.9.3.2.tar.gz#md5=ade5959a6571b1626966d47f3ab2d315
tar xvf oursql-0.9.3.2.tar.gz
cd oursql-0.9.3.2
python setup.py install

pip install Flask Flask-SQLAlchemy Flask-cors Flask-testing oursql requests pyyaml

if [ $? -ne 0 ]; then
  echo "FATAL: Python package installation failed!"
  exit 1;
fi

All the above steps will be part of setup.sh

#!/bin/bash

<<os-pack>>

<<enable-mod-wsgi>>

<<install-mysql>>

<<install-pip>>

<<py-pack>>

exit 0

Configuration

Create the WSGI conduit

Provide one end of the flask application to the apache server for it to route the traffic to flask application.

import sys, os

BASE_DIR = BASE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)))

#sys.path.insert(0, BASE_DIR)
sys.path.insert(0, "/var/www")

from runtime.rest.app import create_app
from runtime.config import flask_app_config as config

application = create_app(config)

Configure the application

Configuring the application involves:

  1. set up the configuration parameters of the application. These include:
    Database parameters
    database userId, Password, dbname, dbhost
    Cross origin pameters
    Whitelist IPs, allowed origins. These parameters are not set currently.
if [ `id -u` -ne 0 ]; then
  echo "You have to execute this script as super user!"
  exit 1;
fi

ABS_PATH_DS=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )

update_app_config () {
  CONFIG_FILE="../runtime/config/flask_app_config.py"
  DB_USER="root"
  DB_PASS=$(cat db_pass.txt)
  DB_NAME="feedback"
  DB_SERVER="localhost"

  # the list of white-listed IPs for POST/PUT requests to data service
  WHITELIST_IPS="['127.0.0.1']"

  # the list of allowed domains for CORS
  ALLOWED_ORIGINS="['*']"

  echo "Updating config.py.."
  # Update parts of the DB URI
  sed -i "s/<userid>/$DB_USER/" $ABS_PATH_DS/$CONFIG_FILE
  sed -i "s/<password>/$DB_PASS/" $ABS_PATH_DS/$CONFIG_FILE
  sed -i "s/<servername>/$DB_SERVER/" $ABS_PATH_DS/$CONFIG_FILE
  sed -i "s/<db_name>/$DB_NAME/" $ABS_PATH_DS/$CONFIG_FILE
  # update SQLALCHEMY_ECHO
  sed -i "s/^SQLALCHEMY_ECHO.*$/SQLALCHEMY_ECHO = False/" $ABS_PATH_DS/$CONFIG_FILE

  # update WHITELIST_IPS
  #sed -i "s/^WHITELIST_IPS.*$/WHITELIST_IPS = $WHITELIST_IPS/" $CONFIG_FILE
  # update ALLOWED_ORIGINS
  #sed -i "s/^ALLOWED_ORIGINS.*$/ALLOWED_ORIGINS = $ALLOWED_ORIGINS/" $CONFIG_FILE

  # NOTE: this is hardcoded now..somehow the log file when dynamically created
  # is owned by root. then the app fails to run.. hence the following is
  # necessary
}

Configre the web server

The wsgi conduit is configured with the apache. This is necessary since apache web server has to forward the traffic on the / to the feedback application that uses flask web server.

update_apache_config() {
  PROC_NAME="feedback"
  WSGI_SCRIPT="feedback.wsgi"
  APACHE_VHOST_FILE="/etc/apache2/sites-available/000-default.conf"

  sed -i "/<\/VirtualHost>/i \
    WSGIScriptAlias / $ABS_PATH_DS/$WSGI_SCRIPT
  " $APACHE_VHOST_FILE

}

Create the database

An empty database is created for the application to use.

setup_db() {
  echo "Creating database: $DB_NAME"
  mysql -u $DB_USER -p$DB_PASS -Bse "create database $DB_NAME;"
  if [ $? -ne 0 ]; then
    echo "Failed to create database $DB_NAME"
    exit 1;
  fi

}

All the above steps will be part of configure.sh

#!/bin/bash

<<configure-app>>

<<configure-wserver>>

<<create-db>>

update_app_config
if [ $? -ne 0 ]; then
  echo "FATAL: Failed to update application flask_app_config.py"
  exit 1;
fi

update_apache_config
if [ $? -ne 0 ]; then
  echo "FATAL: Failed to update apache config"
  exit 1;
fi

service apache2 restart
export PYTHONPATH="/var/www"
if [ $? -ne 0 ]; then
  echo "FATAL: Failed to restart apache2 webserver"
  exit 1;
fi


setup_db
if [ $? -ne 0 ]; then
  echo "FATAL: Failed to create database"
  exit 1;
fi

exit 0

Tangle

print "deployment package"