Use custom warnings everywhere

Build on change I3846e8fcffdb5de2afe64365952d90b5ecb0f74a by switching
all callers of 'warning.warn' to use our custom warnings. This allows
users (like OSC) to filter these out as needed.

Since we have new types of warning, the docs are updated accordingly.

Change-Id: I5039fd8585e3352798a6d2fae7d5623fbc1adb6a
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
Stephen Finucane 2023-05-25 13:22:14 +01:00
parent e74301292a
commit 3f9685ffad
13 changed files with 109 additions and 74 deletions

@ -3,12 +3,13 @@ Warnings
openstacksdk uses the `warnings`__ infrastructure to warn users about openstacksdk uses the `warnings`__ infrastructure to warn users about
deprecated resources and resource fields, as well as deprecated behavior in deprecated resources and resource fields, as well as deprecated behavior in
openstacksdk itself. Currently, these warnings are all derived from openstacksdk itself. These warnings are derived from ``Warning`` or
``DeprecationWarning``. In Python, deprecation warnings are silenced by ``DeprecationWarning``. In Python, warnings are emitted by default while
default. You must turn them on using the ``-Wa`` Python command line option or deprecation warnings are silenced by default and must be turned on using the
the ``PYTHONWARNINGS`` environment variable. If you are writing an application ``-Wa`` Python command line option or the ``PYTHONWARNINGS`` environment
that uses openstacksdk, you may wish to enable some of these warnings during variable. If you are writing an application that uses openstacksdk, you may
test runs to ensure you migrate away from deprecated behavior. wish to enable some of these warnings during test runs to ensure you migrate
away from deprecated behavior.
Available warnings Available warnings
------------------ ------------------

@ -23,6 +23,7 @@ import jsonpatch
from openstack.baremetal.v1._proxy import Proxy from openstack.baremetal.v1._proxy import Proxy
from openstack.cloud import exc from openstack.cloud import exc
from openstack import warnings as os_warnings
def _normalize_port_list(nics): def _normalize_port_list(nics):
@ -317,7 +318,7 @@ class BaremetalCloudMixin:
if wait is not None: if wait is not None:
warnings.warn( warnings.warn(
"wait argument is deprecated and has no effect", "wait argument is deprecated and has no effect",
DeprecationWarning, os_warnings.OpenStackDeprecationWarning,
) )
machine = self.get_machine(uuid) machine = self.get_machine(uuid)
@ -480,9 +481,8 @@ class BaremetalCloudMixin:
def validate_node(self, uuid): def validate_node(self, uuid):
warnings.warn( warnings.warn(
'validate_node is deprecated, please use ' 'validate_node is deprecated, please use validate_machine instead',
'validate_machine instead', os_warnings.OpenStackDeprecationWarning,
DeprecationWarning,
) )
self.baremetal.validate_node(uuid) self.baremetal.validate_node(uuid)
@ -623,7 +623,7 @@ class BaremetalCloudMixin:
warnings.warn( warnings.warn(
"The set_node_instance_info call is deprecated, " "The set_node_instance_info call is deprecated, "
"use patch_machine or update_machine instead", "use patch_machine or update_machine instead",
DeprecationWarning, os_warnings.OpenStackDeprecationWarning,
) )
return self.patch_machine(uuid, patch) return self.patch_machine(uuid, patch)
@ -631,7 +631,7 @@ class BaremetalCloudMixin:
warnings.warn( warnings.warn(
"The purge_node_instance_info call is deprecated, " "The purge_node_instance_info call is deprecated, "
"use patch_machine or update_machine instead", "use patch_machine or update_machine instead",
DeprecationWarning, os_warnings.OpenStackDeprecationWarning,
) )
return self.patch_machine( return self.patch_machine(
uuid, dict(path='/instance_info', op='remove') uuid, dict(path='/instance_info', op='remove')
@ -649,6 +649,6 @@ class BaremetalCloudMixin:
"The wait_for_baremetal_node_lock call is deprecated " "The wait_for_baremetal_node_lock call is deprecated "
"in favor of wait_for_node_reservation on the baremetal " "in favor of wait_for_node_reservation on the baremetal "
"proxy", "proxy",
DeprecationWarning, os_warnings.OpenStackDeprecationWarning,
) )
self.baremetal.wait_for_node_reservation(node, timeout) self.baremetal.wait_for_node_reservation(node, timeout)

