New UI implementation (WIP)
This commit is contained in:
parent
6b892c61c2
commit
f1155f53ec
@ -1,2 +1,2 @@
|
|||||||
webui: gunicorn --error-logfile - --log-level info ostack_validator.webui:app
|
webui: gunicorn --error-logfile - --log-level info ostack_validator.webui:app --bind 0.0.0.0:8000
|
||||||
worker: celery worker --app=ostack_validator.celery:app
|
worker: celery worker --app=ostack_validator.celery:app
|
@ -10,16 +10,16 @@
|
|||||||
<title>Feed Example - Semantic</title>
|
<title>Feed Example - Semantic</title>
|
||||||
|
|
||||||
<link href='http://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700|Open+Sans:300italic,400,300,700' rel='stylesheet' type='text/css'>
|
<link href='http://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700|Open+Sans:300italic,400,300,700' rel='stylesheet' type='text/css'>
|
||||||
<link rel="stylesheet" type="text/css" href="semantic-ui/packaged/css/semantic.css">
|
<link rel="stylesheet" type="text/css" href="/static/semantic-ui/packaged/css/semantic.css">
|
||||||
|
|
||||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.js"></script>
|
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.js"></script>
|
||||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery.address/1.6/jquery.address.js"></script>
|
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery.address/1.6/jquery.address.js"></script>
|
||||||
<script src="semantic-ui/packaged/javascript/semantic.js"></script>
|
<script src="/static/semantic-ui/packaged/javascript/semantic.js"></script>
|
||||||
<script src="lib/angular.min.js"></script>
|
<script src="/static/lib/angular.min.js"></script>
|
||||||
<script src="lib/moment.min.js"></script>
|
<script src="/static/lib/moment.min.js"></script>
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="css/main.css">
|
<link rel="stylesheet" type="text/css" href="/static/css/main.css">
|
||||||
<script src="js/main.js"></script>
|
<script src="/static/js/main.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
|
import os.path
|
||||||
|
|
||||||
from flask import Flask, request, redirect, render_template, json
|
from flask import Flask, request, redirect, render_template, json, send_file
|
||||||
from flask_bootstrap import Bootstrap
|
from flask_bootstrap import Bootstrap
|
||||||
from flask_wtf import Form
|
from flask_wtf import Form
|
||||||
from wtforms import StringField, TextAreaField, SubmitField
|
from wtforms import StringField, TextAreaField, SubmitField, SelectMultipleField
|
||||||
from wtforms.validators import DataRequired
|
from wtforms.validators import DataRequired
|
||||||
|
import wtforms_json
|
||||||
|
|
||||||
from ostack_validator.celery import app as celery, ostack_inspect_task, InspectionRequest
|
from ostack_validator.celery import app as celery, ostack_inspect_task, InspectionRequest
|
||||||
from ostack_validator.common import Issue, MarkedIssue
|
from ostack_validator.common import Issue, MarkedIssue
|
||||||
from ostack_validator.model import Openstack
|
from ostack_validator.model import Openstack
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__, static_folder='../config-validator-ui-concept', static_url_path='/static')
|
||||||
Bootstrap(app)
|
Bootstrap(app)
|
||||||
app.debug = True
|
app.debug = True
|
||||||
app.config.update(
|
app.config.update(
|
||||||
@ -18,16 +20,57 @@ app.config.update(
|
|||||||
)
|
)
|
||||||
app.secret_key = 'A0Zr98j/3fooN]LWX/,?RT'
|
app.secret_key = 'A0Zr98j/3fooN]LWX/,?RT'
|
||||||
|
|
||||||
|
wtforms_json.init()
|
||||||
|
|
||||||
class ValidationLaunchForm(Form):
|
def connect_to_db():
|
||||||
|
mongo_url = os.environ.get("MONGODB_URI") or "mongodb://localhost/rubick"
|
||||||
|
client = MongoClient(mongo_url)
|
||||||
|
return client[mongo_url.split('/')[-1]]
|
||||||
|
|
||||||
|
def get_db():
|
||||||
|
db = connect_to_db()
|
||||||
|
return db
|
||||||
|
|
||||||
|
class Cluster(object):
|
||||||
|
@classmethod
|
||||||
|
def from_doc(klass, doc):
|
||||||
|
return Cluster(doc['name'], doc['seed_nodes'], doc['nodes'], doc['private_key'])
|
||||||
|
|
||||||
|
def __init__(self, id, name, seed_nodes, private_key, nodes):
|
||||||
|
super(Cluster, self).__init__()
|
||||||
|
self.id = id
|
||||||
|
self.name = name
|
||||||
|
self.seed_nodes = seed_nodes
|
||||||
|
self.private_key = private_key
|
||||||
|
self.nodes = nodes
|
||||||
|
|
||||||
|
class RuleGroup:
|
||||||
|
VALIDITY='validity'
|
||||||
|
HA='high-availability'
|
||||||
|
BEST_PRACTICES='best-practices'
|
||||||
|
|
||||||
|
all = [VALIDITY, HA, BEST_PRACTICES]
|
||||||
|
|
||||||
|
class Rule(object):
|
||||||
|
@classmethod
|
||||||
|
def from_doc(klass, doc):
|
||||||
|
return Rule(doc['id'], doc['group'], doc['name'], doc['text'])
|
||||||
|
|
||||||
|
def __init__(self, id, group, name, text):
|
||||||
|
super(Rule, self).__init__()
|
||||||
|
self.id = id
|
||||||
|
self.group = group
|
||||||
|
self.name = name
|
||||||
|
self.text = text
|
||||||
|
|
||||||
|
class ClusterForm(Form):
|
||||||
|
name = StringField('Name', validators=[DataRequired()])
|
||||||
nodes = StringField('Nodes', validators=[DataRequired()])
|
nodes = StringField('Nodes', validators=[DataRequired()])
|
||||||
username = StringField(
|
|
||||||
'Username',
|
|
||||||
default='root',
|
|
||||||
validators=[DataRequired()])
|
|
||||||
private_key = TextAreaField('Private Key', validators=[DataRequired()])
|
private_key = TextAreaField('Private Key', validators=[DataRequired()])
|
||||||
|
|
||||||
launch = SubmitField('Launch validation')
|
class ValidateClusterForm(Form):
|
||||||
|
cluster_id = StringField('Cluster', validators=[DataRequired()])
|
||||||
|
rules = SelectMultipleField('Rules')
|
||||||
|
|
||||||
|
|
||||||
@app.template_filter()
|
@app.template_filter()
|
||||||
@ -42,7 +85,31 @@ def to_label(s):
|
|||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
return redirect('/validation')
|
return send_file(os.path.join(app.static_folder, 'index.html'))
|
||||||
|
|
||||||
|
@app.route('/clusters')
|
||||||
|
def get_clusters():
|
||||||
|
db = get_db()
|
||||||
|
return json.dumps([Cluster.from_doc(doc) for doc in db['clusters'].find()])
|
||||||
|
|
||||||
|
@app.route('/clusters', methods=['POST'])
|
||||||
|
def add_cluster():
|
||||||
|
form = ClusterForm.from_json(json.loads(request.data))
|
||||||
|
if form.validate():
|
||||||
|
cluster = Cluster()
|
||||||
|
form.populate_obj(cluster)
|
||||||
|
get_db()['clusters'].save(cluster)
|
||||||
|
return '', 201
|
||||||
|
else:
|
||||||
|
return json.dumps(dict(errors=form.errors)), 422
|
||||||
|
|
||||||
|
@app.route('/rules/<group>')
|
||||||
|
def get_rules(group):
|
||||||
|
if not group in RuleGroup.all:
|
||||||
|
return 'Unknown rule group "%s"' % group, 404
|
||||||
|
|
||||||
|
rules = [Rule.from_doc(doc) for doc in db['rules'].find({'group': group})]
|
||||||
|
return json.dumps(rules)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/validation', methods=['GET', 'POST'])
|
@app.route('/validation', methods=['GET', 'POST'])
|
||||||
|
@ -2,6 +2,7 @@ spur==0.3.5
|
|||||||
Flask==0.10.1
|
Flask==0.10.1
|
||||||
Flask-Bootstrap>=3.0.0
|
Flask-Bootstrap>=3.0.0
|
||||||
Flask-WTF==0.9.2
|
Flask-WTF==0.9.2
|
||||||
|
WTForms-JSON>=0.2.2
|
||||||
gunicorn==18.0
|
gunicorn==18.0
|
||||||
celery-with-redis>=3.0
|
celery-with-redis>=3.0
|
||||||
# Jinja2==2.7.1
|
# Jinja2==2.7.1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user