Update openstacksdk construction
The queens release of python-openstacksdk breaks the sdk and senlin code that's in heat right now. This shifts us to the new world order. python-senlinclient is actually just a thin wrapper around python-openstacksdk. Instead of reworking the constructor in the Senlin plugin, just remove use of python-senlinclient and use the openstacksdk client plugin instead. Change-Id: Idf0acebf7b3774db26e335b3f3229227bfe68502
This commit is contained in:
parent
164a8ab2ba
commit
b9d7d1e640
@ -60,4 +60,3 @@ We have integration with
|
|||||||
* https://git.openstack.org/cgit/openstack/python-mistralclient (workflow service)
|
* https://git.openstack.org/cgit/openstack/python-mistralclient (workflow service)
|
||||||
* https://git.openstack.org/cgit/openstack/python-zaqarclient (messaging service)
|
* https://git.openstack.org/cgit/openstack/python-zaqarclient (messaging service)
|
||||||
* https://git.openstack.org/cgit/openstack/python-monascaclient (monitoring service)
|
* https://git.openstack.org/cgit/openstack/python-monascaclient (monitoring service)
|
||||||
* https://git.openstack.org/cgit/openstack/python-senlinclient (clustering service)
|
|
||||||
|
@ -11,12 +11,15 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from openstack.config import cloud_region
|
||||||
from openstack import connection
|
from openstack import connection
|
||||||
from openstack import exceptions
|
from openstack import exceptions
|
||||||
from openstack import profile
|
import os_service_types
|
||||||
|
|
||||||
|
from heat.common import config
|
||||||
from heat.engine.clients import client_plugin
|
from heat.engine.clients import client_plugin
|
||||||
from heat.engine import constraints
|
from heat.engine import constraints
|
||||||
|
import heat.version
|
||||||
|
|
||||||
CLIENT_NAME = 'openstack'
|
CLIENT_NAME = 'openstack'
|
||||||
|
|
||||||
@ -25,24 +28,39 @@ class OpenStackSDKPlugin(client_plugin.ClientPlugin):
|
|||||||
|
|
||||||
exceptions_module = exceptions
|
exceptions_module = exceptions
|
||||||
|
|
||||||
service_types = [NETWORK] = ['network']
|
service_types = [NETWORK, CLUSTERING] = ['network', 'clustering']
|
||||||
service_client_map = {NETWORK: 'neutron'}
|
|
||||||
api_version_map = {NETWORK: '2.0'}
|
|
||||||
|
|
||||||
def _create(self, version=None):
|
def _create(self, version=None):
|
||||||
prof = profile.Profile()
|
config = cloud_region.from_session(
|
||||||
for svc_type in self.service_types:
|
# TODO(mordred) The way from_session calculates a cloud name
|
||||||
interface = self._get_client_option(
|
# doesn't interact well with the mocks in the test cases. The
|
||||||
self.service_client_map[svc_type], 'endpoint_type')
|
# name is used in logging to distinguish requests made to different
|
||||||
prof.set_interface(svc_type, interface)
|
# clouds. For now, set it to local - but maybe find a way to set
|
||||||
prof.set_region(svc_type, self._get_region_name())
|
# it to something more meaningful later.
|
||||||
prof.set_version(svc_type, self.api_version_map[svc_type])
|
name='local',
|
||||||
|
session=self.context.keystone_session,
|
||||||
|
config=self._get_service_interfaces(),
|
||||||
|
region_name=self._get_region_name(),
|
||||||
|
app_name='heat',
|
||||||
|
app_version=heat.version.version_info.version_string())
|
||||||
|
return connection.Connection(config=config)
|
||||||
|
|
||||||
key_session = self.context.keystone_session
|
def _get_service_interfaces(self):
|
||||||
return connection.Connection(authenticator=key_session.auth,
|
interfaces = {}
|
||||||
verify=key_session.verify,
|
if not os_service_types:
|
||||||
cert=key_session.cert,
|
return interfaces
|
||||||
profile=prof)
|
types = os_service_types.ServiceTypes()
|
||||||
|
for name, _ in config.list_opts():
|
||||||
|
if not name or not name.startswith('clients_'):
|
||||||
|
continue
|
||||||
|
project_name = name.split("_", 1)[0]
|
||||||
|
service_data = types.get_service_data_for_project(project_name)
|
||||||
|
if not service_data:
|
||||||
|
continue
|
||||||
|
service_type = service_data['service_type']
|
||||||
|
interfaces[service_type + '_interface'] = self._get_client_option(
|
||||||
|
service_type, 'endpoint_type')
|
||||||
|
return interfaces
|
||||||
|
|
||||||
def is_not_found(self, ex):
|
def is_not_found(self, ex):
|
||||||
return isinstance(ex, exceptions.ResourceNotFound)
|
return isinstance(ex, exceptions.ResourceNotFound)
|
||||||
|
@ -11,30 +11,23 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from openstack import exceptions
|
||||||
|
|
||||||
from heat.common import exception
|
from heat.common import exception
|
||||||
from heat.common.i18n import _
|
from heat.common.i18n import _
|
||||||
from heat.engine.clients import client_plugin
|
from heat.engine.clients.os import openstacksdk as sdk_plugin
|
||||||
from heat.engine import constraints
|
from heat.engine import constraints
|
||||||
|
|
||||||
from openstack import profile
|
|
||||||
from senlinclient.common import exc
|
|
||||||
from senlinclient.v1 import client
|
|
||||||
|
|
||||||
CLIENT_NAME = 'senlin'
|
CLIENT_NAME = 'senlin'
|
||||||
|
|
||||||
|
|
||||||
class SenlinClientPlugin(client_plugin.ClientPlugin):
|
class SenlinClientPlugin(sdk_plugin.OpenStackSDKPlugin):
|
||||||
|
|
||||||
service_types = [CLUSTERING] = ['clustering']
|
exceptions_module = exceptions
|
||||||
|
|
||||||
def _create(self):
|
def _create(self, version=None):
|
||||||
interface = self._get_client_option(CLIENT_NAME, 'endpoint_type')
|
client = super(SenlinClientPlugin, self)._create(version=version)
|
||||||
prof = profile.Profile()
|
return client.clustering
|
||||||
prof.set_interface(self.CLUSTERING, interface)
|
|
||||||
prof.set_region(self.CLUSTERING, self._get_region_name())
|
|
||||||
key_session = self.context.keystone_session
|
|
||||||
return client.Client(prof=prof,
|
|
||||||
authenticator=key_session.auth)
|
|
||||||
|
|
||||||
def generate_spec(self, spec_type, spec_props):
|
def generate_spec(self, spec_type, spec_props):
|
||||||
spec = {'properties': spec_props}
|
spec = {'properties': spec_props}
|
||||||
@ -64,11 +57,8 @@ class SenlinClientPlugin(client_plugin.ClientPlugin):
|
|||||||
policy = self.client().get_policy(policy_name)
|
policy = self.client().get_policy(policy_name)
|
||||||
return policy.id
|
return policy.id
|
||||||
|
|
||||||
def is_not_found(self, ex):
|
|
||||||
return isinstance(ex, exc.sdkexc.ResourceNotFound)
|
|
||||||
|
|
||||||
def is_bad_request(self, ex):
|
def is_bad_request(self, ex):
|
||||||
return (isinstance(ex, exc.sdkexc.HttpException) and
|
return (isinstance(ex, exceptions.HttpException) and
|
||||||
ex.status_code == 400)
|
ex.status_code == 400)
|
||||||
|
|
||||||
def execute_actions(self, actions):
|
def execute_actions(self, actions):
|
||||||
@ -93,24 +83,24 @@ class SenlinClientPlugin(client_plugin.ClientPlugin):
|
|||||||
|
|
||||||
|
|
||||||
class ProfileConstraint(constraints.BaseCustomConstraint):
|
class ProfileConstraint(constraints.BaseCustomConstraint):
|
||||||
# If name is not unique, will raise exc.sdkexc.HttpException
|
# If name is not unique, will raise exceptions.HttpException
|
||||||
expected_exceptions = (exc.sdkexc.HttpException,)
|
expected_exceptions = (exceptions.HttpException,)
|
||||||
|
|
||||||
def validate_with_client(self, client, profile):
|
def validate_with_client(self, client, profile):
|
||||||
client.client(CLIENT_NAME).get_profile(profile)
|
client.client(CLIENT_NAME).get_profile(profile)
|
||||||
|
|
||||||
|
|
||||||
class ClusterConstraint(constraints.BaseCustomConstraint):
|
class ClusterConstraint(constraints.BaseCustomConstraint):
|
||||||
# If name is not unique, will raise exc.sdkexc.HttpException
|
# If name is not unique, will raise exceptions.HttpException
|
||||||
expected_exceptions = (exc.sdkexc.HttpException,)
|
expected_exceptions = (exceptions.HttpException,)
|
||||||
|
|
||||||
def validate_with_client(self, client, value):
|
def validate_with_client(self, client, value):
|
||||||
client.client(CLIENT_NAME).get_cluster(value)
|
client.client(CLIENT_NAME).get_cluster(value)
|
||||||
|
|
||||||
|
|
||||||
class PolicyConstraint(constraints.BaseCustomConstraint):
|
class PolicyConstraint(constraints.BaseCustomConstraint):
|
||||||
# If name is not unique, will raise exc.sdkexc.HttpException
|
# If name is not unique, will raise exceptions.HttpException
|
||||||
expected_exceptions = (exc.sdkexc.HttpException,)
|
expected_exceptions = (exceptions.HttpException,)
|
||||||
|
|
||||||
def validate_with_client(self, client, value):
|
def validate_with_client(self, client, value):
|
||||||
client.client(CLIENT_NAME).get_policy(value)
|
client.client(CLIENT_NAME).get_policy(value)
|
||||||
@ -121,8 +111,8 @@ class ProfileTypeConstraint(constraints.BaseCustomConstraint):
|
|||||||
expected_exceptions = (exception.StackValidationFailed,)
|
expected_exceptions = (exception.StackValidationFailed,)
|
||||||
|
|
||||||
def validate_with_client(self, client, value):
|
def validate_with_client(self, client, value):
|
||||||
senlin_client = client.client(CLIENT_NAME)
|
conn = client.client(CLIENT_NAME)
|
||||||
type_list = senlin_client.profile_types()
|
type_list = conn.profile_types()
|
||||||
names = [pt.name for pt in type_list]
|
names = [pt.name for pt in type_list]
|
||||||
if value not in names:
|
if value not in names:
|
||||||
not_found_message = (
|
not_found_message = (
|
||||||
@ -138,8 +128,8 @@ class PolicyTypeConstraint(constraints.BaseCustomConstraint):
|
|||||||
expected_exceptions = (exception.StackValidationFailed,)
|
expected_exceptions = (exception.StackValidationFailed,)
|
||||||
|
|
||||||
def validate_with_client(self, client, value):
|
def validate_with_client(self, client, value):
|
||||||
senlin_client = client.client(CLIENT_NAME)
|
conn = client.client(CLIENT_NAME)
|
||||||
type_list = senlin_client.policy_types()
|
type_list = conn.policy_types()
|
||||||
names = [pt.name for pt in type_list]
|
names = [pt.name for pt in type_list]
|
||||||
if value not in names:
|
if value not in names:
|
||||||
not_found_message = (
|
not_found_message = (
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
from senlinclient.common import exc
|
from openstack import exceptions
|
||||||
|
|
||||||
from heat.engine.clients.os import senlin as senlin_plugin
|
from heat.engine.clients.os import senlin as senlin_plugin
|
||||||
from heat.tests import common
|
from heat.tests import common
|
||||||
@ -32,10 +32,10 @@ class SenlinClientPluginTest(common.HeatTestCase):
|
|||||||
|
|
||||||
def test_is_bad_request(self):
|
def test_is_bad_request(self):
|
||||||
self.assertTrue(self.plugin.is_bad_request(
|
self.assertTrue(self.plugin.is_bad_request(
|
||||||
exc.sdkexc.HttpException(http_status=400)))
|
exceptions.HttpException(http_status=400)))
|
||||||
self.assertFalse(self.plugin.is_bad_request(Exception))
|
self.assertFalse(self.plugin.is_bad_request(Exception))
|
||||||
self.assertFalse(self.plugin.is_bad_request(
|
self.assertFalse(self.plugin.is_bad_request(
|
||||||
exc.sdkexc.HttpException(http_status=404)))
|
exceptions.HttpException(http_status=404)))
|
||||||
|
|
||||||
def test_check_action_success(self):
|
def test_check_action_success(self):
|
||||||
mock_action = mock.MagicMock()
|
mock_action = mock.MagicMock()
|
||||||
@ -87,10 +87,10 @@ class ProfileConstraintTest(common.HeatTestCase):
|
|||||||
self.assertTrue(self.constraint.validate("PROFILE_ID", self.ctx))
|
self.assertTrue(self.constraint.validate("PROFILE_ID", self.ctx))
|
||||||
|
|
||||||
def test_validate_false(self):
|
def test_validate_false(self):
|
||||||
self.mock_get_profile.side_effect = exc.sdkexc.ResourceNotFound(
|
self.mock_get_profile.side_effect = exceptions.ResourceNotFound(
|
||||||
'PROFILE_ID')
|
'PROFILE_ID')
|
||||||
self.assertFalse(self.constraint.validate("PROFILE_ID", self.ctx))
|
self.assertFalse(self.constraint.validate("PROFILE_ID", self.ctx))
|
||||||
self.mock_get_profile.side_effect = exc.sdkexc.HttpException(
|
self.mock_get_profile.side_effect = exceptions.HttpException(
|
||||||
'PROFILE_ID')
|
'PROFILE_ID')
|
||||||
self.assertFalse(self.constraint.validate("PROFILE_ID", self.ctx))
|
self.assertFalse(self.constraint.validate("PROFILE_ID", self.ctx))
|
||||||
|
|
||||||
@ -112,10 +112,10 @@ class ClusterConstraintTest(common.HeatTestCase):
|
|||||||
self.assertTrue(self.constraint.validate("CLUSTER_ID", self.ctx))
|
self.assertTrue(self.constraint.validate("CLUSTER_ID", self.ctx))
|
||||||
|
|
||||||
def test_validate_false(self):
|
def test_validate_false(self):
|
||||||
self.mock_get_cluster.side_effect = exc.sdkexc.ResourceNotFound(
|
self.mock_get_cluster.side_effect = exceptions.ResourceNotFound(
|
||||||
'CLUSTER_ID')
|
'CLUSTER_ID')
|
||||||
self.assertFalse(self.constraint.validate("CLUSTER_ID", self.ctx))
|
self.assertFalse(self.constraint.validate("CLUSTER_ID", self.ctx))
|
||||||
self.mock_get_cluster.side_effect = exc.sdkexc.HttpException(
|
self.mock_get_cluster.side_effect = exceptions.HttpException(
|
||||||
'CLUSTER_ID')
|
'CLUSTER_ID')
|
||||||
self.assertFalse(self.constraint.validate("CLUSTER_ID", self.ctx))
|
self.assertFalse(self.constraint.validate("CLUSTER_ID", self.ctx))
|
||||||
|
|
||||||
@ -137,10 +137,10 @@ class PolicyConstraintTest(common.HeatTestCase):
|
|||||||
self.assertTrue(self.constraint.validate("POLICY_ID", self.ctx))
|
self.assertTrue(self.constraint.validate("POLICY_ID", self.ctx))
|
||||||
|
|
||||||
def test_validate_false(self):
|
def test_validate_false(self):
|
||||||
self.mock_get_policy.side_effect = exc.sdkexc.ResourceNotFound(
|
self.mock_get_policy.side_effect = exceptions.ResourceNotFound(
|
||||||
'POLICY_ID')
|
'POLICY_ID')
|
||||||
self.assertFalse(self.constraint.validate("POLICY_ID", self.ctx))
|
self.assertFalse(self.constraint.validate("POLICY_ID", self.ctx))
|
||||||
self.mock_get_policy.side_effect = exc.sdkexc.HttpException(
|
self.mock_get_policy.side_effect = exceptions.HttpException(
|
||||||
'POLICY_ID')
|
'POLICY_ID')
|
||||||
self.assertFalse(self.constraint.validate("POLICY_ID", self.ctx))
|
self.assertFalse(self.constraint.validate("POLICY_ID", self.ctx))
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ from heat.engine import scheduler
|
|||||||
from heat.engine import template
|
from heat.engine import template
|
||||||
from heat.tests import common
|
from heat.tests import common
|
||||||
from heat.tests import utils
|
from heat.tests import utils
|
||||||
from senlinclient.common import exc
|
from openstack import exceptions
|
||||||
|
|
||||||
|
|
||||||
cluster_stack_template = """
|
cluster_stack_template = """
|
||||||
@ -165,7 +165,7 @@ class SenlinClusterTest(common.HeatTestCase):
|
|||||||
def test_cluster_delete_success(self):
|
def test_cluster_delete_success(self):
|
||||||
cluster = self._create_cluster(self.t)
|
cluster = self._create_cluster(self.t)
|
||||||
self.senlin_mock.get_cluster.side_effect = [
|
self.senlin_mock.get_cluster.side_effect = [
|
||||||
exc.sdkexc.ResourceNotFound('SenlinCluster'),
|
exceptions.ResourceNotFound('SenlinCluster'),
|
||||||
]
|
]
|
||||||
scheduler.TaskRunner(cluster.delete)()
|
scheduler.TaskRunner(cluster.delete)()
|
||||||
self.senlin_mock.delete_cluster.assert_called_once_with(
|
self.senlin_mock.delete_cluster.assert_called_once_with(
|
||||||
|
@ -25,7 +25,7 @@ from heat.engine import scheduler
|
|||||||
from heat.engine import template
|
from heat.engine import template
|
||||||
from heat.tests import common
|
from heat.tests import common
|
||||||
from heat.tests import utils
|
from heat.tests import utils
|
||||||
from senlinclient.common import exc
|
from openstack import exceptions
|
||||||
|
|
||||||
|
|
||||||
node_stack_template = """
|
node_stack_template = """
|
||||||
@ -127,7 +127,7 @@ class SenlinNodeTest(common.HeatTestCase):
|
|||||||
def test_node_delete_success(self):
|
def test_node_delete_success(self):
|
||||||
node = self._create_node()
|
node = self._create_node()
|
||||||
self.senlin_mock.get_node.side_effect = [
|
self.senlin_mock.get_node.side_effect = [
|
||||||
exc.sdkexc.ResourceNotFound('SenlinNode'),
|
exceptions.ResourceNotFound('SenlinNode'),
|
||||||
]
|
]
|
||||||
scheduler.TaskRunner(node.delete)()
|
scheduler.TaskRunner(node.delete)()
|
||||||
self.senlin_mock.delete_node.assert_called_once_with(
|
self.senlin_mock.delete_node.assert_called_once_with(
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
import copy
|
import copy
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
|
from openstack import exceptions
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from senlinclient.common import exc
|
|
||||||
|
|
||||||
from heat.common import exception
|
from heat.common import exception
|
||||||
from heat.common import template_format
|
from heat.common import template_format
|
||||||
@ -134,7 +134,7 @@ class SenlinPolicyTest(common.HeatTestCase):
|
|||||||
'action': 'fake_action'}
|
'action': 'fake_action'}
|
||||||
policy = self._create_policy(self.t)
|
policy = self._create_policy(self.t)
|
||||||
self.senlin_mock.get_policy.side_effect = [
|
self.senlin_mock.get_policy.side_effect = [
|
||||||
exc.sdkexc.ResourceNotFound('SenlinPolicy'),
|
exceptions.ResourceNotFound('SenlinPolicy'),
|
||||||
]
|
]
|
||||||
scheduler.TaskRunner(policy.delete)()
|
scheduler.TaskRunner(policy.delete)()
|
||||||
self.senlin_mock.cluster_detach_policy.assert_called_once_with(
|
self.senlin_mock.cluster_detach_policy.assert_called_once_with(
|
||||||
@ -145,10 +145,10 @@ class SenlinPolicyTest(common.HeatTestCase):
|
|||||||
def test_policy_delete_not_attached(self):
|
def test_policy_delete_not_attached(self):
|
||||||
policy = self._create_policy(self.t)
|
policy = self._create_policy(self.t)
|
||||||
self.senlin_mock.get_policy.side_effect = [
|
self.senlin_mock.get_policy.side_effect = [
|
||||||
exc.sdkexc.ResourceNotFound('SenlinPolicy'),
|
exceptions.ResourceNotFound('SenlinPolicy'),
|
||||||
]
|
]
|
||||||
self.senlin_mock.cluster_detach_policy.side_effect = [
|
self.senlin_mock.cluster_detach_policy.side_effect = [
|
||||||
exc.sdkexc.HttpException(http_status=400),
|
exceptions.HttpException(http_status=400),
|
||||||
]
|
]
|
||||||
scheduler.TaskRunner(policy.delete)()
|
scheduler.TaskRunner(policy.delete)()
|
||||||
self.senlin_mock.cluster_detach_policy.assert_called_once_with(
|
self.senlin_mock.cluster_detach_policy.assert_called_once_with(
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
from senlinclient.common import exc
|
from openstack import exceptions
|
||||||
|
|
||||||
from heat.common import template_format
|
from heat.common import template_format
|
||||||
from heat.engine.clients.os import senlin
|
from heat.engine.clients.os import senlin
|
||||||
@ -106,7 +106,7 @@ class SenlinReceiverTest(common.HeatTestCase):
|
|||||||
|
|
||||||
def test_recv_delete_not_found(self):
|
def test_recv_delete_not_found(self):
|
||||||
self.senlin_mock.delete_receiver.side_effect = [
|
self.senlin_mock.delete_receiver.side_effect = [
|
||||||
exc.sdkexc.ResourceNotFound(http_status=404)
|
exceptions.ResourceNotFound(http_status=404)
|
||||||
]
|
]
|
||||||
recv = self._create_recv(self.t)
|
recv = self._create_recv(self.t)
|
||||||
scheduler.TaskRunner(recv.delete)()
|
scheduler.TaskRunner(recv.delete)()
|
||||||
|
@ -46,7 +46,6 @@ python-novaclient>=9.1.0 # Apache-2.0
|
|||||||
python-octaviaclient>=1.3.0 # Apache-2.0
|
python-octaviaclient>=1.3.0 # Apache-2.0
|
||||||
python-openstackclient>=3.12.0 # Apache-2.0
|
python-openstackclient>=3.12.0 # Apache-2.0
|
||||||
python-saharaclient>=1.4.0 # Apache-2.0
|
python-saharaclient>=1.4.0 # Apache-2.0
|
||||||
python-senlinclient>=1.1.0 # Apache-2.0
|
|
||||||
python-swiftclient>=3.2.0 # Apache-2.0
|
python-swiftclient>=3.2.0 # Apache-2.0
|
||||||
python-troveclient>=2.2.0 # Apache-2.0
|
python-troveclient>=2.2.0 # Apache-2.0
|
||||||
python-zaqarclient>=1.0.0 # Apache-2.0
|
python-zaqarclient>=1.0.0 # Apache-2.0
|
||||||
|
Loading…
Reference in New Issue
Block a user