Add quotas and quota classes
Change-Id: I6ecdb63e633f145614b1a0d57712352dace7acf2 Implements: blueprint quota-support
This commit is contained in:
@@ -70,6 +70,12 @@ openstack.container.v1 =
|
||||
appcontainer_rebuild = zunclient.osc.v1.containers:RebuildContainer
|
||||
appcontainer_action_list = zunclient.osc.v1.containers:ActionList
|
||||
appcontainer_action_show = zunclient.osc.v1.containers:ActionShow
|
||||
appcontainer_quota_get = zunclient.osc.v1.quotas:GetQuota
|
||||
appcontainer_quota_default = zunclient.osc.v1.quotas:GetDefaultQuota
|
||||
appcontainer_quota_delete = zunclient.osc.v1.quotas:DeleteQuota
|
||||
appcontainer_quota_update = zunclient.osc.v1.quotas:UpdateQuota
|
||||
appcontainer_quota_class_update = zunclient.osc.v1.quotas:UpdateQuotaClass
|
||||
appcontainer_quota_class_get = zunclient.osc.v1.quotas:GetQuotaClass
|
||||
|
||||
[build_sphinx]
|
||||
source-dir = doc/source
|
||||
|
@@ -31,7 +31,7 @@ if not LOG.handlers:
|
||||
HEADER_NAME = "OpenStack-API-Version"
|
||||
SERVICE_TYPE = "container"
|
||||
MIN_API_VERSION = '1.1'
|
||||
MAX_API_VERSION = '1.25'
|
||||
MAX_API_VERSION = '1.26'
|
||||
DEFAULT_API_VERSION = '1.latest'
|
||||
|
||||
_SUBSTITUTIONS = {}
|
||||
|
@@ -230,18 +230,21 @@ def keys_and_vals_to_strs(dictionary):
|
||||
return dict((to_str(k), to_str(v)) for k, v in dictionary.items())
|
||||
|
||||
|
||||
def print_dict(dct, dict_property="Property", wrap=0):
|
||||
def print_dict(dct, dict_property="Property", wrap=0, value_fields=None):
|
||||
"""Print a `dict` as a table of two columns.
|
||||
|
||||
:param dct: `dict` to print
|
||||
:param dict_property: name of the first column
|
||||
:param wrap: wrapping for the second column
|
||||
:param value_fields: attributes that correspond to columns, in order
|
||||
"""
|
||||
pt = prettytable.PrettyTable([dict_property, 'Value'])
|
||||
if value_fields:
|
||||
pt = prettytable.PrettyTable([dict_property] + list(value_fields))
|
||||
pt.align = 'l'
|
||||
for k, v in dct.items():
|
||||
# convert dict to str to check length
|
||||
if isinstance(v, dict):
|
||||
if isinstance(v, dict) and not value_fields:
|
||||
v = six.text_type(keys_and_vals_to_strs(v))
|
||||
if wrap > 0:
|
||||
v = textwrap.fill(six.text_type(v), wrap)
|
||||
@@ -255,6 +258,9 @@ def print_dict(dct, dict_property="Property", wrap=0):
|
||||
for line in lines:
|
||||
pt.add_row([col1, line])
|
||||
col1 = ''
|
||||
elif isinstance(v, dict):
|
||||
vals = [v[field] for field in v if field in value_fields]
|
||||
pt.add_row([k] + vals)
|
||||
elif isinstance(v, list):
|
||||
val = str([str(i) for i in v])
|
||||
pt.add_row([k, val])
|
||||
|
91
zunclient/osc/v1/quota_classes.py
Normal file
91
zunclient/osc/v1/quota_classes.py
Normal file
@@ -0,0 +1,91 @@
|
||||
# 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 osc_lib.command import command
|
||||
from osc_lib import utils
|
||||
from oslo_log import log as logging
|
||||
|
||||
|
||||
def _quota_class_columns(quota_class):
|
||||
return quota_class.__dict__.keys()
|
||||
|
||||
|
||||
def _get_client(obj, parsed_args):
|
||||
obj.log.debug("take_action(%s)" % parsed_args)
|
||||
return obj.app.client_manager.container
|
||||
|
||||
|
||||
class UpdateQuotaClass(command.ShowOne):
|
||||
"""Update the quotas for a quota class"""
|
||||
|
||||
log = logging.getLogger(__name__ + ".UpdateQuotaClass")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(UpdateQuotaClass, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--containers',
|
||||
metavar='<containers>',
|
||||
help='The number of containers allowed per project')
|
||||
parser.add_argument(
|
||||
'--memory',
|
||||
metavar='<memory>',
|
||||
help='The number of megabytes of container RAM '
|
||||
'allowed per project')
|
||||
parser.add_argument(
|
||||
'--cpu',
|
||||
metavar='<cpu>',
|
||||
help='The number of container cores or vCPUs '
|
||||
'allowed per project')
|
||||
parser.add_argument(
|
||||
'--disk',
|
||||
metavar='<disk>',
|
||||
help='The number of gigabytes of container Disk '
|
||||
'allowed per project')
|
||||
parser.add_argument(
|
||||
'quota_class_name',
|
||||
metavar='<quota_class_name>',
|
||||
help='The name of quota class')
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = _get_client(self, parsed_args)
|
||||
opts = {}
|
||||
opts['containers'] = parsed_args.containers
|
||||
opts['memory'] = parsed_args.memory
|
||||
opts['cpu'] = parsed_args.cpu
|
||||
opts['disk'] = parsed_args.disk
|
||||
quota_class_name = parsed_args.quota_class_name
|
||||
quota_class = client.quota_classes.update(
|
||||
quota_class_name, **opts)
|
||||
columns = _quota_class_columns(quota_class)
|
||||
return columns, utils.get_item_properties(quota_class, columns)
|
||||
|
||||
|
||||
class GetQuotaClass(command.ShowOne):
|
||||
"""List the quotas for a quota class"""
|
||||
|
||||
log = logging.getLogger(__name__ + '.GetQuotaClass')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(GetQuotaClass, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'quota_class_name',
|
||||
metavar='<quota_class_name>',
|
||||
help='The name of quota class')
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = _get_client(self, parsed_args)
|
||||
quota_class_name = parsed_args.quota_class_name
|
||||
quota_class = client.quota_class.get(quota_class_name)
|
||||
columns = _quota_class_columns(quota_class_name)
|
||||
return columns, utils.get_item_properties(quota_class, columns)
|
113
zunclient/osc/v1/quotas.py
Normal file
113
zunclient/osc/v1/quotas.py
Normal file
@@ -0,0 +1,113 @@
|
||||
# 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 osc_lib.command import command
|
||||
from osc_lib import utils
|
||||
from oslo_log import log as logging
|
||||
|
||||
from zunclient.i18n import _
|
||||
|
||||
|
||||
def _quota_columns(quota):
|
||||
return quota._info.keys()
|
||||
|
||||
|
||||
def _get_client(obj, parsed_args):
|
||||
obj.log.debug("take_action(%s)" % parsed_args)
|
||||
return obj.app.client_manager.container
|
||||
|
||||
|
||||
class UpdateQuota(command.ShowOne):
|
||||
"""Update the quotas of the project"""
|
||||
|
||||
log = logging.getLogger(__name__ + ".UpdateQuota")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(UpdateQuota, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--containers',
|
||||
metavar='<containers>',
|
||||
help='The number of containers allowed per project')
|
||||
parser.add_argument(
|
||||
'--memory',
|
||||
metavar='<memory>',
|
||||
help='The number of megabytes of container RAM '
|
||||
'allowed per project')
|
||||
parser.add_argument(
|
||||
'--cpu',
|
||||
metavar='<cpu>',
|
||||
help='The number of container cores or vCPUs '
|
||||
'allowed per project')
|
||||
parser.add_argument(
|
||||
'--disk',
|
||||
metavar='<disk>',
|
||||
help='The number of gigabytes of container Disk '
|
||||
'allowed per project')
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = _get_client(self, parsed_args)
|
||||
opts = {}
|
||||
opts['containers'] = parsed_args.containers
|
||||
opts['memory'] = parsed_args.memory
|
||||
opts['cpu'] = parsed_args.cpu
|
||||
opts['disk'] = parsed_args.disk
|
||||
quota = client.quotas.update(**opts)
|
||||
columns = _quota_columns(quota)
|
||||
return columns, utils.get_item_properties(quota, columns)
|
||||
|
||||
|
||||
class GetQuota(command.ShowOne):
|
||||
"""Get quota of the project"""
|
||||
|
||||
log = logging.getLogger(__name__ + '.GetQuota')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(GetQuota, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--usages',
|
||||
action='store_true',
|
||||
help='Whether show quota usage statistic or not')
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = _get_client(self, parsed_args)
|
||||
quota = client.quotas.get(usages=parsed_args.usages)
|
||||
columns = _quota_columns(quota)
|
||||
return columns, utils.get_item_properties(quota, columns)
|
||||
|
||||
|
||||
class GetDefaultQuota(command.ShowOne):
|
||||
"""Get default quota of the project"""
|
||||
|
||||
log = logging.getLogger(__name__ + '.GetDefeaultQuota')
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = _get_client(self, parsed_args)
|
||||
default_quota = client.quotas.defaults()
|
||||
columns = _quota_columns(default_quota)
|
||||
return columns, utils.get_item_properties(
|
||||
default_quota, columns)
|
||||
|
||||
|
||||
class DeleteQuota(command.Command):
|
||||
"""Delete quota of the project"""
|
||||
|
||||
log = logging.getLogger(__name__ + '.DeleteQuota')
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = _get_client(self, parsed_args)
|
||||
try:
|
||||
client.quotas.delete()
|
||||
print(_('Request to delete quotas has been accepted.'))
|
||||
except Exception as e:
|
||||
print("Delete for quotas failed: %(e)s" % {'e': e})
|
@@ -249,32 +249,32 @@ class ShellTest(utils.TestCase):
|
||||
project_domain_id='', project_domain_name='',
|
||||
user_domain_id='', user_domain_name='', profile=None,
|
||||
endpoint_override=None, insecure=False, cacert=None,
|
||||
version=api_versions.APIVersion('1.25'))
|
||||
version=api_versions.APIVersion('1.26'))
|
||||
|
||||
def test_main_option_region(self):
|
||||
self.make_env()
|
||||
self._test_main_region(
|
||||
'--zun-api-version 1.25 '
|
||||
'--zun-api-version 1.26 '
|
||||
'--os-region-name=myregion service-list', 'myregion')
|
||||
|
||||
def test_main_env_region(self):
|
||||
fake_env = dict(utils.FAKE_ENV, OS_REGION_NAME='myregion')
|
||||
self.make_env(fake_env=fake_env)
|
||||
self._test_main_region(
|
||||
'--zun-api-version 1.25 '
|
||||
'--zun-api-version 1.26 '
|
||||
'service-list', 'myregion')
|
||||
|
||||
def test_main_no_region(self):
|
||||
self.make_env()
|
||||
self._test_main_region(
|
||||
'--zun-api-version 1.25 '
|
||||
'--zun-api-version 1.26 '
|
||||
'service-list', None)
|
||||
|
||||
@mock.patch('zunclient.client.Client')
|
||||
def test_main_endpoint_public(self, mock_client):
|
||||
self.make_env()
|
||||
self.shell(
|
||||
'--zun-api-version 1.25 '
|
||||
'--zun-api-version 1.26 '
|
||||
'--endpoint-type publicURL service-list')
|
||||
mock_client.assert_called_once_with(
|
||||
username='username', password='password',
|
||||
@@ -284,13 +284,13 @@ class ShellTest(utils.TestCase):
|
||||
project_domain_id='', project_domain_name='',
|
||||
user_domain_id='', user_domain_name='', profile=None,
|
||||
endpoint_override=None, insecure=False, cacert=None,
|
||||
version=api_versions.APIVersion('1.25'))
|
||||
version=api_versions.APIVersion('1.26'))
|
||||
|
||||
@mock.patch('zunclient.client.Client')
|
||||
def test_main_endpoint_internal(self, mock_client):
|
||||
self.make_env()
|
||||
self.shell(
|
||||
'--zun-api-version 1.25 '
|
||||
'--zun-api-version 1.26 '
|
||||
'--endpoint-type internalURL service-list')
|
||||
mock_client.assert_called_once_with(
|
||||
username='username', password='password',
|
||||
@@ -300,7 +300,7 @@ class ShellTest(utils.TestCase):
|
||||
project_domain_id='', project_domain_name='',
|
||||
user_domain_id='', user_domain_name='', profile=None,
|
||||
endpoint_override=None, insecure=False, cacert=None,
|
||||
version=api_versions.APIVersion('1.25'))
|
||||
version=api_versions.APIVersion('1.26'))
|
||||
|
||||
|
||||
class ShellTestKeystoneV3(ShellTest):
|
||||
@@ -323,7 +323,7 @@ class ShellTestKeystoneV3(ShellTest):
|
||||
def test_main_endpoint_public(self, mock_client):
|
||||
self.make_env(fake_env=FAKE_ENV4)
|
||||
self.shell(
|
||||
'--zun-api-version 1.25 '
|
||||
'--zun-api-version 1.26 '
|
||||
'--endpoint-type publicURL service-list')
|
||||
mock_client.assert_called_once_with(
|
||||
username='username', password='password',
|
||||
@@ -334,4 +334,4 @@ class ShellTestKeystoneV3(ShellTest):
|
||||
user_domain_id='', user_domain_name='Default',
|
||||
endpoint_override=None, insecure=False, profile=None,
|
||||
cacert=None,
|
||||
version=api_versions.APIVersion('1.25'))
|
||||
version=api_versions.APIVersion('1.26'))
|
||||
|
91
zunclient/tests/unit/v1/test_quotas.py
Normal file
91
zunclient/tests/unit/v1/test_quotas.py
Normal file
@@ -0,0 +1,91 @@
|
||||
# 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 testtools
|
||||
|
||||
from zunclient.tests.unit import utils
|
||||
from zunclient.v1 import quotas
|
||||
|
||||
|
||||
DEFAULT_QUOTAS = {
|
||||
'containers': '40',
|
||||
'memory': '51200',
|
||||
'cpu': '20',
|
||||
'disk': '100'
|
||||
}
|
||||
|
||||
MODIFIED_QUOTAS = {
|
||||
'containers': '50',
|
||||
'memory': '51200',
|
||||
'cpu': '20',
|
||||
'disk': '100'
|
||||
}
|
||||
|
||||
MODIFIED_USAGE_QUOTAS = {
|
||||
'containers': {
|
||||
'limit': '50',
|
||||
'in_use': '30'
|
||||
},
|
||||
'memory': {},
|
||||
'cpu': {},
|
||||
'disk': {}
|
||||
}
|
||||
|
||||
fake_responses = {
|
||||
'/v1/quotas':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
MODIFIED_QUOTAS
|
||||
),
|
||||
'PUT': (
|
||||
{},
|
||||
MODIFIED_QUOTAS
|
||||
),
|
||||
'DELETE': (
|
||||
{},
|
||||
None
|
||||
)
|
||||
},
|
||||
'/v1/quotas/defaults':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
DEFAULT_QUOTAS
|
||||
)
|
||||
},
|
||||
'/v1/quotas?usages=True':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
MODIFIED_USAGE_QUOTAS
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class QuotaManagerTest(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(QuotaManagerTest, self).setUp()
|
||||
self.api = utils.FakeAPI(fake_responses)
|
||||
self.mgr = quotas.QuotaManager(self.api)
|
||||
|
||||
def test_quotas_get_defaults(self):
|
||||
quotas = self.mgr.defaults()
|
||||
expect = [
|
||||
('GET', '/v1/quotas/defaults', {}, None)
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(quotas.containers, DEFAULT_QUOTAS['containers'])
|
||||
self.assertEqual(quotas.memory, DEFAULT_QUOTAS['memory'])
|
||||
self.assertEqual(quotas.cpu, DEFAULT_QUOTAS['cpu'])
|
||||
self.assertEqual(quotas.disk, DEFAULT_QUOTAS['disk'])
|
@@ -23,6 +23,8 @@ from zunclient.v1 import capsules
|
||||
from zunclient.v1 import containers
|
||||
from zunclient.v1 import hosts
|
||||
from zunclient.v1 import images
|
||||
from zunclient.v1 import quota_classes
|
||||
from zunclient.v1 import quotas
|
||||
from zunclient.v1 import services
|
||||
from zunclient.v1 import versions
|
||||
|
||||
@@ -132,6 +134,8 @@ class Client(object):
|
||||
self.capsules = capsules.CapsuleManager(self.http_client)
|
||||
self.availability_zones = az.AvailabilityZoneManager(self.http_client)
|
||||
self.actions = actions.ActionManager(self.http_client)
|
||||
self.quotas = quotas.QuotaManager(self.http_client)
|
||||
self.quota_classes = quota_classes.QuotaClassManager(self.http_client)
|
||||
|
||||
@property
|
||||
def api_version(self):
|
||||
|
43
zunclient/v1/quota_classes.py
Normal file
43
zunclient/v1/quota_classes.py
Normal file
@@ -0,0 +1,43 @@
|
||||
# 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 zunclient.common import base
|
||||
|
||||
|
||||
class QuotaClass(base.Resource):
|
||||
def __repr__(self):
|
||||
return "<QuotaClass %s>" % self._info
|
||||
|
||||
|
||||
class QuotaClassManager(base.Manager):
|
||||
resource_class = QuotaClass
|
||||
|
||||
@staticmethod
|
||||
def _path(quota_class_name):
|
||||
return '/v1/quota_classes/{}' . format(quota_class_name)
|
||||
|
||||
def get(self, quota_class_name):
|
||||
return self._list(self._path(quota_class_name))[0]
|
||||
|
||||
def update(self, quota_class_name, containers=None,
|
||||
memory=None, cpu=None, disk=None):
|
||||
resources = {}
|
||||
if cpu is not None:
|
||||
resources['cpu'] = cpu
|
||||
if memory is not None:
|
||||
resources['memory'] = memory
|
||||
if containers is not None:
|
||||
resources['containers'] = containers
|
||||
if disk is not None:
|
||||
resources['disk'] = disk
|
||||
return self._update(self._path(quota_class_name),
|
||||
resources, method='PUT')
|
56
zunclient/v1/quota_classes_shell.py
Normal file
56
zunclient/v1/quota_classes_shell.py
Normal file
@@ -0,0 +1,56 @@
|
||||
# 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 zunclient.common import cliutils as utils
|
||||
|
||||
|
||||
@utils.arg(
|
||||
'--containers',
|
||||
metavar='<containers>',
|
||||
type=int,
|
||||
help='The number of containers allowed per project')
|
||||
@utils.arg(
|
||||
'--cpu',
|
||||
metavar='<cpu>',
|
||||
type=int,
|
||||
help='The number of container cores or vCPUs allowed per project')
|
||||
@utils.arg(
|
||||
'--memory',
|
||||
metavar='<memory>',
|
||||
type=int,
|
||||
help='The number of megabytes of container RAM allowed per project')
|
||||
@utils.arg(
|
||||
'--disk',
|
||||
metavar='<disk>',
|
||||
type=int,
|
||||
help='The number of gigabytes of container Disk allowed per project')
|
||||
@utils.arg(
|
||||
'quota_class_name',
|
||||
metavar='<quota_class_name>',
|
||||
help='The name of quota class')
|
||||
def do_quota_class_update(cs, args):
|
||||
"""Print an updated quotas for a quota class"""
|
||||
utils.print_dict(cs.quota_classes.update(
|
||||
args.quota_class_name,
|
||||
containers=args.containers,
|
||||
memory=args.memory,
|
||||
cpu=args.cpu,
|
||||
disk=args.disk)._info)
|
||||
|
||||
|
||||
@utils.arg(
|
||||
'quota_class_name',
|
||||
metavar='<quota_class_name>',
|
||||
help='The name of quota class')
|
||||
def do_quota_class_get(cs, args):
|
||||
"""Print a quotas for a quota class"""
|
||||
utils.print_dict(cs.quota_classes.get(args.quota_class_name)._info)
|
50
zunclient/v1/quotas.py
Normal file
50
zunclient/v1/quotas.py
Normal file
@@ -0,0 +1,50 @@
|
||||
# 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 zunclient.common import base
|
||||
|
||||
|
||||
class Quota(base.Resource):
|
||||
def __repr__(self):
|
||||
return "<Quota %s>" % self._info
|
||||
|
||||
|
||||
class QuotaManager(base.Manager):
|
||||
resource_class = Quota
|
||||
|
||||
@staticmethod
|
||||
def _path():
|
||||
return '/v1/quotas'
|
||||
|
||||
def get(self, **kwargs):
|
||||
if not kwargs.get('usages'):
|
||||
kwargs = {}
|
||||
return self._list(self._path(), qparams=kwargs)[0]
|
||||
|
||||
def update(self, containers=None, memory=None,
|
||||
cpu=None, disk=None):
|
||||
resources = {}
|
||||
if cpu is not None:
|
||||
resources['cpu'] = cpu
|
||||
if memory is not None:
|
||||
resources['memory'] = memory
|
||||
if containers is not None:
|
||||
resources['containers'] = containers
|
||||
if disk is not None:
|
||||
resources['disk'] = disk
|
||||
return self._update(self._path(), resources, method='PUT')
|
||||
|
||||
def defaults(self):
|
||||
return self._list(self._path() + '/defaults')[0]
|
||||
|
||||
def delete(self):
|
||||
return self._delete(self._path())
|
65
zunclient/v1/quotas_shell.py
Normal file
65
zunclient/v1/quotas_shell.py
Normal file
@@ -0,0 +1,65 @@
|
||||
# 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 zunclient.common import cliutils as utils
|
||||
|
||||
|
||||
@utils.arg(
|
||||
'--containers',
|
||||
metavar='<containers>',
|
||||
type=int,
|
||||
help='The number of containers allowed per project')
|
||||
@utils.arg(
|
||||
'--cpu',
|
||||
metavar='<cpu>',
|
||||
type=int,
|
||||
help='The number of container cores or vCPUs allowed per project')
|
||||
@utils.arg(
|
||||
'--memory',
|
||||
metavar='<memory>',
|
||||
type=int,
|
||||
help='The number of megabytes of container RAM allowed per project')
|
||||
@utils.arg(
|
||||
'--disk',
|
||||
metavar='<disk>',
|
||||
type=int,
|
||||
help='The number of gigabytes of container Disk allowed per project')
|
||||
def do_quota_update(cs, args):
|
||||
"""Print an updated quotas for a project"""
|
||||
utils.print_dict(cs.quotas.update(containers=args.containers,
|
||||
memory=args.memory,
|
||||
cpu=args.cpu,
|
||||
disk=args.disk)._info)
|
||||
|
||||
|
||||
@utils.arg(
|
||||
'--usages',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help='Whether show quota usage statistic or not')
|
||||
def do_quota_get(cs, args):
|
||||
"""Print a quotas for a project with usages (optional)"""
|
||||
if args.usages:
|
||||
utils.print_dict(cs.quotas.get(usages=args.usages)._info,
|
||||
value_fields=('limit', 'in_use'))
|
||||
else:
|
||||
utils.print_dict(cs.quotas.get(usages=args.usages)._info)
|
||||
|
||||
|
||||
def do_quota_defaults(cs, args):
|
||||
"""Print a default quotas for a project"""
|
||||
utils.print_dict(cs.quotas.defaults()._info)
|
||||
|
||||
|
||||
def do_quota_delete(cs, args):
|
||||
"""Delete quotas for a project"""
|
||||
cs.quotas.delete()
|
@@ -19,6 +19,8 @@ from zunclient.v1 import capsules_shell
|
||||
from zunclient.v1 import containers_shell
|
||||
from zunclient.v1 import hosts_shell
|
||||
from zunclient.v1 import images_shell
|
||||
from zunclient.v1 import quota_classes_shell
|
||||
from zunclient.v1 import quotas_shell
|
||||
from zunclient.v1 import services_shell
|
||||
from zunclient.v1 import versions_shell
|
||||
|
||||
@@ -31,4 +33,6 @@ COMMAND_MODULES = [
|
||||
versions_shell,
|
||||
capsules_shell,
|
||||
actions_shell,
|
||||
quotas_shell,
|
||||
quota_classes_shell,
|
||||
]
|
||||
|
Reference in New Issue
Block a user