From 833c823a71ecb337a7b843195e3bb695043d62a0 Mon Sep 17 00:00:00 2001 From: Steven Tran Date: Tue, 27 Jan 2015 09:12:18 -0800 Subject: [PATCH] Adds driver for Murano datasource Adds driver to populate datasource tables based on Murano object model. Excludes python-muranoclient from requirements.txt. Replaces it with a mock in unit test. Implements: blueprint murano-driver Change-Id: I2a9b411bf841e58b7fce4f234f834eb099a332ab --- congress/datasources/murano_driver.py | 214 ++++++++++++ .../tests/datasources/test_murano_driver.py | 309 ++++++++++++++++++ etc/datasources.conf.sample | 7 + examples/murano/predeploy_simulate.sh | 116 +++++++ 4 files changed, 646 insertions(+) create mode 100755 congress/datasources/murano_driver.py create mode 100755 congress/tests/datasources/test_murano_driver.py create mode 100755 examples/murano/predeploy_simulate.sh diff --git a/congress/datasources/murano_driver.py b/congress/datasources/murano_driver.py new file mode 100755 index 000000000..28eaf7b3f --- /dev/null +++ b/congress/datasources/murano_driver.py @@ -0,0 +1,214 @@ +# Copyright (c) 2015 Hewlett-Packard. 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 keystoneclient.v2_0.client as ksclient +import muranoclient.client + +from congress.datasources import datasource_driver +from congress.datasources import datasource_utils +from congress.openstack.common import log as logging +from congress.utils import value_to_congress + + +logger = logging.getLogger(__name__) + + +def d6service(name, keys, inbox, datapath, args): + """This method is called by d6cage to create a dataservice instance.""" + return MuranoDriver(name, keys, inbox, datapath, args) + + +class MuranoDriver(datasource_driver.DataSourceDriver): + OBJECTS = "objects" + PARENT_TYPES = "parent_types" + PROPERTIES = "properties" + RELATIONSHIPS = "relationships" + STATES = "states" + + instance_types = [ + 'io.murano.resources.Instance', + 'io.murano.resources.LinuxInstance', + 'io.murano.resources.LinuxMuranoInstance', + 'io.murano.resources.WindowsInstance'] + + def __init__(self, name='', keys='', inbox=None, datapath=None, args=None): + super(MuranoDriver, self).__init__(name, keys, inbox, datapath, args) + self.creds = datasource_utils.get_credentials(name, args) + logger.debug("Credentials = %s" % self.creds) + keystone = ksclient.Client(**self.creds) + murano_endpoint = keystone.service_catalog.url_for( + service_type='application_catalog', + endpoint_type='publicURL') + logger.debug("murano_endpoint = %s" % murano_endpoint) + client_version = "1" + self.murano_client = muranoclient.client.Client( + client_version, + endpoint=murano_endpoint, + token=keystone.auth_token) + logger.debug("Successfully created murano_client") + + self.initialized = True + + def update_from_datasource(self): + """Called when it is time to pull new data from this datasource. + + Sets self.state[tablename] = + for every tablename exported by this datasource. + """ + logger.debug("Murano grabbing environments") + environments = self.murano_client.environments.list() + self.state[self.STATES] = set() + self.state[self.OBJECTS] = set() + self.state[self.PROPERTIES] = set() + self.state[self.PARENT_TYPES] = set() + + self._translate_environments(environments) + self._translate_services(environments) + + logger.debug("Murano grabbing packages") + packages = self.murano_client.packages.list() + self._translate_packages(packages) + + @classmethod + def get_schema(cls): + """Returns a dictionary of table schema. + + The dictionary mapping tablenames to the list of column names + for that table. Both tablenames and columnnames are strings. + """ + d = {} + d[cls.OBJECTS] = ('object_id', 'owner_id', 'type') + d[cls.PARENT_TYPES] = ('id', 'parent_type') + d[cls.PROPERTIES] = ('id', 'name', 'value') + d[cls.RELATIONSHIPS] = ('source_id', 'target_id', 'name') + d[cls.STATES] = ('id', 'state') + return d + + def _translate_environments(self, environments): + """Translate the environments into tables. + + Assigns self.state[tablename] for all those TABLENAMEs + generated from environments + """ + logger.debug("_translate_environments: %s", environments) + if not environments: + return + self.state[self.STATES] = set() + if self.OBJECTS not in self.state: + self.state[self.OBJECTS] = set() + if self.PROPERTIES not in self.state: + self.state[self.PROPERTIES] = set() + if self.PARENT_TYPES not in self.state: + self.state[self.PARENT_TYPES] = set() + + for env in environments: + self.state[self.OBJECTS].add( + (env.id, env.tenant_id, 'io.murano.Environment')) + self.state[self.PROPERTIES].add((env.id, 'name', env.name)) + self.state[self.STATES].add((env.id, env.status)) + logger.debug("Environments: %s", self.state[self.OBJECTS]) + + def _translate_services(self, environments): + """Translate the environment services into tables. + + Assigns self.state[tablename] for all those TABLENAMEs + generated from services + """ + logger.debug("Murano grabbing environments services") + if not environments: + return + for env in environments: + services = self.murano_client.services.list(env.id) + self._translate_environment_services(services, env.id) + + def _translate_environment_services(self, services, env_id): + """Translate the environment services into tables. + + Assigns self.state[tablename] for all those TABLENAMEs + generated from services + """ + if not services: + return + for s in services: + s_dict = s.to_dict() + s_id = s_dict['?']['id'] + s_type = s_dict['?']['type'] + self.state[self.OBJECTS].add((s_id, env_id, s_type)) + self.state[self.PROPERTIES].add((s_id, 'name', s.name)) + if 'io.murano.apps' in s_type: + self.state[self.PARENT_TYPES].add( + (s_id, 'io.murano.Application')) + + if 'instance' not in s_dict: + continue + # populate service instance + si_dict = s.instance + si_id = si_dict['?']['id'] + si_type = si_dict['?']['type'] + self.state[self.OBJECTS].add((si_id, s_id, si_type)) + if 'securityGroupName' in si_dict and si_dict['securityGroupName']: + si_security_group_name = value_to_congress( + si_dict['securityGroupName']) + self.state[self.PROPERTIES].add( + (si_id, 'security_group_name', si_security_group_name)) + self.state[self.PROPERTIES].add( + (si_id, 'name', si_dict['name'])) + if 'flavor' in si_dict: + self.state[self.PROPERTIES].add( + (si_id, 'flavor', si_dict['flavor'])) + if 'image' in si_dict: + self.state[self.PROPERTIES].add( + (si_id, 'image', si_dict['image'])) + if si_type in self.instance_types: + self.state[self.PARENT_TYPES].add( + (si_id, 'io.murano.resources.Instance')) + + if 'ipAddresses' in si_dict: + for ip_addr in si_dict['ipAddresses']: + self.state[self.PROPERTIES].add( + (si_id, 'ip_address', ip_addr)) + if 'floatingIpAddress' in si_dict and si_dict['floatingIpAddress']: + self.state[self.PROPERTIES].add( + (si_id, 'floating_ip_address', + si_dict['floatingIpAddress'])) + + def _translate_packages(self, packages): + """Translate the packages into tables. + + Assigns self.state[tablename] for all those TABLENAMEs + generated from packages/applications + """ + # packages is a generator type + if not packages: + return + if self.OBJECTS not in self.state: + self.state[self.OBJECTS] = set() + if self.PROPERTIES not in self.state: + self.state[self.PROPERTIES] = set() + + for pkg in packages: + logger.debug("pkg=%s", pkg.to_dict()) + self.state[self.OBJECTS].add((pkg.id, pkg.owner_id, pkg.type)) + self.state[self.PROPERTIES].add((pkg.id, 'name', pkg.name)) + self.state[self.PROPERTIES].add( + (pkg.id, 'fully_qualified_name', pkg.fully_qualified_name)) + self.state[self.PROPERTIES].add((pkg.id, 'enabled', pkg.enabled)) + self.state[self.PROPERTIES].add((pkg.id, 'author', pkg.author)) + self.state[self.PROPERTIES].add( + (pkg.id, 'is_public', pkg.is_public)) + for tag in pkg.tags: + self.state[self.PROPERTIES].add((pkg.id, 'tag', tag)) + for category in pkg.categories: + self.state[self.PROPERTIES].add( + (pkg.id, 'category', category)) diff --git a/congress/tests/datasources/test_murano_driver.py b/congress/tests/datasources/test_murano_driver.py new file mode 100755 index 000000000..2e1530ff1 --- /dev/null +++ b/congress/tests/datasources/test_murano_driver.py @@ -0,0 +1,309 @@ +#!/usr/bin/env python +# Copyright (c) 2015 Hewlett-Packard. 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 mock + +# mocking muranoclient so that python-muranoclient +# doesn't need to be included in requirements.txt. +# (Including python-muranoclient in requirements.txt will +# cause failures in Jenkins because python-muranoclient is not +# included in global_requirements.txt) +import sys + +sys.modules['muranoclient'] = mock.Mock() +sys.modules['muranoclient.client'] = mock.Mock() + +from congress.datasources import murano_driver +from congress.tests import base +from congress.tests.datasources.util import ResponseObj +from congress.tests import helper + + +class TestMuranoDriver(base.TestCase): + def setUp(self): + super(TestMuranoDriver, self).setUp() + self.keystone_client_p = mock.patch( + "keystoneclient.v2_0.client.Client") + self.keystone_client_p.start() + self.murano_client = mock.MagicMock() + self.murano_client.environments.list.return_value = env_response + self.murano_client.services.list.return_value = service_response + self.murano_client.deployments.list.return_value = deployment_response + self.murano_client.packages.list.return_value = package_response + args = helper.datasource_openstack_args() + self.driver = murano_driver.MuranoDriver(args=args) + self.driver.murano_client = self.murano_client + + def test_list_environments(self): + """Test conversion of environments objects to tables.""" + env_list = self.driver.murano_client.environments.list() + self.driver.state[self.driver.STATES] = set() + self.driver.state[self.driver.OBJECTS] = set() + self.driver.state[self.driver.PROPERTIES] = set() + self.driver.state[self.driver.PARENT_TYPES] = set() + self.driver._translate_environments(env_list) + + env_list = list(self.driver.state['states']) + + # the list shouldn't be empty + self.assertIsNotNone(env_list) + + # the list should contain two elements + self.assertEqual(2, len(env_list)) + + # check the environment states + self.assertTrue( + (u'0c45ff66ce744568a524936da7ebaa7d', u'pending') in env_list) + self.assertTrue( + (u'9d929a329182469cb11a1841db95b8da', u'ready') in env_list) + + def test_translate_services(self): + """Test conversion of environments objects to tables.""" + env_list = self.driver.murano_client.environments.list() + self.driver.state[self.driver.STATES] = set() + self.driver.state[self.driver.OBJECTS] = set() + self.driver.state[self.driver.PROPERTIES] = set() + self.driver.state[self.driver.PARENT_TYPES] = set() + self.driver._translate_services(env_list) + + # the object list + obj_list = list(self.driver.state[self.driver.OBJECTS]) + + # the list shouldn't be empty + self.assertIsNotNone(obj_list) + + # the list should contain two elements + self.assertEqual(3, len(obj_list)) + + # check the environment states + self.assertTrue( + (u'03a0137f-4644-4943-9be9-66b612e8f885', + u'9d929a329182469cb11a1841db95b8da', + u'io.murano.apps.linux.Telnet') in obj_list) + self.assertTrue( + (u'03a0137f-4644-4943-9be9-66b612e8f885', + u'9d929a329182469cb11a1841db95b8da', + u'io.murano.apps.linux.Telnet') in obj_list) + + def test_translate_environment_services(self): + """Test conversion of environments objects to tables.""" + env_list = self.driver.murano_client.environments.list() + self.driver.state[self.driver.STATES] = set() + self.driver.state[self.driver.OBJECTS] = set() + self.driver.state[self.driver.PROPERTIES] = set() + self.driver.state[self.driver.PARENT_TYPES] = set() + self.driver._translate_services(env_list) + + for env in env_list: + services = self.murano_client.services.list(env.id) + self.driver._translate_environment_services(services, env.id) + + # the object list + obj_list = list(self.driver.state[self.driver.OBJECTS]) + + # the list shouldn't be empty + self.assertIsNotNone(obj_list) + + # the list should contain two elements + self.assertEqual(3, len(obj_list)) + + # check the environment states + self.assertTrue( + (u'03a0137f-4644-4943-9be9-66b612e8f885', + u'9d929a329182469cb11a1841db95b8da', + u'io.murano.apps.linux.Telnet') in obj_list) + self.assertTrue( + (u'03a0137f-4644-4943-9be9-66b612e8f885', + u'9d929a329182469cb11a1841db95b8da', + u'io.murano.apps.linux.Telnet') in obj_list) + + def test_translate_packages(self): + """Test conversion of environments objects to tables.""" + pkg_list = self.driver.murano_client.packages.list() + self.driver.state[self.driver.STATES] = set() + self.driver.state[self.driver.OBJECTS] = set() + self.driver.state[self.driver.PROPERTIES] = set() + self.driver.state[self.driver.PARENT_TYPES] = set() + self.driver._translate_packages(pkg_list) + + # the object list + obj_list = list(self.driver.state[self.driver.OBJECTS]) + + properties_list = list(self.driver.state[self.driver.PROPERTIES]) + + # the list shouldn't be empty + self.assertIsNotNone(obj_list) + self.assertIsNotNone(properties_list) + + # the list should contain two elements + self.assertEqual(2, len(obj_list)) + self.assertEqual(17, len(properties_list)) + + # check the environment states + self.assertTrue((u'68cd33f3a1bc41abbd9a7b7a8e2a3ae1', + 'enabled', True) in properties_list) + self.assertTrue((u'68cd33f3a1bc41abbd9a7b7a8e2a3ae1', + 'is_public', False) in properties_list) + self.assertTrue((u'68cd33f3a1bc41abbd9a7b7a8e2a3ae1', + 'tag', u'Pages') in properties_list) + self.assertTrue((u'68cd33f3a1bc41abbd9a7b7a8e2a3ae1', + 'tag', u'Java') in properties_list) + self.assertTrue((u'68cd33f3a1bc41abbd9a7b7a8e2a3ae1', + 'tag', u'Server') in properties_list) + self.assertTrue((u'68cd33f3a1bc41abbd9a7b7a8e2a3ae1', + 'tag', u'Servlets') in properties_list) + self.assertTrue((u'68cd33f3a1bc41abbd9a7b7a8e2a3ae1', + 'name', u'Apache Tomcat') in properties_list) + self.assertTrue( + (u'68cd33f3a1bc41abbd9a7b7a8e2a3ae1', + 'fully_qualified_name', + u'io.murano.apps.apache.Tomcat') in properties_list) + self.assertTrue((u'68cd33f3a1bc41abbd9a7b7a8e2a3ae1', + 'author', u'Mirantis, Inc') in properties_list) + self.assertTrue((u'68cd33f3a1bc41abbd9a7b7a8e2a3ae1', + 'category', u'Web') in properties_list) + self.assertTrue((u'18d7a400ab034a368e2cb6f7466d8214', + 'tag', u'connection') in properties_list) + self.assertTrue((u'18d7a400ab034a368e2cb6f7466d8214', + 'author', u'Mirantis, Inc') in properties_list) + self.assertTrue( + (u'18d7a400ab034a368e2cb6f7466d8214', + 'fully_qualified_name', + u'io.murano.apps.linux.Telnet') in properties_list) + self.assertTrue((u'18d7a400ab034a368e2cb6f7466d8214', + 'name', u'Telnet') in properties_list) + self.assertTrue((u'18d7a400ab034a368e2cb6f7466d8214', + 'tag', u'Linux') in properties_list) + self.assertTrue((u'18d7a400ab034a368e2cb6f7466d8214', + 'is_public', False) in properties_list) + self.assertTrue((u'18d7a400ab034a368e2cb6f7466d8214', + 'enabled', True) in properties_list) + +# Sample responses from murano-client +env_response = [ + ResponseObj({u'status': u'ready', + u'updated': u'2015-01-08T22:01:52', + u'networking': {}, + u'name': u'quick-env-1', + u'created': u'2015-01-08T21:53:08', + u'tenant_id': u'db4ca49cb1074cb093353b89f83615ef', + u'version': 1, + u'id': u'9d929a329182469cb11a1841db95b8da'}), + ResponseObj({'status': u'pending', + 'updated': u'2015-01-08T22:14:20', + 'networking': {}, + 'name': u'second_env', + 'created': u'2015-01-08T22:14:20', + 'tenant_id': u'db4ca49cb1074cb093353b89f83615ef', + 'version': 0, + 'id': u'0c45ff66ce744568a524936da7ebaa7d'})] + +service_response = [ResponseObj( + {u'instance': {u'name': u'tuerfi4oo8pp71', + u'securityGroupName': None, + u'assignFloatingIp': True, + u'ipAddresses': [u'10.0.8.2', u'172.24.4.4'], + u'networks': {u'useFlatNetwork': False, + u'primaryNetwork': None, + u'useEnvironmentNetwork': True, + u'customNetworks': []}, + u'keyname': u'cloud', + u'sharedIps': [], + u'floatingIpAddress': u'172.24.4.4', + u'flavor': u'm1.small', + u'image': u'ubuntu-murano', + u'?': {u'_actions': {}, + u'type': u'io.murano.resources.LinuxMuranoInstance', + u'id': u'6392a024-ebf8-49d2-990a-d6ba33ac70c9'}}, + u'name': u'Telnet', + u'?': {u'status': u'ready', + u'_26411a1861294160833743e45d0eaad9': {u'name': u'Telnet'}, + u'type': u'io.murano.apps.linux.Telnet', + u'id': u'03a0137f-4644-4943-9be9-66b612e8f885', + u'_actions': {}}})] + +deployment_response = [ResponseObj( + {u'updated': u'2015-01-08T22:01:52', + u'environment_id': u'9d929a329182469cb11a1841db95b8da', + u'description': {u'services': + [{u'instance': + {u'name': u'tuerfi4oo8pp71', + u'assignFloatingIp': True, + u'keyname': u'cloud', + u'flavor': u'm1.small', + u'image': u'ubuntu-murano', + u'?': {u'type': + u'io.murano.resources.LinuxMuranoInstance', + u'id': + u'6392a024-ebf8-49d2-990a-d6ba33ac70c9'}}, + u'name': u'Telnet', + u'?': {u'_26411a1861294160833743e45d0eaad9': + {u'name': u'Telnet'}, + u'type': u'io.murano.apps.linux.Telnet', + u'id': + u'03a0137f-4644-4943-9be9-66b612e8f885'}}], + u'defaultNetworks': + {u'environment': + {u'name': u'quick-env-1-network', + u'?': {u'type': u'io.murano.resources.NeutronNetwork', + u'id': u'afcfe791222a408989bf8c29ce1562f3'}}, + u'flat': None}, + u'name': u'quick-env-1', + u'?': {u'type': u'io.murano.Environment', + u'id': u'9d929a329182469cb11a1841db95b8da'}}, + u'created': u'2015-01-08T21:53:14', + u'started': u'2015-01-08T21:53:14', + u'state': u'success', + u'finished': u'2015-01-08T22:01:52', + u'action': {u'args': {}, + u'method': u'deploy', + u'object_id': u'9d929a329182469cb11a1841db95b8da'}, + u'id': u'77102e350687424ebdad048cde92bac2'})] + +package_response = [ + ResponseObj({u'class_definitions': [u'io.murano.apps.apache.Tomcat'], + u'description': u'Apache Tomcat is an open source software ' + + 'implementation of the Java Servlet and JavaServer ' + + 'Pages technologies.\n', + u'tags': [u'Servlets', u'Server', + u'Pages', u'Java'], + u'owner_id': u'db4ca49cb1074cb093353b89f83615ef', + u'author': u'Mirantis, Inc', + u'enabled': True, + u'updated': u'2015-01-08T21:45:57', + u'created': u'2015-01-08T21:45:57', + u'supplier': {}, + u'is_public': False, + u'fully_qualified_name': u'io.murano.apps.apache.Tomcat', + u'type': u'Application', + u'id': u'68cd33f3a1bc41abbd9a7b7a8e2a3ae1', + u'categories': [u'Web'], + u'name': u'Apache Tomcat'}), + ResponseObj({u'class_definitions': [u'io.murano.apps.linux.Telnet'], + u'description': u'Telnet is the traditional protocol for ' + + 'making remote console connections over TCP.\n', + u'tags': [u'Linux', u'connection'], + u'owner_id': u'db4ca49cb1074cb093353b89f83615ef', + u'author': u'Mirantis, Inc', + u'enabled': True, + u'updated': u'2015-01-08T21:45:32', + u'created': u'2015-01-08T21:45:32', + u'supplier': {}, + u'is_public': False, + u'fully_qualified_name': u'io.murano.apps.linux.Telnet', + u'type': u'Application', + u'id': u'18d7a400ab034a368e2cb6f7466d8214', + u'categories': [], + u'name': u'Telnet'})] diff --git a/etc/datasources.conf.sample b/etc/datasources.conf.sample index 176a4d973..7ae95915f 100644 --- a/etc/datasources.conf.sample +++ b/etc/datasources.conf.sample @@ -61,3 +61,10 @@ tenant_name: admin #auth_url: vCenterURL #max_Hosts: 999 #max_VMs: 999 + +[murano] +module: datasources/murano_driver.py +username: admin +password: password +auth_url: http://127.0.0.1:5000/v2.0 +tenant_name: admin diff --git a/examples/murano/predeploy_simulate.sh b/examples/murano/predeploy_simulate.sh new file mode 100755 index 000000000..25ff46eba --- /dev/null +++ b/examples/murano/predeploy_simulate.sh @@ -0,0 +1,116 @@ +cd /opt/stack/congress +source ~/devstack/openrc admin admin + +echo "Deleting all existing rules of murano_system policy" +rule_ids=(`openstack congress policy rule list murano_system | grep "// ID:" | awk '{print $3}'`) +for i in "${rule_ids[@]}" +do + echo "delete rule ${i}" + openstack congress policy rule delete murano_system ${i} +done + +echo "Rule deleting done." + +echo +echo "Create murano_system policy" +openstack congress policy create murano_system + +openstack congress policy rule create murano_system ' +allowed_flavors(flavor) :- + nova:flavors(flavor_id, flavor, vcpus, ram, disk, ephemeral, rxtx_factor), + equal(flavor, "m1.medium")' + +openstack congress policy rule create murano_system ' +allowed_flavors(flavor) :- + nova:flavors(flavor_id, flavor, vcpus, ram, disk, ephemeral, rxtx_factor), + equal(flavor, "m1.small")' + +openstack congress policy rule create murano_system ' +allowed_flavors(flavor) :- + nova:flavors(flavor_id, flavor, vcpus, ram, disk, ephemeral, rxtx_factor), + equal(flavor, "m1.tiny")' + +openstack congress policy rule create murano_system ' +murano.environments(env_id, env_name) :- + murano.objects(env_id, owner_id, "io.murano.Environment"), + murano.properties(env_id, "name", env_name)' + +openstack congress policy rule create murano_system ' +murano.instances(env_id, obj_id) :- + murano.objects(obj_id, service_id, instance_type), + murano.objects(service_id, env_id, service_type), + murano.parent_types(obj_id, "io.murano.resources.Instance")' + +openstack congress policy rule create murano_system ' +predeploy_error(env_id) :- + murano.environments(env_id, env_name), + murano.instances(env_id, obj_id), + murano.properties(obj_id, "flavor", flavor), + murano.states(env_id, env_state), + equal(env_state, "pending"), + not allowed_flavors(flavor)' + +openstack congress policy rule create murano_system ' +untyped_predeploy_error(env_id) :- + murano.objects(env_id, tenant_id, "io.murano.Environment"), + murano.objects(instance_id, service_id, instance_type), + murano.objects(service_id, env_id, service_type), + murano.parent_types(instance_id, "io.murano.resources.Instance"), + murano.properties(instance_id, "flavor", flavor), + murano.states(env_id, env_state), + equal(env_state, "pending"), + not allowed_flavors(flavor)' + +echo "Define rules using murano datasource" +openstack congress policy rule create murano_system ' +untyped_predeploy_error2(env_id) :- + murano:objects(env_id, tenant_id, "io.murano.Environment"), + murano:objects(instance_id, service_id, instance_type), + murano:objects(service_id, env_id, service_type), + murano:parent_types(instance_id, "io.murano.resources.Instance"), + murano:properties(instance_id, "flavor", flavor), + murano:states(env_id, env_state), + equal(env_state, "pending"), + not allowed_flavors(flavor)' + +echo "" +echo "--- simulate policy ---" +echo 'env_id = "env_uuid", flavor = "m1.small"' +openstack congress policy simulate murano_system 'untyped_predeploy_error(env_id)' ' + murano.objects+("env_uuid", "env_owner_uuid", "io.murano.Environment") + murano.objects+("svc_uuid", "env_uuid", "service_type") + murano.objects+("inst_uuid", "svc_uuid", "instance_type") + murano.parent_types+("inst_uuid", "io.murano.resources.Instance") + murano.properties+("inst_uuid", "flavor", "m1.small") + murano.states+("env_uuid", "pending")' action + +echo "---" +echo 'env_id = "env_uuid", flavor = "m1.large"' +openstack congress policy simulate murano_system 'untyped_predeploy_error(env_id)' ' + murano.objects+("env_uuid", "env_owner_uuid", "io.murano.Environment") + murano.objects+("svc_uuid", "env_uuid", "service_type") + murano.objects+("inst_uuid", "svc_uuid", "instance_type") + murano.parent_types+("inst_uuid", "io.murano.resources.Instance") + murano.properties+("inst_uuid", "flavor", "m1.large") + murano.states+("env_uuid", "pending")' action + +echo "---" +echo 'Simulate using datasource tables. env_id = "env_uuid", flavor = "m1.large"' +openstack congress policy simulate murano_system 'untyped_predeploy_error2(env_id)' ' + murano:objects+("env_uuid", "env_owner_uuid", "io.murano.Environment") + murano:objects+("svc_uuid", "env_uuid", "service_type") + murano:objects+("inst_uuid", "svc_uuid", "instance_type") + murano:parent_types+("inst_uuid", "io.murano.resources.Instance") + murano:properties+("inst_uuid", "flavor", "m1.large") + murano:states+("env_uuid", "pending")' action + +echo "---" +echo 'env_id = "env_uuid", flavor = "m1.large"' +openstack congress policy simulate murano_system 'predeploy_error(env_id)' ' + murano.objects+("env_uuid", "env_owner_uuid", "io.murano.Environment") + murano.properties+("env_uuid", "name", "second_env") + murano.objects+("svc_uuid", "env_uuid", "service_type") + murano.objects+("inst_uuid", "svc_uuid", "instance_type") + murano.parent_types+("inst_uuid", "io.murano.resources.Instance") + murano.properties+("inst_uuid", "flavor", "m1.large") + murano.states+("env_uuid", "pending")' action