Merge pull request #14 from tgerla/play

initial commit of a simple Play webapp and Ansible playbooks (Original a...
pull/63/head
Tim Gerla 11 years ago
commit 60526841a4
  1. 108
      play-webapp/README.md
  2. 2
      play-webapp/hosts
  3. BIN
      play-webapp/images/play_webapp.png
  4. 29
      play-webapp/roles/common/files/RPM-GPG-KEY-EPEL-6
  5. 26
      play-webapp/roles/common/files/epel.repo
  6. 3
      play-webapp/roles/common/handlers/main.yml
  7. 30
      play-webapp/roles/common/tasks/main.yml
  8. 15
      play-webapp/roles/common/templates/iptables.j2
  9. BIN
      play-webapp/roles/webapp/files/ansible-facts-webapp.tgz
  10. 108
      play-webapp/roles/webapp/files/play.initscript
  11. 3
      play-webapp/roles/webapp/handlers/main.yml
  12. 32
      play-webapp/roles/webapp/tasks/main.yml
  13. 8
      play-webapp/site.yml

@ -0,0 +1,108 @@
# Deploying a Play/Scala-based web application with Ansible
- Requires Ansible 1.2
- Expects CentOS/RHEL 6 hosts (64 bit)
### A Primer into Play Framework
----------------------------------
- Play Framework: Play is a pure Java and Scala framework used to develop Web
Applications, It focuses on developer productivity, modern web and mobile
applications, and predictable, minimal resource consumption (CPU, memory,
threads) resulting in highly performant, highly scalable applications, Play
compiles Java and Scala sources directly and hot-reloads them into the JVM
without the need to restart the server.
- Akka: Akka is a toolkit and runtime for building highly concurrent,
distributed, and fault tolerant event-driven applications on the JVM.
- Scala: Scala is a general purpose programming language designed to express
common programming patterns in a concise, elegant, and type-safe way. Scala
smoothly integrates features of object-oriented and functional languages,
enabling developers to be more productive while retaining full interoperability
with Java and taking advantage of modern multicore hardware. Scala makes it
easy to avoid shared state, so that computation can be readily distributed
across cores on a multicore server, and across servers in a datacenter. This
makes Scala an especially good match for modern multicore CPUs and distributed
cloud-computing workloads that require concurrency and parallelism.
## Example Deployment using Ansible
This example deploys a very simple application which takes a hostname as a parameter
from the user and uses Ansible itself to gather and display facts from that machine.
It shows how to deploy a simple Play-based app, as well as how to call out to Ansible
from inside Scala.
Before running the playbook, modify the inventory file 'hosts' to match your
environment. Here's an example inventory:
[webapp_server]
play_server
Run the playbook to deploy the app:
ansible-playbook -i hosts site.yml
Once the playbooks complete, you can check the deployment by logging into the
server console at http://<server-ip>:9000/. You should get a page similar to
image below.
![Alt text](/images/play_webapp.png "webapp")
## Fetching Facts from Hosts
To use the example webapp and fetch facts from a host, enter the hostname of
host as shown in the figure above and press submit. Please note that the
application uses Ansible to gather facts so the hosts should have SSH keys
set up and the host entry should be available in the Ansible inventory file in
/etc/ansible/hosts.
Upon submission, the application should return a valid json consisting the host
facts:
localhost | success >> {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"192.168.2.51"
],
"ansible_all_ipv6_addresses": [
"fe80::5054:ff:fe58:776d"
],
"ansible_architecture": "x86_64",
"ansible_bios_date": "01/01/2007",
"ansible_bios_version": "0.5.1",
"ansible_cmdline": {
"KEYBOARDTYPE": "pc",
"KEYTABLE": "us",
"LANG": "en_US.UTF-8",
"SYSFONT": "latarcyrheb-sun16",
"quiet": true,
"rd_NO_DM": true,
"rd_NO_LUKS": true,
"rd_NO_LVM": true,
"rd_NO_MD": true,
"rhgb": true,
"ro": true,
"root": "UUID=5202a2bc-1a30-424f-855b-5d51a3cba8df"
},
"ansible_date_time": {
"date": "2013-05-25",
"day": "25",
"epoch": "1369483888",
"hour": "17",
"iso8601": "2013-05-25T12:11:28Z",
"iso8601_micro": "2013-05-25T12:11:28.551538Z",
"minute": "41",
"month": "05",
"second": "28",
"time": "17:41:28",
"tz": "IST",
"year": "2013"
},
The facts can also be fetched by making a GET request with following url.
http://<serverip>:9000/inventoryID?hostname=<hostname>

@ -0,0 +1,2 @@
[webapp_server]
webserver1

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

@ -0,0 +1,29 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.5 (GNU/Linux)
mQINBEvSKUIBEADLGnUj24ZVKW7liFN/JA5CgtzlNnKs7sBg7fVbNWryiE3URbn1
JXvrdwHtkKyY96/ifZ1Ld3lE2gOF61bGZ2CWwJNee76Sp9Z+isP8RQXbG5jwj/4B
M9HK7phktqFVJ8VbY2jfTjcfxRvGM8YBwXF8hx0CDZURAjvf1xRSQJ7iAo58qcHn
XtxOAvQmAbR9z6Q/h/D+Y/PhoIJp1OV4VNHCbCs9M7HUVBpgC53PDcTUQuwcgeY6
pQgo9eT1eLNSZVrJ5Bctivl1UcD6P6CIGkkeT2gNhqindRPngUXGXW7Qzoefe+fV
QqJSm7Tq2q9oqVZ46J964waCRItRySpuW5dxZO34WM6wsw2BP2MlACbH4l3luqtp
Xo3Bvfnk+HAFH3HcMuwdaulxv7zYKXCfNoSfgrpEfo2Ex4Im/I3WdtwME/Gbnwdq
3VJzgAxLVFhczDHwNkjmIdPAlNJ9/ixRjip4dgZtW8VcBCrNoL+LhDrIfjvnLdRu
vBHy9P3sCF7FZycaHlMWP6RiLtHnEMGcbZ8QpQHi2dReU1wyr9QgguGU+jqSXYar
1yEcsdRGasppNIZ8+Qawbm/a4doT10TEtPArhSoHlwbvqTDYjtfV92lC/2iwgO6g
YgG9XrO4V8dV39Ffm7oLFfvTbg5mv4Q/E6AWo/gkjmtxkculbyAvjFtYAQARAQAB
tCFFUEVMICg2KSA8ZXBlbEBmZWRvcmFwcm9qZWN0Lm9yZz6JAjYEEwECACAFAkvS
KUICGw8GCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRA7Sd8qBgi4lR/GD/wLGPv9
qO39eyb9NlrwfKdUEo1tHxKdrhNz+XYrO4yVDTBZRPSuvL2yaoeSIhQOKhNPfEgT
9mdsbsgcfmoHxmGVcn+lbheWsSvcgrXuz0gLt8TGGKGGROAoLXpuUsb1HNtKEOwP
Q4z1uQ2nOz5hLRyDOV0I2LwYV8BjGIjBKUMFEUxFTsL7XOZkrAg/WbTH2PW3hrfS
WtcRA7EYonI3B80d39ffws7SmyKbS5PmZjqOPuTvV2F0tMhKIhncBwoojWZPExft
HpKhzKVh8fdDO/3P1y1Fk3Cin8UbCO9MWMFNR27fVzCANlEPljsHA+3Ez4F7uboF
p0OOEov4Yyi4BEbgqZnthTG4ub9nyiupIZ3ckPHr3nVcDUGcL6lQD/nkmNVIeLYP
x1uHPOSlWfuojAYgzRH6LL7Idg4FHHBA0to7FW8dQXFIOyNiJFAOT2j8P5+tVdq8
wB0PDSH8yRpn4HdJ9RYquau4OkjluxOWf0uRaS//SUcCZh+1/KBEOmcvBHYRZA5J
l/nakCgxGb2paQOzqqpOcHKvlyLuzO5uybMXaipLExTGJXBlXrbbASfXa/yGYSAG
iVrGz9CE6676dMlm8F+s3XXE13QZrXmjloc6jwOljnfAkjTGXjiB7OULESed96MR
XtfLk0W5Ab9pd7tKDR6QHI7rgHXfCopRnZ2VVQ==
=V/6I
-----END PGP PUBLIC KEY BLOCK-----

@ -0,0 +1,26 @@
[epel]
name=Extra Packages for Enterprise Linux 6 - $basearch
#baseurl=http://download.fedoraproject.org/pub/epel/6/$basearch
mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-6&arch=$basearch
failovermethod=priority
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6
[epel-debuginfo]
name=Extra Packages for Enterprise Linux 6 - $basearch - Debug
#baseurl=http://download.fedoraproject.org/pub/epel/6/$basearch/debug
mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-debug-6&arch=$basearch
failovermethod=priority
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6
gpgcheck=1
[epel-source]
name=Extra Packages for Enterprise Linux 6 - $basearch - Source
#baseurl=http://download.fedoraproject.org/pub/epel/6/SRPMS
mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-source-6&arch=$basearch
failovermethod=priority
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6
gpgcheck=1

@ -0,0 +1,3 @@
---
- name: restart iptables
service: name=iptables state=restarted

@ -0,0 +1,30 @@
---
# plays common across all servers
- name: Copy the EPEL Repository.
copy: src=epel.repo dest=/etc/yum.repos.d/epel.repo
- name: Create the GPG key for EPEL
copy: src=RPM-GPG-KEY-EPEL-6 dest=/etc/pki/rpm-gpg
- name: install Java and other dependencies
yum: name={{ item }} state=installed
with_items:
- java-1.6.0-openjdk
- java-1.6.0-openjdk-devel
- libselinux-python
- ansible
- zip
- unzip
- wget
- name: Ensure the user has a ssh key
user: name={{ ansible_ssh_user }} generate_ssh_key=yes
- name: Make sure we have the authorized_key for local user
shell: cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys ; touch ~/.ssh/key_authorized
creates=~/.ssh/key_authorized
- name: setup iptables rules
template: src=iptables.j2 dest=/etc/sysconfig/iptables
notify: restart iptables

@ -0,0 +1,15 @@
# Firewall configuration written by system-config-firewall
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -p tcp --dport 9000 -j ACCEPT
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

@ -0,0 +1,108 @@
#!/bin/bash
# chkconfig: 345 20 80
# description: Play start/shutdown script
# processname: play
#
# Instalation:
# copy file to /etc/init.d
# chmod +x /etc/init.d/play
# chkconfig --add /etc/init.d/play
# chkconfig play on
#
# Usage: (as root)
# service play start
# service play stop
# service play status
#
# Remember, you need python 2.6 to run the play command, it doesn't come standard with RedHat/Centos 5.5
# Also, you may want to temporarily remove the >/dev/null for debugging purposes
# Path to play install folder
PLAY_HOME=/opt/play
PLAY=$PLAY_HOME/play
# Source function library.
. /etc/rc.d/init.d/functions
# Path to the JVM
JAVA_HOME=/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/
export JAVA_HOME
# User running the Play process
USER=root
# Path to the application
APPLICATION_PATH=/opt/webapp/
APPLICATION_MODE=prod
#APPLICATION2_PATH=/path/to/application2
#APPLICATION_MODE=prod
# source function library
. /etc/init.d/functions
RETVAL=0
start() {
echo -n "Starting Play service: "
daemon "/opt/webapp/target/start >/dev/null &"
RETVAL=$?
# You may want to start more applications as follows
# [ $RETVAL -eq 0 ] && su -s /bin/sh $USER -c "${PLAY} start ${APPLICATION2_PATH} --%${APPLICATION_MODE} > /dev/null"
# RETVAL=$?
if [ $RETVAL -eq 0 ]; then
echo_success
else
echo_failure
fi
echo
}
stop() {
echo -n "Shutting down Play service: "
(cd ${APPLICATION_PATH} ; ${PLAY} stop .)
RETVAL=$?
if [ $RETVAL -eq 0 ]; then
echo_success
else
echo_failure
fi
echo
}
status() {
test -f ${APPLICATION_PATH}/RUNNING_PID
RETVAL=$?
if [ $RETVAL -eq 0 ]; then
echo play is running as pid `cat ${APPLICATION_PATH}/RUNNING_PID`
else
echo play is not running
fi
}
clean() {
rm -f ${APPLICATION_PATH}/RUNNING_PID
}
case "$1" in
start)
clean
start
;;
stop)
stop
;;
restart|reload)
stop
sleep 10
start
;;
status)
status
;;
clean)
clean
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
esac
exit 0

