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
|
||||
Author: efedorova <efedorova@mirantis.com>
|
||||
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 *
|
||||
|
||||
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 .gitreview
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[DEFAULT]
|
||||
# Address to bind the server to
|
||||
host = 172.18.10.111
|
||||
host = localhost
|
||||
#Port the bind the server to
|
||||
port = 5000
|
||||
|
||||
|
@ -10,4 +10,4 @@
|
||||
# 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.
|
||||
# under the License.
|
||||
|
@ -10,4 +10,4 @@
|
||||
# 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.
|
||||
# under the License.
|
||||
|
@ -1,19 +1,20 @@
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
from flask import Blueprint, make_response, send_file
|
||||
|
||||
from flask import Blueprint, send_file
|
||||
from flask import jsonify, request, abort
|
||||
from werkzeug import secure_filename
|
||||
|
||||
@ -26,116 +27,132 @@ CONF = cfg.CONF
|
||||
v1_api = Blueprint('v1', __name__)
|
||||
|
||||
|
||||
@v1_api.route('/client/ui')
|
||||
def get_ui_data():
|
||||
def get_archive(client):
|
||||
parser = ManifestParser(CONF.manifests)
|
||||
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')
|
||||
def get_conductor_data():
|
||||
parser = ManifestParser(CONF.manifests)
|
||||
manifests = parser.parse()
|
||||
archive_name = Archiver().create(manifests,
|
||||
"heat",
|
||||
"agent",
|
||||
"scripts")
|
||||
return send_file(archive_name)
|
||||
return send_file(get_archive('conductor'))
|
||||
|
||||
|
||||
@v1_api.route('/admin/<data_type>', methods=['GET', 'POST'])
|
||||
@v1_api.route('/admin/<data_type>')
|
||||
def get_data_type_locations(data_type):
|
||||
####### validation ########
|
||||
if data_type not in DATA_TYPES:
|
||||
abort(404)
|
||||
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)
|
||||
check_data_type(data_type)
|
||||
result_path = compose_path(data_type)
|
||||
return get_locations(data_type, result_path)
|
||||
|
||||
|
||||
@v1_api.route('/admin/<data_type>/<path:path>', methods=['GET', 'POST'])
|
||||
def get_data_type_locations_by_path_or_get_file(data_type, path):
|
||||
if data_type not in DATA_TYPES:
|
||||
abort(404)
|
||||
result_path = os.path.join(os.path.join(CONF.manifests,
|
||||
getattr(CONF, data_type),
|
||||
path))
|
||||
@v1_api.route('/admin/<data_type>', methods=['POST'])
|
||||
def upload_file(data_type):
|
||||
check_data_type(data_type)
|
||||
result_path = compose_path(data_type)
|
||||
try:
|
||||
return save_file(request, result_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):
|
||||
abort(404)
|
||||
|
||||
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)
|
||||
if os.path.isfile(result_path):
|
||||
try:
|
||||
os.makedirs(result_path)
|
||||
except Exception as e:
|
||||
abort(403)
|
||||
return resp
|
||||
|
||||
if request.method == 'DELETE':
|
||||
if not os.path.exists(result_path):
|
||||
os.remove(result_path)
|
||||
except Exception:
|
||||
abort(404)
|
||||
if os.path.isfile(result_path):
|
||||
try:
|
||||
os.remove(result_path)
|
||||
except Exception as e:
|
||||
abort(404)
|
||||
else:
|
||||
try:
|
||||
os.rmdir(result_path)
|
||||
except Exception as e:
|
||||
abort(403)
|
||||
resp = make_response()
|
||||
return resp
|
||||
else:
|
||||
try:
|
||||
os.rmdir(result_path)
|
||||
except Exception:
|
||||
abort(403)
|
||||
return jsonify(result='success')
|
||||
|
@ -10,4 +10,4 @@
|
||||
# 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.
|
||||
# under the License.
|
||||
|
@ -28,8 +28,8 @@ possible_topdir = os.path.normpath(os.path.join(os.path.abspath(__file__),
|
||||
os.pardir,
|
||||
os.pardir))
|
||||
if os.path.exists(os.path.join(possible_topdir,
|
||||
'muranorepository',
|
||||
'__init__.py')):
|
||||
'muranorepository',
|
||||
'__init__.py')):
|
||||
sys.path.insert(0, possible_topdir)
|
||||
|
||||
from muranorepository import config
|
||||
@ -43,7 +43,7 @@ LOG = log.getLogger(__name__)
|
||||
def main():
|
||||
dev_conf = os.path.join(possible_topdir,
|
||||
'etc',
|
||||
'muranorepository.conf')
|
||||
'murano-repository.conf')
|
||||
config_files = None
|
||||
if os.path.exists(dev_conf):
|
||||
config_files = [dev_conf]
|
||||
|
@ -20,4 +20,4 @@ HEAT = 'heat'
|
||||
AGENT = 'agent'
|
||||
SCRIPTS = 'scripts'
|
||||
|
||||
DATA_TYPES = [UI, WORKFLOW, HEAT, AGENT, SCRIPTS, MANIFEST]
|
||||
DATA_TYPES = [UI, WORKFLOW, HEAT, AGENT, SCRIPTS, MANIFEST]
|
||||
|
@ -16,4 +16,4 @@
|
||||
class Manifest(object):
|
||||
def __init__(self, initial_data):
|
||||
for key in initial_data:
|
||||
setattr(self, key, initial_data[key])
|
||||
setattr(self, key, initial_data[key])
|
||||
|
@ -104,8 +104,7 @@ def _listen(host, start_port, end_port, listen_func):
|
||||
try:
|
||||
return listen_func((host, try_port))
|
||||
except socket.error as exc:
|
||||
if (exc.errno != errno.EADDRINUSE or
|
||||
try_port >= end_port):
|
||||
if (exc.errno != errno.EADDRINUSE or try_port >= end_port):
|
||||
raise
|
||||
try_port += 1
|
||||
|
||||
|
@ -425,7 +425,8 @@ def _setup_logging_from_conf():
|
||||
|
||||
if CONF.publish_errors:
|
||||
handler = importutils.import_object(
|
||||
"muranorepository.openstack.common.log_handler.PublishErrorsHandler",
|
||||
"muranorepository.openstack.common.log_handler."
|
||||
"PublishErrorsHandler",
|
||||
logging.ERROR)
|
||||
log_root.addHandler(handler)
|
||||
|
||||
|
@ -29,7 +29,8 @@ class BaseTestCase(testtools.TestCase):
|
||||
super(BaseTestCase, self).setUp()
|
||||
self._set_timeout()
|
||||
self._fake_output()
|
||||
self.useFixture(fixtures.FakeLogger('muranorepository.openstack.common'))
|
||||
self.useFixture(
|
||||
fixtures.FakeLogger('muranorepository.openstack.common'))
|
||||
self.useFixture(fixtures.NestedTempfile())
|
||||
|
||||
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)
|
@ -10,4 +10,4 @@
|
||||
# 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.
|
||||
# under the License.
|
||||
|
@ -18,16 +18,44 @@ import shutil
|
||||
import logging as log
|
||||
from oslo.config import cfg
|
||||
from muranorepository.consts import DATA_TYPES
|
||||
OUTPUT_CONF = cfg.CONF.output
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
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):
|
||||
"""
|
||||
manifests -- list of Manifest objects
|
||||
*types - desired data types to be added to archive
|
||||
|
||||
return: absolute path to created archive
|
||||
"""
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
for data_type in types:
|
||||
@ -38,44 +66,18 @@ class Archiver(object):
|
||||
for manifest in manifests:
|
||||
if not manifest.enabled and not manifest.valid:
|
||||
continue
|
||||
|
||||
if hasattr(manifest, data_type):
|
||||
file_list = getattr(manifest, data_type)
|
||||
dst_directory = os.path.join(temp_dir,
|
||||
getattr(OUTPUT_CONF,
|
||||
getattr(CONF.output,
|
||||
data_type))
|
||||
scr_directory = os.path.join(CONF.manifests,
|
||||
getattr(CONF, data_type))
|
||||
|
||||
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))
|
||||
self._copy_data(file_list, scr_directory, dst_directory)
|
||||
else:
|
||||
log.info(
|
||||
"Manifest for {0} service has no file definitions for "
|
||||
"{1}".format(manifest.service_display_name, data_type))
|
||||
|
||||
target_archive = "service_metadata.tar"
|
||||
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)
|
||||
|
||||
|
||||
|
||||
|
||||
return self._compose_archive(temp_dir)
|
||||
|
@ -32,7 +32,8 @@ author-email = openstack-dev@lists.openstack.org
|
||||
home-page = https://launchpad.net/murano
|
||||
|
||||
[global]
|
||||
setup-hooks = pbr.hooks.setup_hook
|
||||
setup-hooks =
|
||||
pbr.hooks.setup_hook
|
||||
|
||||
[files]
|
||||
packages =
|
||||
@ -54,8 +55,9 @@ tag_date = 0
|
||||
tag_svn_revision = 0
|
||||
|
||||
[compile_catalog]
|
||||
directory = murano-repository/locale
|
||||
domain = murano-repository
|
||||
directory = muranorepository/locale
|
||||
domain = muranorepository
|
||||
|
||||
|
||||
[extract_messages]
|
||||
keywords = _ gettext ngettext l_ lazy_gettext
|
||||
|
@ -2,16 +2,11 @@
|
||||
pep8==1.4.5
|
||||
pyflakes>=0.7.2,<0.7.4
|
||||
flake8==2.0
|
||||
hacking>=0.5.6,<0.8
|
||||
|
||||
coverage>=3.6
|
||||
flask-testing
|
||||
docutils==0.9.1
|
||||
fixtures>=0.3.14
|
||||
mock>=1.0
|
||||
nose
|
||||
openstack.nose_plugin>=0.7
|
||||
mockfs
|
||||
oslo.sphinx
|
||||
pylint==0.25.2
|
||||
sphinx>=1.1.2
|
||||
sphinxcontrib-httpdomain
|
||||
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
|
||||
deps = -r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
commands = nosetests
|
||||
|
||||
[testenv:pep8]
|
||||
deps = pep8==1.3.3
|
||||
commands = pep8 --repeat --show-source murano-repository 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}
|
||||
commands = pep8 --repeat --show-source muranorepository setup.py
|
||||
|
||||
[testenv:pyflakes]
|
||||
deps = flake8
|
||||
commands = flake8
|
||||
|
||||
[testenv:venv]
|
||||
commands = {posargs}
|
||||
|
||||
[testenv:cover]
|
||||
commands = nosetests --cover-erase --cover-package=muranorepository --with-xcoverage
|
||||
|
||||
[tox:jenkins]
|
||||
downloadcache = ~/cache/pip
|
||||
|
||||
[flake8]
|
||||
# H301 one import per line
|
||||
# H302 import only modules
|
||||
ignore = H301,H302
|
||||
# H201 no 'except:' at least use 'except Exception:'
|
||||
ignore = H301,H302,F403,H201
|
||||
show-source = true
|
||||
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