@ -22,6 +22,7 @@ from openstack.cloud import _utils
from openstack.cloud import exc from openstack.cloud import exc
from openstack import exceptions from openstack import exceptions
from openstack import proxy from openstack import proxy
from openstack import warnings as os_warnings
def _no_pending_volumes(volumes): def _no_pending_volumes(volumes):
@ -46,7 +47,7 @@ class BlockStorageCloudMixin:
warnings.warn( warnings.warn(
"the 'cache' argument is deprecated and no longer does anything; " "the 'cache' argument is deprecated and no longer does anything; "
"consider removing it from calls", "consider removing it from calls",
DeprecationWarning, os_warnings.OpenStackDeprecationWarning,
) )
return list(self.block_storage.volumes()) return list(self.block_storage.volumes())
@ -63,7 +64,7 @@ class BlockStorageCloudMixin:
warnings.warn( warnings.warn(
"the 'get_extra' argument is deprecated and no longer does " "the 'get_extra' argument is deprecated and no longer does "
"anything; consider removing it from calls", "anything; consider removing it from calls",
DeprecationWarning, os_warnings.OpenStackDeprecationWarning,
) )
return list(self.block_storage.types()) return list(self.block_storage.types())

@ -26,6 +26,7 @@ from openstack import exceptions
from openstack.network.v2._proxy import Proxy from openstack.network.v2._proxy import Proxy
from openstack import proxy from openstack import proxy
from openstack import utils from openstack import utils
from openstack import warnings as os_warnings
_CONFIG_DOC_URL = ( _CONFIG_DOC_URL = (
"https://docs.openstack.org/openstacksdk/latest/" "https://docs.openstack.org/openstacksdk/latest/"
@ -66,8 +67,8 @@ class FloatingIPCloudMixin:
# `filters` could be a jmespath expression which Neutron server doesn't # `filters` could be a jmespath expression which Neutron server doesn't
# understand, obviously. # understand, obviously.
warnings.warn( warnings.warn(
"search_floating_ips is deprecated. " "search_floating_ips is deprecated. Use search_resource instead.",
"Use search_resource instead." os_warnings.OpenStackDeprecationWarning,
) )
if self._use_neutron_floating() and isinstance(filters, dict): if self._use_neutron_floating() and isinstance(filters, dict):
return list(self.network.ips(**filters)) return list(self.network.ips(**filters))

@ -36,7 +36,7 @@ from openstack.config import cloud_region as cloud_region_mod
from openstack import exceptions from openstack import exceptions
from openstack import proxy from openstack import proxy
from openstack import utils from openstack import utils
from openstack import warnings as os_warnings
DEFAULT_SERVER_AGE = 5 DEFAULT_SERVER_AGE = 5
DEFAULT_PORT_AGE = 5 DEFAULT_PORT_AGE = 5
@ -303,7 +303,7 @@ class _OpenStackCloudMixin:
app_name=self.config._app_name, app_name=self.config._app_name,
app_version=self.config._app_version, app_version=self.config._app_version,
discovery_cache=self.session._discovery_cache, discovery_cache=self.session._discovery_cache,
**params **params,
) )
# Override the cloud name so that logging/location work right # Override the cloud name so that logging/location work right
@ -433,23 +433,21 @@ class _OpenStackCloudMixin:
api_major = self._get_major_version_id(api_version) api_major = self._get_major_version_id(api_version)
# If we detect a different version that was configured, warn the user. # If we detect a different version that was configured, warn the user.
# shade still knows what to do - but if the user gave us an explicit # openstacksdk still knows what to do - but if the user gave us an
# version and we couldn't find it, they may want to investigate. # explicit version and we couldn't find it, they may want to
# investigate
if api_version and config_version and (api_major != config_major): if api_version and config_version and (api_major != config_major):
api_version_str = '.'.join([str(f) for f in api_version])
warning_msg = ( warning_msg = (
'{service_type} is configured for {config_version}' f'{service_type} is configured for {config_version} but only '
' but only {api_version} is available. shade is happy' f'{api_version_str} is available. openstacksdk is happy '
' with this version, but if you were trying to force an' f'with this version, but if you were trying to force an '
' override, that did not happen. You may want to check' f'override, that did not happen. You may want to check '
' your cloud, or remove the version specification from' f'your cloud, or remove the version specification from '
' your config.'.format( f'your config.'
service_type=service_type,
config_version=config_version,
api_version='.'.join([str(f) for f in api_version]),
)
) )
self.log.debug(warning_msg) self.log.debug(warning_msg)
warnings.warn(warning_msg) warnings.warn(warning_msg, os_warnings.OpenStackDeprecationWarning)
return adapter return adapter
# TODO(shade) This should be replaced with using openstack Connection # TODO(shade) This should be replaced with using openstack Connection
@ -790,7 +788,7 @@ class _OpenStackCloudMixin:
get_kwargs=None, get_kwargs=None,
list_args=None, list_args=None,
list_kwargs=None, list_kwargs=None,
**filters **filters,
): ):
"""Search resources """Search resources

