diff --git a/Procfile b/Procfile
new file mode 100644
index 0000000..e256fa4
--- /dev/null
+++ b/Procfile
@@ -0,0 +1,4 @@
+webui: gunicorn --error-logfile - --log-level info ostack_validator.webui:app
+redis: redis-server
+worker: celery worker --app=ostack_validator.celery:app
+
diff --git a/Vagrantfile b/Vagrantfile
new file mode 100644
index 0000000..2e203d4
--- /dev/null
+++ b/Vagrantfile
@@ -0,0 +1,15 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+Vagrant::Config.run do |config|
+ config.vm.box = "ubuntu12.04-server-amd64"
+ # config.vm.box_url = "http://domain.com/path/to/above.box"
+
+ # config.vm.forward_port 80, 8080
+ config.vm.forward_port 5000, 5000
+
+ config.vm.provision :chef_solo do |chef|
+ chef.cookbooks_path = ["vagrant/cookbooks"]
+ chef.add_recipe "openstack-validator"
+ end
+end
diff --git a/ostack_validator/celery.py b/ostack_validator/celery.py
new file mode 100644
index 0000000..2a44172
--- /dev/null
+++ b/ostack_validator/celery.py
@@ -0,0 +1,22 @@
+from __future__ import absolute_import
+import os
+import time
+
+from celery import Celery
+
+broker_url = os.getenv('CELERY_BROKER_URL', 'redis://localhost:6379/0')
+backend_url = os.getenv('CELERY_RESULT_BACKEND', broker_url)
+
+app = Celery('ostack_validator', broker=broker_url, backend=backend_url)
+app.conf.update(
+ CELERY_TRACK_STARTED=True
+)
+
+@app.task
+def ostack_inspect_task(nodes, username, password=None, private_key=None):
+ time.sleep(10)
+ return username[::-1]
+
+if __name__ == '__main__':
+ app.start()
+
diff --git a/ostack_validator/templates/validation_form.html b/ostack_validator/templates/validation_form.html
new file mode 100644
index 0000000..4bfc417
--- /dev/null
+++ b/ostack_validator/templates/validation_form.html
@@ -0,0 +1,13 @@
+{% extends "bootstrap/base.html" %}
+{% import "bootstrap/wtf.html" as wtf %}
+
+{% block title %}OpenStack Validator{% endblock %}
+
+{% block content %}
+
+
OpenStack Validator
+ {{ wtf.quick_form(form, action='/validation', method='POST', button_map={'launch': 'primary'}) }}
+
+
+{% endblock %}
+
diff --git a/ostack_validator/webui.py b/ostack_validator/webui.py
new file mode 100644
index 0000000..c16779e
--- /dev/null
+++ b/ostack_validator/webui.py
@@ -0,0 +1,53 @@
+from flask import Flask, request, redirect, render_template, json
+from flask_bootstrap import Bootstrap
+from flask_wtf import Form
+from wtforms import StringField, TextAreaField, SubmitField
+from wtforms.validators import DataRequired
+
+from ostack_validator.celery import app as celery, ostack_inspect_task
+
+app = Flask(__name__)
+Bootstrap(app)
+app.debug = True
+app.config.update(
+ WTF_CSRF_SECRET_KEY = 'foo bar baz'
+)
+app.secret_key = 'A0Zr98j/3fooN]LWX/,?RT'
+
+
+class ValidationLaunchForm(Form):
+ nodes = StringField('Nodes', validators=[DataRequired()])
+ username = StringField('Username', default='root', validators=[DataRequired()])
+ private_key = TextAreaField('Private Key', validators=[DataRequired()])
+
+ launch = SubmitField('Launch validation')
+
+@app.route('/')
+def index():
+ return redirect('/validation')
+
+@app.route('/validation', methods=['GET', 'POST'])
+def launch_validation():
+ form = ValidationLaunchForm()
+ if form.validate_on_submit():
+ nodes = form.nodes.data.split(' ')
+ username = form.username.data
+ private_key = form.private_key.data
+
+ job = ostack_inspect_task.delay(nodes=nodes, username=username, private_key=private_key)
+
+ return redirect('/validation/%s' % job.id)
+ else:
+ return render_template('validation_form.html', form=form)
+
+@app.route('/validation/')
+def job(id):
+ job = celery.AsyncResult(id)
+ if job.ready():
+ return 'Result is %s' % job.result
+ else:
+ return 'State is %s' % job.state
+
+if __name__ == '__main__':
+ app.run(host='0.0.0.0', debug=True)
+
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..bb837a4
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,8 @@
+spur==0.3.5
+Flask==0.10.1
+Flask-Bootstrap>=3.0.0
+Flask-WTF==0.9.2
+gunicorn==18.0
+celery-with-redis>=3.0
+# Jinja2==2.7.1
+
diff --git a/vagrant/cookbooks/openstack-validator/recipes/default.rb b/vagrant/cookbooks/openstack-validator/recipes/default.rb
new file mode 100644
index 0000000..cedff4d
--- /dev/null
+++ b/vagrant/cookbooks/openstack-validator/recipes/default.rb
@@ -0,0 +1,8 @@
+package 'redis-server'
+package 'python-pip'
+
+bash 'Install python dependencies' do
+ code 'pip install -r requirements.txt'
+ cwd '/vagrant'
+end
+