@ -0,0 +1,3 @@
---
- name: restart play
service: name=play state=restarted

@ -0,0 +1,32 @@
---
- name: copy the webapp
copy: src=ansible-facts-webapp.tgz dest=/opt/
- name: download the play framework
get_url: url=http://downloads.typesafe.com/play/2.1.1/play-2.1.1.zip dest=/opt/play-2.1.1.zip
- name: extract the play framework
command: chdir=/opt/ unzip play-2.1.1.zip
creates=/opt/play-2.1.1
- name: symlink for convenience
file: src=/opt/play-2.1.1 path=/opt/play state=link
- name: extract the webapp folder
command: chdir=/opt/ tar -xvzf ansible-facts-webapp.tgz
creates=/opt/webapp
- name: Build and compile the webapp
shell: chdir=/opt/webapp export PATH=$PATH:/opt/play-2.1.1/; play clean compile stage
creates=/opt/webapp/target
notify: restart play
- name: Copy the ansible hosts file
copy: src=hosts dest=/etc/ansible/hosts
- name: Copy the webapp startup file
copy: src=play.initscript dest=/etc/init.d/play mode=0755
notify: restart play
- name: Start Play
service: name=play state=started enabled=yes

@ -0,0 +1,8 @@
---
# Main Play webapp deployment playbook
- hosts: webapp_server
user: root
roles:
- role: common
- role: webapp