diff --git a/murano_tempest_tests/config.py b/murano_tempest_tests/config.py
index fe0d2e239..a88e2af15 100644
--- a/murano_tempest_tests/config.py
+++ b/murano_tempest_tests/config.py
@@ -49,6 +49,10 @@ ApplicationCatalogGroup = [
"If no such region is found in the service catalog, "
"the first found one is used."),
+ cfg.StrOpt("linux_image",
+ default="debian-8-m-agent.qcow2",
+ help="Image for linux services"),
+
cfg.StrOpt("catalog_type",
default="application-catalog",
help="Catalog type of Application Catalog."),
@@ -70,7 +74,14 @@ ApplicationCatalogGroup = [
cfg.BoolOpt("glare_backend",
default=False,
help="Tells tempest about murano glare backend "
- "configuration.")
+ "configuration."),
+ cfg.BoolOpt("cinder_volume_tests",
+ default=False,
+ help="Whether or not cinder volumes attachment tests "
+ "are expected to run"),
+ cfg.BoolOpt("deployment_tests",
+ default=False,
+ help="Whether or not deployment tests are expected to run")
]
ServiceBrokerGroup = [
diff --git a/murano_tempest_tests/extras/io.murano.apps.test.ApacheHttpServerCustom/Classes/ApacheHttpServer.yaml b/murano_tempest_tests/extras/io.murano.apps.test.ApacheHttpServerCustom/Classes/ApacheHttpServer.yaml
new file mode 100644
index 000000000..cd13ff970
--- /dev/null
+++ b/murano_tempest_tests/extras/io.murano.apps.test.ApacheHttpServerCustom/Classes/ApacheHttpServer.yaml
@@ -0,0 +1,81 @@
+# 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.
+
+Namespaces:
+ =: io.murano.apps.test
+ std: io.murano
+ res: io.murano.resources
+ sys: io.murano.system
+ conf: io.murano.configuration
+
+
+Name: ApacheHttpServerCustom
+
+Extends: std:Application
+
+Properties:
+ name:
+ Contract: $.string().notNull()
+
+ instance:
+ Contract: $.class(res:Instance).notNull()
+
+ userName:
+ Contract: $.string()
+
+Methods:
+ initialize:
+ Body:
+ - $._environment: $.find(std:Environment).require()
+
+ deploy:
+ Body:
+ - If: not $.getAttr(deployed, false)
+ Then:
+ - $._environment.reporter.report($this, 'Creating VM for Apache Server.')
+ - $securityGroupIngress:
+ - ToPort: 80
+ FromPort: 80
+ IpProtocol: tcp
+ External: true
+ - ToPort: 443
+ FromPort: 443
+ IpProtocol: tcp
+ External: true
+ - $._environment.securityGroupManager.addGroupIngress($securityGroupIngress)
+ - $.instance.deploy()
+ - $._environment.reporter.report($this, 'Instance is created. Deploying Apache')
+
+ - $resources: new(sys:Resources)
+ - $linux: new(conf:Linux)
+
+ - $linux.runCommand($.instance.agent, 'apt-get -y install apache2')
+ - $linux.runCommand($.instance.agent, 'iptables -I INPUT 1 -p tcp --dport 443 -j ACCEPT')
+ - $linux.runCommand($.instance.agent, 'iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT')
+ - $._environment.reporter.report($this, 'Apache is installed.')
+
+ - If: $.userName != ''
+ Then:
+ - $linux.runCommand($.instance.agent, 'service apache2 stop')
+ - $fileReplacements:
+ "%USER_NAME%": $.userName
+ - $fileContent: $resources.string('index.html').replace($fileReplacements)
+ - $linux.putFile($.instance.agent, $fileContent, '/var/www/html/index.html')
+ - $linux.runCommand($.instance.agent, 'service apache2 start')
+
+ - If: $.instance.assignFloatingIp
+ Then:
+ - $host: $.instance.floatingIpAddress
+ Else:
+ - $host: $.instance.ipAddresses[0]
+ - $._environment.reporter.report($this, format('Apache is available at http://{0}', $host))
+ - $.setAttr(deployed, true)
diff --git a/murano_tempest_tests/extras/io.murano.apps.test.ApacheHttpServerCustom/Resources/index.html b/murano_tempest_tests/extras/io.murano.apps.test.ApacheHttpServerCustom/Resources/index.html
new file mode 100644
index 000000000..68436975b
--- /dev/null
+++ b/murano_tempest_tests/extras/io.murano.apps.test.ApacheHttpServerCustom/Resources/index.html
@@ -0,0 +1,8 @@
+
+
+
+ Hello World
+
+Hello world. This is my first web page. My name is %USER_NAME%.
+
+
diff --git a/murano_tempest_tests/extras/io.murano.apps.test.ApacheHttpServerCustom/manifest.yaml b/murano_tempest_tests/extras/io.murano.apps.test.ApacheHttpServerCustom/manifest.yaml
new file mode 100644
index 000000000..b0ab7c3d7
--- /dev/null
+++ b/murano_tempest_tests/extras/io.murano.apps.test.ApacheHttpServerCustom/manifest.yaml
@@ -0,0 +1,28 @@
+# 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.
+
+Format: 1.0
+Type: Application
+FullName: io.murano.test.apache.ApacheHttpServerCustom
+Name: Apache HTTP Server Custom
+Description: |
+ The Apache HTTP Server Project is an effort to develop and maintain an
+ open-source HTTP server for modern operating systems including UNIX and
+ Windows NT. The goal of this project is to provide a secure, efficient and
+ extensible server that provides HTTP services in sync with the current HTTP
+ standards.
+ Apache httpd has been the most popular web server on the Internet since
+ April 1996, and celebrated its 17th birthday as a project this February.
+Author: 'Mirantis, Inc'
+Tags: [HTTP, Server, WebServer, HTML, Apache]
+Classes:
+ io.murano.apps.test.ApacheHttpServerCustom: ApacheHttpServer.yaml
diff --git a/murano_tempest_tests/extras/io.murano.apps.test.Lighttpd/Classes/Lighttpd.yaml b/murano_tempest_tests/extras/io.murano.apps.test.Lighttpd/Classes/Lighttpd.yaml
new file mode 100644
index 000000000..c719f1204
--- /dev/null
+++ b/murano_tempest_tests/extras/io.murano.apps.test.Lighttpd/Classes/Lighttpd.yaml
@@ -0,0 +1,55 @@
+# 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.
+
+Namespaces:
+ =: io.murano.apps.test
+ std: io.murano
+ sys: io.murano.system
+
+Name: Lighttpd
+
+Extends: std:Application
+
+Properties:
+ updater:
+ Contract: $.class(UpdateExecutor).notNull()
+
+Methods:
+ initialize:
+ Body:
+ - $._environment: $.find(std:Environment).require()
+
+ deploy:
+ Body:
+ - If: not $.getAttr(deployed, false)
+ Then:
+ - $securityGroupIngress:
+ - ToPort: 80
+ FromPort: 80
+ IpProtocol: tcp
+ External: true
+ - ToPort: 443
+ FromPort: 443
+ IpProtocol: tcp
+ External: true
+ - $._environment.securityGroupManager.addGroupIngress($securityGroupIngress)
+ - $._environment.reporter.report($this, 'Ensuring Updater is deployed.')
+ - $.updater.deploy()
+ - $resources: new(sys:Resources)
+ - $template: $resources.yaml('DeployLighttpd.template')
+ - $.updater.instance.agent.call($template, $resources)
+
+ - If: $.updater.instance.assignFloatingIp
+ Then:
+ - $address: $.updater.instance.floatingIpAddress
+ - $._environment.reporter.report($this, format('Running at http://{0}', $address))
+ - $.setAttr(deployed, true)
diff --git a/murano_tempest_tests/extras/io.murano.apps.test.Lighttpd/Resources/DeployLighttpd.template b/murano_tempest_tests/extras/io.murano.apps.test.Lighttpd/Resources/DeployLighttpd.template
new file mode 100644
index 000000000..7eba0d5a6
--- /dev/null
+++ b/murano_tempest_tests/extras/io.murano.apps.test.Lighttpd/Resources/DeployLighttpd.template
@@ -0,0 +1,27 @@
+# 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.
+
+FormatVersion: 2.0.0
+Version: 1.0.0
+Name: Deploy Lighttpd
+
+Body: |
+ deploy()
+
+Scripts:
+ deploy:
+ Type: Application
+ Version: 1.0.0
+ EntryPoint: deployLighttpd.sh
+ Options:
+ captureStdout: true
+ captureStderr: true
diff --git a/murano_tempest_tests/extras/io.murano.apps.test.Lighttpd/Resources/scripts/deployLighttpd.sh b/murano_tempest_tests/extras/io.murano.apps.test.Lighttpd/Resources/scripts/deployLighttpd.sh
new file mode 100644
index 000000000..09dcd46b6
--- /dev/null
+++ b/murano_tempest_tests/extras/io.murano.apps.test.Lighttpd/Resources/scripts/deployLighttpd.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+# 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.
+
+sudo apt-get -y -q install lighttpd
diff --git a/murano_tempest_tests/extras/io.murano.apps.test.Lighttpd/manifest.yaml b/murano_tempest_tests/extras/io.murano.apps.test.Lighttpd/manifest.yaml
new file mode 100644
index 000000000..5bdb9029f
--- /dev/null
+++ b/murano_tempest_tests/extras/io.murano.apps.test.Lighttpd/manifest.yaml
@@ -0,0 +1,24 @@
+# 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.
+
+Format: 1.0
+Type: Application
+FullName: io.murano.apps.test.Lighttpd
+Name: Lighttpd
+Description: |
+ Lighttpd... :)
+Author: 'Mirantis, Inc'
+Tags: [Web]
+Classes:
+ io.murano.apps.test.Lighttpd: Lighttpd.yaml
+Require:
+ io.murano.apps.test.UpdateExecutor:
diff --git a/murano_tempest_tests/extras/io.murano.apps.test.UpdateExecutor/Classes/UpdateExecutor.yaml b/murano_tempest_tests/extras/io.murano.apps.test.UpdateExecutor/Classes/UpdateExecutor.yaml
new file mode 100644
index 000000000..fd47e8854
--- /dev/null
+++ b/murano_tempest_tests/extras/io.murano.apps.test.UpdateExecutor/Classes/UpdateExecutor.yaml
@@ -0,0 +1,47 @@
+# 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.
+
+Namespaces:
+ =: io.murano.apps.test
+ std: io.murano
+ res: io.murano.resources
+ sys: io.murano.system
+ conf: io.murano.configuration
+
+
+Name: UpdateExecutor
+
+Extends: std:Application
+
+Properties:
+ name:
+ Contract: $.string().notNull()
+
+ instance:
+ Contract: $.class(res:Instance).notNull()
+
+Methods:
+ initialize:
+ Body:
+ - $._environment: $.find(std:Environment).require()
+
+ deploy:
+ Body:
+ - If: not $.getAttr(deployed, false)
+ Then:
+ - $._environment.reporter.report($this, 'Creating VM.')
+ - $.instance.deploy()
+ - $._environment.reporter.report($this, 'Starting packages updating.')
+ - $file: sys:Resources.string('scripts/update.sh')
+ - conf:Linux.runCommand($.instance.agent, $file)
+ - $._environment.reporter.report($this, 'Update completed.')
+ - $.setAttr(deployed, true)
diff --git a/murano_tempest_tests/extras/io.murano.apps.test.UpdateExecutor/Resources/scripts/update.sh b/murano_tempest_tests/extras/io.murano.apps.test.UpdateExecutor/Resources/scripts/update.sh
new file mode 100644
index 000000000..28cddd559
--- /dev/null
+++ b/murano_tempest_tests/extras/io.murano.apps.test.UpdateExecutor/Resources/scripts/update.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+# 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.
+
+sudo apt-get update
diff --git a/murano_tempest_tests/extras/io.murano.apps.test.UpdateExecutor/manifest.yaml b/murano_tempest_tests/extras/io.murano.apps.test.UpdateExecutor/manifest.yaml
new file mode 100644
index 000000000..49137b479
--- /dev/null
+++ b/murano_tempest_tests/extras/io.murano.apps.test.UpdateExecutor/manifest.yaml
@@ -0,0 +1,22 @@
+# 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.
+
+Format: 1.0
+Type: Application
+FullName: io.murano.apps.test.UpdateExecutor
+Name: Update Executor
+Description: |
+ Test application, which updates packages on VM
+Author: 'Mirantis, Inc'
+Tags: [application]
+Classes:
+ io.murano.apps.test.UpdateExecutor: UpdateExecutor.yaml
diff --git a/murano_tempest_tests/tests/scenario/__init__.py b/murano_tempest_tests/tests/scenario/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/murano_tempest_tests/tests/scenario/application_catalog/__init__.py b/murano_tempest_tests/tests/scenario/application_catalog/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/murano_tempest_tests/tests/scenario/application_catalog/base.py b/murano_tempest_tests/tests/scenario/application_catalog/base.py
new file mode 100644
index 000000000..be10e235a
--- /dev/null
+++ b/murano_tempest_tests/tests/scenario/application_catalog/base.py
@@ -0,0 +1,335 @@
+# Copyright (c) 2016 Mirantis, Inc.
+# All Rights Reserved.
+#
+# 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 requests
+import socket
+import time
+
+from tempest.clients import Manager as services_manager
+from tempest.common import credentials_factory as common_creds
+from tempest.common import dynamic_creds
+from tempest.common import waiters
+from tempest import config
+from tempest.lib import base
+from tempest.lib import exceptions
+
+from murano_tempest_tests import clients
+from murano_tempest_tests import utils
+
+CONF = config.CONF
+
+
+class BaseApplicationCatalogScenarioTest(base.BaseTestCase):
+ """Base test class for Murano Application Catalog Scenario tests."""
+
+ @classmethod
+ def setUpClass(cls):
+ super(BaseApplicationCatalogScenarioTest, cls).setUpClass()
+ cls.resource_setup()
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.resource_cleanup()
+ super(BaseApplicationCatalogScenarioTest, cls).tearDownClass()
+
+ @classmethod
+ def get_client_with_isolated_creds(cls, type_of_creds="admin"):
+
+ creds = cls.get_configured_isolated_creds(type_of_creds=type_of_creds)
+
+ os = clients.Manager(credentials=creds)
+ client = os.application_catalog_client
+
+ return client
+
+ @classmethod
+ def get_configured_isolated_creds(cls, type_of_creds='admin'):
+ identity_version = CONF.identity.auth_version
+ if identity_version == 'v3':
+ cls.admin_role = CONF.identity.admin_role
+ else:
+ cls.admin_role = 'admin'
+ if not hasattr(cls, 'dynamic_cred'):
+ cls.dynamic_cred = dynamic_creds.DynamicCredentialProvider(
+ identity_version=CONF.identity.auth_version,
+ name=cls.__name__, admin_role=cls.admin_role,
+ admin_creds=common_creds.get_configured_admin_credentials(
+ 'identity_admin'))
+ if type_of_creds == 'primary':
+ creds = cls.dynamic_cred.get_primary_creds()
+ elif type_of_creds == 'admin':
+ creds = cls.dynamic_cred.get_admin_creds()
+ elif type_of_creds == 'alt':
+ creds = cls.dynamic_cred.get_alt_creds()
+ else:
+ creds = cls.dynamic_cred.get_credentials(type_of_creds)
+ cls.dynamic_cred.type_of_creds = type_of_creds
+
+ return creds.credentials
+
+ @classmethod
+ def verify_nonempty(cls, *args):
+ if not all(args):
+ msg = "Missing API credentials in configuration."
+ raise cls.skipException(msg)
+
+ @classmethod
+ def resource_setup(cls):
+ if not CONF.service_available.murano:
+ skip_msg = "Murano is disabled"
+ raise cls.skipException(skip_msg)
+ if not hasattr(cls, "os"):
+ creds = cls.get_configured_isolated_creds(type_of_creds='primary')
+ cls.os = clients.Manager(credentials=creds)
+ cls.services_manager = services_manager(creds)
+ cls.linux_image = CONF.application_catalog.linux_image
+ cls.application_catalog_client = cls.os.application_catalog_client
+ cls.artifacts_client = cls.os.artifacts_client
+ cls.servers_client = cls.services_manager.servers_client
+ cls.orchestration_client = cls.services_manager.orchestration_client
+ cls.snapshots_client = cls.services_manager.snapshots_client
+ cls.volumes_client = cls.services_manager.volumes_client
+ cls.backups_client = cls.services_manager.backups_client
+
+ @classmethod
+ def resource_cleanup(cls):
+ cls.clear_isolated_creds()
+
+ @classmethod
+ def clear_isolated_creds(cls):
+ if hasattr(cls, "dynamic_cred"):
+ cls.dynamic_cred.clear_creds()
+
+ def environment_delete(self, environment_id, timeout=180):
+ self.application_catalog_client.delete_environment(environment_id)
+
+ start_time = time.time()
+ while time.time() - start_time > timeout:
+ try:
+ self.application_catalog_client.get_environment(environment_id)
+ except exceptions.NotFound:
+ return
+
+ @classmethod
+ def purge_stacks(cls):
+ stacks = cls.orchestration_client.list_stacks()['stacks']
+ for stack in stacks:
+ cls.orchestration_client.delete_stack(stack['id'])
+ cls.orchestration_client.wait_for_stack_status(stack['id'],
+ 'DELETE_COMPLETE')
+
+ def get_service(self, environment, session, service_name):
+ for service in self.application_catalog_client.get_services_list(
+ environment, session):
+ if service['name'] == service_name:
+ return service
+
+ def get_stack_id(self, environment_id):
+ stacks = self.orchestration_client.list_stacks()['stacks']
+ for stack in stacks:
+ if environment_id in self.orchestration_client.show_stack(
+ stack['id'])['stack']['description']:
+ return stack['id']
+
+ def get_stack_template(self, stack):
+ return self.orchestration_client.show_template(stack)
+
+ def get_instance_id(self, name):
+ instance_list = self.servers_client.list_servers()['servers']
+ for instance in instance_list:
+ if name in instance['name']:
+ return instance['id']
+
+ def apache_cinder(
+ self, attributes=None, userName=None, flavor='m1.medium'):
+ post_body = {
+ "instance": {
+ "flavor": flavor,
+ "image": self.linux_image,
+ "assignFloatingIp": True,
+ "availabilityZone": "nova",
+ "volumes": attributes,
+ "?": {
+ "type": "io.murano.resources.LinuxMuranoInstance",
+ "id": utils.generate_uuid()
+ },
+ "name": utils.generate_name("testMurano")
+ },
+ "name": utils.generate_name("ApacheHTTPServer"),
+ "userName": userName,
+ "?": {
+ "_{id}".format(id=utils.generate_uuid()): {
+ "name": "ApacheHTTPServer"
+ },
+ "type": "io.murano.apps.test.ApacheHttpServerCustom",
+ "id": utils.generate_uuid()
+ }
+ }
+ return post_body
+
+ def update_executor(self, flavor='m1.medium'):
+ post_body = {
+ "instance": {
+ "flavor": flavor,
+ "image": self.linux_image,
+ "assignFloatingIp": True,
+ "?": {
+ "type": "io.murano.resources.LinuxMuranoInstance",
+ "id": utils.generate_uuid()
+ },
+ "name": utils.generate_name('testMurano')
+ },
+ "name": utils.generate_name('dummy'),
+ "?": {
+ "type": "io.murano.apps.test.UpdateExecutor",
+ "id": utils.generate_uuid()
+ }
+ }
+ return post_body
+
+ def deploy_environment(self, environment, session):
+ self.application_catalog_client.deploy_session(environment['id'],
+ session['id'])
+ return self.wait_for_environment_deploy(environment)
+
+ def wait_for_environment_deploy(self, environment):
+ start_time = time.time()
+ status = self.application_catalog_client.\
+ get_environment(environment['id'])['status']
+ while status != 'ready':
+ status = self.application_catalog_client.\
+ get_environment(environment['id'])['status']
+ if time.time() - start_time > 1800:
+ time.sleep(60)
+ self.fail(
+ 'Environment deployment is not finished in 1200 seconds')
+ elif status == 'deploy failure':
+ time.sleep(60)
+ self.fail('Environment has incorrect status {0}'.
+ format(status))
+ time.sleep(5)
+ return self.application_catalog_client.\
+ get_environment(environment['id'])
+
+ def status_check(self, environment_id, configurations):
+ for configuration in configurations:
+ inst_name = configuration[0]
+ ports = configuration[1:]
+ ip = self.get_ip_by_instance_name(environment_id, inst_name)
+ if ip and ports:
+ for port in ports:
+ self.check_port_access(ip, port)
+ else:
+ self.fail('Instance does not have floating IP')
+
+ def check_path(self, environment_id, path, inst_name=None):
+ environment = self.application_catalog_client.\
+ get_environment(environment_id)
+ if inst_name:
+ ip = self.get_ip_by_instance_name(environment_id, inst_name)
+ else:
+ ip = environment.services[0]['instance']['floatingIpAddress']
+ resp = requests.get('http://{0}/{1}'.format(ip, path))
+ if resp.status_code == 200:
+ return resp
+ else:
+ self.fail("Service path unavailable")
+
+ def get_ip_by_instance_name(self, environment_id, inst_name):
+ for service in self.application_catalog_client.\
+ get_services_list(environment_id):
+ if inst_name in service['instance']['name']:
+ return service['instance']['floatingIpAddress']
+
+ def check_port_access(self, ip, port):
+ result = 1
+ start_time = time.time()
+ while time.time() - start_time < 600:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ result = sock.connect_ex((str(ip), port))
+ sock.close()
+ if result == 0:
+ break
+ time.sleep(5)
+ self.assertEqual(0, result, '%s port is closed on instance' % port)
+
+ @classmethod
+ def create_volume(cls):
+ volume = cls.volumes_client.create_volume()['volume']
+ waiters.wait_for_volume_status(cls.volumes_client,
+ volume['id'], 'available')
+ return volume['id']
+
+ @classmethod
+ def delete_volume(cls, volume_id):
+ cls.volumes_client.delete_volume(volume_id)
+ is_volume_deleted = False
+ while not is_volume_deleted:
+ is_volume_deleted = cls.volumes_client.\
+ is_resource_deleted(volume_id)
+ time.sleep(1)
+
+ def create_snapshot(self, volume_id):
+ snapshot = self.snapshots_client.\
+ create_snapshot(volume_id=volume_id)['snapshot']
+ waiters.wait_for_snapshot_status(self.snapshots_client,
+ snapshot['id'], 'available')
+ return snapshot['id']
+
+ def delete_snapshot(self, snapshot_id):
+ self.snapshots_client.delete_snapshot(snapshot_id)
+ is_snapshot_deleted = False
+ while not is_snapshot_deleted:
+ is_snapshot_deleted = self.snapshots_client.\
+ is_resource_deleted(snapshot_id)
+ time.sleep(1)
+
+ def create_backup(self, volume_id):
+ backup = self.backups_client.create_backup(
+ volume_id=volume_id,
+ force=True)['backup']
+ self.backups_client.wait_for_backup_status(backup['id'], 'available')
+ return backup['id']
+
+ def delete_backup(self, backup_id):
+ self.backups_client.delete_backup(backup_id)
+ return self.backups_client.wait_for_backup_deletion(backup_id)
+
+ def get_volume(self, environment_id):
+ stack = self.get_stack_id(environment_id)
+ stack_outputs = self.orchestration_client.\
+ show_stack(stack)['stack']['outputs']
+ for output in stack_outputs:
+ if 'vol' in output['output_key']:
+ volume_id = output['output_value']
+ return self.volumes_client.show_volume(volume_id)['volume']
+
+ def check_volume_attached(self, name, volume_id):
+ instance_id = self.get_instance_id(name)
+ attached_volumes = self.servers_client.\
+ list_volume_attachments(instance_id)['volumeAttachments']
+ assert attached_volumes[0]['id'] == volume_id
+
+
+class BaseApplicationCatalogScenarioIsolatedAdminTest(
+ BaseApplicationCatalogScenarioTest):
+
+ @classmethod
+ def resource_setup(cls):
+ creds = cls.get_configured_isolated_creds(type_of_creds='admin')
+ cls.os = clients.Manager(credentials=creds)
+ cls.services_manager = services_manager(creds)
+ super(BaseApplicationCatalogScenarioIsolatedAdminTest, cls).\
+ resource_setup()
diff --git a/murano_tempest_tests/utils.py b/murano_tempest_tests/utils.py
index c29dee364..837e53384 100644
--- a/murano_tempest_tests/utils.py
+++ b/murano_tempest_tests/utils.py
@@ -34,7 +34,8 @@ MANIFEST = {'Format': 'MuranoPL/1.0',
def compose_package(app_name, manifest, package_dir,
- require=None, archive_dir=None, add_class_name=False):
+ require=None, archive_dir=None, add_class_name=False,
+ manifest_required=True):
"""Composes a murano package
Composes package `app_name` with `manifest` file as a template for the
@@ -43,15 +44,16 @@ def compose_package(app_name, manifest, package_dir,
Puts the resulting .zip file into `acrhive_dir` if present or in the
`package_dir`.
"""
- with open(manifest, 'w') as f:
- fqn = 'io.murano.apps.' + app_name
- mfest_copy = MANIFEST.copy()
- mfest_copy['FullName'] = fqn
- mfest_copy['Name'] = app_name
- mfest_copy['Classes'] = {fqn: 'mock_muranopl.yaml'}
- if require:
- mfest_copy['Require'] = require
- f.write(yaml.dump(mfest_copy, default_flow_style=False))
+ if manifest_required:
+ with open(manifest, 'w') as f:
+ fqn = 'io.murano.apps.' + app_name
+ mfest_copy = MANIFEST.copy()
+ mfest_copy['FullName'] = fqn
+ mfest_copy['Name'] = app_name
+ mfest_copy['Classes'] = {fqn: 'mock_muranopl.yaml'}
+ if require:
+ mfest_copy['Require'] = require
+ f.write(yaml.dump(mfest_copy, default_flow_style=False))
if add_class_name:
class_file = os.path.join(package_dir, 'Classes', 'mock_muranopl.yaml')
@@ -82,7 +84,8 @@ def compose_package(app_name, manifest, package_dir,
return archive_path, name
-def prepare_package(name, require=None, add_class_name=False):
+def prepare_package(name, require=None, add_class_name=False,
+ app='MockApp', manifest_required=True):
"""Prepare package.
:param name: Package name to compose
@@ -90,13 +93,13 @@ def prepare_package(name, require=None, add_class_name=False):
:param add_class_name: Option to write class name to class file
:return: Path to archive, directory with archive, filename of archive
"""
- app_dir = acquire_package_directory()
- target_arc_path = app_dir.rsplit('MockApp', 1)[0]
+ app_dir = acquire_package_directory(app=app)
+ target_arc_path = app_dir.rsplit(app, 1)[0]
arc_path, filename = compose_package(
name, os.path.join(app_dir, 'manifest.yaml'),
app_dir, require=require, archive_dir=target_arc_path,
- add_class_name=add_class_name)
+ add_class_name=add_class_name, manifest_required=manifest_required)
return arc_path, target_arc_path, filename
@@ -111,7 +114,7 @@ def generate_name(prefix):
return '{0}_{1}'.format(prefix, suffix)
-def acquire_package_directory():
+def acquire_package_directory(app='MockApp'):
"""Obtain absolutely directory with package files.
Should be called inside tests dir.
@@ -119,7 +122,7 @@ def acquire_package_directory():
"""
top_plugin_dir = os.path.realpath(os.path.join(os.getcwd(),
os.path.dirname(__file__)))
- expected_package_dir = '/extras/MockApp'
+ expected_package_dir = '/extras/' + app
app_dir = top_plugin_dir + expected_package_dir
return app_dir