python-openstackclient/openstackclient/common/limits.py
Stephen Finucane 6693f555bc quota: Allow 'quota set' to function without volume service
Unlike cinderclient, SDK attempts to connect to a service as soon as you
create a client. A keystoneauth1.exceptions.catalog.EndpointNotFound
exception can be raised if this service does not exist in the service
catalog. Avoid this for the quota and limits commands by first checking
if the service is enabled.

In the process, we rework the 'is_volume_endpoint_enabled' helper we are
using to check for the existence of the service to *not* require a
volume client, since this was causing a chicken and egg issue for us
(and was also pretty much unnecessary).

Change-Id: I56e68f00ea221d689eb7f668e9e5ffa7d1a20184
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
Closes-bug: #2076229
2024-08-07 11:56:07 +00:00

174 lines
5.5 KiB
Python

# Copyright 2012-2013 OpenStack Foundation
#
# 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.
#
"""Limits Action Implementation"""
import itertools
from osc_lib.command import command
from osc_lib import utils
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")
def get_parser(self, prog_name):
parser = super().get_parser(prog_name)
type_group = parser.add_mutually_exclusive_group(required=True)
type_group.add_argument(
"--absolute",
dest="is_absolute",
action="store_true",
default=False,
help=_("Show absolute limits"),
)
type_group.add_argument(
"--rate",
dest="is_rate",
action="store_true",
default=False,
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)"),
)
parser.add_argument(
'--project',
metavar='<project>',
help=_(
'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)'
),
)
return parser
def take_action(self, parsed_args):
project_id = None
if parsed_args.project is not None:
identity_client = self.app.client_manager.identity
if parsed_args.domain is not None:
domain = identity_common.find_domain(
identity_client, parsed_args.domain
)
project_id = utils.find_resource(
identity_client.projects,
parsed_args.project,
domain_id=domain.id,
).id
else:
project_id = utils.find_resource(
identity_client.projects, parsed_args.project
).id
compute_limits = None
volume_limits = None
if self.app.client_manager.is_compute_endpoint_enabled():
compute_client = self.app.client_manager.sdk_connection.compute
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 = self.app.client_manager.sdk_connection.volume
volume_limits = volume_client.get_limits(
project_id=project_id,
)
if parsed_args.is_absolute:
columns = ["Name", "Value"]
info = {}
if compute_limits:
info.update(_format_absolute_limit(compute_limits.absolute))
if volume_limits:
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",
"Value",
"Remain",
"Unit",
"Next Available",
]
return (
columns,
[
(
s['verb'],
s['uri'],
s['value'],
s['remaining'],
s['unit'],
s.get('next-available') or s['next_available'],
)
for s in data
],
)