Refactoring API and Archiver module
* Set uo manifest.in and tox.ini * Add test module Change-Id: I265401658922c75b50db4d1232af17215ee1b6fc
This commit is contained in:
parent
e4b9fe765e
commit
de388f5e64
4
.gitreview
Normal file
4
.gitreview
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[gerrit]
|
||||||
|
host=review.openstack.org
|
||||||
|
port=29418
|
||||||
|
project=stackforge/murano-repository.git
|
38
ChangeLog
38
ChangeLog
@ -1,3 +1,41 @@
|
|||||||
|
commit d259b6c33a4379c12dd673cb8cabc769545739d0
|
||||||
|
Author: efedorova <efedorova@mirantis.com>
|
||||||
|
Date: Thu Oct 17 19:18:08 2013 +0400
|
||||||
|
|
||||||
|
Refactoring API and Archiver module
|
||||||
|
|
||||||
|
* Set uo manifest.in and tox.ini
|
||||||
|
* Add test module
|
||||||
|
|
||||||
|
Change-Id: I265401658922c75b50db4d1232af17215ee1b6fc
|
||||||
|
|
||||||
|
commit e4b9fe765e912a13ff02a394b329ecd117a0edb7
|
||||||
|
Author: efedorova <efedorova@mirantis.com>
|
||||||
|
Date: Tue Oct 15 19:03:09 2013 +0400
|
||||||
|
|
||||||
|
Fix buf with manifests listing
|
||||||
|
|
||||||
|
commit b24d260524d16dce96a682fd32629951e2ac17ee
|
||||||
|
Author: efedorova <efedorova@mirantis.com>
|
||||||
|
Date: Tue Oct 15 18:47:27 2013 +0400
|
||||||
|
|
||||||
|
Update api
|
||||||
|
|
||||||
|
commit ecb0c93b3077755192929fa8ddf045ef43d43112
|
||||||
|
Author: efedorova <efedorova@mirantis.com>
|
||||||
|
Date: Mon Oct 14 16:54:00 2013 +0400
|
||||||
|
|
||||||
|
Fix typos
|
||||||
|
|
||||||
|
commit c46bfbde86728d689677a2d7d484b2db04893186
|
||||||
|
Author: efedorova <efedorova@mirantis.com>
|
||||||
|
Date: Mon Oct 14 16:34:33 2013 +0400
|
||||||
|
|
||||||
|
Remove service to muranorepository
|
||||||
|
|
||||||
|
Add venv support
|
||||||
|
Update requirements
|
||||||
|
|
||||||
commit 28cbd261871038cf1fc4fa67d36c26ae9e9a4747
|
commit 28cbd261871038cf1fc4fa67d36c26ae9e9a4747
|
||||||
Author: efedorova <efedorova@mirantis.com>
|
Author: efedorova <efedorova@mirantis.com>
|
||||||
Date: Mon Oct 14 13:27:09 2013 +0400
|
Date: Mon Oct 14 13:27:09 2013 +0400
|
||||||
|
15
MANIFEST.in
15
MANIFEST.in
@ -1,10 +1,13 @@
|
|||||||
include AUTHORS
|
|
||||||
include README.rst
|
|
||||||
include ChangeLog
|
|
||||||
include LICENSE
|
|
||||||
|
|
||||||
recursive-include Services *
|
recursive-include Services *
|
||||||
|
include ChangeLog
|
||||||
|
include README.rst
|
||||||
|
include MANIFEST.in
|
||||||
|
include AUTHORS
|
||||||
|
include LICENSE
|
||||||
|
include ChangeLog
|
||||||
|
include babel.cfg
|
||||||
|
include tox.ini
|
||||||
|
include muranorepository/tests/test.conf
|
||||||
exclude .gitignore
|
exclude .gitignore
|
||||||
exclude .gitreview
|
exclude .gitreview
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
# Address to bind the server to
|
# Address to bind the server to
|
||||||
host = 172.18.10.111
|
host = localhost
|
||||||
#Port the bind the server to
|
#Port the bind the server to
|
||||||
port = 5000
|
port = 5000
|
||||||
|
|
||||||
|
@ -1,19 +1,20 @@
|
|||||||
# Copyright (c) 2013 Mirantis, Inc.
|
# Copyright (c) 2013 Mirantis, Inc.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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
|
# not use this file except in compliance with the License. You may obtain
|
||||||
# a copy of the License at
|
# a copy of the License at
|
||||||
#
|
#
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
#
|
#
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
# distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from flask import Blueprint, make_response, send_file
|
|
||||||
|
from flask import Blueprint, send_file
|
||||||
from flask import jsonify, request, abort
|
from flask import jsonify, request, abort
|
||||||
from werkzeug import secure_filename
|
from werkzeug import secure_filename
|
||||||
|
|
||||||
@ -26,116 +27,132 @@ CONF = cfg.CONF
|
|||||||
v1_api = Blueprint('v1', __name__)
|
v1_api = Blueprint('v1', __name__)
|
||||||
|
|
||||||
|
|
||||||
@v1_api.route('/client/ui')
|
def get_archive(client):
|
||||||
def get_ui_data():
|
|
||||||
parser = ManifestParser(CONF.manifests)
|
parser = ManifestParser(CONF.manifests)
|
||||||
manifests = parser.parse()
|
manifests = parser.parse()
|
||||||
archive_name = Archiver().create(manifests, "ui")
|
if client == 'conductor':
|
||||||
|
return Archiver().create(manifests,
|
||||||
|
'heat',
|
||||||
|
'agent',
|
||||||
|
'scripts')
|
||||||
|
else:
|
||||||
|
return Archiver().create(manifests, client)
|
||||||
|
|
||||||
return send_file(archive_name)
|
|
||||||
|
def get_locations(data_type, result_path):
|
||||||
|
locations = []
|
||||||
|
if data_type == MANIFEST:
|
||||||
|
for item in os.listdir(result_path):
|
||||||
|
if '-manifest' in item and \
|
||||||
|
os.path.isfile(os.path.join(result_path, item)):
|
||||||
|
locations.append(item)
|
||||||
|
else:
|
||||||
|
for path, subdirs, files in os.walk(result_path):
|
||||||
|
for name in files:
|
||||||
|
if path != result_path:
|
||||||
|
base, diff = path.rsplit(result_path, 2)
|
||||||
|
# split base path and remove slash
|
||||||
|
name = os.path.join(diff[1:], name)
|
||||||
|
locations.append(name)
|
||||||
|
return jsonify({data_type: locations})
|
||||||
|
|
||||||
|
|
||||||
|
def save_file(request, result_path):
|
||||||
|
file_to_upload = request.files.get('file')
|
||||||
|
if file_to_upload:
|
||||||
|
filename = secure_filename(file_to_upload.filename)
|
||||||
|
file_to_upload.save(os.path.join(result_path, filename))
|
||||||
|
return jsonify(result='success')
|
||||||
|
else:
|
||||||
|
abort(400)
|
||||||
|
|
||||||
|
|
||||||
|
def compose_path(data_type, path=None):
|
||||||
|
if path:
|
||||||
|
return os.path.join(CONF.manifests, getattr(CONF, data_type), path)
|
||||||
|
else:
|
||||||
|
return os.path.join(CONF.manifests, getattr(CONF, data_type))
|
||||||
|
|
||||||
|
|
||||||
|
def check_data_type(data_type):
|
||||||
|
if data_type not in DATA_TYPES:
|
||||||
|
abort(404)
|
||||||
|
|
||||||
|
|
||||||
|
@v1_api.route('/client/ui')
|
||||||
|
def get_ui_data():
|
||||||
|
return send_file(get_archive('ui'))
|
||||||
|
|
||||||
|
|
||||||
@v1_api.route('/client/conductor')
|
@v1_api.route('/client/conductor')
|
||||||
def get_conductor_data():
|
def get_conductor_data():
|
||||||
parser = ManifestParser(CONF.manifests)
|
return send_file(get_archive('conductor'))
|
||||||
manifests = parser.parse()
|
|
||||||
archive_name = Archiver().create(manifests,
|
|
||||||
"heat",
|
|
||||||
"agent",
|
|
||||||
"scripts")
|
|
||||||
return send_file(archive_name)
|
|
||||||
|
|
||||||
|
|
||||||
@v1_api.route('/admin/<data_type>', methods=['GET', 'POST'])
|
@v1_api.route('/admin/<data_type>')
|
||||||
def get_data_type_locations(data_type):
|
def get_data_type_locations(data_type):
|
||||||
####### validation ########
|
check_data_type(data_type)
|
||||||
if data_type not in DATA_TYPES:
|
result_path = compose_path(data_type)
|
||||||
abort(404)
|
return get_locations(data_type, result_path)
|
||||||
result_path = os.path.join(CONF.manifests, getattr(CONF, data_type))
|
|
||||||
####### end validation ########
|
|
||||||
if request.method == 'GET':
|
|
||||||
locations = []
|
|
||||||
if data_type == MANIFEST:
|
|
||||||
for item in os.listdir(result_path):
|
|
||||||
if '-manifest' in item:
|
|
||||||
locations.append(item)
|
|
||||||
else:
|
|
||||||
for path, subdirs, files in os.walk(result_path):
|
|
||||||
for name in files:
|
|
||||||
locations.append(name)
|
|
||||||
result = {data_type: locations}
|
|
||||||
return jsonify(result)
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
|
||||||
try:
|
|
||||||
file_to_upload = request.files.get('files')
|
|
||||||
if file_to_upload:
|
|
||||||
filename = secure_filename(file_to_upload.filename)
|
|
||||||
file_to_upload.save(os.path.join(result_path, filename))
|
|
||||||
return jsonify(result="success")
|
|
||||||
except:
|
|
||||||
abort(403)
|
|
||||||
|
|
||||||
|
|
||||||
@v1_api.route('/admin/<data_type>/<path:path>', methods=['GET', 'POST'])
|
@v1_api.route('/admin/<data_type>', methods=['POST'])
|
||||||
def get_data_type_locations_by_path_or_get_file(data_type, path):
|
def upload_file(data_type):
|
||||||
if data_type not in DATA_TYPES:
|
check_data_type(data_type)
|
||||||
abort(404)
|
result_path = compose_path(data_type)
|
||||||
result_path = os.path.join(os.path.join(CONF.manifests,
|
try:
|
||||||
getattr(CONF, data_type),
|
return save_file(request, result_path)
|
||||||
path))
|
except:
|
||||||
|
abort(403)
|
||||||
|
|
||||||
|
|
||||||
|
@v1_api.route('/admin/<data_type>/<path:path>')
|
||||||
|
def get_locations_in_nested_path_or_get_file(data_type, path):
|
||||||
|
check_data_type(data_type)
|
||||||
|
result_path = compose_path(data_type, path)
|
||||||
|
if os.path.isfile(result_path):
|
||||||
|
return send_file(result_path)
|
||||||
|
else:
|
||||||
|
return get_locations(data_type, result_path)
|
||||||
|
|
||||||
|
|
||||||
|
@v1_api.route('/admin/<data_type>/<path:path>', methods=['POST'])
|
||||||
|
def upload_file_in_nested_path(data_type, path):
|
||||||
|
check_data_type(data_type)
|
||||||
|
result_path = compose_path(data_type, path)
|
||||||
|
return save_file(request, result_path)
|
||||||
|
|
||||||
|
|
||||||
|
@v1_api.route('/admin/<data_type>/<path:path>', methods=['PUT'])
|
||||||
|
def create_dirs(data_type, path):
|
||||||
|
check_data_type(data_type)
|
||||||
|
result_path = compose_path(data_type, path)
|
||||||
|
resp = jsonify(result='success')
|
||||||
|
if os.path.exists(result_path):
|
||||||
|
return resp
|
||||||
|
if data_type == MANIFEST:
|
||||||
|
abort(403)
|
||||||
|
try:
|
||||||
|
os.makedirs(result_path)
|
||||||
|
except Exception:
|
||||||
|
abort(403)
|
||||||
|
return resp
|
||||||
|
|
||||||
|
|
||||||
|
@v1_api.route('/admin/<data_type>/<path:path>', methods=['DELETE'])
|
||||||
|
def delete_dirictory_or_file(data_type, path):
|
||||||
|
check_data_type(data_type)
|
||||||
|
result_path = compose_path(data_type, path)
|
||||||
if not os.path.exists(result_path):
|
if not os.path.exists(result_path):
|
||||||
abort(404)
|
abort(404)
|
||||||
|
if os.path.isfile(result_path):
|
||||||
if request.method == 'GET':
|
|
||||||
locations = []
|
|
||||||
if os.path.isfile(result_path):
|
|
||||||
return send_file(result_path)
|
|
||||||
else:
|
|
||||||
for file in os.listdir(result_path):
|
|
||||||
locations.append(file)
|
|
||||||
result = {data_type: locations}
|
|
||||||
return jsonify(result)
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
|
||||||
file_to_upload = request.files.get('files')
|
|
||||||
if file_to_upload:
|
|
||||||
filename = secure_filename(file_to_upload.filename)
|
|
||||||
file_to_upload.save(os.path.join(result_path, filename))
|
|
||||||
return jsonify(result="success")
|
|
||||||
else:
|
|
||||||
abort(403)
|
|
||||||
|
|
||||||
|
|
||||||
@v1_api.route('/admin/<data_type>/<path:path>', methods=['PUT', 'DELETE'])
|
|
||||||
def create_dirs(data_type, path):
|
|
||||||
if data_type not in DATA_TYPES:
|
|
||||||
abort(404)
|
|
||||||
result_path = os.path.join(CONF.manifests, getattr(CONF, data_type), path)
|
|
||||||
if request.method == 'PUT':
|
|
||||||
resp = make_response()
|
|
||||||
if os.path.exists(result_path):
|
|
||||||
return resp
|
|
||||||
if data_type == MANIFEST:
|
|
||||||
abort(403)
|
|
||||||
try:
|
try:
|
||||||
os.makedirs(result_path)
|
os.remove(result_path)
|
||||||
except Exception as e:
|
except Exception:
|
||||||
abort(403)
|
|
||||||
return resp
|
|
||||||
|
|
||||||
if request.method == 'DELETE':
|
|
||||||
if not os.path.exists(result_path):
|
|
||||||
abort(404)
|
abort(404)
|
||||||
if os.path.isfile(result_path):
|
else:
|
||||||
try:
|
try:
|
||||||
os.remove(result_path)
|
os.rmdir(result_path)
|
||||||
except Exception as e:
|
except Exception:
|
||||||
abort(404)
|
abort(403)
|
||||||
else:
|
return jsonify(result='success')
|
||||||
try:
|
|
||||||
os.rmdir(result_path)
|
|
||||||
except Exception as e:
|
|
||||||
abort(403)
|
|
||||||
resp = make_response()
|
|
||||||
return resp
|
|
||||||
|
@ -28,8 +28,8 @@ possible_topdir = os.path.normpath(os.path.join(os.path.abspath(__file__),
|
|||||||
os.pardir,
|
os.pardir,
|
||||||
os.pardir))
|
os.pardir))
|
||||||
if os.path.exists(os.path.join(possible_topdir,
|
if os.path.exists(os.path.join(possible_topdir,
|
||||||
'muranorepository',
|
'muranorepository',
|
||||||
'__init__.py')):
|
'__init__.py')):
|
||||||
sys.path.insert(0, possible_topdir)
|
sys.path.insert(0, possible_topdir)
|
||||||
|
|
||||||
from muranorepository import config
|
from muranorepository import config
|
||||||
@ -43,7 +43,7 @@ LOG = log.getLogger(__name__)
|
|||||||
def main():
|
def main():
|
||||||
dev_conf = os.path.join(possible_topdir,
|
dev_conf = os.path.join(possible_topdir,
|
||||||
'etc',
|
'etc',
|
||||||
'muranorepository.conf')
|
'murano-repository.conf')
|
||||||
config_files = None
|
config_files = None
|
||||||
if os.path.exists(dev_conf):
|
if os.path.exists(dev_conf):
|
||||||
config_files = [dev_conf]
|
config_files = [dev_conf]
|
||||||
|
@ -104,8 +104,7 @@ def _listen(host, start_port, end_port, listen_func):
|
|||||||
try:
|
try:
|
||||||
return listen_func((host, try_port))
|
return listen_func((host, try_port))
|
||||||
except socket.error as exc:
|
except socket.error as exc:
|
||||||
if (exc.errno != errno.EADDRINUSE or
|
if (exc.errno != errno.EADDRINUSE or try_port >= end_port):
|
||||||
try_port >= end_port):
|
|
||||||
raise
|
raise
|
||||||
try_port += 1
|
try_port += 1
|
||||||
|
|
||||||
|
@ -425,7 +425,8 @@ def _setup_logging_from_conf():
|
|||||||
|
|
||||||
if CONF.publish_errors:
|
if CONF.publish_errors:
|
||||||
handler = importutils.import_object(
|
handler = importutils.import_object(
|
||||||
"muranorepository.openstack.common.log_handler.PublishErrorsHandler",
|
"muranorepository.openstack.common.log_handler."
|
||||||
|
"PublishErrorsHandler",
|
||||||
logging.ERROR)
|
logging.ERROR)
|
||||||
log_root.addHandler(handler)
|
log_root.addHandler(handler)
|
||||||
|
|
||||||
|
@ -29,7 +29,8 @@ class BaseTestCase(testtools.TestCase):
|
|||||||
super(BaseTestCase, self).setUp()
|
super(BaseTestCase, self).setUp()
|
||||||
self._set_timeout()
|
self._set_timeout()
|
||||||
self._fake_output()
|
self._fake_output()
|
||||||
self.useFixture(fixtures.FakeLogger('muranorepository.openstack.common'))
|
self.useFixture(
|
||||||
|
fixtures.FakeLogger('muranorepository.openstack.common'))
|
||||||
self.useFixture(fixtures.NestedTempfile())
|
self.useFixture(fixtures.NestedTempfile())
|
||||||
|
|
||||||
def _set_timeout(self):
|
def _set_timeout(self):
|
||||||
|
Binary file not shown.
0
muranorepository/tests/fixtures/__init__.py
vendored
Normal file
0
muranorepository/tests/fixtures/__init__.py
vendored
Normal file
42
muranorepository/tests/fixtures/consts.py
vendored
Normal file
42
muranorepository/tests/fixtures/consts.py
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# Copyright (c) 2013 Mirantis Inc.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
MANIFEST_FILE = ''
|
||||||
|
'version: 0.1'
|
||||||
|
'service_display_name: Test'
|
||||||
|
|
||||||
|
'description: >-'
|
||||||
|
' <strong> This goes a description'
|
||||||
|
|
||||||
|
'full_service_name: test_service'
|
||||||
|
'author: Mirantis Inc.'
|
||||||
|
'service_version: 1.0'
|
||||||
|
'enabled: True'
|
||||||
|
|
||||||
|
'ui:'
|
||||||
|
' - test1.yaml'
|
||||||
|
|
||||||
|
'workflows:'
|
||||||
|
' - test1.xml'
|
||||||
|
|
||||||
|
'heat:'
|
||||||
|
' - Windows.template'
|
||||||
|
|
||||||
|
'agents:'
|
||||||
|
' - test1.template'
|
||||||
|
|
||||||
|
|
||||||
|
'scripts:'
|
||||||
|
' - test1.sh'
|
28
muranorepository/tests/test.conf
Normal file
28
muranorepository/tests/test.conf
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
[DEFAULT]
|
||||||
|
# Address to bind the server to
|
||||||
|
host = localhost
|
||||||
|
#Port the bind the server to
|
||||||
|
port = 5000
|
||||||
|
|
||||||
|
|
||||||
|
# Provide information about data types
|
||||||
|
# absolute path to manifest location(root directory)
|
||||||
|
#manifests = /home/fervent/Projects/my_repo/muranorepository/tests/var
|
||||||
|
manifests = /bin/server
|
||||||
|
|
||||||
|
# Parameter name corresponds to section in manifest file
|
||||||
|
# Parameter value corresponds to relative path to data type
|
||||||
|
ui = ui
|
||||||
|
workflows = workflows
|
||||||
|
heat = heat
|
||||||
|
agent = agent
|
||||||
|
scripts = scripts
|
||||||
|
|
||||||
|
# Configure archive structure
|
||||||
|
# data_type = desired folder
|
||||||
|
[output]
|
||||||
|
ui = service_forms
|
||||||
|
workflows = workflows
|
||||||
|
heat = templates/cf
|
||||||
|
agent = templates/agent
|
||||||
|
scripts = templates/agent/script
|
87
muranorepository/tests/test_main.py
Normal file
87
muranorepository/tests/test_main.py
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import sys
|
||||||
|
import os
|
||||||
|
from flask.ext.testing import TestCase as FlaskTestCase
|
||||||
|
import shutil
|
||||||
|
from StringIO import StringIO
|
||||||
|
import mockfs
|
||||||
|
possible_topdir = os.path.normpath(os.path.join(os.path.abspath(__file__),
|
||||||
|
os.pardir,
|
||||||
|
os.pardir,
|
||||||
|
os.pardir))
|
||||||
|
if os.path.exists(os.path.join(possible_topdir,
|
||||||
|
'muranorepository',
|
||||||
|
'__init__.py')):
|
||||||
|
sys.path.insert(0, possible_topdir)
|
||||||
|
from muranorepository.consts import MANIFEST
|
||||||
|
from muranorepository.tests.fixtures.consts import MANIFEST_FILE
|
||||||
|
from muranorepository import config
|
||||||
|
from muranorepository.main import make_app
|
||||||
|
|
||||||
|
|
||||||
|
class TestAdminAPI(FlaskTestCase):
|
||||||
|
url = "/v1/admin/{0}"
|
||||||
|
url_with_path = "/v1/admin/{0}/{1}"
|
||||||
|
|
||||||
|
def create_app(self):
|
||||||
|
test_app = make_app()
|
||||||
|
test_app.config['TESTING'] = True
|
||||||
|
return test_app
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
config_files = [os.path.join(possible_topdir,
|
||||||
|
'muranorepository',
|
||||||
|
'tests',
|
||||||
|
'test.conf')]
|
||||||
|
|
||||||
|
config.parse_configs(None, config_files)
|
||||||
|
self.mfs = mockfs.replace_builtins()
|
||||||
|
self.mfs.add_entries(
|
||||||
|
{
|
||||||
|
'/bin/server': {
|
||||||
|
'test-manifest.yaml': MANIFEST_FILE,
|
||||||
|
'ui': {'test1.yaml': ''},
|
||||||
|
'heat':
|
||||||
|
{'Windows.template': '',
|
||||||
|
'folder_to_delete': {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
mockfs.restore_builtins()
|
||||||
|
|
||||||
|
def test_list_manifests(self):
|
||||||
|
response = self.client.get(self.url.format(MANIFEST))
|
||||||
|
expected_result = {MANIFEST: ['test-manifest.yaml']}
|
||||||
|
self.assert200(response)
|
||||||
|
self.assertEquals(response.json, expected_result)
|
||||||
|
|
||||||
|
def test_list_ui(self):
|
||||||
|
response = self.client.get(self.url.format('ui'))
|
||||||
|
expected_result = {'ui': ['test1.yaml']}
|
||||||
|
self.assert200(response)
|
||||||
|
self.assertEquals(response.json, expected_result)
|
||||||
|
|
||||||
|
def test_create_ui_subfolder(self):
|
||||||
|
response = self.client.put(self.url_with_path.format('ui', 'test'))
|
||||||
|
expected_result = {'result': 'success'}
|
||||||
|
self.assert200(response)
|
||||||
|
self.assertEquals(response.json, expected_result)
|
||||||
|
shutil.rmtree('bin/server/ui/test')
|
||||||
|
|
||||||
|
def test_delete_heat_subfolder(self):
|
||||||
|
url = self.url_with_path.format('heat',
|
||||||
|
'folder_to_delete')
|
||||||
|
response = self.client.delete(url)
|
||||||
|
self.assert200(response)
|
||||||
|
expected_result = {'result': 'success'}
|
||||||
|
self.assertEquals(response.json, expected_result)
|
||||||
|
|
||||||
|
def test_upload_ui_file(self):
|
||||||
|
upload_data = {'file': (StringIO('content'), 'test.yaml')}
|
||||||
|
response = self.client.post(self.url.format('ui'),
|
||||||
|
data=upload_data)
|
||||||
|
'test.yaml' in os.listdir('bin/server/ui')
|
||||||
|
self.assert200(response)
|
||||||
|
expected_result = {'result': 'success'}
|
||||||
|
self.assertEquals(response.json, expected_result)
|
@ -18,16 +18,44 @@ import shutil
|
|||||||
import logging as log
|
import logging as log
|
||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
from muranorepository.consts import DATA_TYPES
|
from muranorepository.consts import DATA_TYPES
|
||||||
OUTPUT_CONF = cfg.CONF.output
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
|
|
||||||
|
|
||||||
class Archiver(object):
|
class Archiver(object):
|
||||||
|
def _copy_data(self, file_lists, src, dst):
|
||||||
|
if not os.path.exists(dst):
|
||||||
|
os.makedirs(dst)
|
||||||
|
|
||||||
|
for path in file_lists:
|
||||||
|
source = os.path.join(src, path)
|
||||||
|
destination = os.path.join(dst, path)
|
||||||
|
base_dir = os.path.dirname(destination)
|
||||||
|
|
||||||
|
if (base_dir != dst) and (not os.path.exists(base_dir)):
|
||||||
|
os.makedirs(os.path.dirname(destination))
|
||||||
|
try:
|
||||||
|
shutil.copyfile(source, destination)
|
||||||
|
except IOError:
|
||||||
|
log.error("Unable to copy file "
|
||||||
|
"{0}".format(file))
|
||||||
|
|
||||||
|
def _compose_archive(self, path):
|
||||||
|
target_archive = "service_metadata.tar"
|
||||||
|
with tarfile.open(target_archive, "w") as tar:
|
||||||
|
for item in os.listdir(path):
|
||||||
|
tar.add(os.path.join(path, item), item)
|
||||||
|
try:
|
||||||
|
shutil.rmtree(path, ignore_errors=True)
|
||||||
|
except Exception as e:
|
||||||
|
log.error("Unable to delete temp directory: {0}".format(e))
|
||||||
|
return os.path.abspath(target_archive)
|
||||||
|
|
||||||
def create(self, manifests, *types):
|
def create(self, manifests, *types):
|
||||||
"""
|
"""
|
||||||
manifests -- list of Manifest objects
|
manifests -- list of Manifest objects
|
||||||
*types - desired data types to be added to archive
|
*types - desired data types to be added to archive
|
||||||
|
|
||||||
|
return: absolute path to created archive
|
||||||
"""
|
"""
|
||||||
temp_dir = tempfile.mkdtemp()
|
temp_dir = tempfile.mkdtemp()
|
||||||
for data_type in types:
|
for data_type in types:
|
||||||
@ -38,44 +66,18 @@ class Archiver(object):
|
|||||||
for manifest in manifests:
|
for manifest in manifests:
|
||||||
if not manifest.enabled and not manifest.valid:
|
if not manifest.enabled and not manifest.valid:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if hasattr(manifest, data_type):
|
if hasattr(manifest, data_type):
|
||||||
|
file_list = getattr(manifest, data_type)
|
||||||
dst_directory = os.path.join(temp_dir,
|
dst_directory = os.path.join(temp_dir,
|
||||||
getattr(OUTPUT_CONF,
|
getattr(CONF.output,
|
||||||
data_type))
|
data_type))
|
||||||
scr_directory = os.path.join(CONF.manifests,
|
scr_directory = os.path.join(CONF.manifests,
|
||||||
getattr(CONF, data_type))
|
getattr(CONF, data_type))
|
||||||
|
self._copy_data(file_list, scr_directory, dst_directory)
|
||||||
if not os.path.exists(dst_directory):
|
|
||||||
os.makedirs(dst_directory)
|
|
||||||
|
|
||||||
for path in getattr(manifest, data_type):
|
|
||||||
source = os.path.join(scr_directory, path)
|
|
||||||
destination = os.path.join(dst_directory, path)
|
|
||||||
base_dir = os.path.dirname(destination)
|
|
||||||
|
|
||||||
if (base_dir != dst_directory) \
|
|
||||||
and (not os.path.exists(base_dir)):
|
|
||||||
os.makedirs(os.path.dirname(destination))
|
|
||||||
try:
|
|
||||||
shutil.copyfile(source, destination)
|
|
||||||
except IOError:
|
|
||||||
log.error("Unable to copy file "
|
|
||||||
"{0}".format(file))
|
|
||||||
else:
|
else:
|
||||||
log.info(
|
log.info(
|
||||||
"Manifest for {0} service has no file definitions for "
|
"Manifest for {0} service has no file definitions for "
|
||||||
"{1}".format(manifest.service_display_name, data_type))
|
"{1}".format(manifest.service_display_name, data_type))
|
||||||
|
|
||||||
target_archive = "service_metadata.tar"
|
return self._compose_archive(temp_dir)
|
||||||
with tarfile.open(target_archive, "w") as tar:
|
|
||||||
for item in os.listdir(temp_dir):
|
|
||||||
tar.add(os.path.join(temp_dir, item), item)
|
|
||||||
try:
|
|
||||||
shutil.rmtree(temp_dir, ignore_errors=True)
|
|
||||||
except Exception as e:
|
|
||||||
log.error("Unable to delete temp directory: {0}".format(e))
|
|
||||||
return os.path.abspath(target_archive)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,7 +32,8 @@ author-email = openstack-dev@lists.openstack.org
|
|||||||
home-page = https://launchpad.net/murano
|
home-page = https://launchpad.net/murano
|
||||||
|
|
||||||
[global]
|
[global]
|
||||||
setup-hooks = pbr.hooks.setup_hook
|
setup-hooks =
|
||||||
|
pbr.hooks.setup_hook
|
||||||
|
|
||||||
[files]
|
[files]
|
||||||
packages =
|
packages =
|
||||||
@ -54,8 +55,9 @@ tag_date = 0
|
|||||||
tag_svn_revision = 0
|
tag_svn_revision = 0
|
||||||
|
|
||||||
[compile_catalog]
|
[compile_catalog]
|
||||||
directory = murano-repository/locale
|
directory = muranorepository/locale
|
||||||
domain = murano-repository
|
domain = muranorepository
|
||||||
|
|
||||||
|
|
||||||
[extract_messages]
|
[extract_messages]
|
||||||
keywords = _ gettext ngettext l_ lazy_gettext
|
keywords = _ gettext ngettext l_ lazy_gettext
|
||||||
|
@ -2,16 +2,11 @@
|
|||||||
pep8==1.4.5
|
pep8==1.4.5
|
||||||
pyflakes>=0.7.2,<0.7.4
|
pyflakes>=0.7.2,<0.7.4
|
||||||
flake8==2.0
|
flake8==2.0
|
||||||
hacking>=0.5.6,<0.8
|
flask-testing
|
||||||
|
|
||||||
coverage>=3.6
|
|
||||||
docutils==0.9.1
|
docutils==0.9.1
|
||||||
fixtures>=0.3.14
|
fixtures>=0.3.14
|
||||||
mock>=1.0
|
mock>=1.0
|
||||||
nose
|
mockfs
|
||||||
openstack.nose_plugin>=0.7
|
|
||||||
oslo.sphinx
|
oslo.sphinx
|
||||||
pylint==0.25.2
|
pylint==0.25.2
|
||||||
sphinx>=1.1.2
|
|
||||||
sphinxcontrib-httpdomain
|
|
||||||
unittest2
|
unittest2
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
print_hint() {
|
|
||||||
echo "Try \`${0##*/} --help' for more information." >&2
|
|
||||||
}
|
|
||||||
|
|
||||||
PARSED_OPTIONS=$(getopt -n "${0##*/}" -o hb:p:o: \
|
|
||||||
--long help,base-dir:,package-name:,output-dir: -- "$@")
|
|
||||||
|
|
||||||
if [ $? != 0 ] ; then print_hint ; exit 1 ; fi
|
|
||||||
|
|
||||||
eval set -- "$PARSED_OPTIONS"
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
case "$1" in
|
|
||||||
-h|--help)
|
|
||||||
echo "${0##*/} [options]"
|
|
||||||
echo ""
|
|
||||||
echo "options:"
|
|
||||||
echo "-h, --help show brief help"
|
|
||||||
echo "-b, --base-dir=DIR Project base directory (required)"
|
|
||||||
echo "-p, --package-name=NAME Project package name"
|
|
||||||
echo "-o, --output-dir=DIR File output directory"
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
-b|--base-dir)
|
|
||||||
shift
|
|
||||||
BASEDIR=`echo $1 | sed -e 's/\/*$//g'`
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-p|--package-name)
|
|
||||||
shift
|
|
||||||
PACKAGENAME=`echo $1`
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-o|--output-dir)
|
|
||||||
shift
|
|
||||||
OUTPUTDIR=`echo $1 | sed -e 's/\/*$//g'`
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
--)
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ -z $BASEDIR ] || ! [ -d $BASEDIR ]
|
|
||||||
then
|
|
||||||
echo "${0##*/}: missing project base directory" >&2 ; print_hint ; exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
PACKAGENAME=${PACKAGENAME:-${BASEDIR##*/}}
|
|
||||||
|
|
||||||
OUTPUTDIR=${OUTPUTDIR:-$BASEDIR/etc}
|
|
||||||
if ! [ -d $OUTPUTDIR ]
|
|
||||||
then
|
|
||||||
echo "${0##*/}: cannot access \`$OUTPUTDIR': No such file or directory" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
BASEDIRESC=`echo $BASEDIR | sed -e 's/\//\\\\\//g'`
|
|
||||||
FILES=$(find $BASEDIR/$PACKAGENAME -type f -name "*.py" ! -path "*/tests/*" \
|
|
||||||
-exec grep -l "Opt(" {} + | sed -e "s/^$BASEDIRESC\///g" | sort -u)
|
|
||||||
|
|
||||||
export EVENTLET_NO_GREENDNS=yes
|
|
||||||
|
|
||||||
MODULEPATH=murano-repository.openstack.common.config.generator
|
|
||||||
OUTPUTFILE=$OUTPUTDIR/$PACKAGENAME.conf.sample
|
|
||||||
python -m $MODULEPATH $FILES > $OUTPUTFILE
|
|
46
tox.ini
46
tox.ini
@ -10,49 +10,29 @@ setenv = VIRTUAL_ENV={envdir}
|
|||||||
NOSE_OPENSTACK_SHOW_ELAPSED=1
|
NOSE_OPENSTACK_SHOW_ELAPSED=1
|
||||||
deps = -r{toxinidir}/requirements.txt
|
deps = -r{toxinidir}/requirements.txt
|
||||||
-r{toxinidir}/test-requirements.txt
|
-r{toxinidir}/test-requirements.txt
|
||||||
commands = nosetests
|
|
||||||
|
|
||||||
[testenv:pep8]
|
[testenv:pep8]
|
||||||
deps = pep8==1.3.3
|
deps = pep8==1.3.3
|
||||||
commands = pep8 --repeat --show-source murano-repository setup.py
|
commands = pep8 --repeat --show-source muranorepository setup.py
|
||||||
|
|
||||||
[testenv:venv]
|
|
||||||
commands = {posargs}
|
|
||||||
|
|
||||||
[testenv:cover]
|
|
||||||
commands = nosetests --cover-erase --cover-package=murano-repository --with-xcoverage
|
|
||||||
|
|
||||||
[tox:jenkins]
|
|
||||||
downloadcache = ~/cache/pip
|
|
||||||
|
|
||||||
[testenv:jenkins26]
|
|
||||||
basepython = python2.6
|
|
||||||
setenv = NOSE_WITH_XUNIT=1
|
|
||||||
deps = file://{toxinidir}/.cache.bundle
|
|
||||||
|
|
||||||
[testenv:jenkins27]
|
|
||||||
basepython = python2.7
|
|
||||||
setenv = NOSE_WITH_XUNIT=1
|
|
||||||
deps = file://{toxinidir}/.cache.bundle
|
|
||||||
|
|
||||||
[testenv:jenkinscover]
|
|
||||||
deps = file://{toxinidir}/.cache.bundle
|
|
||||||
setenv = NOSE_WITH_XUNIT=1
|
|
||||||
commands = nosetests --cover-erase --cover-package=muranoapi --with-xcoverage
|
|
||||||
|
|
||||||
[testenv:jenkinsvenv]
|
|
||||||
deps = file://{toxinidir}/.cache.bundle
|
|
||||||
setenv = NOSE_WITH_XUNIT=1
|
|
||||||
commands = {posargs}
|
|
||||||
|
|
||||||
[testenv:pyflakes]
|
[testenv:pyflakes]
|
||||||
deps = flake8
|
deps = flake8
|
||||||
commands = flake8
|
commands = flake8
|
||||||
|
|
||||||
|
[testenv:venv]
|
||||||
|
commands = {posargs}
|
||||||
|
|
||||||
|
[testenv:cover]
|
||||||
|
commands = nosetests --cover-erase --cover-package=muranorepository --with-xcoverage
|
||||||
|
|
||||||
|
[tox:jenkins]
|
||||||
|
downloadcache = ~/cache/pip
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
# H301 one import per line
|
# H301 one import per line
|
||||||
# H302 import only modules
|
# H302 import only modules
|
||||||
ignore = H301,H302
|
# H201 no 'except:' at least use 'except Exception:'
|
||||||
|
ignore = H301,H302,F403,H201
|
||||||
show-source = true
|
show-source = true
|
||||||
builtins = _
|
builtins = _
|
||||||
exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,tools
|
exclude=.build,.venv,.git,.tox,dist,doc,*/openstack,*lib/python*,*egg,tools
|
||||||
|
Loading…
Reference in New Issue
Block a user