Support murano plugin installation in OSTF tests

- Add discover mechanism for murano if it enabled via plugin installation

Change-Id: I2e60a65676fcb3b452c2acf3793ef8e251182cae
targets: blueprint murano-fuel-plugin
Closes-Bug: #1584791
This commit is contained in:
Victor Ryzhenkin 2016-03-14 16:29:51 +03:00
parent d2f04c2981
commit 7cc4b17cee
7 changed files with 442 additions and 48 deletions

View File

@ -401,61 +401,65 @@ class MuranoTest(fuel_health.nmanager.PlatformServicesBaseClass):
if inst_name in service['instance']['name']:
return service['instance']['floatingIpAddress']
def get_list_packages(self):
def get_list_packages(self, artifacts=False):
try:
packages = self.murano_client.packages.list()
if artifacts:
packages_list = self.murano_art_client.packages.list()
packages = []
for package in packages_list:
packages.append(package)
else:
packages_list = self.murano_client.packages.list()
packages = list(packages_list)
except exceptions.ClientException:
self.fail("Can not get list of packages")
packages_list = list(packages)
LOG.debug('Packages List: {0}'.format(packages_list))
self.assertIsInstance(packages_list, list)
return packages_list
LOG.debug('Packages List: {0}'.format(packages))
self.assertIsInstance(packages, list)
return packages
def generate_fqn_list(self):
def generate_fqn_list(self, artifacts=False):
fqn_list = []
packages = self.get_list_packages()
packages = self.get_list_packages(artifacts)
for package in packages:
fqn_list.append(package.to_dict()['fully_qualified_name'])
LOG.debug('FQN List: {0}'.format(fqn_list))
return fqn_list
def upload_package(self, package_name, body, app):
def upload_package(self, package_name, body, app, artifacts=False):
files = {'%s' % package_name: open(app, 'rb')}
package = self.murano_client.packages.create(body, files)
if artifacts:
package = self.murano_art_client.packages.create(body, files)
else:
package = self.murano_client.packages.create(body, files)
self.packages.append(package)
return package
def package_exists(self, *packages):
fqn_list = self.generate_fqn_list()
def package_exists(self, artifacts=False, *packages):
fqn_list = self.generate_fqn_list(artifacts)
LOG.debug("Response for packages is {0}".format(fqn_list))
for package in packages:
if package not in fqn_list:
return False
return True
def get_package(self, package_id):
resp = requests.get(self.endpoint + 'catalog/packages/{0}'.
format(package_id), headers=self.headers,
verify=False)
self.assertEqual(200, resp.status_code)
return resp.json()
def get_package(self, package_id, artifacts=False):
if artifacts:
package = self.murano_art_client.packages.get(package_id)
else:
package = self.murano_client.packages.get(package_id)
return package
def get_package_by_fqdn(self, package_name):
resp = requests.get(self.endpoint + 'catalog/packages',
headers=self.headers, verify=False)
for package in resp.json()["packages"]:
if package["fully_qualified_name"] == package_name:
def get_package_by_fqdn(self, package_name, artifacts=False):
package_list = self.get_list_packages(artifacts)
for package in package_list:
if package.to_dict()["fully_qualified_name"] == package_name:
return package
def delete_package(self, package_id):
resp = requests.delete(self.endpoint + 'catalog/packages/{0}'.
format(package_id), headers=self.headers,
verify=False)
try:
self.assertEqual(200, resp.status_code)
except Exception:
self.assertEqual(404, resp.status_code)
LOG.debug("Package not exists.")
def delete_package(self, package_id, artifacts=False):
if artifacts:
self.murano_art_client.packages.delete(package_id)
else:
self.murano_client.packages.delete(package_id)
def get_list_categories(self):
resp = requests.get(self.endpoint + 'catalog/packages/categories',

View File

@ -58,6 +58,11 @@ try:
except Exception:
LOG.exception()
LOG.warning('Ironic client could not be imported')
try:
import muranoclient.glance.client as art_client
except Exception:
LOG.exception()
LOG.warning('Artifacts client could not be imported')
import aodhclient.client
import cinderclient.client
@ -116,6 +121,8 @@ class OfficialClientManager(fuel_health.manager.Manager):
self.glance_client_v1 = self._get_glance_client(version=1)
self.ironic_client = self._get_ironic_client()
self.aodh_client = self._get_aodh_client()
self.artifacts_client = self._get_artifacts_client()
self.murano_art_client = self._get_murano_client(artifacts=True)
self.client_attr_names = [
'compute_client',
'identity_client',
@ -129,7 +136,9 @@ class OfficialClientManager(fuel_health.manager.Manager):
'ceilometer_client',
'neutron_client',
'ironic_client',
'aodh_client'
'aodh_client',
'artifacts_client',
'murano_art_client'
]
def _get_compute_client(self, username=None, password=None,
@ -264,7 +273,7 @@ class OfficialClientManager(fuel_health.manager.Manager):
token=token,
insecure=True)
def _get_murano_client(self):
def _get_murano_client(self, artifacts=False):
"""This method returns Murano API client
"""
keystone = self._get_identity_client(
@ -283,10 +292,16 @@ class OfficialClientManager(fuel_health.manager.Manager):
'not found. Murano client cannot be initialized.')
return
return muranoclient.v1.client.Client(
endpoint,
token=self.token_id,
insecure=True)
if artifacts:
return muranoclient.v1.client.Client(
endpoint,
token=self.token_id,
insecure=True, artifacts_client=self.artifacts_client)
else:
return muranoclient.v1.client.Client(
endpoint,
token=self.token_id,
insecure=True)
def _get_sahara_client(self):
sahara_api_version = self.config.sahara.api_version
@ -351,6 +366,21 @@ class OfficialClientManager(fuel_health.manager.Manager):
os_auth_token=keystone.auth_token,
ironic_url=endpoint, insecure=True)
def _get_artifacts_client(self, version='1'):
keystone = self._get_identity_client()
try:
endpoint = keystone.service_catalog.url_for(
service_type='artifact',
endpoint_type='publicURL')
except keystoneclient.exceptions.EndpointNotFound:
LOG.warning('Can not initialize artifacts client')
return None
return art_client.Client(endpoint=endpoint,
type_name='murano',
type_version=version,
token=keystone.auth_token,
insecure=True)
def _get_aodh_client(self, version='2'):
username = self.config.identity.admin_username
password = self.config.identity.admin_password

