Merge "Client support for Require section in manifest"

This commit is contained in:
Jenkins 2015-03-13 11:29:50 +00:00 committed by Gerrit Code Review
commit 51058b6238
4 changed files with 122 additions and 53 deletions

View File

@ -15,14 +15,17 @@
from __future__ import print_function
import logging
import os
import re
import StringIO
import sys
import tempfile
import textwrap
import types
import urlparse
import uuid
import zipfile
from oslo.serialization import jsonutils
from oslo.utils import encodeutils
@ -36,6 +39,8 @@ import yaql.exceptions
from muranoclient.common import exceptions
LOG = logging.getLogger(__name__)
# Decorator for cli-args
def arg(*args, **kwargs):
@ -250,6 +255,47 @@ class Package(FileWrapperMixin):
file_obj = File(file_obj)
return Package(file_obj)
@property
def manifest(self):
"""Parsed manifest file of a package."""
if not hasattr(self, '_manifest'):
try:
self._file.seek(0)
zip_obj = zipfile.ZipFile(
StringIO.StringIO(self._file.read()))
self._manifest = yaml.safe_load(zip_obj.open('manifest.yaml'))
except (zipfile.BadZipfile, KeyError, yaml.error.YAMLError) as e:
LOG.exception("An error occurred,"
" while extracting manifest from package")
raise ValueError(e)
return self._manifest
def requirements(self, base_url, dep_dict=None):
"""Recursively scan Require section of manifests of all the
dependencies. Returns a dict with FQPNs as keys and respective
PackageFiles as values
"""
if not dep_dict:
dep_dict = {}
dep_dict[self.manifest['FullName']] = self
if 'Require' in self.manifest:
for dep_name, ver in self.manifest['Require'].iteritems():
if dep_name in dep_dict:
continue
try:
dep_url = to_url(dep_name, base_url, version=ver,
path='/apps/', extension='.zip')
req_file = Package.fromFile(dep_url)
dep_dict.update(req_file.requirements(
base_url=base_url, dep_dict=dep_dict))
except Exception:
LOG.exception("Error occured during parsing dependecies "
"of {0} requirement".format(
self.manifest['FullName']))
continue
return dep_dict
class Bundle(FileWrapperMixin):
"""Represents murano bundle contents."""
@ -269,7 +315,7 @@ class Bundle(FileWrapperMixin):
pass
if bundle is None:
try:
bundle = yaml.load(self._file)
bundle = yaml.safe_load(self._file)
except yaml.error.YAMLError:
pass

View File

@ -14,6 +14,7 @@
import os
import re
import StringIO
import sys
import tempfile
@ -23,6 +24,7 @@ import requests
import six
from testtools import matchers
from muranoclient.common import utils
from muranoclient.openstack.common.apiclient import exceptions
import muranoclient.shell
from muranoclient.tests import base
@ -281,13 +283,16 @@ class ShellPackagesOperations(ShellTest):
args.categories = ['Cat1', 'Cat2 with space']
args.is_public = True
v1_shell.do_package_import(self.client, args)
result = {RESULT_PACKAGE: utils.Package.fromFile(
StringIO.StringIO("123"))}
with mock.patch(
'muranoclient.common.utils.Package.requirements',
mock.Mock(side_effect=lambda *args, **kwargs: result)):
v1_shell.do_package_import(self.client, args)
self.client.packages.create.assert_called_once_with(
{'categories': ['Cat1', 'Cat2 with space'], 'is_public': True},
((RESULT_PACKAGE, mock.ANY),),
murano_repo_url=args.murano_repo_url,
version=args.version,
{RESULT_PACKAGE: mock.ANY},
)
def test_package_import_no_categories(self):
@ -299,13 +304,17 @@ class ShellPackagesOperations(ShellTest):
args.categories = None
args.is_public = False
v1_shell.do_package_import(self.client, args)
result = {RESULT_PACKAGE: utils.Package.fromFile(
StringIO.StringIO("123"))}
with mock.patch(
'muranoclient.common.utils.Package.requirements',
mock.Mock(side_effect=lambda *args, **kwargs: result)):
v1_shell.do_package_import(self.client, args)
self.client.packages.create.assert_called_once_with(
{'is_public': False},
((RESULT_PACKAGE, mock.ANY),),
murano_repo_url=args.murano_repo_url,
version=args.version,
{RESULT_PACKAGE: mock.ANY},
)
def test_package_import_url(self):
@ -317,21 +326,24 @@ class ShellPackagesOperations(ShellTest):
resp = requests.Response()
resp.status_code = 200
resp.raw = True
resp.raw = StringIO.StringIO("123")
result = {args.filename: utils.Package.fromFile(
StringIO.StringIO("123"))}
with mock.patch(
'requests.get',
mock.Mock(side_effect=lambda k, *args, **kwargs: resp)):
with mock.patch(
'muranoclient.common.utils.Package.requirements',
mock.Mock(side_effect=lambda *args, **kwargs: result)):
v1_shell.do_package_import(self.client, args)
v1_shell.do_package_import(self.client, args)
self.client.packages.create.assert_called_once_with(
{'is_public': False},
((args.filename, mock.ANY),),
murano_repo_url=args.murano_repo_url,
version=args.version,
{args.filename: mock.ANY},
)
def test_package_import_fqpn(self):
def test_package_import_by_name(self):
args = TestArgs()
args.filename = "io.test.apps.test_application"
@ -341,17 +353,19 @@ class ShellPackagesOperations(ShellTest):
resp = requests.Response()
resp.status_code = 200
resp.raw = True
resp.raw = StringIO.StringIO("123")
result = {args.filename: utils.Package.fromFile(
StringIO.StringIO("123"))}
with mock.patch(
'requests.get',
mock.Mock(side_effect=lambda k, *args, **kwargs: resp)):
v1_shell.do_package_import(self.client, args)
with mock.patch(
'muranoclient.common.utils.Package.requirements',
mock.Mock(side_effect=lambda *args, **kwargs: result)):
v1_shell.do_package_import(self.client, args)
self.assertTrue(self.client.packages.create.called)
self.client.packages.create.assert_called_once_with(
{'is_public': False},
((args.filename, mock.ANY),),
murano_repo_url=args.murano_repo_url,
version=args.version,
{args.filename: mock.ANY},
)