@ -40,6 +40,7 @@ from openstack.network.v2 import security_group as _sg
from openstack import proxy from openstack import proxy
from openstack import resource from openstack import resource
from openstack import utils from openstack import utils
from openstack import warnings as os_warnings
class Proxy(proxy.Proxy): class Proxy(proxy.Proxy):
@ -483,7 +484,7 @@ class Proxy(proxy.Proxy):
warnings.warn( warnings.warn(
'This API is a proxy to the image service and has been ' 'This API is a proxy to the image service and has been '
'deprecated; use the image service proxy API instead', 'deprecated; use the image service proxy API instead',
DeprecationWarning, os_warnings.OpenStackDeprecationWarning,
) )
self._delete(_image.Image, image, ignore_missing=ignore_missing) self._delete(_image.Image, image, ignore_missing=ignore_missing)
@ -508,7 +509,7 @@ class Proxy(proxy.Proxy):
warnings.warn( warnings.warn(
'This API is a proxy to the image service and has been ' 'This API is a proxy to the image service and has been '
'deprecated; use the image service proxy API instead', 'deprecated; use the image service proxy API instead',
DeprecationWarning, os_warnings.OpenStackDeprecationWarning,
) )
return self._find( return self._find(
_image.Image, _image.Image,
@ -529,7 +530,7 @@ class Proxy(proxy.Proxy):
warnings.warn( warnings.warn(
'This API is a proxy to the image service and has been ' 'This API is a proxy to the image service and has been '
'deprecated; use the image service proxy API instead', 'deprecated; use the image service proxy API instead',
DeprecationWarning, os_warnings.OpenStackDeprecationWarning,
) )
return self._get(_image.Image, image) return self._get(_image.Image, image)
@ -548,7 +549,7 @@ class Proxy(proxy.Proxy):
warnings.warn( warnings.warn(
'This API is a proxy to the image service and has been ' 'This API is a proxy to the image service and has been '
'deprecated; use the image service proxy API instead', 'deprecated; use the image service proxy API instead',
DeprecationWarning, os_warnings.OpenStackDeprecationWarning,
) )
base_path = '/images/detail' if details else None base_path = '/images/detail' if details else None
return self._list(_image.Image, base_path=base_path, **query) return self._list(_image.Image, base_path=base_path, **query)
@ -1859,7 +1860,10 @@ class Proxy(proxy.Proxy):
'argument. This is legacy behavior that will be removed in ' 'argument. This is legacy behavior that will be removed in '
'a future version. Update callers to use a volume argument.' 'a future version. Update callers to use a volume argument.'
) )
warnings.warn(deprecation_msg, DeprecationWarning) warnings.warn(
deprecation_msg,
os_warnings.OpenStackDeprecationWarning,
)
else: else:
volume_id = resource.Resource._get_id(volume) volume_id = resource.Resource._get_id(volume)
@ -1932,7 +1936,10 @@ class Proxy(proxy.Proxy):
if isinstance(server, _volume.Volume) or isinstance( if isinstance(server, _volume.Volume) or isinstance(
volume, _server.Server volume, _server.Server
): ):
warnings.warn(deprecation_msg, DeprecationWarning) warnings.warn(
deprecation_msg,
os_warnings.OpenStackDeprecationWarning,
)
return volume, server return volume, server
# without type info we have to try a find the server corresponding to # without type info we have to try a find the server corresponding to
@ -1940,7 +1947,10 @@ class Proxy(proxy.Proxy):
if self.find_server(server, ignore_missing=True) is not None: if self.find_server(server, ignore_missing=True) is not None:
return server, volume return server, volume
else: else:
warnings.warn(deprecation_msg, DeprecationWarning) warnings.warn(
deprecation_msg,
os_warnings.OpenStackDeprecationWarning,
)
return volume, server return volume, server
def delete_volume_attachment(self, server, volume, ignore_missing=True): def delete_volume_attachment(self, server, volume, ignore_missing=True):

