common: Migrate 'limits show' to SDK
This is done for both the compute and block storage services even though the compute service hasn't supported rate limits since API v2.1 was introduced [1]. [1] https://github.com/openstack/nova/commit/ca4ec762804 Change-Id: Idd9f4a1c23952a6087f08c03ac8b5bebd5a0c86d Co-authored-by: Stephen Finucane <stephenfin@redhat.com> Depends-on: https://review.opendev.org/c/openstack/openstacksdk/+/918519
This commit is contained in:
		
				
					committed by
					
						
						Stephen Finucane
					
				
			
			
				
	
			
			
			
						parent
						
							55cbb84e60
						
					
				
				
					commit
					9d39437282
				
			@@ -133,7 +133,17 @@ class ClientManager(clientmanager.ClientManager):
 | 
			
		||||
        # NOTE(jcross): Cinder did some interesting things with their service
 | 
			
		||||
        #               name so we need to figure out which version to look
 | 
			
		||||
        #               for when calling is_service_available()
 | 
			
		||||
        volume_version = volume_client.api_version.ver_major
 | 
			
		||||
        endpoint_data = volume_client.get_endpoint_data()
 | 
			
		||||
        # Not sure how endpoint data stores the api version for v2 API,
 | 
			
		||||
        # for v3 it is a tuple (3, 0)
 | 
			
		||||
        if endpoint_data.api_version and isinstance(
 | 
			
		||||
            endpoint_data.api_version, tuple
 | 
			
		||||
        ):
 | 
			
		||||
            volume_version = endpoint_data.api_version[0]
 | 
			
		||||
        else:
 | 
			
		||||
            # Setting volume_version as 2 here if it doesn't satisfy the
 | 
			
		||||
            # conditions for version 3
 | 
			
		||||
            volume_version = 2
 | 
			
		||||
        if (
 | 
			
		||||
            self.is_service_available("volumev%s" % volume_version)
 | 
			
		||||
            is not False
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,31 @@ from openstackclient.i18n import _
 | 
			
		||||
from openstackclient.identity import common as identity_common
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _format_absolute_limit(absolute_limits):
 | 
			
		||||
    info = {}
 | 
			
		||||
 | 
			
		||||
    for key in set(absolute_limits):
 | 
			
		||||
        if key in ('id', 'name', 'location'):
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
        info[key] = absolute_limits[key]
 | 
			
		||||
 | 
			
		||||
    return info
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _format_rate_limit(rate_limits):
 | 
			
		||||
    # flatten this:
 | 
			
		||||
    #
 | 
			
		||||
    #   {'uri': '<uri>', 'limit': [{'value': '<value>', ...], ...}
 | 
			
		||||
    #
 | 
			
		||||
    # to this:
 | 
			
		||||
    #
 | 
			
		||||
    #   {'uri': '<uri>', 'value': '<value>', ...}, ...}
 | 
			
		||||
    return itertools.chain(
 | 
			
		||||
        *[[{'uri': x['uri'], **y} for y in x['limit']] for x in rate_limits]
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ShowLimits(command.Lister):
 | 
			
		||||
    _description = _("Show compute and block storage limits")
 | 
			
		||||
 | 
			
		||||
@@ -42,36 +67,42 @@ class ShowLimits(command.Lister):
 | 
			
		||||
            dest="is_rate",
 | 
			
		||||
            action="store_true",
 | 
			
		||||
            default=False,
 | 
			
		||||
            help=_("Show rate limits"),
 | 
			
		||||
            help=_(
 | 
			
		||||
                'Show rate limits. This is not supported by the compute '
 | 
			
		||||
                'service since the 12.0.0 (Liberty) release and is only '
 | 
			
		||||
                'supported by the block storage service when the '
 | 
			
		||||
                'rate-limiting middleware is enabled. It is therefore a no-op '
 | 
			
		||||
                'in most deployments.'
 | 
			
		||||
            ),
 | 
			
		||||
        )
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            "--reserved",
 | 
			
		||||
            dest="is_reserved",
 | 
			
		||||
            action="store_true",
 | 
			
		||||
            default=False,
 | 
			
		||||
            help=_("Include reservations count [only valid with --absolute]"),
 | 
			
		||||
            help=_("Include reservations count (only valid with --absolute)"),
 | 
			
		||||
        )
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--project',
 | 
			
		||||
            metavar='<project>',
 | 
			
		||||
            help=_(
 | 
			
		||||
                'Show limits for a specific project (name or ID)'
 | 
			
		||||
                ' [only valid with --absolute]'
 | 
			
		||||
                'Show limits for a specific project (name or ID) '
 | 
			
		||||
                '(only valid with --absolute)'
 | 
			
		||||
            ),
 | 
			
		||||
        )
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--domain',
 | 
			
		||||
            metavar='<domain>',
 | 
			
		||||
            help=_(
 | 
			
		||||
                'Domain the project belongs to (name or ID)'
 | 
			
		||||
                ' [only valid with --absolute]'
 | 
			
		||||
                'Domain the project belongs to (name or ID) '
 | 
			
		||||
                '(only valid with --absolute)'
 | 
			
		||||
            ),
 | 
			
		||||
        )
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        compute_client = self.app.client_manager.compute
 | 
			
		||||
        volume_client = self.app.client_manager.volume
 | 
			
		||||
        compute_client = self.app.client_manager.sdk_connection.compute
 | 
			
		||||
        volume_client = self.app.client_manager.sdk_connection.volume
 | 
			
		||||
 | 
			
		||||
        project_id = None
 | 
			
		||||
        if parsed_args.project is not None:
 | 
			
		||||
