Fix for package import

Previous attempt to implement import of Murano packages was buggy.
It didn't assume that names in packages/application_package and in
db/models are different. We need to map names from one format to
another.

A big piece of functionality introduced in this patch is related
to archiving of package definition in a zip file. That is required
by our package format stored in the database.

Change-Id: I9660ba6fde00d777ec332c4912c972d1e2744718
This commit is contained in:
Ruslan Kamaldinov 2014-04-08 17:37:48 +04:00
parent 6291c85940
commit 25b551ddbb
3 changed files with 65 additions and 12 deletions

View File

@ -135,7 +135,7 @@ function init_murano() {
$MURANO_BIN_DIR/murano-manage --config-file $MURANO_CONF_FILE db-sync $MURANO_BIN_DIR/murano-manage --config-file $MURANO_CONF_FILE db-sync
$MURANO_BIN_DIR/murano-manage --config-file $MURANO_CONF_FILE import-package $MURANO_DIR/meta/io.murano $MURANO_BIN_DIR/murano-manage --config-file $MURANO_CONF_FILE import-package $MURANO_DIR/meta/io.murano
$MURANO_BIN_DIR/murano-manage --config-file $MURANO_CONF_FILE import-package $MURANO_DIR/meta/io.murano.windows.ActiveDirectory $MURANO_BIN_DIR/murano-manage --config-file $MURANO_CONF_FILE import-package $MURANO_DIR/meta/io.murano.windows.ActiveDirectory -c "Microsoft Services"
} }

View File

@ -17,10 +17,12 @@
""" """
import sys import sys
import traceback
from oslo.config import cfg from oslo.config import cfg
import muranoapi import muranoapi
from muranoapi.common import consts
from muranoapi.db.catalog import api as db_catalog_api from muranoapi.db.catalog import api as db_catalog_api
from muranoapi.db import session as db_session from muranoapi.db import session as db_session
from muranoapi.openstack.common import log as logging from muranoapi.openstack.common import log as logging
@ -40,20 +42,38 @@ def do_db_sync():
db_session.db_sync() db_session.db_sync()
def _do_import_package(_dir): def _do_import_package(_dir, categories):
LOG.info("Going to import Murano package from {0}".format(_dir)) LOG.info("Going to import Murano package from {0}".format(_dir))
pkg = application_package.load_from_dir(_dir) pkg = application_package.load_from_dir(_dir)
result = db_catalog_api.package_upload(pkg.__dict__, None) package = {
'fully_qualified_name': pkg.full_name,
'type': pkg.package_type,
'author': pkg.author,
'name': pkg.display_name,
'description': pkg.description,
# note: we explicitly mark all the imported packages as public,
# until a parameter added to control visibility scope of a package
'is_public': True,
#'tags': pkg.tags,
'logo': pkg.logo,
'ui_definition': pkg.raw_ui,
'class_definition': pkg.classes,
'archive': pkg.blob,
'categories': categories or []
}
# note(ruhe): the second parameter is tenant_id
# it is a required field in the DB, that's why we pass an empty string
result = db_catalog_api.package_upload(package, '')
LOG.info("Finished import of package {0}".format(result.id)) LOG.info("Finished import of package {0}".format(result.id))
# TODO(ruhe): proper error handling # TODO(ruhe): proper error handling
def do_import_package(): def do_import_package():
""" """
Import Murano packages from local directories. Import Murano package from local directory.
""" """
for _dir in CONF.command.directories: _do_import_package(CONF.command.directory, CONF.command.categories)
_do_import_package(_dir)
def add_command_parsers(subparsers): def add_command_parsers(subparsers):
@ -64,10 +84,14 @@ def add_command_parsers(subparsers):
parser = subparsers.add_parser('import-package') parser = subparsers.add_parser('import-package')
parser.set_defaults(func=do_import_package) parser.set_defaults(func=do_import_package)
parser.add_argument('directories', parser.add_argument('directory',
nargs='+', help='A directory with Murano package.')
help="list of directories with Murano packages "
"separated by space") parser.add_argument('-c', '--categories',
choices=consts.CATEGORIES,
nargs='*',
help='An optional list of categories this package '
'to be assigned to.')
command_opt = cfg.SubCommandOpt('command', command_opt = cfg.SubCommandOpt('command',
@ -85,13 +109,16 @@ def main():
default_config_files=default_config_files) default_config_files=default_config_files)
logging.setup("murano-api") logging.setup("murano-api")
except RuntimeError as e: except RuntimeError as e:
LOG.error("murano-manage command failed: %s" % e) LOG.error("failed to initialize murano-manage: %s" % e)
sys.exit("ERROR: %s" % e) sys.exit("ERROR: %s" % e)
try: try:
CONF.command.func() CONF.command.func()
except Exception as e: except Exception as e:
sys.exit("ERROR: %s" % e) tb = traceback.format_exc()
err_msg = "murano-manage command failed: {0}\n{1}".format(e, tb)
LOG.error(err_msg)
sys.exit(err_msg)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -21,6 +21,8 @@ import tempfile
import yaml import yaml
import zipfile import zipfile
from sqlalchemy.util import byte_buffer
import muranoapi.packages.exceptions as e import muranoapi.packages.exceptions as e
import muranoapi.packages.versions.v1 import muranoapi.packages.versions.v1
@ -60,6 +62,7 @@ class ApplicationPackage(object):
self._raw_ui_cache = None self._raw_ui_cache = None
self._logo_cache = None self._logo_cache = None
self._classes_cache = {} self._classes_cache = {}
self._blob_cache = None
@property @property
def full_name(self): def full_name(self):
@ -107,6 +110,12 @@ class ApplicationPackage(object):
self._load_logo(False) self._load_logo(False)
return self._logo_cache return self._logo_cache
@property
def blob(self):
if not self._blob_cache:
self._blob_cache = _pack_dir(self._source_directory)
return self._blob_cache
def get_class(self, name): def get_class(self, name):
if name not in self._classes_cache: if name not in self._classes_cache:
self._load_class(name) self._load_class(name)
@ -209,6 +218,23 @@ def load_from_dir(source_directory, filename='manifest.yaml', preload=False,
return package return package
def _zipdir(path, zipf):
for root, dirs, files in os.walk(path):
for f in files:
abspath = os.path.join(root, f)
relpath = os.path.relpath(abspath, path)
zipf.write(abspath, relpath)
def _pack_dir(source_directory):
blob = byte_buffer()
zipf = zipfile.ZipFile(blob, mode='w')
_zipdir(source_directory, zipf)
zipf.close()
return blob.getvalue()
def load_from_file(archive_path, target_dir=None, drop_dir=False, def load_from_file(archive_path, target_dir=None, drop_dir=False,
loader=DummyLoader): loader=DummyLoader):
if not os.path.isfile(archive_path): if not os.path.isfile(archive_path):