commit
2df2b47b4e
@ -1,8 +1,7 @@
|
||||
RefStack
|
||||
========
|
||||
|
||||
Vendor-facing API for registration of interop-compliance endpoints and credentials for on-demand testing.
|
||||
Vendor-facing API for registration of interop-compliance endpoints and credentials for on-demand testing.
|
||||
|
||||
Running at http://refstack.org
|
||||
See (living) documentation at https://etherpad.openstack.org/RefStackBlueprint
|
||||
|
||||
|
@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (c) 2013 Piston Cloud Computing, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
# os.environ['YOURAPPLICATION_CONFIG'] = '/var/www/yourapplication/application.cfg'
|
||||
from refstack.app import app
|
@ -1,15 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2013 Piston Cloud Computing, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
@ -1,15 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2013 Piston Cloud Computing, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
@ -14,9 +14,12 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import os
|
||||
from flask import Flask, session
|
||||
|
||||
"""Common Flask app config."""
|
||||
|
||||
import os
|
||||
|
||||
import flask
|
||||
|
||||
|
||||
#db_path = os.path.abspath(
|
||||
@ -24,7 +27,9 @@ from flask import Flask, session
|
||||
|
||||
db_path = 'tmp'
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
|
||||
|
||||
app.config['MAILGUN_KEY'] = '#@#@#@#@'
|
||||
app.config['MAILGUN_DOMAIN'] = 'refstack.org'
|
||||
|
@ -14,8 +14,6 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
"""
|
||||
"""
|
||||
import sys
|
||||
import argparse
|
||||
from textwrap import dedent
|
||||
@ -26,8 +24,8 @@ from refstack.common.tester import Tester
|
||||
|
||||
|
||||
def add(args):
|
||||
"""adds a cloud
|
||||
|
||||
"""adds a cloud
|
||||
|
||||
refstack add --endpoint='http://127.0.0.1:5000/v3/' --test-user='demo' \
|
||||
--test-key='pass' --admin-endpoint='http://127.0.0.1:5000/v3/' \
|
||||
--admin-user='admin' --admin-key='pass'
|
||||
@ -51,7 +49,7 @@ def add(args):
|
||||
clouds(args)
|
||||
|
||||
except IntegrityError:
|
||||
print 'A Cloud with %s as its endpoint has already been added. ' % args.endpoint
|
||||
print 'A Cloud with %s as its endpoint has already been added. ' % args.endpoint
|
||||
|
||||
|
||||
def config(args):
|
||||
@ -64,23 +62,23 @@ def config(args):
|
||||
sys.exit(1)
|
||||
|
||||
t = TempestConfig(args.cloud_id)
|
||||
|
||||
|
||||
print t.build_config_from_keystone()
|
||||
|
||||
|
||||
def remove(args):
|
||||
"""removes a cloud
|
||||
"""removes a cloud
|
||||
refstack remove {cloud_id}
|
||||
|
||||
confirms that cloud-id 123 has been removed from the database as well as
|
||||
confirms that cloud-id 123 has been removed from the database as well as
|
||||
all tests assosiateed with it."""
|
||||
cloud = db.query(Cloud).get(args.cloud_id)
|
||||
|
||||
if cloud is None:
|
||||
print 'Invalid cloud-id, Please use one from this list.'
|
||||
clouds(args)
|
||||
|
||||
else:
|
||||
|
||||
else:
|
||||
db.delete(cloud)
|
||||
db.commit()
|
||||
print 'cloud %s has been deleted.' % args.cloud_id
|
||||
@ -92,16 +90,16 @@ def clouds(args):
|
||||
print 'id | endpoint | test-user | admin-user '
|
||||
print '---------------------------------------'
|
||||
for row in db.query(Cloud).all():
|
||||
print "%s | %s | %s | %s " % (row.id, row.endpoint, row.test_user, row.admin_user)
|
||||
print "%s | %s | %s | %s " % (row.id, row.endpoint, row.test_user, row.admin_user)
|
||||
print ''
|
||||
|
||||
|
||||
def start(args):
|
||||
"""start test command
|
||||
|
||||
refstack start {cloud_id} --sha {sha}
|
||||
refstack start {cloud_id} --sha {sha}
|
||||
|
||||
triggers local run of tempest with specified cloud_id returns a
|
||||
triggers local run of tempest with specified cloud_id returns a
|
||||
test_id so that the user can check status or cancel the test"""
|
||||
#load the cloud from the specified id
|
||||
cloud = db.query(Cloud).get(args.cloud_id)
|
||||
@ -115,7 +113,7 @@ def start(args):
|
||||
t = Tester(args.cloud_id)
|
||||
results = t.run_local()
|
||||
|
||||
# store the results
|
||||
# store the results
|
||||
test = db.query(Test).filter_by(cloud_id=args.cloud_id).first()
|
||||
|
||||
# creat a new test
|
||||
@ -126,18 +124,19 @@ def start(args):
|
||||
db.commit()
|
||||
print 'test added with id: %s' % test.id
|
||||
|
||||
|
||||
|
||||
'''
|
||||
# do cleanup and then mark the last status to 'canceled'
|
||||
test_result = TestResults()
|
||||
test_result.test_id = test.id
|
||||
test_result.subunit = result
|
||||
test_result.subunit = result
|
||||
|
||||
|
||||
|
||||
db.add(test_result)
|
||||
db.commit()
|
||||
'''
|
||||
|
||||
|
||||
def status(args):
|
||||
"""get the status of a running test
|
||||
|
||||
@ -150,7 +149,7 @@ def status(args):
|
||||
print '%s is not a valid test-id.' % args.test_id
|
||||
sys.exit(1)
|
||||
else:
|
||||
|
||||
|
||||
test_status = db.query(TestStatus).filter_by(test_id=test.id).order_by(TestStatus.id.desc()).all()
|
||||
|
||||
print 'Status Log for test-id %s (top is most recent)' % args.test_id
|
||||
@ -181,7 +180,7 @@ def cancel(args):
|
||||
test_status = TestStatus(test.id, 'canceled')
|
||||
db.add(test_status)
|
||||
db.commit()
|
||||
|
||||
|
||||
else:
|
||||
print 'test %s does not apear to be running' % args.test_id
|
||||
|
||||
@ -215,17 +214,17 @@ def tests(args):
|
||||
print '---------------------------------------'
|
||||
for row in db.query(Test).filter_by(cloud_id=args.cloud_id).all():
|
||||
_status = db.query(TestStatus).filter_by(test_id=row.id).order_by(TestStatus.id.desc()).first()
|
||||
print "%s | %s " % (row.id, _status.message)
|
||||
print "%s | %s " % (row.id, _status.message)
|
||||
print ''
|
||||
|
||||
|
||||
def subcommands(subparsers):
|
||||
"""argparse options for the clouds command """
|
||||
"""argparse options for the clouds command """
|
||||
clouds_parser = subparsers.add_parser('clouds', help='list clouds')
|
||||
|
||||
"""argparse subparsers with """
|
||||
"""argparse subparsers with """
|
||||
add_cloud_parser = subparsers.add_parser('add', help='Add a new Cloud')
|
||||
|
||||
|
||||
add_cloud_parser.add_argument('--endpoint',
|
||||
required=True,
|
||||
action='store',
|
||||
@ -262,14 +261,14 @@ def subcommands(subparsers):
|
||||
dest='admin_key',
|
||||
help='Admin keystone key or password')
|
||||
|
||||
"""argparse options for the remove command """
|
||||
"""argparse options for the remove command """
|
||||
remove_parser = subparsers.add_parser('remove', help='remove a Cloud')
|
||||
|
||||
remove_parser.add_argument(action='store',
|
||||
dest='cloud_id',
|
||||
help='The id of the cloud you want to remove')
|
||||
|
||||
"""argparse options for the start command """
|
||||
"""argparse options for the start command """
|
||||
start_parser = subparsers.add_parser('start', help='start tests on cloud')
|
||||
|
||||
start_parser.add_argument(action='store',
|
||||
@ -282,7 +281,7 @@ def subcommands(subparsers):
|
||||
dest='sha',
|
||||
help='optionally specify a sha for the tempest version to use')
|
||||
|
||||
"""argparse options for the status command """
|
||||
"""argparse options for the status command """
|
||||
status_parser = subparsers.add_parser('status', help='returns status of test')
|
||||
status_parser.add_argument(action='store',
|
||||
dest='test_id',
|
||||
@ -294,35 +293,36 @@ def subcommands(subparsers):
|
||||
help='list status history')
|
||||
|
||||
|
||||
"""argparse options for the cancel command """
|
||||
"""argparse options for the cancel command """
|
||||
cancel_parser = subparsers.add_parser('cancel', help='cancel a test')
|
||||
|
||||
|
||||
cancel_parser.add_argument(action='store',
|
||||
dest='test_id',
|
||||
help='The id of the test you want to cancel')
|
||||
|
||||
|
||||
|
||||
"""argparse options for the result command """
|
||||
"""argparse options for the result command """
|
||||
result_parser = subparsers.add_parser('result', help='provides results')
|
||||
result_parser.add_argument(action='store',
|
||||
dest='test_id',
|
||||
help='The id of the test you want to cancel')
|
||||
|
||||
"""argparse options for the tests command """
|
||||
|
||||
"""argparse options for the tests command """
|
||||
tests_parser = subparsers.add_parser('tests', help='list tests')
|
||||
|
||||
tests_parser.add_argument(action='store',
|
||||
dest='cloud_id',
|
||||
help='The id of the cloud you want to test')
|
||||
|
||||
"""argparse options for the tests command """
|
||||
"""argparse options for the tests command """
|
||||
tests_parser = subparsers.add_parser('config', help='output tempest config for cloud')
|
||||
|
||||
tests_parser.add_argument(action='store',
|
||||
dest='cloud_id',
|
||||
help='The id of the cloud you want a config for')
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
@ -364,6 +364,5 @@ def main():
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
main()
|
||||
|
@ -1,15 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2013 Piston Cloud Computing, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
@ -1,69 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2013 Piston Cloud Computing, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
from keystoneclient.v2_0 import client
|
||||
from refstack.common import *
|
||||
import refstack.models
|
||||
|
||||
class Clouds
|
||||
|
||||
class Cloud(object):
|
||||
""" Cloud functions"""
|
||||
cloud_id = None
|
||||
|
||||
def __init__(self, cloud_id = None):
|
||||
""" init method loads specified id or fails"""
|
||||
self.cloud_id = cloud_id
|
||||
|
||||
if not cloud_id:
|
||||
# we have a new cloud.
|
||||
# do nothing because now we'll call the add method
|
||||
return None
|
||||
else:
|
||||
# load an existing cloud
|
||||
self._cloud = models.Cloud.query.filter_by(id=self.cloud_id).first()
|
||||
|
||||
if not self._cloud:
|
||||
# cloud not found.. invalid id
|
||||
# maybe I should do someting about this ..
|
||||
return None
|
||||
|
||||
self._keystone = client.Client(username=self._cloud.admin_user,
|
||||
password=self._cloud.admin_key,
|
||||
auth_url=self._cloud.admin_endpoint )
|
||||
|
||||
self._end_point = None
|
||||
|
||||
def add(self,endpoint,test_user,test_key,
|
||||
admin_endpoint,admin_user,admin_key,vendor_id=None):
|
||||
#adds a new cloud to the db
|
||||
models.db.session.add(Cloud(endpoint,test_user,test_key,
|
||||
admin_endpoint,admin_user,admin_key,vendor_id))
|
||||
models.db.session.commit()
|
||||
|
||||
@property
|
||||
def end_point(self):
|
||||
"""end_point property"""
|
||||
return self._end_point
|
||||
|
||||
@end_point.setter
|
||||
def end_point(self, value):
|
||||
self._end_point = value
|
||||
|
||||
def get_config(self):
|
||||
"""uses end_point and creditials from the specified cloud_id to
|
||||
get a list of services and enpoints from keystone then outputs a
|
||||
usable tempest config"""
|
||||
|
@ -17,11 +17,10 @@ from keystoneclient.v2_0 import client
|
||||
from refstack.models import *
|
||||
|
||||
|
||||
|
||||
class TempestConfig(object):
|
||||
"""temptest config options. gets converted to a tempest config file"""
|
||||
config = {}
|
||||
|
||||
|
||||
def output(self):
|
||||
"""outputs config in propper format"""
|
||||
output = ''
|
||||
@ -34,19 +33,18 @@ class TempestConfig(object):
|
||||
|
||||
|
||||
def build_config_from_keystone(self):
|
||||
"""uses the keystoneclient libs to query a clouds endpoint and
|
||||
retrive a service catelog. that it then uses to populate the
|
||||
"""uses the keystoneclient libs to query a clouds endpoint and
|
||||
retrive a service catelog. that it then uses to populate the
|
||||
values for our specific tempest config"""
|
||||
# load an existing cloud
|
||||
self._cloud = db.query(Cloud).filter_by(id=self.cloud_id).first()
|
||||
|
||||
if not self._cloud:
|
||||
# cloud not found.. invalid id
|
||||
# maybe I should do someting about this ..
|
||||
# cloud not found.. invalid id
|
||||
# maybe I should do someting about this ..
|
||||
return None
|
||||
|
||||
|
||||
# This stuff we know before hitting up keystone
|
||||
# This stuff we know before hitting up keystone
|
||||
self.config['identity']['uri'] = self._cloud.admin_endpoint
|
||||
self.config['identity']['admin_username'] = self._cloud.admin_user
|
||||
self.config['identity']['admin_password'] = self._cloud.admin_key
|
||||
@ -54,7 +52,7 @@ class TempestConfig(object):
|
||||
self.config['identity']['password'] = self._cloud.test_key
|
||||
self.config['identity']['tenant_name'] = self._cloud.admin_user
|
||||
|
||||
# keystone client object
|
||||
# keystone client object
|
||||
self._keystone = client.Client(username=self._cloud.admin_user,
|
||||
password=self._cloud.admin_key,
|
||||
tenant_name=self._cloud.admin_user,
|
||||
@ -87,15 +85,14 @@ class TempestConfig(object):
|
||||
if self.service_catalog.has_key(service):
|
||||
self.config['service_available'][service] = True
|
||||
|
||||
# boto settings
|
||||
# boto settings
|
||||
self.config['boto']['ec2_url'] = self.service_catalog['ec2']
|
||||
self.config['boto']['s3_url'] = self.service_catalog['s3']
|
||||
|
||||
|
||||
# return the actual config
|
||||
return self.output()
|
||||
|
||||
|
||||
|
||||
def __init__(self, cloud_id):
|
||||
""" sets up the default configs"""
|
||||
self.cloud_id = cloud_id
|
||||
@ -190,7 +187,7 @@ class TempestConfig(object):
|
||||
'backend2_name': 'BACKEND_2',
|
||||
'storage_protocol': 'iSCSI',
|
||||
'vendor_name': 'Open Source' }
|
||||
|
||||
|
||||
self.config['object-storage'] = {
|
||||
'catalog_type': 'object-store',
|
||||
'container_sync_timeout': 120,
|
||||
|
@ -14,11 +14,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import os
|
||||
import sys
|
||||
import errno
|
||||
from subprocess import call
|
||||
from textwrap import dedent
|
||||
from refstack.app import app
|
||||
from refstack.common.tempest_config import TempestConfig
|
||||
import testrepository.repository.file
|
||||
from testrepository import ui
|
||||
@ -27,11 +23,12 @@ from testrepository.commands import init
|
||||
|
||||
import gear
|
||||
|
||||
|
||||
class TesterWorker(object):
|
||||
"""gearman worker code"""
|
||||
def __init__(self,app):
|
||||
self.worker = gear.Worker('run_remote_test')
|
||||
|
||||
|
||||
self.worker.addServer(app.gearman_server)
|
||||
self.worker.registerFunction('run_remote_test')
|
||||
|
||||
@ -46,7 +43,6 @@ class TesterWorker(object):
|
||||
job.sendWorkComplete(job.arguments.reverse())
|
||||
|
||||
|
||||
|
||||
class TestRepositoryUI(ui.AbstractUI):
|
||||
"""nothing"""
|
||||
def __init__(self, here):
|
||||
@ -57,11 +53,10 @@ class TestRepositoryUI(ui.AbstractUI):
|
||||
self.here = here
|
||||
|
||||
|
||||
|
||||
class TestRepositorySource(object):
|
||||
"""Get test results from a testrepository.
|
||||
|
||||
Reloading asks testr to re-run (and implicitly record) a new
|
||||
Reloading asks testr to re-run (and implicitly record) a new
|
||||
test result.
|
||||
|
||||
:ivar testr_directory: path to directory containing .testr repository
|
||||
@ -70,7 +65,7 @@ class TestRepositorySource(object):
|
||||
def __init__(self, testr_directory):
|
||||
self.testr_directory = os.path.expanduser(testr_directory)
|
||||
self._ui = TestRepositoryUI(self.testr_directory)
|
||||
|
||||
|
||||
self.init_repo()
|
||||
|
||||
|
||||
@ -89,7 +84,7 @@ class TestRepositorySource(object):
|
||||
cmd.run()
|
||||
except OSError:
|
||||
# if this happens its fine .. just means the repo is already there
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
def run(self):
|
||||
@ -98,20 +93,19 @@ class TestRepositorySource(object):
|
||||
self._ui.c = self.testr_directory+'tempest.conf'
|
||||
|
||||
cmd = run.run(self._ui)
|
||||
|
||||
|
||||
res = cmd.execute()
|
||||
|
||||
|
||||
|
||||
def testrepository_last_stream(self):
|
||||
factory = testrepository.repository.file.RepositoryFactory()
|
||||
repo = factory.open(self.testr_directory)
|
||||
# this is poor because it just returns a stringio for the whole
|
||||
# thing; we should instead try to read from it as a file so we can
|
||||
# this is poor because it just returns a stringio for the whole
|
||||
# thing; we should instead try to read from it as a file so we can
|
||||
# get nonblocking io
|
||||
return repo.get_test_run(repo.latest_id()).get_subunit_stream()
|
||||
|
||||
|
||||
|
||||
class Tester(object):
|
||||
""" Test functions"""
|
||||
test_id = None
|
||||
@ -125,7 +119,7 @@ class Tester(object):
|
||||
if not test_id:
|
||||
#create a new test id
|
||||
self.test_id = 10
|
||||
else:
|
||||
else:
|
||||
# set test id
|
||||
self.test_id = id
|
||||
|
||||
@ -136,29 +130,28 @@ class Tester(object):
|
||||
|
||||
|
||||
def run_remote(self):
|
||||
"""triggers remote run"""
|
||||
"""triggers remote run"""
|
||||
# install tempest in virt env
|
||||
# start tests against cloud_id using sha of tempest
|
||||
# start tests against cloud_id using sha of tempest
|
||||
# no sha indicates trunk
|
||||
|
||||
|
||||
def run_local(self):
|
||||
"""triggers local run"""
|
||||
# make sure we have a folder to put a repo in..
|
||||
# make sure we have a folder to put a repo in..
|
||||
if not os.path.exists(self.test_path):
|
||||
os.makedirs(self.test_path)
|
||||
|
||||
|
||||
# write the tempest config to that folder
|
||||
self.write_config(self.test_path)
|
||||
|
||||
# setup the repo wrapper.. this creates the repo if its not already there
|
||||
tr = TestRepositorySource(self.test_path)
|
||||
|
||||
"""TODO: So this is supposed to use the testr wrapper to trigger a run.. however..
|
||||
I am completly blocked on how to make it work the right way.. so I am moving on
|
||||
for now once the congigs are setup and repo initiated it will call a subprocess
|
||||
run the command .. THEN query the repo for the last set of results and store the
|
||||
subunit stream.
|
||||
"""TODO: So this is supposed to use the testr wrapper to trigger a run.. however..
|
||||
I am completly blocked on how to make it work the right way.. so I am moving on
|
||||
for now once the congigs are setup and repo initiated it will call a subprocess
|
||||
run the command .. THEN query the repo for the last set of results and store the
|
||||
subunit stream.
|
||||
|
||||
# run tests
|
||||
#tr.run()
|
||||
@ -168,10 +161,10 @@ class Tester(object):
|
||||
call([self.test_path+'runtests.sh']) # replace this
|
||||
print "finished with tests"
|
||||
|
||||
# get back the results
|
||||
# get back the results
|
||||
result = tr.testrepository_last_stream()
|
||||
|
||||
# write results to database maybe .. or return them .. not sure which ..
|
||||
# write results to database maybe .. or return them .. not sure which ..
|
||||
return result.read()
|
||||
#return None
|
||||
|
||||
@ -196,7 +189,7 @@ test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
|
||||
test_id_option=--load-list $IDFILE
|
||||
test_list_option=--list
|
||||
group_regex=([^\.]*\.)*"""
|
||||
|
||||
|
||||
with open(path+"runtests.sh", "w") as runtests_script_file:
|
||||
runtests_script_file.write(runtests_script)
|
||||
|
||||
@ -208,12 +201,9 @@ group_regex=([^\.]*\.)*"""
|
||||
with open(path+".testr.conf", "w") as testr_config_file:
|
||||
testr_config_file.write(testr_output)
|
||||
|
||||
|
||||
|
||||
def cancel(self):
|
||||
""" cancels a running test"""
|
||||
|
||||
|
||||
@property
|
||||
def status(self):
|
||||
"""The status property."""
|
||||
@ -225,9 +215,8 @@ group_regex=([^\.]*\.)*"""
|
||||
del self._status
|
||||
return locals()
|
||||
|
||||
|
||||
@property
|
||||
def config(self):
|
||||
"""The config property. outputs a tempest config based on settings"""
|
||||
"""The config property. outputs a tempest config based on settings"""
|
||||
return self.tempest_config.output()
|
||||
|
||||
|
@ -17,7 +17,7 @@ from refstack.common import *
|
||||
|
||||
|
||||
class Vendor:
|
||||
""" Vendor functions"""
|
||||
"""Vendor functions"""
|
||||
def __init__(self, id):
|
||||
""" init method loads specified id or fails"""
|
||||
|
||||
|
@ -13,15 +13,15 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
"""striaght up sqlalchemy declarative_base model structure.
|
||||
"""striaght up sqlalchemy declarative_base model structure.
|
||||
|
||||
*I created this because i was having a problem getting
|
||||
the cli to use the models that were generated for the flask
|
||||
webapp. The plan is to use this for both. But I have not
|
||||
*I created this because i was having a problem getting
|
||||
the cli to use the models that were generated for the flask
|
||||
webapp. The plan is to use this for both. But I have not
|
||||
started my serious efforts on the web interface. dl 10.2013
|
||||
|
||||
*For now in dev I have this database in /tmp we can talk
|
||||
about someplace else for it by default.
|
||||
*For now in dev I have this database in /tmp we can talk
|
||||
about someplace else for it by default.
|
||||
"""
|
||||
from datetime import datetime
|
||||
from sqlalchemy import create_engine
|
||||
@ -38,7 +38,6 @@ Base = declarative_base()
|
||||
Base.query = db.query_property()
|
||||
|
||||
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = 'user'
|
||||
id = Column(Integer, primary_key=True)
|
||||
@ -62,11 +61,10 @@ class User(Base):
|
||||
return self.name
|
||||
|
||||
|
||||
|
||||
"""
|
||||
Note: The vendor list will be pre-populated from the sponsoring company database.
|
||||
Note: The vendor list will be pre-populated from the sponsoring company database.
|
||||
TODO: better define the vendor object and its relationship with user
|
||||
it needs the ability to facilitate a login.
|
||||
it needs the ability to facilitate a login.
|
||||
"""
|
||||
class Vendor(Base):
|
||||
__tablename__ = 'vendor'
|
||||
@ -79,13 +77,12 @@ class Vendor(Base):
|
||||
return self.vendor_name
|
||||
|
||||
|
||||
|
||||
class Cloud(Base):
|
||||
"""*need to take the time to descibe this stuff in detail.
|
||||
"""*need to take the time to descibe this stuff in detail.
|
||||
"""
|
||||
__tablename__ = 'cloud'
|
||||
id = Column(Integer, primary_key=True)
|
||||
|
||||
|
||||
label = Column(String(60), unique=False)
|
||||
endpoint = Column(String(120), unique=True)
|
||||
test_user = Column(String(80), unique=False)
|
||||
@ -112,7 +109,6 @@ class Test(Base):
|
||||
self.cloud_id = cloud_id
|
||||
|
||||
|
||||
|
||||
class TestStatus(Base):
|
||||
__tablename__ = 'test_status'
|
||||
id = Column(Integer, primary_key=True)
|
||||
@ -130,7 +126,6 @@ class TestStatus(Base):
|
||||
self.finished = finished
|
||||
|
||||
|
||||
|
||||
class TestResults(Base):
|
||||
__tablename__ = 'test_results'
|
||||
id = Column(Integer, primary_key=True)
|
||||
|
@ -15,8 +15,10 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import os
|
||||
|
||||
from web import app
|
||||
|
||||
|
||||
app.logger.setLevel('DEBUG')
|
||||
port = int(os.environ.get('PORT', 5000))
|
||||
app.run(host='172.16.200.128', port=port, debug=True)
|
||||
app.run(host='172.16.200.128', port=port, debug=True)
|
||||
|
@ -1,3 +1,3 @@
|
||||
CREATE TABLE IF NOT EXISTS VENDORS
|
||||
( vendor_id integer primary key asc autoincrement,
|
||||
vendor_name TEXT NOT NULL);
|
||||
CREATE TABLE IF NOT EXISTS VENDORS
|
||||
(vendor_id integer primary key asc autoincrement,
|
||||
vendor_name TEXT NOT NULL);
|
||||
|
@ -13,8 +13,6 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import os
|
||||
import requests
|
||||
from flask import Flask, abort, flash, request, redirect, url_for, \
|
||||
render_template, g, session
|
||||
from flask_openid import OpenID
|
||||
@ -26,7 +24,7 @@ from wtforms import Form, BooleanField, TextField, \
|
||||
PasswordField, validators
|
||||
from flask_mail import Mail
|
||||
|
||||
from refstack.app import app
|
||||
from refstack.app import app
|
||||
from refstack.models import *
|
||||
|
||||
mail = Mail(app)
|
||||
@ -37,11 +35,10 @@ admin = Admin(app, base_template='admin/master.html')
|
||||
|
||||
|
||||
class SecureView(ModelView):
|
||||
""" """
|
||||
def is_accessible(self):
|
||||
""" """
|
||||
return g.user.su is not False
|
||||
|
||||
|
||||
admin.add_view(SecureView(Vendor, db))
|
||||
admin.add_view(SecureView(Cloud, db))
|
||||
admin.add_view(SecureView(User, db))
|
||||
@ -49,17 +46,17 @@ admin.add_view(SecureView(User, db))
|
||||
|
||||
@app.before_request
|
||||
def before_request():
|
||||
"""Runs before the request it self"""
|
||||
"""Runs before the request itself."""
|
||||
g.user = None
|
||||
if 'openid' in session:
|
||||
g.user = User.query.filter_by(openid=session['openid']).first()
|
||||
|
||||
|
||||
|
||||
@app.route('/', methods=['POST', 'GET'])
|
||||
def index():
|
||||
"""Index view"""
|
||||
"""Index view."""
|
||||
if g.user is not None:
|
||||
# something else
|
||||
# something else
|
||||
clouds = Cloud.query.filter_by(user_id=g.user.id).all()
|
||||
return render_template('home.html', clouds=clouds)
|
||||
else:
|
||||
@ -70,15 +67,16 @@ def index():
|
||||
@app.route('/login', methods=['GET', 'POST'])
|
||||
@oid.loginhandler
|
||||
def login():
|
||||
"""Does the login via OpenID. Has to call into `oid.try_login`
|
||||
to start the OpenID machinery.
|
||||
"""Does the login via OpenID.
|
||||
|
||||
Has to call into `oid.try_login` to start the OpenID machinery.
|
||||
"""
|
||||
# if we are already logged in, go back to were we came from
|
||||
if g.user is not None:
|
||||
return redirect(oid.get_next_url())
|
||||
return oid.try_login("https://login.launchpad.net/",
|
||||
ask_for=['email', 'nickname'])
|
||||
|
||||
|
||||
|
||||
@oid.after_login
|
||||
def create_or_login(resp):
|
||||
@ -120,21 +118,23 @@ def create_profile():
|
||||
return render_template(
|
||||
'create_profile.html', next_url=oid.get_next_url())
|
||||
|
||||
|
||||
@app.route('/delete-cloud/<int:cloud_id>', methods=['GET', 'POST'])
|
||||
def delete_cloud(cloud_id):
|
||||
""" delete function for clouds"""
|
||||
"""Delete function for clouds."""
|
||||
c = Cloud.query.filter_by(id=cloud_id).first()
|
||||
|
||||
if not c:
|
||||
flash(u'Not a valid Cloud ID!')
|
||||
elif not c.user_id == g.user.id:
|
||||
flash(u"This isn't your cloud!")
|
||||
flash(u"This isn't your cloud!")
|
||||
else:
|
||||
db.delete(c)
|
||||
db.commit()
|
||||
|
||||
return redirect('/')
|
||||
|
||||
|
||||
@app.route('/edit-cloud/<int:cloud_id>', methods=['GET', 'POST'])
|
||||
def edit_cloud(cloud_id):
|
||||
c = Cloud.query.filter_by(id=cloud_id).first()
|
||||
@ -143,7 +143,7 @@ def edit_cloud(cloud_id):
|
||||
flash(u'Not a valid Cloud ID!')
|
||||
return redirect('/')
|
||||
elif not c.user_id == g.user.id:
|
||||
flash(u"This isn't your cloud!")
|
||||
flash(u"This isn't your cloud!")
|
||||
|
||||
if request.method == 'POST':
|
||||
#validate this biotch
|
||||
@ -169,7 +169,7 @@ def edit_cloud(cloud_id):
|
||||
c.admin_endpoint = request.form['admin_endpoint']
|
||||
c.admin_user = request.form['admin_user']
|
||||
c.admin_key = request.form['admin_key']
|
||||
|
||||
|
||||
db.commit()
|
||||
|
||||
flash(u'Cloud Saved!')
|
||||
@ -190,8 +190,8 @@ def edit_cloud(cloud_id):
|
||||
|
||||
@app.route('/create-cloud', methods=['GET', 'POST'])
|
||||
def create_cloud():
|
||||
"""This is the handler for creating a new cloud"""
|
||||
|
||||
"""This is the handler for creating a new cloud."""
|
||||
|
||||
#if g.user is None:
|
||||
# abort(401)
|
||||
if request.method == 'POST':
|
||||
@ -227,10 +227,9 @@ def create_cloud():
|
||||
return render_template('create_cloud.html', next_url='/')
|
||||
|
||||
|
||||
|
||||
@app.route('/profile/edit', methods=['GET', 'POST'])
|
||||
def edit_profile():
|
||||
"""Updates a profile"""
|
||||
"""Updates a profile."""
|
||||
if g.user is None:
|
||||
abort(401)
|
||||
form = dict(name=g.user.name, email=g.user.email)
|
||||
@ -258,16 +257,16 @@ def edit_profile():
|
||||
|
||||
@app.route('/profile', methods=['GET', 'POST'])
|
||||
def view_profile():
|
||||
"""Updates a profile"""
|
||||
"""Updates a profile."""
|
||||
if g.user is None:
|
||||
abort(401)
|
||||
|
||||
|
||||
return render_template('view_profile.html', user=g.user)
|
||||
|
||||
|
||||
@app.route('/logout')
|
||||
def logout():
|
||||
"""logout route"""
|
||||
"""Log out."""
|
||||
session.pop('openid', None)
|
||||
flash(u'You have been signed out')
|
||||
return redirect(oid.get_next_url())
|
||||
|
@ -12,9 +12,9 @@ WTForms==1.0.4
|
||||
Werkzeug==0.8.3
|
||||
alembic==0.5.0
|
||||
gunicorn==0.17.4
|
||||
psycopg2==2.5
|
||||
#psycopg2==2.5
|
||||
pyOpenSSL==0.13
|
||||
pycrypto==2.6
|
||||
python-openid==2.2.5
|
||||
requests==1.2.3
|
||||
python-keystoneclient
|
||||
python-keystoneclient
|
||||
|
Loading…
x
Reference in New Issue
Block a user