View File

@ -33,7 +33,7 @@ class MuranoSanityTests(muranomanager.MuranoTest):
Duration: 10 s.
Deployment tags: Murano
Deployment tags: Murano | murano_plugin
"""
fail_msg = "Can't create environment. Murano API isn't available. "
@ -55,7 +55,7 @@ class MuranoSanityTests(muranomanager.MuranoTest):
Duration: 10 s.
Deployment tags: Murano
Deployment tags: Murano | murano_plugin
"""
fail_msg = "Can't get list of categories. Murano API isn't available. "
self.verify(10, self.get_list_categories, 1, fail_msg,
@ -70,8 +70,23 @@ class MuranoSanityTests(muranomanager.MuranoTest):
Duration: 10 s.
Deployment tags: Murano
Deployment tags: Murano | murano_plugin, murano_without_glare
"""
fail_msg = "Can't get list of packages. Murano API isn't available. "
self.verify(10, self.get_list_packages, 1, fail_msg,
"getting list of packages")
def test_get_list_artifacts_packages(self):
"""Get list of Murano Artifact applications packages
Target component: Murano
Scenario:
1. Send request to get list of artifact packages
Duration: 10 s.
Deployment tags: Murano | murano_plugin, murano_use_glare
"""
fail_msg = "Can't get list of packages. Murano API isn't available. "
self.verify(10, self.get_list_packages, 1, fail_msg,
"getting list of packages", artifacts=True)

View File

@ -43,7 +43,7 @@ class MuranoDeployLinuxServicesTests(muranomanager.MuranoTest):
self.dummy_fqdn = 'io.murano.apps.Simple'
# Flavor with 2 vCPU and 40Gb HDD will allow to sucessfully
# Flavor with 2 vCPU and 40Gb HDD will allow to successfully
# deploy all Murano applications.
self.flavor_name = rand_name("ostf_test_Murano_flavor")
flavor = self.compute_client.flavors.create(
@ -70,7 +70,7 @@ class MuranoDeployLinuxServicesTests(muranomanager.MuranoTest):
10. Send request to delete package.
Duration: 1200 s.
Deployment tags: Murano, Heat
Deployment tags: Murano | murano_plugin, murano_without_glare
Available since release: 2014.2-6.1
"""
@ -163,6 +163,116 @@ class MuranoDeployLinuxServicesTests(muranomanager.MuranoTest):
self.verify(5, self.delete_package, 10, fail_msg, "deleting_package",
self.package.id)
def test_deploy_dummy_app_with_glare(self):
"""Check application deployment in Murano environment with GLARE
Target component: Murano
Scenario:
1. Prepare test app.
2. Upload test app.
3. Send request to create environment.
4. Send request to create session for environment.
5. Send request to create test service.
6. Send request to deploy session.
7. Checking environment status.
8. Checking deployment status.
9. Send request to delete environment.
10. Send request to delete package.
Duration: 1200 s.
Deployment tags: Murano | murano_plugin, murano_use_glare
Available since release: 2014.2-6.1
"""
artifacts = True
vms_count = self.get_info_about_available_resources(
self.min_required_ram_mb, 40, 2)
if vms_count < 1:
msg = ('This test requires more hardware resources of your '
'OpenStack cluster: your cloud should allow to create '
'at least 1 VM with {0} MB of RAM, {1} HDD and {2} vCPUs. '
'You need to remove some resources or add compute nodes '
'to have an ability to run this OSTF test.'
.format(self.min_required_ram_mb, 40, 2))
LOG.debug(msg)
self.skipTest(msg)
if self.package_exists(artifacts, self.dummy_fqdn):
package = self.get_package_by_fqdn(self.dummy_fqdn, artifacts)
self.delete_package(package.to_dict()["id"], artifacts)
fail_msg = ("Package preparation failed. Please refer to "
"OSTF logs for more information")
zip_path = self.verify(10, self.zip_dir, 1, fail_msg,
'prepare package',
os.path.dirname(__file__), self.dummy_fqdn)
fail_msg = ("Package uploading failed. "
"Please refer to Openstack and OSTF logs")
self.package = self.verify(10, self.upload_package, 2, fail_msg,
'uploading package', 'SimpleApp',
{"categories": ["Web"], "tags": ["tag"]},
zip_path, artifacts)
fail_msg = "Can't create environment. Murano API is not available. "
self.environment = self.verify(15, self.create_environment,
3, fail_msg, 'creating environment',
self.env_name)
fail_msg = "User can't create session for environment. "
session = self.verify(5, self.create_session,
4, fail_msg, "session creating",
self.environment.id)
post_body = {
"instance": {
"flavor": self.flavor_name,
"image": "TestVM",
"assignFloatingIp": True,
"?": {
"type": "io.murano.resources.LinuxMuranoInstance",
"id": str(uuid.uuid4())
},
"name": rand_name("testMurano")
},
"name": rand_name("teMurano"),
"?": {
"_{id}".format(id=uuid.uuid4().hex): {
"name": "SimpleApp"
},
"type": self.dummy_fqdn,
"id": str(uuid.uuid4())
}
}
fail_msg = "User can't create service. "
self.verify(5, self.create_service,
5, fail_msg, "service creating",
self.environment.id, session.id, post_body)
fail_msg = "User can't deploy session. "
self.verify(5, self.deploy_session,
6, fail_msg,
"sending session on deployment",
self.environment.id, session.id)
fail_msg = "Deployment was not completed correctly. "
self.verify(860, self.deploy_check,
7, fail_msg, 'deployment is going',
self.environment)
self.verify(5, self.deployments_status_check, 8, fail_msg,
'Check deployments status',
self.environment.id)
fail_msg = "Can't delete environment. "
self.verify(60, self.environment_delete_check,
9, fail_msg, "deleting environment",
self.environment.id)
fail_msg = "Can't delete package"
self.verify(5, self.delete_package, 10, fail_msg, "deleting_package",
self.package.id, artifacts)
def test_deploy_apache_service(self):
"""Check that user can deploy Apache service in Murano environment
Target component: Murano
@ -178,7 +288,7 @@ class MuranoDeployLinuxServicesTests(muranomanager.MuranoTest):
8. Send request to delete environment.
Duration: 2140 s.
Deployment tags: Murano, Heat
Deployment tags: Murano | murano_plugin, murano_without_artifacts
Available since release: 2014.2-6.0
"""
@ -287,7 +397,7 @@ class MuranoDeployLinuxServicesTests(muranomanager.MuranoTest):
11. Send request to delete environment.
Duration: 2140 s.
Deployment tags: Murano, Heat
Deployment tags: Murano | murano_plugin, murano_without_artifacts
Available since release: 2014.2-6.1
"""

View File

@ -30,10 +30,8 @@ from sqlalchemy.orm import joinedload
from fuel_plugin.ostf_adapter.nose_plugin import nose_utils
from fuel_plugin.ostf_adapter.storage import models
LOG = logging.getLogger(__name__)
TEST_REPOSITORY = []
# TODO(ikutukov): remove hardcoded Nailgun API urls here and below
NAILGUN_VERSION_API_URL = 'http://{0}:{1}/api/v1/version'
@ -242,6 +240,33 @@ def _get_cluster_attrs(cluster_id, token=None):
for comp in comp_names:
processor(comp)
# TODO(freerunner): Rework murano part after removal murano from the box
murano_settings = response['editable'].get('murano_settings', None)
# NOTE(freerunner): Murano settings appears only if murano enabled
murano_artifacts = None
if murano_settings:
murano_artifacts = (murano_settings
['murano_glance_artifacts_plugin']['value'])
detach_murano = response['editable'].get('detach-murano', None)
murano_plugin_enabled = None
if detach_murano:
murano_plugin_enabled = detach_murano['metadata'].get('enabled', None)
if murano_plugin_enabled:
additional_depl_tags.add('murano_plugin')
# TODO(freerunner): Rework GLARE discover mechanism after
# TODO(freerunner): removal murano from the box
if murano_artifacts:
additional_depl_tags.add('murano_use_glare')
# NOTE(freerunner): Murano plugin will always support only one version
elif detach_murano and murano_plugin_enabled and (
detach_murano['metadata']['versions'][0]
['murano_glance_artifacts'].get('value', None)):
additional_depl_tags.add('murano_use_glare')
# NOTE(freerunner): Set this tag only if murano is present
elif murano_plugin_enabled or murano_settings:
additional_depl_tags.add('murano_without_glare')
storage_components = response['editable'].get('storage', dict())
storage_comp = ['volumes_ceph', 'images_ceph', 'ephemeral_ceph',

View File

@ -236,7 +236,121 @@ CLUSTERS = {
'common': {}
}
}
}
},
9: {
'cluster_meta': {
'release_id': 9,
'mode': 'multinode'
},
'release_data': {
'operating_system': 'ubuntu',
'version': '2016.1-9.0'
},
'cluster_node': {
},
'cluster_attributes': {
'editable': {
'detach-murano': {
'metadata': {
'enabled': True,
'versions': [
{
'murano_glance_artifacts': {
"value": True
}
}
]
}
},
'additional_components': {},
'common': {}
}
}
},
10: {
'cluster_meta': {
'release_id': 10,
'mode': 'multinode'
},
'release_data': {
'operating_system': 'ubuntu',
'version': '2016.1-9.0'
},
'cluster_node': {
},
'cluster_attributes': {
'editable': {
'detach-murano': {
'metadata': {
'enabled': True,
'versions': [
{
'murano_glance_artifacts': {
"value": False
}
}
]
}
},
'additional_components': {},
'common': {}
}
}
},
11: {
'cluster_meta': {
'release_id': 11,
'mode': 'multinode'
},
'release_data': {
'operating_system': 'ubuntu',
'version': '2016.1-9.0'
},
'cluster_node': {
},
'cluster_attributes': {
'editable': {
'additional_components': {
'murano': {
'value': True
}
},
'murano_settings': {
'murano_glance_artifacts_plugin': {
'value': True
}
},
'common': {}
}
}
},
12: {
'cluster_meta': {
'release_id': 12,
'mode': 'multinode'
},
'release_data': {
'operating_system': 'ubuntu',
'version': '2016.1-9.0'
},
'cluster_node': {
},
'cluster_attributes': {
'editable': {
'additional_components': {
'murano': {
'value': True
}
},
'murano_settings': {
'murano_glance_artifacts_plugin': {
'value': False
}
},
'common': {}
}
}
},
}

View File

@ -108,3 +108,99 @@ class TestDeplTagsGetter(base.BaseUnitTest):
res = mixins._get_cluster_attrs(expected['cluster_id'])
self.assertEqual(res, expected['attrs'])
class TestDeplMuranoTags(base.BaseUnitTest):
def setUp(self):
config.init_config([])
self.expected = {
'attrs': {
'deployment_tags': set(
['multinode', 'ubuntu', 'additional_components',
'nova_network', 'public_on_all_nodes',
'enable_without_ceph', 'computes_without_dpdk']),
'release_version': '2016.1-9.0'
}
}
def test_get_murano_plugin_tags_with_artifacts(self):
expected = self.expected
expected['cluster_id'] = 9
expected['attrs']['deployment_tags'].add('murano_plugin')
expected['attrs']['deployment_tags'].add('murano_use_glare')
with requests_mock.Mocker() as m:
cluster = base.CLUSTERS[expected['cluster_id']]
m.register_uri('GET', '/api/clusters/9',
json=cluster['cluster_meta'])
m.register_uri('GET', '/api/clusters/9/attributes',
json=cluster['cluster_attributes'])
m.register_uri('GET', '/api/releases/9',
json=cluster['release_data'])
m.register_uri('GET', '/api/nodes?cluster_id=9',
json=cluster['cluster_node'])
res = mixins._get_cluster_attrs(expected['cluster_id'])
self.assertEqual(res, expected['attrs'])
def test_get_murano_plugin_tags_without_artifacts(self):
expected = self.expected
expected['cluster_id'] = 10
expected['attrs']['deployment_tags'].add('murano_plugin')
expected['attrs']['deployment_tags'].add('murano_without_glare')
with requests_mock.Mocker() as m:
cluster = base.CLUSTERS[expected['cluster_id']]
m.register_uri('GET', '/api/clusters/10',
json=cluster['cluster_meta'])
m.register_uri('GET', '/api/clusters/10/attributes',
json=cluster['cluster_attributes'])
m.register_uri('GET', '/api/releases/10',
json=cluster['release_data'])
m.register_uri('GET', '/api/nodes?cluster_id=10',
json=cluster['cluster_node'])
res = mixins._get_cluster_attrs(expected['cluster_id'])
self.assertEqual(res, expected['attrs'])
def test_get_murano_tags_with_artifacts(self):
expected = self.expected
expected['cluster_id'] = 11
expected['attrs']['deployment_tags'].add('murano')
expected['attrs']['deployment_tags'].add('murano_use_glare')
with requests_mock.Mocker() as m:
cluster = base.CLUSTERS[expected['cluster_id']]
m.register_uri('GET', '/api/clusters/11',
json=cluster['cluster_meta'])
m.register_uri('GET', '/api/clusters/11/attributes',
json=cluster['cluster_attributes'])
m.register_uri('GET', '/api/releases/11',
json=cluster['release_data'])
m.register_uri('GET', '/api/nodes?cluster_id=11',
json=cluster['cluster_node'])
res = mixins._get_cluster_attrs(expected['cluster_id'])
self.assertEqual(res, expected['attrs'])
def test_get_murano_tags_without_artifacts(self):
expected = self.expected
expected['cluster_id'] = 12
expected['attrs']['deployment_tags'].add('murano')
expected['attrs']['deployment_tags'].add('murano_without_glare')
with requests_mock.Mocker() as m:
cluster = base.CLUSTERS[expected['cluster_id']]
m.register_uri('GET', '/api/clusters/12',
json=cluster['cluster_meta'])
m.register_uri('GET', '/api/clusters/12/attributes',
json=cluster['cluster_attributes'])
m.register_uri('GET', '/api/releases/12',
json=cluster['release_data'])
m.register_uri('GET', '/api/nodes?cluster_id=12',
json=cluster['cluster_node'])
res = mixins._get_cluster_attrs(expected['cluster_id'])
self.assertEqual(res, expected['attrs'])