@@ -94,33 +125,30 @@ class ShowLimits(command.Lister):
 | 
			
		||||
        volume_limits = None
 | 
			
		||||
 | 
			
		||||
        if self.app.client_manager.is_compute_endpoint_enabled():
 | 
			
		||||
            compute_limits = compute_client.limits.get(
 | 
			
		||||
                parsed_args.is_reserved, tenant_id=project_id
 | 
			
		||||
            compute_limits = compute_client.get_limits(
 | 
			
		||||
                reserved=parsed_args.is_reserved, tenant_id=project_id
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        if self.app.client_manager.is_volume_endpoint_enabled(volume_client):
 | 
			
		||||
            volume_limits = volume_client.limits.get()
 | 
			
		||||
 | 
			
		||||
        data = []
 | 
			
		||||
        if parsed_args.is_absolute:
 | 
			
		||||
            if compute_limits:
 | 
			
		||||
                data.append(compute_limits.absolute)
 | 
			
		||||
            if volume_limits:
 | 
			
		||||
                data.append(volume_limits.absolute)
 | 
			
		||||
            columns = ["Name", "Value"]
 | 
			
		||||
            return (
 | 
			
		||||
                columns,
 | 
			
		||||
                (
 | 
			
		||||
                    utils.get_item_properties(s, columns)
 | 
			
		||||
                    for s in itertools.chain(*data)
 | 
			
		||||
                ),
 | 
			
		||||
            volume_limits = volume_client.get_limits(
 | 
			
		||||
                project_id=project_id,
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        elif parsed_args.is_rate:
 | 
			
		||||
        if parsed_args.is_absolute:
 | 
			
		||||
            columns = ["Name", "Value"]
 | 
			
		||||
            info = {}
 | 
			
		||||
            if compute_limits:
 | 
			
		||||
                data.append(compute_limits.rate)
 | 
			
		||||
                info.update(_format_absolute_limit(compute_limits.absolute))
 | 
			
		||||
            if volume_limits:
 | 
			
		||||
                data.append(volume_limits.rate)
 | 
			
		||||
                info.update(_format_absolute_limit(volume_limits.absolute))
 | 
			
		||||
 | 
			
		||||
            return (columns, sorted(info.items(), key=lambda x: x[0]))
 | 
			
		||||
        else:  # parsed_args.is_rate
 | 
			
		||||
            data = []
 | 
			
		||||
            if compute_limits:
 | 
			
		||||
                data.extend(_format_rate_limit(compute_limits.rate))
 | 
			
		||||
            if volume_limits:
 | 
			
		||||
                data.extend(_format_rate_limit(volume_limits.rate))
 | 
			
		||||
            columns = [
 | 
			
		||||
                "Verb",
 | 
			
		||||
                "URI",
 | 
			
		||||
@@ -129,12 +157,18 @@ class ShowLimits(command.Lister):
 | 
			
		||||
                "Unit",
 | 
			
		||||
                "Next Available",
 | 
			
		||||
            ]
 | 
			
		||||
 | 
			
		||||
            return (
 | 
			
		||||
                columns,
 | 
			
		||||
                (
 | 
			
		||||
                    utils.get_item_properties(s, columns)
 | 
			
		||||
                    for s in itertools.chain(*data)
 | 
			
		||||
                ),
 | 
			
		||||
                [
 | 
			
		||||
                    (
 | 
			
		||||
                        s['verb'],
 | 
			
		||||
                        s['uri'],
 | 
			
		||||
                        s['value'],
 | 
			
		||||
                        s['remaining'],
 | 
			
		||||
                        s['unit'],
 | 
			
		||||
                        s.get('next-available') or s['next_available'],
 | 
			
		||||
                    )
 | 
			
		||||
                    for s in data
 | 
			
		||||
                ],
 | 
			
		||||
            )
 | 
			
		||||
        else:
 | 
			
		||||
            return {}, {}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,23 +13,62 @@
 | 
			
		||||
 | 
			
		||||
from openstackclient.common import limits
 | 
			
		||||
from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
 | 
			
		||||
from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes
 | 
			
		||||
from openstackclient.tests.unit.volume.v3 import fakes as volume_fakes
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestComputeLimits(compute_fakes.TestComputev2):
 | 
			
		||||
    absolute_columns = [
 | 
			
		||||
        'Name',
 | 
			
		||||
        'Value',
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    absolute_columns = ['Name', 'Value']
 | 
			
		||||
    rate_columns = ["Verb", "URI", "Value", "Remain", "Unit", "Next Available"]
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        super().setUp()
 | 
			
		||||
        self.app.client_manager.volume_endpoint_enabled = False
 | 
			
		||||
 | 
			
		||||
        self.fake_limits = compute_fakes.FakeLimits()
 | 
			
		||||
        self.compute_client.limits.get.return_value = self.fake_limits
 | 
			
		||||
        self.fake_limits = compute_fakes.create_limits()
 | 
			
		||||
 | 
			
		||||
        self.absolute_data = [
 | 
			
		||||
            ('floating_ips', 10),
 | 
			
		||||
            ('floating_ips_used', 0),
 | 
			
		||||
            ('image_meta', 128),
 | 
			
		||||
            ('instances', 10),
 | 
			
		||||
            ('instances_used', 0),
 | 
			
		||||
            ('keypairs', 100),
 | 
			
		||||
            ('max_image_meta', 128),
 | 
			
		||||
            ('max_security_group_rules', 20),
 | 
			
		||||
            ('max_security_groups', 10),
 | 
			
		||||
            ('max_server_group_members', 10),
 | 
			
		||||
            ('max_server_groups', 10),
 | 
			
		||||
            ('max_server_meta', 128),
 | 
			
		||||
            ('max_total_cores', 20),
 | 
			
		||||
            ('max_total_floating_ips', 10),
 | 
			
		||||
            ('max_total_instances', 10),
 | 
			
		||||
            ('max_total_keypairs', 100),
 | 
			
		||||
            ('max_total_ram_size', 51200),
 | 
			
		||||
            ('personality', 5),
 | 
			
		||||
            ('personality_size', 10240),
 | 
			
		||||
            ('security_group_rules', 20),
 | 
			
		||||
            ('security_groups', 10),
 | 
			
		||||
            ('security_groups_used', 0),
 | 
			
		||||
            ('server_group_members', 10),
 | 
			
		||||
            ('server_groups', 10),
 | 
			
		||||
            ('server_groups_used', 0),
 | 
			
		||||
            ('server_meta', 128),
 | 
			
		||||
            ('total_cores', 20),
 | 
			
		||||
            ('total_cores_used', 0),
 | 
			
		||||
            ('total_floating_ips_used', 0),
 | 
			
		||||
            ('total_instances_used', 0),
 | 
			
		||||
            ('total_ram', 51200),
 | 
			
		||||
            ('total_ram_used', 0),
 | 
			
		||||
            ('total_security_groups_used', 0),
 | 
			
		||||
            ('total_server_groups_used', 0),
 | 
			
		||||
        ]
 | 
			
		||||
        self.rate_data = [
 | 
			
		||||
            ('POST', '*', 10, 2, 'MINUTE', '2011-12-15T22:42:45Z'),
 | 
			
		||||
            ('PUT', '*', 10, 2, 'MINUTE', '2011-12-15T22:42:45Z'),
 | 
			
		||||
            ('DELETE', '*', 100, 100, 'MINUTE', '2011-12-15T22:42:45Z'),
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
        self.compute_sdk_client.get_limits.return_value = self.fake_limits
 | 
			
		||||
 | 
			
		||||
    def test_compute_show_absolute(self):
 | 
			
		||||
        arglist = ['--absolute']
 | 
			
		||||
@@ -39,12 +78,8 @@ class TestComputeLimits(compute_fakes.TestComputev2):
 | 
			
		||||
 | 
			
		||||
        columns, data = cmd.take_action(parsed_args)
 | 
			
		||||
 | 
			
		||||
        ret_limits = list(data)
 | 
			
		||||
        compute_reference_limits = self.fake_limits.absolute_limits()
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(self.absolute_columns, columns)
 | 
			
		||||
        self.assertEqual(compute_reference_limits, ret_limits)
 | 
			
		||||
        self.assertEqual(19, len(ret_limits))
 | 
			
		||||
        self.assertEqual(self.absolute_data, data)
 | 
			
		||||
 | 
			
		||||
    def test_compute_show_rate(self):
 | 
			
		||||
        arglist = ['--rate']
 | 
			
		||||
@@ -54,28 +89,39 @@ class TestComputeLimits(compute_fakes.TestComputev2):
 | 
			
		||||
 | 
			
		||||
        columns, data = cmd.take_action(parsed_args)
 | 
			
		||||
 | 
			
		||||
        ret_limits = list(data)
 | 
			
		||||
        compute_reference_limits = self.fake_limits.rate_limits()
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(self.rate_columns, columns)
 | 
			
		||||
        self.assertEqual(compute_reference_limits, ret_limits)
 | 
			
		||||
        self.assertEqual(3, len(ret_limits))
 | 
			
		||||
        self.assertEqual(self.rate_data, data)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestVolumeLimits(volume_fakes.TestVolume):
 | 
			
		||||
    absolute_columns = [
 | 
			
		||||
        'Name',
 | 
			
		||||
        'Value',
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    absolute_columns = ['Name', 'Value']
 | 
			
		||||
    rate_columns = ["Verb", "URI", "Value", "Remain", "Unit", "Next Available"]
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        super().setUp()
 | 
			
		||||
        self.app.client_manager.compute_endpoint_enabled = False
 | 
			
		||||
 | 
			
		||||
        self.fake_limits = volume_fakes.FakeLimits()
 | 
			
		||||
        self.volume_client.limits.get.return_value = self.fake_limits
 | 
			
		||||
        self.fake_limits = volume_fakes.create_limits()
 | 
			
		||||
 | 
			
		||||
        self.absolute_data = [
 | 
			
		||||
            ('max_total_backup_gigabytes', 1000),
 | 
			
		||||
            ('max_total_backups', 10),
 | 
			
		||||
            ('max_total_snapshots', 10),
 | 
			
		||||
            ('max_total_volume_gigabytes', 1000),
 | 
			
		||||
            ('max_total_volumes', 10),
 | 
			
		||||
            ('total_backup_gigabytes_used', 0),
 | 
			
		||||
            ('total_backups_used', 0),
 | 
			
		||||
            ('total_gigabytes_used', 35),
 | 
			
		||||
            ('total_snapshots_used', 1),
 | 
			
		||||
            ('total_volumes_used', 4),
 | 
			
		||||
        ]
 | 
			
		||||
        self.rate_data = [
 | 
			
		||||
            ('POST', '*', 10, 2, 'MINUTE', '2011-12-15T22:42:45Z'),
 | 
			
		||||
            ('PUT', '*', 10, 2, 'MINUTE', '2011-12-15T22:42:45Z'),
 | 
			
		||||
            ('DELETE', '*', 100, 100, 'MINUTE', '2011-12-15T22:42:45Z'),
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
        self.volume_sdk_client.get_limits.return_value = self.fake_limits
 | 
			
		||||
 | 
			
		||||
    def test_volume_show_absolute(self):
 | 
			
		||||
        arglist = ['--absolute']
 | 
			
		||||
@@ -85,12 +131,8 @@ class TestVolumeLimits(volume_fakes.TestVolume):
 | 
			
		||||
 | 
			
		||||
        columns, data = cmd.take_action(parsed_args)
 | 
			
		||||
 | 
			
		||||
        ret_limits = list(data)
 | 
			
		||||
        compute_reference_limits = self.fake_limits.absolute_limits()
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(self.absolute_columns, columns)
 | 
			
		||||
        self.assertEqual(compute_reference_limits, ret_limits)
 | 
			
		||||
        self.assertEqual(10, len(ret_limits))
 | 
			
		||||
        self.assertEqual(self.absolute_data, data)
 | 
			
		||||
 | 
			
		||||
    def test_volume_show_rate(self):
 | 
			
		||||
        arglist = ['--rate']
 | 
			
		||||
@@ -100,9 +142,5 @@ class TestVolumeLimits(volume_fakes.TestVolume):
 | 
			
		||||
 | 
			
		||||
        columns, data = cmd.take_action(parsed_args)
 | 
			
		||||
 | 
			
		||||
        ret_limits = list(data)
 | 
			
		||||
        compute_reference_limits = self.fake_limits.rate_limits()
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(self.rate_columns, columns)
 | 
			
		||||
        self.assertEqual(compute_reference_limits, ret_limits)
 | 
			
		||||
        self.assertEqual(3, len(ret_limits))
 | 
			
		||||
        self.assertEqual(self.rate_data, data)
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,7 @@ from openstack.compute.v2 import extension as _extension
 | 
			
		||||
from openstack.compute.v2 import flavor as _flavor
 | 
			
		||||
from openstack.compute.v2 import hypervisor as _hypervisor
 | 
			
		||||
from openstack.compute.v2 import keypair as _keypair
 | 
			
		||||
from openstack.compute.v2 import limits as _limits
 | 
			
		||||
from openstack.compute.v2 import migration as _migration
 | 
			
		||||
from openstack.compute.v2 import server as _server
 | 
			
		||||
from openstack.compute.v2 import server_action as _server_action
 | 
			
		||||
@@ -91,9 +92,6 @@ class FakeComputev2Client:
 | 
			
		||||
        self.images = mock.Mock()
 | 
			
		||||
        self.images.resource_class = fakes.FakeResource(None, {})
 | 
			
		||||
 | 
			
		||||
        self.limits = mock.Mock()
 | 
			
		||||
        self.limits.resource_class = fakes.FakeResource(None, {})
 | 
			
		||||
 | 
			
		||||
        self.servers = mock.Mock()
 | 
			
		||||
        self.servers.resource_class = fakes.FakeResource(None, {})
 | 
			
		||||
 | 
			
		||||
@@ -1177,11 +1175,12 @@ def create_one_comp_detailed_quota(attrs=None):
 | 
			
		||||
    return quota
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FakeLimits:
 | 
			
		||||
    """Fake limits"""
 | 
			
		||||
def create_limits(attrs=None):
 | 
			
		||||
    """Create a fake limits object."""
 | 
			
		||||
    attrs = attrs or {}
 | 
			
		||||
 | 
			
		||||
    def __init__(self, absolute_attrs=None, rate_attrs=None):
 | 
			
		||||
        self.absolute_limits_attrs = {
 | 
			
		||||
    limits_attrs = {
 | 
			
		||||
        'absolute': {
 | 
			
		||||
            'maxServerMeta': 128,
 | 
			
		||||
            'maxTotalInstances': 10,
 | 
			
		||||
            'maxPersonality': 5,
 | 
			
		||||
@@ -1201,11 +1200,8 @@ class FakeLimits:
 | 
			
		||||
            'maxTotalFloatingIps': 10,
 | 
			
		||||
            'totalSecurityGroupsUsed': 0,
 | 
			
		||||
            'maxTotalCores': 20,
 | 
			
		||||
        }
 | 
			
		||||
        absolute_attrs = absolute_attrs or {}
 | 
			
		||||
        self.absolute_limits_attrs.update(absolute_attrs)
 | 
			
		||||
 | 
			
		||||
        self.rate_limits_attrs = [
 | 
			
		||||
        },
 | 
			
		||||
        'rate': [
 | 
			
		||||
            {
 | 
			
		||||
                "uri": "*",
 | 
			
		||||
                "limit": [
 | 
			
		||||
@@ -1232,69 +1228,12 @@ class FakeLimits:
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
        ],
 | 
			
		||||
    }
 | 
			
		||||
    limits_attrs.update(attrs)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def absolute(self):
 | 
			
		||||
        for name, value in self.absolute_limits_attrs.items():
 | 
			
		||||
            yield FakeAbsoluteLimit(name, value)
 | 
			
		||||
 | 
			
		||||
    def absolute_limits(self):
 | 
			
		||||
        reference_data = []
 | 
			
		||||
        for name, value in self.absolute_limits_attrs.items():
 | 
			
		||||
            reference_data.append((name, value))
 | 
			
		||||
        return reference_data
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def rate(self):
 | 
			
		||||
        for group in self.rate_limits_attrs:
 | 
			
		||||
            uri = group['uri']
 | 
			
		||||
            for rate in group['limit']:
 | 
			
		||||
                yield FakeRateLimit(
 | 
			
		||||
                    rate['verb'],
 | 
			
		||||
                    uri,
 | 
			
		||||
                    rate['value'],
 | 
			
		||||
                    rate['remaining'],
 | 
			
		||||
                    rate['unit'],
 | 
			
		||||
                    rate['next-available'],
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
    def rate_limits(self):
 | 
			
		||||
        reference_data = []
 | 
			
		||||
        for group in self.rate_limits_attrs:
 | 
			
		||||
            uri = group['uri']
 | 
			
		||||
            for rate in group['limit']:
 | 
			
		||||
                reference_data.append(
 | 
			
		||||
                    (
 | 
			
		||||
                        rate['verb'],
 | 
			
		||||
                        uri,
 | 
			
		||||
                        rate['value'],
 | 
			
		||||
                        rate['remaining'],
 | 
			
		||||
                        rate['unit'],
 | 
			
		||||
                        rate['next-available'],
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
        return reference_data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FakeAbsoluteLimit:
 | 
			
		||||
    """Data model that represents an absolute limit"""
 | 
			
		||||
 | 
			
		||||
    def __init__(self, name, value):
 | 
			
		||||
        self.name = name
 | 
			
		||||
        self.value = value
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FakeRateLimit:
 | 
			
		||||
    """Data model that represents a flattened view of a single rate limit"""
 | 
			
		||||
 | 
			
		||||
    def __init__(self, verb, uri, value, remain, unit, next_available):
 | 
			
		||||
        self.verb = verb
 | 
			
		||||
        self.uri = uri
 | 
			
		||||
        self.value = value
 | 
			
		||||
        self.remain = remain
 | 
			
		||||
        self.unit = unit
 | 
			
		||||
        self.next_available = next_available
 | 
			
		||||
    limits = _limits.Limits(**limits_attrs)
 | 
			
		||||
    return limits
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def create_one_migration(attrs=None):
 | 
			
		||||
 
 | 
			
		||||
@@ -1062,114 +1062,3 @@ def create_one_detailed_quota(attrs=None):
 | 
			
		||||
    quota = fakes.FakeResource(info=copy.deepcopy(quota_attrs), loaded=True)
 | 
			
		||||
 | 
			
		||||
    return quota
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FakeLimits:
 | 
			
		||||
    """Fake limits"""
 | 
			
		||||
 | 
			
		||||
    def __init__(self, absolute_attrs=None):
 | 
			
		||||
        self.absolute_limits_attrs = {
 | 
			
		||||
            'totalSnapshotsUsed': 1,
 | 
			
		||||
            'maxTotalBackups': 10,
 | 
			
		||||
            'maxTotalVolumeGigabytes': 1000,
 | 
			
		||||
            'maxTotalSnapshots': 10,
 | 
			
		||||
            'maxTotalBackupGigabytes': 1000,
 | 
			
		||||
            'totalBackupGigabytesUsed': 0,
 | 
			
		||||
            'maxTotalVolumes': 10,
 | 
			
		||||
            'totalVolumesUsed': 4,
 | 
			
		||||
            'totalBackupsUsed': 0,
 | 
			
		||||
            'totalGigabytesUsed': 35,
 | 
			
		||||
        }
 | 
			
		||||
        absolute_attrs = absolute_attrs or {}
 | 
			
		||||
        self.absolute_limits_attrs.update(absolute_attrs)
 | 
			
		||||
 | 
			
		||||
        self.rate_limits_attrs = [
 | 
			
		||||
            {
 | 
			
		||||
                "uri": "*",
 | 
			
		||||
                "limit": [
 | 
			
		||||
                    {
 | 
			
		||||
                        "value": 10,
 | 
			
		||||
                        "verb": "POST",
 | 
			
		||||
                        "remaining": 2,
 | 
			
		||||
                        "unit": "MINUTE",
 | 
			
		||||
                        "next-available": "2011-12-15T22:42:45Z",
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        "value": 10,
 | 
			
		||||
                        "verb": "PUT",
 | 
			
		||||
                        "remaining": 2,
 | 
			
		||||
                        "unit": "MINUTE",
 | 
			
		||||
                        "next-available": "2011-12-15T22:42:45Z",
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        "value": 100,
 | 
			
		||||
                        "verb": "DELETE",
 | 
			
		||||
                        "remaining": 100,
 | 
			
		||||
                        "unit": "MINUTE",
 | 
			
		||||
                        "next-available": "2011-12-15T22:42:45Z",
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def absolute(self):
 | 
			
		||||
        for name, value in self.absolute_limits_attrs.items():
 | 
			
		||||
            yield FakeAbsoluteLimit(name, value)
 | 
			
		||||
 | 
			
		||||
    def absolute_limits(self):
 | 
			
		||||
        reference_data = []
 | 
			
		||||
        for name, value in self.absolute_limits_attrs.items():
 | 
			
		||||
            reference_data.append((name, value))
 | 
			
		||||
        return reference_data
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def rate(self):
 | 
			
		||||
        for group in self.rate_limits_attrs:
 | 
			
		||||
            uri = group['uri']
 | 
			
		||||
            for rate in group['limit']:
 | 
			
		||||
                yield FakeRateLimit(
 | 
			
		||||
                    rate['verb'],
 | 
			
		||||
                    uri,
 | 
			
		||||
                    rate['value'],
 | 
			
		||||
                    rate['remaining'],
 | 
			
		||||
                    rate['unit'],
 | 
			
		||||
                    rate['next-available'],
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
    def rate_limits(self):
 | 
			
		||||
        reference_data = []
 | 
			
		||||
        for group in self.rate_limits_attrs:
 | 
			
		||||
            uri = group['uri']
 | 
			
		||||
            for rate in group['limit']:
 | 
			
		||||
                reference_data.append(
 | 
			
		||||
                    (
 | 
			
		||||
                        rate['verb'],
 | 
			
		||||
                        uri,
 | 
			
		||||
                        rate['value'],
 | 
			
		||||
                        rate['remaining'],
 | 
			
		||||
                        rate['unit'],
 | 
			
		||||
                        rate['next-available'],
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
        return reference_data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FakeAbsoluteLimit:
 | 
			
		||||
    """Data model that represents an absolute limit."""
 | 
			
		||||
 | 
			
		||||
    def __init__(self, name, value):
 | 
			
		||||
        self.name = name
 | 
			
		||||
        self.value = value
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FakeRateLimit:
 | 
			
		||||
    """Data model that represents a flattened view of a single rate limit."""
 | 
			
		||||
 | 
			
		||||
    def __init__(self, verb, uri, value, remain, unit, next_available):
 | 
			
		||||
        self.verb = verb
 | 
			
		||||
        self.uri = uri
 | 
			
		||||
        self.value = value
 | 
			
		||||
        self.remain = remain
 | 
			
		||||
        self.unit = unit
 | 
			
		||||
        self.next_available = next_available
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,7 @@ from openstack.block_storage.v3 import _proxy
 | 
			
		||||
from openstack.block_storage.v3 import availability_zone as _availability_zone
 | 
			
		||||
from openstack.block_storage.v3 import backup as _backup
 | 
			
		||||
from openstack.block_storage.v3 import extension as _extension
 | 
			
		||||
from openstack.block_storage.v3 import limits as _limits
 | 
			
		||||
from openstack.block_storage.v3 import resource_filter as _filters
 | 
			
		||||
from openstack.block_storage.v3 import volume as _volume
 | 
			
		||||
from openstack.compute.v2 import _proxy as _compute_proxy
 | 
			
		||||
@@ -423,6 +424,58 @@ def create_one_encryption_volume_type(attrs=None):
 | 
			
		||||
    return encryption_type
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def create_limits(attrs=None):
 | 
			
		||||
    """Create a fake limits object."""
 | 
			
		||||
    attrs = attrs or {}
 | 
			
		||||
 | 
			
		||||
    limits_attrs = {
 | 
			
		||||
        'absolute': {
 | 
			
		||||
            'totalSnapshotsUsed': 1,
 | 
			
		||||
            'maxTotalBackups': 10,
 | 
			
		||||
            'maxTotalVolumeGigabytes': 1000,
 | 
			
		||||
            'maxTotalSnapshots': 10,
 | 
			
		||||
            'maxTotalBackupGigabytes': 1000,
 | 
			
		||||
            'totalBackupGigabytesUsed': 0,
 | 
			
		||||
            'maxTotalVolumes': 10,
 | 
			
		||||
            'totalVolumesUsed': 4,
 | 
			
		||||
            'totalBackupsUsed': 0,
 | 
			
		||||
            'totalGigabytesUsed': 35,
 | 
			
		||||
        },
 | 
			
		||||
        'rate': [
 | 
			
		||||
            {
 | 
			
		||||
                "uri": "*",
 | 
			
		||||
                "limit": [
 | 
			
		||||
                    {
 | 
			
		||||
                        "value": 10,
 | 
			
		||||
                        "verb": "POST",
 | 
			
		||||
                        "remaining": 2,
 | 
			
		||||
                        "unit": "MINUTE",
 | 
			
		||||
                        "next-available": "2011-12-15T22:42:45Z",
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        "value": 10,
 | 
			
		||||
                        "verb": "PUT",
 | 
			
		||||
                        "remaining": 2,
 | 
			
		||||
                        "unit": "MINUTE",
 | 
			
		||||
                        "next-available": "2011-12-15T22:42:45Z",
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        "value": 100,
 | 
			
		||||
                        "verb": "DELETE",
 | 
			
		||||
                        "remaining": 100,
 | 
			
		||||
                        "unit": "MINUTE",
 | 
			
		||||
                        "next-available": "2011-12-15T22:42:45Z",
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
    }
 | 
			
		||||
    limits_attrs.update(attrs)
 | 
			
		||||
 | 
			
		||||
    limits = _limits.Limit(**limits_attrs)
 | 
			
		||||
    return limits
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def create_one_resource_filter(attrs=None):
 | 
			
		||||
    """Create a fake resource filter.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,4 @@
 | 
			
		||||
---
 | 
			
		||||
upgrade:
 | 
			
		||||
  - |
 | 
			
		||||
    The ``limits show`` command has been migrated to SDK.
 | 
			
		||||
		Reference in New Issue
	
	Block a user