View File

@ -12,19 +12,20 @@
# License for the specific language governing permissions and limitations
# under the License.
import logging
import urllib
from oslo.serialization import jsonutils
import requests
import six
import yaml
from muranoclient.common import base
from muranoclient.common import exceptions
from muranoclient.common import http
from muranoclient.common import utils
LOG = logging.getLogger(__name__)
DEFAULT_PAGE_SIZE = 20
@ -49,27 +50,13 @@ class Category(base.Resource):
class PackageManager(base.Manager):
resource_class = Package
_tracked_packages = set()
def categories(self):
return self._list('/v1/catalog/packages/categories',
response_key='categories', obj_class=Category)
def create(self, data, files, version='', murano_repo_url=None):
files = requests.utils.to_key_val_list(files)
if not files:
raise ValueError("No files to import")
name, file_name = files[0]
if isinstance(file_name, six.string_types):
file_name = utils.to_url(
file_name,
base_url=murano_repo_url,
version=version,
path='/apps/',
extension='.zip')
package = utils.Package.fromFile(file_name)
files = [(name, package.file(), )]
def create(self, data, files):
data = {'data': jsonutils.dumps(data)}
url = '{0}/v1/catalog/packages'.format(self.api.endpoint)
headers = {'X-Auth-Token': self.api.auth_token}

View File

@ -193,7 +193,7 @@ def do_package_delete(mc, args):
help='Make package available for user from other tenants')
@utils.arg('--version', default='',
help='Version of the package to use from repository')
def do_package_import(mc, args, list_packages=True):
def do_package_import(mc, args):
"""Import a package.
`FILE` can be either a path to a zip file, url or a FQPN.
`categories` could be separated by a comma
@ -206,12 +206,23 @@ def do_package_import(mc, args, list_packages=True):
filename = args.filename
if os.path.isfile(filename):
filename = open(filename, 'rb')
mc.packages.create(data, ((args.filename, filename),),
version=args.version,
murano_repo_url=args.murano_repo_url)
if list_packages:
do_package_list(mc)
else:
filename = utils.to_url(
filename,
version=args.version,
base_url=args.murano_repo_url,
extension='.zip',
path='apps/',
)
package = utils.Package.fromFile(filename)
reqs = package.requirements(base_url=args.murano_repo_url)
for name, package in reqs.iteritems():
try:
mc.packages.create(data, {name: package.file()})
except Exception as e:
print("Error {0} occurred while installing package {1}".format(
e, name))
do_package_list(mc)
@utils.arg('filename', metavar='<FILE>',
@ -230,15 +241,26 @@ def do_bundle_import(mc, args):
data = {"is_public": args.is_public}
for package in bundle_file.packages():
for package_info in bundle_file.packages():
try:
mc.packages.create(data, ((package['Name'], package['Name']),),
version=package.get('Version'),
murano_repo_url=args.murano_repo_url)
package = utils.Package.fromFile(
utils.to_url(
package_info['Name'],
version=package_info.get('Version'),
base_url=args.murano_repo_url,
extension='.zip',
path='apps/',
))
except Exception as e:
print("Error '{0}' occurred during import of {1} package".format(
e, package['Name']))
print("Error {0} occurred while "
"parsing package {1}".format(e, package_info['Name']))
reqs = package.requirements(base_url=args.murano_repo_url)
for name, package in reqs.iteritems():
try:
mc.packages.create(data, {name: package.file()})
except Exception as e:
print("Error {0} occurred while "
"installing package {1}".format(e, name))
do_package_list(mc)