From 85d360873e617a242df4ccfeec9b86e4a1ee472d Mon Sep 17 00:00:00 2001 From: zhurong Date: Fri, 5 Aug 2016 08:09:24 +0000 Subject: [PATCH] Add package create to openstack CLI usage: openstack package create [-h] [-t ] [--classes-dir ] [-r ] [-n ] [--full-name ] [-a ] [--tags [ [ ...]]] [-d ] [-o ] [-u ] [--type ] [-l ] Create an application package. Partially implements: blueprint openstack-client-plugin-support Change-Id: I3d81540ede601fe96952dbda483b792924a6fac4 --- muranoclient/osc/v1/package.py | 138 ++++++++++++++++++ .../osc/v1/fixture_data/heat-template.yaml | 1 + .../tests/unit/osc/v1/fixture_data/logo.png | Bin 0 -> 11634 bytes .../test-app/Classes/testapp.yaml | 35 +++++ .../test-app/Resources/Deploy.template | 21 +++ .../test-app/Resources/scripts/common.sh | 1 + .../test-app/Resources/scripts/deploy.sh | 1 + .../test-app/Resources/scripts/installer.sh | 1 + .../unit/osc/v1/fixture_data/test-app/ui.yaml | 1 + .../tests/unit/osc/v1/test_package.py | 103 +++++++++++++ setup.cfg | 2 + 11 files changed, 304 insertions(+) create mode 100644 muranoclient/osc/v1/package.py create mode 100644 muranoclient/tests/unit/osc/v1/fixture_data/heat-template.yaml create mode 100644 muranoclient/tests/unit/osc/v1/fixture_data/logo.png create mode 100644 muranoclient/tests/unit/osc/v1/fixture_data/test-app/Classes/testapp.yaml create mode 100644 muranoclient/tests/unit/osc/v1/fixture_data/test-app/Resources/Deploy.template create mode 100644 muranoclient/tests/unit/osc/v1/fixture_data/test-app/Resources/scripts/common.sh create mode 100644 muranoclient/tests/unit/osc/v1/fixture_data/test-app/Resources/scripts/deploy.sh create mode 100644 muranoclient/tests/unit/osc/v1/fixture_data/test-app/Resources/scripts/installer.sh create mode 100644 muranoclient/tests/unit/osc/v1/fixture_data/test-app/ui.yaml create mode 100644 muranoclient/tests/unit/osc/v1/test_package.py diff --git a/muranoclient/osc/v1/package.py b/muranoclient/osc/v1/package.py new file mode 100644 index 00000000..31d3c78b --- /dev/null +++ b/muranoclient/osc/v1/package.py @@ -0,0 +1,138 @@ +# 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. + +"""Application-catalog v1 package action implementation""" + +import os +import shutil +import tempfile +import zipfile + +from muranoclient.v1.package_creator import hot_package +from muranoclient.v1.package_creator import mpl_package +from osc_lib.command import command +from osc_lib import exceptions as exc +from oslo_log import log as logging + +LOG = logging.getLogger(__name__) + + +class CreatePackage(command.Command): + """Create an application package.""" + + def get_parser(self, prog_name): + parser = super(CreatePackage, self).get_parser(prog_name) + parser.add_argument( + '-t', '--template', + metavar='', + help=("Path to the Heat template to import as " + "an Application Definition."), + ) + parser.add_argument( + '-c', '--classes-dir', + metavar='', + help=("Path to the directory containing application classes."), + ) + parser.add_argument( + '-r', '--resources-dir', + metavar='', + help=("Path to the directory containing application resources."), + ) + parser.add_argument( + '-n', '--name', + metavar='', + help=("Display name of the Application in Catalog."), + ) + parser.add_argument( + '-f', '--full-name', + metavar='', + help=("Fully-qualified name of the Application in Catalog."), + ) + parser.add_argument( + '-a', '--author', + metavar='', + help=("Name of the publisher."), + ) + parser.add_argument( + '--tags', + metavar='', + nargs='*', + help=("A list of keywords connected to the application."), + ) + parser.add_argument( + '-d', '--description', + metavar='', + help=("Detailed description for the Application in Catalog."), + ) + parser.add_argument( + '-o', '--output', + metavar='', + help=("The name of the output file archive to save locally."), + ) + parser.add_argument( + '-u', '--ui', + metavar='', + help=("Dynamic UI form definition."), + ) + parser.add_argument( + '--type', + metavar='', + help=("Package type. Possible values: Application or Library."), + ) + parser.add_argument( + '-l', '--logo', + metavar='', + help=("Path to the package logo."), + ) + + return parser + + def take_action(self, parsed_args): + LOG.debug("take_action({0})".format(parsed_args)) + parsed_args.os_username = os.getenv('OS_USERNAME') + + def _make_archive(archive_name, path): + zip_file = zipfile.ZipFile(archive_name, 'w') + for root, dirs, files in os.walk(path): + for f in files: + zip_file.write(os.path.join(root, f), + arcname=os.path.join( + os.path.relpath(root, path), f)) + + if parsed_args.template and parsed_args.classes_dir: + raise exc.CommandError( + "Provide --template for a HOT-based package, OR" + " --classes-dir for a MuranoPL-based package") + if not parsed_args.template and not parsed_args.classes_dir: + raise exc.CommandError( + "Provide --template for a HOT-based package, OR at least" + " --classes-dir for a MuranoPL-based package") + directory_path = None + try: + archive_name = parsed_args.output if parsed_args.output else None + if parsed_args.template: + directory_path = hot_package.prepare_package(parsed_args) + if not archive_name: + archive_name = os.path.basename(parsed_args.template) + archive_name = os.path.splitext(archive_name)[0] + ".zip" + else: + directory_path = mpl_package.prepare_package(parsed_args) + if not archive_name: + archive_name = tempfile.mkstemp( + prefix="murano_", dir=os.getcwd())[1] + ".zip" + + _make_archive(archive_name, directory_path) + print("Application package is available at " + + os.path.abspath(archive_name)) + finally: + if directory_path: + shutil.rmtree(directory_path) diff --git a/muranoclient/tests/unit/osc/v1/fixture_data/heat-template.yaml b/muranoclient/tests/unit/osc/v1/fixture_data/heat-template.yaml new file mode 100644 index 00000000..d7e80909 --- /dev/null +++ b/muranoclient/tests/unit/osc/v1/fixture_data/heat-template.yaml @@ -0,0 +1 @@ +heat_template_version: 2013-05-23 diff --git a/muranoclient/tests/unit/osc/v1/fixture_data/logo.png b/muranoclient/tests/unit/osc/v1/fixture_data/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e1a24717ead46edf8a7a111f11a97e48bde97693 GIT binary patch literal 11634 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 Cd~?zO literal 0 HcmV?d00001 diff --git a/muranoclient/tests/unit/osc/v1/fixture_data/test-app/Classes/testapp.yaml b/muranoclient/tests/unit/osc/v1/fixture_data/test-app/Classes/testapp.yaml new file mode 100644 index 00000000..95b1210a --- /dev/null +++ b/muranoclient/tests/unit/osc/v1/fixture_data/test-app/Classes/testapp.yaml @@ -0,0 +1,35 @@ +Namespaces: + =: io.murano.apps.test + std: io.murano + res: io.murano.resources + +Name: APP + +Extends: std:Application + +Properties: + name: + Contract: $.string().notNull() + + instance: + Contract: $.class(res:Instance).notNull() + + +Workflow: + initialize: + Body: + - $.environment: $.find(std:Environment).require() + + deploy: + Body: + - $securityGroupIngress: + - ToPort: 23 + FromPort: 23 + IpProtocol: tcp + External: True + - $.environment.securityGroupManager.addGroupIngress($securityGroupIngress) + - $.instance.deploy() + - $resources: new('io.murano.system.Resources') + - $template: $resources.yaml('Deploy.template') + - $.instance.agent.call($template, $resources) + diff --git a/muranoclient/tests/unit/osc/v1/fixture_data/test-app/Resources/Deploy.template b/muranoclient/tests/unit/osc/v1/fixture_data/test-app/Resources/Deploy.template new file mode 100644 index 00000000..04bd4d5e --- /dev/null +++ b/muranoclient/tests/unit/osc/v1/fixture_data/test-app/Resources/Deploy.template @@ -0,0 +1,21 @@ +FormatVersion: 2.0.0 +Version: 1.0.0 +Name: Deploy + +Parameters: + appName: $appName + +Body: | + return deploy(args.appName).stdout + +Scripts: + deploy: + Type: Application + Version: 1.0.0 + EntryPoint: deploy.sh + Files: + - installer.sh + - common.sh + Options: + captureStdout: true + captureStderr: false diff --git a/muranoclient/tests/unit/osc/v1/fixture_data/test-app/Resources/scripts/common.sh b/muranoclient/tests/unit/osc/v1/fixture_data/test-app/Resources/scripts/common.sh new file mode 100644 index 00000000..a9bf588e --- /dev/null +++ b/muranoclient/tests/unit/osc/v1/fixture_data/test-app/Resources/scripts/common.sh @@ -0,0 +1 @@ +#!/bin/bash diff --git a/muranoclient/tests/unit/osc/v1/fixture_data/test-app/Resources/scripts/deploy.sh b/muranoclient/tests/unit/osc/v1/fixture_data/test-app/Resources/scripts/deploy.sh new file mode 100644 index 00000000..a9bf588e --- /dev/null +++ b/muranoclient/tests/unit/osc/v1/fixture_data/test-app/Resources/scripts/deploy.sh @@ -0,0 +1 @@ +#!/bin/bash diff --git a/muranoclient/tests/unit/osc/v1/fixture_data/test-app/Resources/scripts/installer.sh b/muranoclient/tests/unit/osc/v1/fixture_data/test-app/Resources/scripts/installer.sh new file mode 100644 index 00000000..a9bf588e --- /dev/null +++ b/muranoclient/tests/unit/osc/v1/fixture_data/test-app/Resources/scripts/installer.sh @@ -0,0 +1 @@ +#!/bin/bash diff --git a/muranoclient/tests/unit/osc/v1/fixture_data/test-app/ui.yaml b/muranoclient/tests/unit/osc/v1/fixture_data/test-app/ui.yaml new file mode 100644 index 00000000..939ba388 --- /dev/null +++ b/muranoclient/tests/unit/osc/v1/fixture_data/test-app/ui.yaml @@ -0,0 +1 @@ +Version: 2 diff --git a/muranoclient/tests/unit/osc/v1/test_package.py b/muranoclient/tests/unit/osc/v1/test_package.py new file mode 100644 index 00000000..28a4f575 --- /dev/null +++ b/muranoclient/tests/unit/osc/v1/test_package.py @@ -0,0 +1,103 @@ +# 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 +import six +import sys +import tempfile + +from testtools import matchers + +from muranoclient.osc.v1 import package as osc_pkg +from muranoclient.tests.unit.osc.v1 import fakes + +from osc_lib import exceptions as exc + +FIXTURE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), + 'fixture_data')) + + +class TestPackage(fakes.TestApplicationCatalog): + def setUp(self): + super(TestPackage, self).setUp() + self.package_mock = self.app.client_manager.application_catalog.\ + packages + self.package_mock.reset_mock() + + +class TestCreatePackage(TestPackage): + def setUp(self): + super(TestCreatePackage, self).setUp() + + # Command to test + self.cmd = osc_pkg.CreatePackage(self.app, None) + + def test_create_package_without_args(self): + arglist = [] + parsed_args = self.check_parser(self.cmd, arglist, []) + error = self.assertRaises(exc.CommandError, + self.cmd.take_action, parsed_args) + self.assertEqual('Provide --template for a HOT-based package, OR at ' + 'least --classes-dir for a MuranoPL-based package', + str(error)) + + def test_create_package_template_and_classes_args(self): + heat_template = os.path.join(FIXTURE_DIR, 'heat-template.yaml') + classes_dir = os.path.join(FIXTURE_DIR, 'test-app', 'Classes') + arglist = ['--template', heat_template, '--classes-dir', classes_dir] + parsed_args = self.check_parser(self.cmd, arglist, []) + error = self.assertRaises(exc.CommandError, + self.cmd.take_action, parsed_args) + self.assertEqual('Provide --template for a HOT-based package, OR' + ' --classes-dir for a MuranoPL-based package', + str(error)) + + def test_create_hot_based_package(self): + with tempfile.NamedTemporaryFile() as f: + RESULT_PACKAGE = f.name + heat_template = os.path.join(FIXTURE_DIR, 'heat-template.yaml') + logo = os.path.join(FIXTURE_DIR, 'logo.png') + arglist = ['--template', heat_template, '--output', RESULT_PACKAGE, + '-l', logo] + parsed_args = self.check_parser(self.cmd, arglist, []) + orig = sys.stdout + try: + sys.stdout = six.StringIO() + self.cmd.take_action(parsed_args) + finally: + stdout = sys.stdout.getvalue() + sys.stdout.close() + sys.stdout = orig + matchers.MatchesRegex(stdout, + "Application package " + "is available at {0}".format(RESULT_PACKAGE)) + + def test_create_mpl_package(self): + with tempfile.NamedTemporaryFile() as f: + RESULT_PACKAGE = f.name + classes_dir = os.path.join(FIXTURE_DIR, 'test-app', 'Classes') + resources_dir = os.path.join(FIXTURE_DIR, 'test-app', 'Resources') + ui = os.path.join(FIXTURE_DIR, 'test-app', 'ui.yaml') + arglist = ['-c', classes_dir, '-r', resources_dir, + '-u', ui, '-o', RESULT_PACKAGE] + parsed_args = self.check_parser(self.cmd, arglist, []) + orig = sys.stdout + try: + sys.stdout = six.StringIO() + self.cmd.take_action(parsed_args) + finally: + stdout = sys.stdout.getvalue() + sys.stdout.close() + sys.stdout = orig + matchers.MatchesRegex(stdout, + "Application package " + "is available at {0}".format(RESULT_PACKAGE)) diff --git a/setup.cfg b/setup.cfg index 37b246e5..9d2b21c3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -51,6 +51,8 @@ openstack.application_catalog.v1 = deployment_list = muranoclient.osc.v1.deployment:ListDeployment + package_create = muranoclient.osc.v1.package:CreatePackage + static-action_call = muranoclient.osc.v1.action:StaticActionCall class-schema = muranoclient.osc.v1.schema:ShowSchema