@ -15,6 +15,7 @@ import warnings
from openstack import exceptions from openstack import exceptions
from openstack import resource from openstack import resource
from openstack import utils from openstack import utils
from openstack import warnings as os_warnings
class Hypervisor(resource.Resource): class Hypervisor(resource.Resource):
@ -86,7 +87,8 @@ class Hypervisor(resource.Resource):
Updates uptime attribute of the hypervisor object Updates uptime attribute of the hypervisor object
""" """
warnings.warn( warnings.warn(
"This call is deprecated and is only available until Nova 2.88" "This call is deprecated and is only available until Nova 2.88",
os_warnings.LegacyAPIWarning,
) )
if utils.supports_microversion(session, '2.88'): if utils.supports_microversion(session, '2.88'):
raise exceptions.SDKException( raise exceptions.SDKException(

@ -48,6 +48,7 @@ from openstack.config import defaults as config_defaults
from openstack import exceptions from openstack import exceptions
from openstack import proxy from openstack import proxy
from openstack import version as openstack_version from openstack import version as openstack_version
from openstack import warnings as os_warnings
_logger = _log.setup_logging('openstack') _logger = _log.setup_logging('openstack')
@ -100,7 +101,7 @@ def from_session(
force_ipv4=False, force_ipv4=False,
app_name=None, app_name=None,
app_version=None, app_version=None,
**kwargs **kwargs,
): ):
"""Construct a CloudRegion from an existing `keystoneauth1.session.Session` """Construct a CloudRegion from an existing `keystoneauth1.session.Session`
@ -387,11 +388,10 @@ class CloudRegion:
else: else:
if cacert: if cacert:
warnings.warn( warnings.warn(
"You are specifying a cacert for the cloud {full_name}" f"You are specifying a cacert for the cloud "
" but also to ignore the host verification. The host SSL" f"{self.full_name} but also to ignore the host "
" cert will not be verified.".format( f"verification. The host SSL cert will not be verified.",
full_name=self.full_name os_warnings.ConfigurationWarning,
)
) )
cert = self.config.get('cert') cert = self.config.get('cert')
@ -505,9 +505,10 @@ class CloudRegion:
except ValueError: except ValueError:
if 'latest' in version: if 'latest' in version:
warnings.warn( warnings.warn(
"You have a configured API_VERSION with 'latest' in" "You have a configured API_VERSION with 'latest' in "
" it. In the context of openstacksdk this doesn't make" "it. In the context of openstacksdk this doesn't make "
" any sense." "any sense.",
os_warnings.ConfigurationWarning,
) )
return None return None
return version return version
@ -686,7 +687,7 @@ class CloudRegion:
raise exceptions.ConfigException( raise exceptions.ConfigException(
"Problem with auth parameters" "Problem with auth parameters"
) )
(verify, cert) = self.get_requests_verify_args() verify, cert = self.get_requests_verify_args()
# Turn off urllib3 warnings about insecure certs if we have # Turn off urllib3 warnings about insecure certs if we have
# explicitly configured requests to tell it we do not want # explicitly configured requests to tell it we do not want
# cert verification # cert verification
@ -876,7 +877,7 @@ class CloudRegion:
default_microversion=version_request.default_microversion, default_microversion=version_request.default_microversion,
rate_limit=self.get_rate_limit(service_type), rate_limit=self.get_rate_limit(service_type),
concurrency=self.get_concurrency(service_type), concurrency=self.get_concurrency(service_type),
**kwargs **kwargs,
) )
if version_request.default_microversion: if version_request.default_microversion:
default_microversion = version_request.default_microversion default_microversion = version_request.default_microversion
@ -962,7 +963,7 @@ class CloudRegion:
region_name=region_name, region_name=region_name,
interface=interface, interface=interface,
service_name=service_name, service_name=service_name,
**version_kwargs **version_kwargs,
) )
except keystoneauth1.exceptions.catalog.EndpointNotFound: except keystoneauth1.exceptions.catalog.EndpointNotFound:
endpoint = None endpoint = None

