diff --git a/senlin/drivers/base.py b/senlin/drivers/base.py index a8d968d82..84d6b5897 100644 --- a/senlin/drivers/base.py +++ b/senlin/drivers/base.py @@ -41,7 +41,6 @@ class SenlinDriver(object): self.network = backend.network self.octavia = backend.octavia self.orchestration = backend.orchestration - self.telemetry = backend.telemetry self.identity = backend.identity self.message = backend.message self.workflow = backend.workflow diff --git a/senlin/drivers/container/docker_v1.py b/senlin/drivers/container/docker_v1.py index 8c831fb98..7240c539b 100644 --- a/senlin/drivers/container/docker_v1.py +++ b/senlin/drivers/container/docker_v1.py @@ -12,7 +12,7 @@ import docker -from senlin.drivers.openstack import sdk +from senlin.drivers import sdk class DockerClient(object): diff --git a/senlin/drivers/openstack/ceilometer_v2.py b/senlin/drivers/openstack/ceilometer_v2.py deleted file mode 100644 index 65cdf946a..000000000 --- a/senlin/drivers/openstack/ceilometer_v2.py +++ /dev/null @@ -1,50 +0,0 @@ -# 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. - -from senlin.drivers import base -from senlin.drivers.openstack import sdk - - -class CeilometerClient(base.DriverBase): - '''Ceilometer V2 driver.''' - - def __init__(self, params): - super(CeilometerClient, self).__init__(params) - self.conn = sdk.create_connection(params) - - @sdk.translate_exception - def alarm_create(self, **attrs): - return self.conn.telemetry.create_alarm(**attrs) - - @sdk.translate_exception - def alarm_delete(self, value, ignore_missing=True): - return self.conn.telemetry.delete_alarm(value, ignore_missing) - - @sdk.translate_exception - def alarm_find(self, name_or_id, ignore_missing=True): - return self.conn.telemetry.find_alarm(name_or_id, ignore_missing) - - @sdk.translate_exception - def alarm_get(self, value): - return self.conn.telemetry.get_alarm(value) - - @sdk.translate_exception - def alarm_list(self, **query): - return self.conn.telemetry.alarms(**query) - - @sdk.translate_exception - def alarm_update(self, value, **attrs): - return self.conn.telemetry.update_alarm(value, **attrs) - - @sdk.translate_exception - def sample_create(self, **attrs): - return self.conn.telemetry.create_sample(**attrs) diff --git a/senlin/drivers/openstack_test/mistral_v2.py b/senlin/drivers/openstack_test/mistral_v2.py deleted file mode 100644 index 2e18b0ede..000000000 --- a/senlin/drivers/openstack_test/mistral_v2.py +++ /dev/null @@ -1,80 +0,0 @@ -# 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. - - -from oslo_utils import uuidutils - -from senlin.drivers import base -from senlin.drivers.openstack_test import sdk - - -class MistralClient(base.DriverBase): - '''Fake mistral V2 driver for test.''' - - def __init__(self, ctx): - - self.fake_workflow = { - 'created_at': '1970-01-01T00:00:00.000000', - 'definition': 'workflow_def', - 'id': 'ffaed25e-46f5-4089-8e20-b3b4722fd597', - 'input': { - 'cluster_id': '8c74607c-5a74-4490-9414-a3475b1926c2', - 'node_id': 'fba2cc5d-706f-4631-9577-3956048d13a2', - 'flavor_id': '1' - }, - 'name': "cluster-coldmigration", - 'project_id': 'a7eb669e9819420ea4bd1453e672c0a7', - 'scope': 'private', - 'tags': [ - 'large', - 'expensive' - ], - 'updated_at': '1970-01-01T00:00:00.000000', - } - - self.fake_workflow_create = { - 'scope': 'private', - 'id': 'ffaed25e-46f5-4089-8e20-b3b4722fd597', - 'definition': 'workflow_def', - } - - self.fake_execution_create = { - 'id': 'ffaed25e-46f5-4089-8e20-b3b4722fd597', - 'workflow_name': 'cluster-coldmigration', - 'input': { - 'cluster_id': '8c74607c-5a74-4490-9414-a3475b1926c2', - 'node_id': 'fba2cc5d-706f-4631-9577-3956048d13a2', - 'flavor_id': '1' - } - } - - def wait_for_execution(self, execution, status='SUCCESS', - failures=['ERROR'], interval=2, - timeout=None): - return - - def workflow_find(self, name_or_id, ignore_missing=True): - return sdk.FakeResourceObject(self.fake_workflow) - - def workflow_delete(self, workflow, ignore_missing=True): - return - - def execution_delete(self, execution, ignore_missing=True): - return - - def workflow_create(self, definition, scope): - self.fake_workflow_create['id'] = uuidutils.generate_uuid() - return sdk.FakeResourceObject(self.fake_workflow_create) - - def execution_create(self, name, inputs): - self.fake_execution_create['id'] = uuidutils.generate_uuid() - return sdk.FakeResourceObject(self.fake_execution_create) diff --git a/senlin/drivers/openstack_test/sdk.py b/senlin/drivers/openstack_test/sdk.py deleted file mode 100644 index 84c7b5fab..000000000 --- a/senlin/drivers/openstack_test/sdk.py +++ /dev/null @@ -1,28 +0,0 @@ -# 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. - - -class FakeResourceObject(object): - '''Generate a fake SDK resource object based on given dictionary''' - def __init__(self, params): - for key in params: - setattr(self, key, params[key]) - - def to_dict(self): - '''Override this function in subclass to handle special attributes''' - data = {} - for attr in dir(self): - if not attr.startswith('__'): - # Exclude built-in attributes of python object - data[attr] = getattr(self, attr) - - return data diff --git a/senlin/drivers/openstack/__init__.py b/senlin/drivers/os/__init__.py similarity index 62% rename from senlin/drivers/openstack/__init__.py rename to senlin/drivers/os/__init__.py index 09e644176..d593d3823 100644 --- a/senlin/drivers/openstack/__init__.py +++ b/senlin/drivers/os/__init__.py @@ -10,18 +10,18 @@ # License for the specific language governing permissions and limitations # under the License. -from senlin.drivers.openstack import ceilometer_v2 -from senlin.drivers.openstack import cinder_v2 -from senlin.drivers.openstack import heat_v1 -from senlin.drivers.openstack import keystone_v3 -from senlin.drivers.openstack import lbaas -from senlin.drivers.openstack import mistral_v2 -from senlin.drivers.openstack import neutron_v2 -from senlin.drivers.openstack import nova_v2 -from senlin.drivers.openstack import octavia_v2 -from senlin.drivers.openstack import zaqar_v2 +from senlin.drivers.os import cinder_v2 +from senlin.drivers.os import heat_v1 +from senlin.drivers.os import keystone_v3 +from senlin.drivers.os import lbaas +from senlin.drivers.os import mistral_v2 +from senlin.drivers.os import neutron_v2 +from senlin.drivers.os import nova_v2 +from senlin.drivers.os import octavia_v2 +from senlin.drivers.os import zaqar_v2 +block_storage = cinder_v2.CinderClient compute = nova_v2.NovaClient identity = keystone_v3.KeystoneClient loadbalancing = lbaas.LoadBalancerDriver @@ -29,6 +29,4 @@ message = zaqar_v2.ZaqarClient network = neutron_v2.NeutronClient octavia = octavia_v2.OctaviaClient orchestration = heat_v1.HeatClient -telemetry = ceilometer_v2.CeilometerClient workflow = mistral_v2.MistralClient -block_storage = cinder_v2.CinderClient diff --git a/senlin/drivers/openstack/cinder_v2.py b/senlin/drivers/os/cinder_v2.py similarity index 97% rename from senlin/drivers/openstack/cinder_v2.py rename to senlin/drivers/os/cinder_v2.py index da475a92e..daf9d467f 100644 --- a/senlin/drivers/openstack/cinder_v2.py +++ b/senlin/drivers/os/cinder_v2.py @@ -11,7 +11,7 @@ # under the License. from senlin.drivers import base -from senlin.drivers.openstack import sdk +from senlin.drivers import sdk class CinderClient(base.DriverBase): diff --git a/senlin/drivers/openstack/glance_v2.py b/senlin/drivers/os/glance_v2.py similarity index 96% rename from senlin/drivers/openstack/glance_v2.py rename to senlin/drivers/os/glance_v2.py index 2ef13fd9b..5563f5022 100644 --- a/senlin/drivers/openstack/glance_v2.py +++ b/senlin/drivers/os/glance_v2.py @@ -11,7 +11,7 @@ # under the License. from senlin.drivers import base -from senlin.drivers.openstack import sdk +from senlin.drivers import sdk class GlanceClient(base.DriverBase): diff --git a/senlin/drivers/openstack/heat_v1.py b/senlin/drivers/os/heat_v1.py similarity index 98% rename from senlin/drivers/openstack/heat_v1.py rename to senlin/drivers/os/heat_v1.py index ad7dead17..eececda89 100644 --- a/senlin/drivers/openstack/heat_v1.py +++ b/senlin/drivers/os/heat_v1.py @@ -13,7 +13,7 @@ from oslo_config import cfg from senlin.drivers import base -from senlin.drivers.openstack import sdk +from senlin.drivers import sdk class HeatClient(base.DriverBase): diff --git a/senlin/drivers/openstack/keystone_v3.py b/senlin/drivers/os/keystone_v3.py similarity index 99% rename from senlin/drivers/openstack/keystone_v3.py rename to senlin/drivers/os/keystone_v3.py index f0a6163f2..af37b514a 100644 --- a/senlin/drivers/openstack/keystone_v3.py +++ b/senlin/drivers/os/keystone_v3.py @@ -14,7 +14,7 @@ from oslo_config import cfg from oslo_log import log from senlin.drivers import base -from senlin.drivers.openstack import sdk +from senlin.drivers import sdk LOG = log.getLogger(__name__) CONF = cfg.CONF diff --git a/senlin/drivers/openstack/lbaas.py b/senlin/drivers/os/lbaas.py similarity index 99% rename from senlin/drivers/openstack/lbaas.py rename to senlin/drivers/os/lbaas.py index d2cbbcdb0..b3e70aa2b 100644 --- a/senlin/drivers/openstack/lbaas.py +++ b/senlin/drivers/os/lbaas.py @@ -19,8 +19,8 @@ from oslo_log import log as logging from senlin.common import exception from senlin.common.i18n import _ from senlin.drivers import base -from senlin.drivers.openstack import neutron_v2 as neutronclient -from senlin.drivers.openstack import octavia_v2 as octaviaclient +from senlin.drivers.os import neutron_v2 as neutronclient +from senlin.drivers.os import octavia_v2 as octaviaclient from senlin.engine import node as nodem LOG = logging.getLogger(__name__) diff --git a/senlin/drivers/openstack/mistral_v2.py b/senlin/drivers/os/mistral_v2.py similarity index 98% rename from senlin/drivers/openstack/mistral_v2.py rename to senlin/drivers/os/mistral_v2.py index 81a864497..47dd7e4c5 100644 --- a/senlin/drivers/openstack/mistral_v2.py +++ b/senlin/drivers/os/mistral_v2.py @@ -11,8 +11,9 @@ # under the License. from oslo_config import cfg + from senlin.drivers import base -from senlin.drivers.openstack import sdk +from senlin.drivers import sdk class MistralClient(base.DriverBase): diff --git a/senlin/drivers/openstack/neutron_v2.py b/senlin/drivers/os/neutron_v2.py similarity index 99% rename from senlin/drivers/openstack/neutron_v2.py rename to senlin/drivers/os/neutron_v2.py index 3cbdd255f..33343d48a 100644 --- a/senlin/drivers/openstack/neutron_v2.py +++ b/senlin/drivers/os/neutron_v2.py @@ -13,7 +13,7 @@ from oslo_utils import uuidutils from senlin.drivers import base -from senlin.drivers.openstack import sdk +from senlin.drivers import sdk class NeutronClient(base.DriverBase): diff --git a/senlin/drivers/openstack/nova_v2.py b/senlin/drivers/os/nova_v2.py similarity index 99% rename from senlin/drivers/openstack/nova_v2.py rename to senlin/drivers/os/nova_v2.py index 2bd49f640..7bf47b051 100644 --- a/senlin/drivers/openstack/nova_v2.py +++ b/senlin/drivers/os/nova_v2.py @@ -14,7 +14,7 @@ from oslo_config import cfg from oslo_log import log from senlin.drivers import base -from senlin.drivers.openstack import sdk +from senlin.drivers import sdk LOG = log.getLogger(__name__) diff --git a/senlin/drivers/openstack/octavia_v2.py b/senlin/drivers/os/octavia_v2.py similarity index 99% rename from senlin/drivers/openstack/octavia_v2.py rename to senlin/drivers/os/octavia_v2.py index fc211b1f5..5ba63dff0 100644 --- a/senlin/drivers/openstack/octavia_v2.py +++ b/senlin/drivers/os/octavia_v2.py @@ -11,7 +11,7 @@ # under the License. from senlin.drivers import base -from senlin.drivers.openstack import sdk +from senlin.drivers import sdk class OctaviaClient(base.DriverBase): diff --git a/senlin/drivers/openstack/zaqar_v2.py b/senlin/drivers/os/zaqar_v2.py old mode 100755 new mode 100644 similarity index 98% rename from senlin/drivers/openstack/zaqar_v2.py rename to senlin/drivers/os/zaqar_v2.py index e3b933745..af34b3fb2 --- a/senlin/drivers/openstack/zaqar_v2.py +++ b/senlin/drivers/os/zaqar_v2.py @@ -13,7 +13,7 @@ from openstack import exceptions as sdk_exc from senlin.drivers import base -from senlin.drivers.openstack import sdk +from senlin.drivers import sdk class ZaqarClient(base.DriverBase): diff --git a/senlin/drivers/openstack_test/README.rst b/senlin/drivers/os_test/README.rst similarity index 100% rename from senlin/drivers/openstack_test/README.rst rename to senlin/drivers/os_test/README.rst diff --git a/senlin/drivers/openstack_test/__init__.py b/senlin/drivers/os_test/__init__.py similarity index 61% rename from senlin/drivers/openstack_test/__init__.py rename to senlin/drivers/os_test/__init__.py index 79e29fed6..cb2992136 100644 --- a/senlin/drivers/openstack_test/__init__.py +++ b/senlin/drivers/os_test/__init__.py @@ -10,17 +10,16 @@ # License for the specific language governing permissions and limitations # under the License. -from senlin.drivers.openstack import ceilometer_v2 -from senlin.drivers.openstack import keystone_v3 -from senlin.drivers.openstack_test import cinder_v2 -from senlin.drivers.openstack_test import heat_v1 -from senlin.drivers.openstack_test import lbaas -from senlin.drivers.openstack_test import mistral_v2 -from senlin.drivers.openstack_test import neutron_v2 -from senlin.drivers.openstack_test import nova_v2 -from senlin.drivers.openstack_test import octavia_v2 -from senlin.drivers.openstack_test import zaqar_v2 +from senlin.drivers.os_test import cinder_v2 +from senlin.drivers.os_test import heat_v1 +from senlin.drivers.os_test import keystone_v3 +from senlin.drivers.os_test import lbaas +from senlin.drivers.os_test import mistral_v2 +from senlin.drivers.os_test import neutron_v2 +from senlin.drivers.os_test import nova_v2 +from senlin.drivers.os_test import octavia_v2 +from senlin.drivers.os_test import zaqar_v2 block_storage = cinder_v2.CinderClient @@ -31,5 +30,4 @@ message = zaqar_v2.ZaqarClient network = neutron_v2.NeutronClient octavia = octavia_v2.OctaviaClient orchestration = heat_v1.HeatClient -telemetry = ceilometer_v2.CeilometerClient workflow = mistral_v2.MistralClient diff --git a/senlin/drivers/openstack_test/cinder_v2.py b/senlin/drivers/os_test/cinder_v2.py similarity index 98% rename from senlin/drivers/openstack_test/cinder_v2.py rename to senlin/drivers/os_test/cinder_v2.py index a3b3faea6..d2193fdf1 100644 --- a/senlin/drivers/openstack_test/cinder_v2.py +++ b/senlin/drivers/os_test/cinder_v2.py @@ -11,7 +11,7 @@ # under the License. from senlin.drivers import base -from senlin.drivers.openstack_test import sdk +from senlin.drivers import sdk class CinderClient(base.DriverBase): diff --git a/senlin/drivers/openstack_test/heat_v1.py b/senlin/drivers/os_test/heat_v1.py similarity index 98% rename from senlin/drivers/openstack_test/heat_v1.py rename to senlin/drivers/os_test/heat_v1.py index f1f7f9f46..ef85ea936 100644 --- a/senlin/drivers/openstack_test/heat_v1.py +++ b/senlin/drivers/os_test/heat_v1.py @@ -11,7 +11,7 @@ # under the License. from senlin.drivers import base -from senlin.drivers.openstack_test import sdk +from senlin.drivers import sdk class HeatClient(base.DriverBase): diff --git a/senlin/drivers/os_test/keystone_v3.py b/senlin/drivers/os_test/keystone_v3.py new file mode 100644 index 000000000..af37b514a --- /dev/null +++ b/senlin/drivers/os_test/keystone_v3.py @@ -0,0 +1,154 @@ +# 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. + +from oslo_config import cfg +from oslo_log import log + +from senlin.drivers import base +from senlin.drivers import sdk + +LOG = log.getLogger(__name__) +CONF = cfg.CONF + + +class KeystoneClient(base.DriverBase): + '''Keystone V3 driver.''' + + def __init__(self, params): + super(KeystoneClient, self).__init__(params) + self.conn = sdk.create_connection(params) + self.session = self.conn.session + + @sdk.translate_exception + def trust_get_by_trustor(self, trustor, trustee=None, project=None): + '''Get trust by trustor. + + Note we cannot provide two or more filters to keystone due to + constraints in keystone implementation. We do additional filtering + after the results are returned. + + :param trustor: ID of the trustor; + :param trustee: ID of the trustee; + :param project: ID of the project to which the trust is scoped. + :returns: The trust object or None if no matching trust is found. + ''' + filters = {'trustor_user_id': trustor} + + trusts = [t for t in self.conn.identity.trusts(**filters)] + + for trust in trusts: + if (trustee and trust.trustee_user_id != trustee): + continue + + if (project and trust.project_id != project): + continue + + return trust + + return None + + @sdk.translate_exception + def trust_create(self, trustor, trustee, project, roles=None, + impersonation=True): + '''Create trust between two users. + + :param trustor: ID of the user who is the trustor. + :param trustee: ID of the user who is the trustee. + :param project: Scope of the trust which is a project ID. + :param roles: List of roles the trustee will inherit from the trustor. + :param impersonation: Whether the trustee is allowed to impersonate + the trustor. + ''' + + if roles: + role_list = [{'name': role} for role in roles] + else: + role_list = [] + params = { + 'trustor_user_id': trustor, + 'trustee_user_id': trustee, + 'project_id': project, + 'impersonation': impersonation, + 'allow_redelegation': True, + 'roles': role_list + } + + result = self.conn.identity.create_trust(**params) + + return result + + @classmethod + @sdk.translate_exception + def get_token(cls, **creds): + '''Get token using given credential''' + + access_info = sdk.authenticate(**creds) + return access_info['token'] + + @classmethod + @sdk.translate_exception + def get_user_id(cls, **creds): + '''Get ID of the user with given credential''' + + access_info = sdk.authenticate(**creds) + return access_info['user_id'] + + @classmethod + def get_service_credentials(cls, **kwargs): + '''Senlin service credential to use with Keystone. + + :param kwargs: An additional keyword argument list that can be used + for customizing the default settings. + ''' + + creds = { + 'auth_url': CONF.authentication.auth_url, + 'username': CONF.authentication.service_username, + 'password': CONF.authentication.service_password, + 'project_name': CONF.authentication.service_project_name, + 'user_domain_name': cfg.CONF.authentication.service_user_domain, + 'project_domain_name': + cfg.CONF.authentication.service_project_domain, + } + creds.update(**kwargs) + return creds + + @sdk.translate_exception + def validate_regions(self, regions): + """Check whether the given regions are valid. + + :param regions: A list of regions for validation. + :returns: A list of regions that are found available on keystone. + """ + region_list = self.conn.identity.regions() + known = [r['id'] for r in region_list] + + validated = [] + for r in regions: + if r in known: + validated.append(r) + else: + LOG.warning('Region %s is not found.', r) + + return validated + + @sdk.translate_exception + def get_senlin_endpoint(self): + '''Get Senlin service endpoint.''' + region = cfg.CONF.default_region_name + # TODO(Yanyan Hu): Currently, region filtering is unsupported in + # session.get_endpoint(). Need to propose fix to openstacksdk. + base = self.conn.session.get_endpoint(service_type='clustering', + interface='public', + region=region) + + return base diff --git a/senlin/drivers/openstack_test/lbaas.py b/senlin/drivers/os_test/lbaas.py similarity index 100% rename from senlin/drivers/openstack_test/lbaas.py rename to senlin/drivers/os_test/lbaas.py diff --git a/senlin/drivers/os_test/mistral_v2.py b/senlin/drivers/os_test/mistral_v2.py new file mode 100644 index 000000000..059e61473 --- /dev/null +++ b/senlin/drivers/os_test/mistral_v2.py @@ -0,0 +1,42 @@ +# 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. + +from senlin.drivers import base +from senlin.drivers import sdk + + +class MistralClient(base.DriverBase): + '''Fake Mistral V2 driver.''' + + def __init__(self, params): + self.fake_workflow = {} + self.fake_execution = {} + + def workflow_create(self, definition, scope): + return sdk.FakeResourceObject(self.fake_workflow) + + def workflow_delete(self, workflow, ignore_missing=True): + return None + + def workflow_find(self, name_or_id, ignore_missing=True): + return sdk.FakeResourceObject(self.fake_workflow) + + def execution_create(self, name, inputs): + return sdk.FakeResourceObject(self.fake_execution) + + def execution_delete(self, execution, ignore_missing=True): + return None + + def wait_for_execution(self, execution, status='SUCCESS', + failures=['ERROR'], interval=2, + timeout=None): + return None diff --git a/senlin/drivers/openstack_test/neutron_v2.py b/senlin/drivers/os_test/neutron_v2.py similarity index 98% rename from senlin/drivers/openstack_test/neutron_v2.py rename to senlin/drivers/os_test/neutron_v2.py index 2ea509712..e159c067e 100644 --- a/senlin/drivers/openstack_test/neutron_v2.py +++ b/senlin/drivers/os_test/neutron_v2.py @@ -11,7 +11,7 @@ # under the License. from senlin.drivers import base -from senlin.drivers.openstack_test import sdk +from senlin.drivers import sdk class NeutronClient(base.DriverBase): diff --git a/senlin/drivers/openstack_test/nova_v2.py b/senlin/drivers/os_test/nova_v2.py similarity index 99% rename from senlin/drivers/openstack_test/nova_v2.py rename to senlin/drivers/os_test/nova_v2.py index 0d88c9926..0a44f4e50 100644 --- a/senlin/drivers/openstack_test/nova_v2.py +++ b/senlin/drivers/os_test/nova_v2.py @@ -15,7 +15,7 @@ import copy from oslo_utils import uuidutils from senlin.drivers import base -from senlin.drivers.openstack_test import sdk +from senlin.drivers import sdk class NovaClient(base.DriverBase): diff --git a/senlin/drivers/openstack_test/octavia_v2.py b/senlin/drivers/os_test/octavia_v2.py similarity index 99% rename from senlin/drivers/openstack_test/octavia_v2.py rename to senlin/drivers/os_test/octavia_v2.py index 127bd3e0a..8e18e160f 100644 --- a/senlin/drivers/openstack_test/octavia_v2.py +++ b/senlin/drivers/os_test/octavia_v2.py @@ -11,7 +11,7 @@ # under the License. from senlin.drivers import base -from senlin.drivers.openstack_test import sdk +from senlin.drivers import sdk FAKE_LB_ID = "607226db-27ef-4d41-ae89-f2a800e9c2db" FAKE_LISTENER_ID = "023f2e34-7806-443b-bfae-16c324569a3d" diff --git a/senlin/drivers/openstack_test/zaqar_v2.py b/senlin/drivers/os_test/zaqar_v2.py similarity index 95% rename from senlin/drivers/openstack_test/zaqar_v2.py rename to senlin/drivers/os_test/zaqar_v2.py index 2f39dc1d5..30ca65527 100644 --- a/senlin/drivers/openstack_test/zaqar_v2.py +++ b/senlin/drivers/os_test/zaqar_v2.py @@ -11,7 +11,7 @@ # under the License. from senlin.drivers import base -from senlin.drivers.openstack_test import sdk +from senlin.drivers import sdk FAKE_SUBSCRIPTION_ID = "0d8dbb71-1538-42ac-99fb-bb52d0ad1b6f" FAKE_MESSAGE_ID = "51db6f78c508f17ddc924357" @@ -51,24 +51,24 @@ class ZaqarClient(base.DriverBase): return True def queue_delete(self, queue, ignore_missing=True): - return + return None def subscription_create(self, queue_name, **attrs): return sdk.FakeResourceObject(self.fake_subscription) def subscription_delete(self, queue_name, subscription, ignore_missing=True): - return + return None def claim_create(self, queue_name, **attrs): return sdk.FakeResourceObject(self.fake_claim) def claim_delete(self, queue_name, claim, ignore_missing=True): - return + return None def message_delete(self, queue_name, message, claim_id=None, ignore_missing=True): - return + return None def message_post(self, queue_name, message): return sdk.FakeResourceObject(self.fake_message) diff --git a/senlin/drivers/openstack/sdk.py b/senlin/drivers/sdk.py similarity index 89% rename from senlin/drivers/openstack/sdk.py rename to senlin/drivers/sdk.py index d9257d7bf..7641b9579 100644 --- a/senlin/drivers/openstack/sdk.py +++ b/senlin/drivers/sdk.py @@ -16,16 +16,15 @@ SDK Client import sys import functools -from oslo_config import cfg -from oslo_log import log as logging -import six - from openstack import connection from openstack import exceptions as sdk_exc from openstack import profile from openstack import utils as sdk_utils +from oslo_config import cfg +from oslo_log import log as logging from oslo_serialization import jsonutils from requests import exceptions as req_exc +import six from senlin.common import exception as senlin_exc @@ -138,3 +137,20 @@ def authenticate(**kwargs): } return access_info + + +class FakeResourceObject(object): + '''Generate a fake SDK resource object based on given dictionary''' + def __init__(self, params): + for key in params: + setattr(self, key, params[key]) + + def to_dict(self): + '''Override this function in subclass to handle special attributes''' + data = {} + for attr in dir(self): + if not attr.startswith('__'): + # Exclude built-in attributes of python object + data[attr] = getattr(self, attr) + + return data diff --git a/senlin/engine/actions/cluster_action.py b/senlin/engine/actions/cluster_action.py index 846fe4213..b7dcb49fc 100755 --- a/senlin/engine/actions/cluster_action.py +++ b/senlin/engine/actions/cluster_action.py @@ -301,6 +301,13 @@ class ClusterAction(base.Action): result, reason = self._update_nodes(profile_id, self.entity.nodes) return result, reason + def _handle_lifecycle_timeout(self, child): + for action_id, node_id in child: + status = ao.Action.check_status(self.context, action_id, 0) + if (status == consts.ACTION_WAITING_LIFECYCLE_COMPLETION): + ao.Action.update(self.context, action_id, + {'status': base.Action.READY}) + def _delete_nodes(self, node_ids): action_name = consts.NODE_DELETE @@ -319,11 +326,10 @@ class ClusterAction(base.Action): lifecycle_hook_params = lifecycle_hook.get('params') if lifecycle_hook_type == "zaqar": lifecycle_hook_target = lifecycle_hook_params.get('queue') - elif lifecycle_hook_type == "webhook": - lifecycle_hook_target = lifecycle_hook_params.get('url') else: - return self.RES_ERROR, _("Invalid lifecycle hook type " - "specified in deletion policy") + # lifecycle_hook_target = lifecycle_hook_params.get('url') + return self.RES_ERROR, _("Lifecycle hook type '%s' is not " + "implemented") % lifecycle_hook_type child = [] for node_id in node_ids: @@ -355,22 +361,18 @@ class ClusterAction(base.Action): ao.Action.update(self.context, action_id, {'status': status}) if lifecycle_hook: - if lifecycle_hook_type == "zaqar": - # post message to zaqar - kwargs = { - 'user': self.context.user_id, - 'project': self.context.project_id, - 'domain': self.context.domain_id - } + # lifecycle_hook_type has to be "zaqar" + # post message to zaqar + kwargs = { + 'user': self.context.user_id, + 'project': self.context.project_id, + 'domain': self.context.domain_id + } - notifier = msg.Message(lifecycle_hook_target, **kwargs) - notifier.post_lifecycle_hook_message( - action_id, node_id, - consts.LIFECYCLE_NODE_TERMINATION) - else: - reason = _("Lifecycle hook type '{}' is not " - "implemented").format(lifecycle_hook_type) - return self.RES_ERROR, reason + notifier = msg.Message(lifecycle_hook_target, **kwargs) + notifier.post_lifecycle_hook_message( + action_id, node_id, + consts.LIFECYCLE_NODE_TERMINATION) res = None if lifecycle_hook: @@ -378,13 +380,7 @@ class ClusterAction(base.Action): res, reason = self._wait_for_dependents(lifecycle_hook_timeout) if res == self.RES_LIFECYCLE_HOOK_TIMEOUT: - for action_id, node_id in child: - status = ao.Action.check_status(self.context, - action_id, 0) - if (status == - consts.ACTION_WAITING_LIFECYCLE_COMPLETION): - ao.Action.update(self.context, action_id, - {'status': base.Action.READY}) + self._handle_lifecycle_timeout(child) if res is None or res == self.RES_LIFECYCLE_HOOK_TIMEOUT: dispatcher.start_action() diff --git a/senlin/tests/unit/drivers/test_ceilometer_v2.py b/senlin/tests/unit/drivers/test_ceilometer_v2.py deleted file mode 100644 index a2e837f82..000000000 --- a/senlin/tests/unit/drivers/test_ceilometer_v2.py +++ /dev/null @@ -1,108 +0,0 @@ -# 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 - -from senlin.drivers.openstack import ceilometer_v2 -from senlin.drivers.openstack import sdk -from senlin.tests.unit.common import base -from senlin.tests.unit.common import utils - - -class TestCeilometerV2(base.SenlinTestCase): - - def setUp(self): - super(TestCeilometerV2, self).setUp() - - self.ctx = utils.dummy_context() - self.conn_params = self.ctx.to_dict() - self.mock_conn = mock.Mock() - self.mock_create = self.patchobject( - sdk, 'create_connection', - return_value=self.mock_conn) - - def test_init(self): - d = ceilometer_v2.CeilometerClient(self.conn_params) - self.mock_create.assert_called_once_with(self.conn_params) - self.assertEqual(self.mock_conn, d.conn) - - def test_alarm_create(self): - d = ceilometer_v2.CeilometerClient(self.conn_params) - d.alarm_create(name='test_alarm') - self.mock_conn.telemetry.create_alarm.assert_called_once_with( - name='test_alarm') - - def test_alarm_delete(self): - d = ceilometer_v2.CeilometerClient(self.conn_params) - d.alarm_delete('foo', True) - self.mock_conn.telemetry.delete_alarm.assert_called_once_with( - 'foo', True) - - self.mock_conn.telemetry.delete_alarm.reset_mock() - - d.alarm_delete('foo', False) - self.mock_conn.telemetry.delete_alarm.assert_called_once_with( - 'foo', False) - - self.mock_conn.telemetry.delete_alarm.reset_mock() - - d.alarm_delete('foo') - self.mock_conn.telemetry.delete_alarm.assert_called_once_with( - 'foo', True) - - def test_alarm_find(self): - d = ceilometer_v2.CeilometerClient(self.conn_params) - d.alarm_find('fakeid', True) - self.mock_conn.telemetry.find_alarm.assert_called_once_with( - 'fakeid', True) - - self.mock_conn.telemetry.find_alarm.reset_mock() - - d.alarm_find('fakeid', False) - self.mock_conn.telemetry.find_alarm.assert_called_once_with( - 'fakeid', False) - - self.mock_conn.telemetry.find_alarm.reset_mock() - - d.alarm_find('fakeid') - self.mock_conn.telemetry.find_alarm.assert_called_once_with( - 'fakeid', True) - - def test_alarm_get(self): - d = ceilometer_v2.CeilometerClient(self.conn_params) - d.alarm_get('fakeid') - self.mock_conn.telemetry.get_alarm.assert_called_once_with('fakeid') - - def test_alarm_list(self): - d = ceilometer_v2.CeilometerClient(self.conn_params) - d.alarm_list() - self.mock_conn.telemetry.alarms.assert_called_once_with() - - self.mock_conn.telemetry.alarms.reset_mock() - - d.alarm_list(name='fakename') - self.mock_conn.telemetry.alarms.assert_called_once_with( - name='fakename') - - def test_alarm_update(self): - d = ceilometer_v2.CeilometerClient(self.conn_params) - attrs = {'enabled': False} - d.alarm_update('fakeid', **attrs) - self.mock_conn.telemetry.update_alarm.assert_called_once_with( - 'fakeid', **attrs) - - def test_sample_create(self): - d = ceilometer_v2.CeilometerClient(self.conn_params) - attrs = {'foo': 'bar'} - d.sample_create(**attrs) - self.mock_conn.telemetry.create_sample.assert_called_once_with( - foo='bar') diff --git a/senlin/tests/unit/drivers/test_cinder_v2.py b/senlin/tests/unit/drivers/test_cinder_v2.py index 161b6cefa..317c9dda5 100644 --- a/senlin/tests/unit/drivers/test_cinder_v2.py +++ b/senlin/tests/unit/drivers/test_cinder_v2.py @@ -12,8 +12,8 @@ import mock -from senlin.drivers.openstack import cinder_v2 -from senlin.drivers.openstack import sdk +from senlin.drivers.os import cinder_v2 +from senlin.drivers import sdk from senlin.tests.unit.common import base from senlin.tests.unit.common import utils diff --git a/senlin/tests/unit/drivers/test_glance_v2.py b/senlin/tests/unit/drivers/test_glance_v2.py index 982fd675e..1bd4f5d7f 100644 --- a/senlin/tests/unit/drivers/test_glance_v2.py +++ b/senlin/tests/unit/drivers/test_glance_v2.py @@ -12,8 +12,8 @@ import mock -from senlin.drivers.openstack import glance_v2 -from senlin.drivers.openstack import sdk +from senlin.drivers.os import glance_v2 +from senlin.drivers import sdk from senlin.tests.unit.common import base from senlin.tests.unit.common import utils diff --git a/senlin/tests/unit/drivers/test_heat_v1.py b/senlin/tests/unit/drivers/test_heat_v1.py index c0bbb0058..63044f50b 100644 --- a/senlin/tests/unit/drivers/test_heat_v1.py +++ b/senlin/tests/unit/drivers/test_heat_v1.py @@ -13,8 +13,8 @@ import mock from oslo_config import cfg -from senlin.drivers.openstack import heat_v1 -from senlin.drivers.openstack import sdk +from senlin.drivers.os import heat_v1 +from senlin.drivers import sdk from senlin.tests.unit.common import base from senlin.tests.unit.common import utils diff --git a/senlin/tests/unit/drivers/test_keystone_v3.py b/senlin/tests/unit/drivers/test_keystone_v3.py index 447032a30..475af7ad1 100644 --- a/senlin/tests/unit/drivers/test_keystone_v3.py +++ b/senlin/tests/unit/drivers/test_keystone_v3.py @@ -15,8 +15,8 @@ import copy import mock from oslo_config import cfg -from senlin.drivers.openstack import keystone_v3 as kv3 -from senlin.drivers.openstack import sdk +from senlin.drivers.os import keystone_v3 as kv3 +from senlin.drivers import sdk from senlin.tests.unit.common import base from senlin.tests.unit.common import utils diff --git a/senlin/tests/unit/drivers/test_lbaas_driver.py b/senlin/tests/unit/drivers/test_lbaas.py similarity index 99% rename from senlin/tests/unit/drivers/test_lbaas_driver.py rename to senlin/tests/unit/drivers/test_lbaas.py index df275bcb2..be93c020a 100644 --- a/senlin/tests/unit/drivers/test_lbaas_driver.py +++ b/senlin/tests/unit/drivers/test_lbaas.py @@ -17,9 +17,9 @@ from oslo_context import context as oslo_context from senlin.common import exception from senlin.common.i18n import _ -from senlin.drivers.openstack import lbaas -from senlin.drivers.openstack import neutron_v2 -from senlin.drivers.openstack import octavia_v2 +from senlin.drivers.os import lbaas +from senlin.drivers.os import neutron_v2 +from senlin.drivers.os import octavia_v2 from senlin.engine import node as nodem from senlin.tests.unit.common import base from senlin.tests.unit.common import utils diff --git a/senlin/tests/unit/drivers/test_mistral_v2.py b/senlin/tests/unit/drivers/test_mistral_v2.py index 00f287f3b..5e3ef7b57 100644 --- a/senlin/tests/unit/drivers/test_mistral_v2.py +++ b/senlin/tests/unit/drivers/test_mistral_v2.py @@ -12,8 +12,8 @@ import mock -from senlin.drivers.openstack import mistral_v2 -from senlin.drivers.openstack import sdk +from senlin.drivers.os import mistral_v2 +from senlin.drivers import sdk from senlin.tests.unit.common import base from senlin.tests.unit.common import utils diff --git a/senlin/tests/unit/drivers/test_neutron_v2_driver.py b/senlin/tests/unit/drivers/test_neutron_v2.py similarity index 98% rename from senlin/tests/unit/drivers/test_neutron_v2_driver.py rename to senlin/tests/unit/drivers/test_neutron_v2.py index 85adcc887..5d5062096 100644 --- a/senlin/tests/unit/drivers/test_neutron_v2_driver.py +++ b/senlin/tests/unit/drivers/test_neutron_v2.py @@ -13,8 +13,8 @@ import mock from oslo_utils import uuidutils -from senlin.drivers.openstack import neutron_v2 -from senlin.drivers.openstack import sdk +from senlin.drivers.os import neutron_v2 +from senlin.drivers import sdk from senlin.tests.unit.common import base from senlin.tests.unit.common import utils diff --git a/senlin/tests/unit/drivers/test_nova_v2.py b/senlin/tests/unit/drivers/test_nova_v2.py index 86f1db8e4..f86107567 100644 --- a/senlin/tests/unit/drivers/test_nova_v2.py +++ b/senlin/tests/unit/drivers/test_nova_v2.py @@ -13,8 +13,8 @@ import mock from oslo_config import cfg -from senlin.drivers.openstack import nova_v2 -from senlin.drivers.openstack import sdk +from senlin.drivers.os import nova_v2 +from senlin.drivers import sdk from senlin.tests.unit.common import base from senlin.tests.unit.common import utils diff --git a/senlin/tests/unit/drivers/test_octavia_v2.py b/senlin/tests/unit/drivers/test_octavia_v2.py index 182695643..b5e7fb81f 100644 --- a/senlin/tests/unit/drivers/test_octavia_v2.py +++ b/senlin/tests/unit/drivers/test_octavia_v2.py @@ -12,8 +12,8 @@ import mock -from senlin.drivers.openstack import octavia_v2 -from senlin.drivers.openstack import sdk +from senlin.drivers.os import octavia_v2 +from senlin.drivers import sdk from senlin.tests.unit.common import base from senlin.tests.unit.common import utils diff --git a/senlin/tests/unit/drivers/test_sdk.py b/senlin/tests/unit/drivers/test_sdk.py index c8058b159..7d7f9f9da 100644 --- a/senlin/tests/unit/drivers/test_sdk.py +++ b/senlin/tests/unit/drivers/test_sdk.py @@ -20,7 +20,7 @@ from requests import exceptions as req_exc import six from senlin.common import exception as senlin_exc -from senlin.drivers.openstack import sdk +from senlin.drivers import sdk from senlin.tests.unit.common import base diff --git a/senlin/tests/unit/drivers/test_zaqar_v2.py b/senlin/tests/unit/drivers/test_zaqar_v2.py old mode 100755 new mode 100644 index be0d0e884..f04e4734e --- a/senlin/tests/unit/drivers/test_zaqar_v2.py +++ b/senlin/tests/unit/drivers/test_zaqar_v2.py @@ -14,8 +14,8 @@ import mock from openstack import exceptions as sdk_exc -from senlin.drivers.openstack import sdk -from senlin.drivers.openstack import zaqar_v2 +from senlin.drivers.os import zaqar_v2 +from senlin.drivers import sdk from senlin.tests.unit.common import base from senlin.tests.unit.common import utils diff --git a/senlin/tests/unit/engine/actions/test_delete.py b/senlin/tests/unit/engine/actions/test_delete.py index 789ff429e..8a8fef5d1 100755 --- a/senlin/tests/unit/engine/actions/test_delete.py +++ b/senlin/tests/unit/engine/actions/test_delete.py @@ -286,8 +286,7 @@ class ClusterDeleteTest(base.SenlinTestCase): # assertions (other assertions are skipped) self.assertEqual(action.RES_ERROR, res_code) self.assertEqual( - 'Invalid lifecycle hook type specified in deletion policy', - res_msg) + "Lifecycle hook type 'unknown_type' is not implemented", res_msg) @mock.patch.object(ao.Action, 'update') @mock.patch.object(ab.Action, 'create') @@ -317,8 +316,7 @@ class ClusterDeleteTest(base.SenlinTestCase): # assertions (other assertions are skipped) self.assertEqual(action.RES_ERROR, res_code) self.assertEqual( - 'Lifecycle hook type \'webhook\' is not implemented', - res_msg) + "Lifecycle hook type \'webhook\' is not implemented", res_msg) @mock.patch.object(ao.Action, 'update') @mock.patch.object(ab.Action, 'create') diff --git a/setup.cfg b/setup.cfg index c9bd53a67..c588afc99 100644 --- a/setup.cfg +++ b/setup.cfg @@ -41,8 +41,8 @@ oslo.policy.policies = senlin = senlin.common.policies:list_rules senlin.drivers = - openstack = senlin.drivers.openstack - openstack_test = senlin.drivers.openstack_test + openstack = senlin.drivers.os + openstack_test = senlin.drivers.os_test senlin.profiles = os.heat.stack-1.0 = senlin.profiles.os.heat.stack:StackProfile