@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# alias because we already had an option named argparse # alias because we already had an option named argparse
import argparse as argparse_mod import argparse as argparse_mod
import collections import collections
@ -35,6 +34,7 @@ from openstack.config import cloud_region
from openstack.config import defaults from openstack.config import defaults
from openstack.config import vendors from openstack.config import vendors
from openstack import exceptions from openstack import exceptions
from openstack import warnings as os_warnings
APPDIRS = appdirs.AppDirs('openstack', 'OpenStack', multipath='/etc') APPDIRS = appdirs.AppDirs('openstack', 'OpenStack', multipath='/etc')
CONFIG_HOME = APPDIRS.user_config_dir CONFIG_HOME = APPDIRS.user_config_dir
@ -506,9 +506,10 @@ class OpenStackConfig:
regions = config['region_name'].split(',') regions = config['region_name'].split(',')
if len(regions) > 1: if len(regions) > 1:
warnings.warn( warnings.warn(
"Comma separated lists in region_name are deprecated." f"Comma separated lists in region_name are deprecated. "
" Please use a yaml list in the regions" f"Please use a yaml list in the regions "
" parameter in {0} instead.".format(self.config_filename) f"parameter in {self.config_filename} instead.",
os_warnings.OpenStackDeprecationWarning,
) )
return self._expand_regions(regions) return self._expand_regions(regions)
else: else:
@ -585,9 +586,10 @@ class OpenStackConfig:
return return
if 'cloud' in our_cloud: if 'cloud' in our_cloud:
warnings.warn( warnings.warn(
"{0} uses the keyword 'cloud' to reference a known " f"{self.config_filename} uses the keyword 'cloud' to "
"vendor profile. This has been deprecated in favor of the " f"reference a known vendor profile. This has been deprecated "
"'profile' keyword.".format(self.config_filename) f"in favor of the 'profile' keyword.",
os_warnings.OpenStackDeprecationWarning,
) )
vendor_filename, vendor_file = self._load_vendor_file() vendor_filename, vendor_file = self._load_vendor_file()
@ -609,9 +611,8 @@ class OpenStackConfig:
message = profile_data.pop('message', '') message = profile_data.pop('message', '')
if status == 'deprecated': if status == 'deprecated':
warnings.warn( warnings.warn(
"{profile_name} is deprecated: {message}".format( f"{profile_name} is deprecated: {message}",
profile_name=profile_name, message=message os_warnings.OpenStackDeprecationWarning,
)
) )
elif status == 'shutdown': elif status == 'shutdown':
raise exceptions.ConfigException( raise exceptions.ConfigException(
@ -624,8 +625,9 @@ class OpenStackConfig:
else: else:
# Can't find the requested vendor config, go about business # Can't find the requested vendor config, go about business
warnings.warn( warnings.warn(
"Couldn't find the vendor profile '{0}', for" f"Couldn't find the vendor profile {profile_name} for"
" the cloud '{1}'".format(profile_name, name) f"the cloud {name}",
os_warnings.ConfigurationWarning,
) )
def _project_scoped(self, cloud): def _project_scoped(self, cloud):
@ -687,11 +689,10 @@ class OpenStackConfig:
) )
if key in cloud: if key in cloud:
warnings.warn( warnings.warn(
"{key} is deprecated. Please replace with an entry in" f"{key} is deprecated. Please replace with an entry in "
" a dict inside of the networks list with name: {name}" f"a dict inside of the networks list with name: "
" and routes_externally: {external}".format( f"{cloud[key]} and routes_externally: {external}",
key=key, name=cloud[key], external=external os_warnings.OpenStackDeprecationWarning,
)
) )
networks.append( networks.append(
dict( dict(

@ -18,6 +18,7 @@ from openstack import exceptions
from openstack.image.v1 import image as _image from openstack.image.v1 import image as _image
from openstack import proxy from openstack import proxy
from openstack import utils from openstack import utils
from openstack import warnings as os_warnings
def _get_name_and_filename(name, image_format): def _get_name_and_filename(name, image_format):
@ -258,7 +259,10 @@ class Proxy(proxy.Proxy):
:returns: The results of image creation :returns: The results of image creation
:rtype: :class:`~openstack.image.v1.image.Image` :rtype: :class:`~openstack.image.v1.image.Image`
""" """
warnings.warn("upload_image is deprecated. Use create_image instead.") warnings.warn(
"upload_image is deprecated. Use create_image instead.",
os_warnings.OpenStackDeprecationWarning,
)
return self._create(_image.Image, **attrs) return self._create(_image.Image, **attrs)
def _upload_image( def _upload_image(

@ -27,6 +27,7 @@ from openstack.image.v2 import task as _task
from openstack import proxy from openstack import proxy
from openstack import resource from openstack import resource
from openstack import utils from openstack import utils
from openstack import warnings as os_warnings
# Rackspace returns this for intermittent import errors # Rackspace returns this for intermittent import errors
_IMAGE_ERROR_396 = "Image cannot be imported. Error code: '396'" _IMAGE_ERROR_396 = "Image cannot be imported. Error code: '396'"
@ -500,7 +501,10 @@ class Proxy(proxy.Proxy):
:returns: The results of image creation :returns: The results of image creation
:rtype: :class:`~openstack.image.v2.image.Image` :rtype: :class:`~openstack.image.v2.image.Image`
""" """
warnings.warn("upload_image is deprecated. Use create_image instead.") warnings.warn(
"upload_image is deprecated. Use create_image instead.",
os_warnings.OpenStackDeprecationWarning,
)
# container_format and disk_format are required to be set # container_format and disk_format are required to be set
# on the image by the time upload_image is called, but they're not # on the image by the time upload_image is called, but they're not
# required by the _create call. Enforce them here so that we don't # required by the _create call. Enforce them here so that we don't

@ -39,6 +39,7 @@ from openstack.compute.v2 import usage
from openstack.compute.v2 import volume_attachment from openstack.compute.v2 import volume_attachment
from openstack import resource from openstack import resource
from openstack.tests.unit import test_proxy_base from openstack.tests.unit import test_proxy_base
from openstack import warnings as os_warnings
class TestComputeProxy(test_proxy_base.TestProxyBase): class TestComputeProxy(test_proxy_base.TestProxyBase):
@ -523,7 +524,10 @@ class TestVolumeAttachment(TestComputeProxy):
) )
self.assertEqual(1, len(w)) self.assertEqual(1, len(w))
self.assertEqual(w[-1].category, DeprecationWarning) self.assertEqual(
os_warnings.OpenStackDeprecationWarning,
w[-1].category,
)
self.assertIn( self.assertIn(
'This method was called with a volume_id or volumeId argument', 'This method was called with a volume_id or volumeId argument',
str(w[-1]), str(w[-1]),

@ -31,5 +31,13 @@ class LegacyAPIWarning(OpenStackDeprecationWarning):
"""Indicates an API that is in 'legacy' status, a long term deprecation.""" """Indicates an API that is in 'legacy' status, a long term deprecation."""
class UnsupportedServiceVersion(Warning): class OpenStackWarning(Warning):
"""Base class for general warnings in openstacksdk."""
class ConfigurationWarning(OpenStackWarning):
"""Indicates an issue with configuration."""
class UnsupportedServiceVersion(OpenStackWarning):
"""Indicates a major version that SDK doesn't understand.""" """Indicates a major version that SDK doesn't understand."""