Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #384 - Add a percentage and current limit when running in report mode #587

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions awslimitchecker/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# The idea of this file is to enable running the package with
# `python -m awslimitchecker` or `python -m awslimitchecker [args]`.
# This enables debugging the package when installed in editable mode
# (`pip install -e .`) and running the package from the command line.

import sys

from . import runner


def main(args=None):
if args is None:
args = sys.argv[1:]
# Parse arguments and run your package's main functionality
print("Running awslimitchecker with arguments:", args)
runner.console_entry_point()


if __name__ == "__main__":
main()
3 changes: 1 addition & 2 deletions awslimitchecker/limit.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,9 +431,8 @@ class instance. Return True if usage is within thresholds, or false if
limit = u.get_maximum() or self.get_limit()
if limit is None or limit == 0:
continue
pct = (usage / (limit * 1.0)) * 100
pct = (usage / limit) * 100
if crit_int is not None and usage >= crit_int:
self._criticals.append(u)
all_ok = False
elif pct >= crit_pct:
self._criticals.append(u)
Expand Down
41 changes: 31 additions & 10 deletions awslimitchecker/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,20 @@
##############################################################################
"""

import sys
import argparse
import logging
import json
import boto3
import logging
import sys
import time

import boto3
import tabulate

from .alerts import AlertProvider
from .checker import AwsLimitChecker
from .utils import StoreKeyValuePair, dict2cols, issue_string_tuple
from .limit import SOURCE_TA, SOURCE_API, SOURCE_QUOTAS
from .limit import SOURCE_API, SOURCE_QUOTAS, SOURCE_TA
from .metrics import MetricsProvider
from .alerts import AlertProvider
from .utils import StoreKeyValuePair, dict2cols, issue_string_tuple

try:
from urllib.parse import urlparse
Expand Down Expand Up @@ -319,12 +321,31 @@ def show_usage(self):
service=self.service_name, use_ta=(not self.skip_ta))
limits = self.checker.get_limits(
service=self.service_name, use_ta=(not self.skip_ta))
data = {}
headers = ['Service Limit', 'Resource', 'Usage #', 'Usage %', 'Limit']
table = []
for svc in sorted(limits.keys()):
for lim in sorted(limits[svc].keys()):
data["{s}/{l}".format(s=svc, l=lim)] = '{v}'.format(
v=limits[svc][lim].get_current_usage_str())
print(dict2cols(data))
data = limits[svc][lim]
for usage in data.get_current_usage():
service = svc
limit_name = lim
resource = usage.resource_id or '-'
limit = "<unknown>"
if data.quotas_limit:
limit = int(data.quotas_limit)
use = usage.value
use_percent = "-"
if isinstance(limit, (int, float)):
use_percent = "{:.0f} %".format((use / limit) * 100)
table.append([
f"{service}/{limit_name}",
resource,
str(use),
use_percent,
str(limit),
])
print(tabulate.tabulate(
table, headers=headers, tablefmt="simple_outline"))

def check_thresholds(self, metrics=None):
have_warn = False
Expand Down
72 changes: 46 additions & 26 deletions awslimitchecker/tests/test_limit.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,23 +602,33 @@ def test_int_warn(self):
assert mock_get_limit.mock_calls == [call(), call(), call()]

def test_int_warn_crit(self):
limit = AwsLimit('limitname', self.mock_svc, 100, 1, 2)
u1 = AwsLimitUsage(limit, 4, resource_id='foo4bar')
u2 = AwsLimitUsage(limit, 1, resource_id='foo3bar')
u3 = AwsLimitUsage(limit, 7, resource_id='foo2bar')
limit = AwsLimit(
name='limitname',
service=self.mock_svc,
default_limit=10,
def_warning_threshold=40,
def_critical_threshold=60,
)
u1 = AwsLimitUsage(
limit=limit,
value=4,
resource_id='foo4bar',
)
u2 = AwsLimitUsage(
limit=limit,
value=1,
resource_id='foo3bar',
)
u3 = AwsLimitUsage(
limit=limit,
value=7,
resource_id='foo2bar',
)
limit._current_usage = [u1, u2, u3]
with patch('awslimitchecker.limit.AwsLimit.'
'_get_thresholds') as mock_get_thresh:
with patch('awslimitchecker.limit.AwsLimit.get_'
'limit') as mock_get_limit:
mock_get_thresh.return_value = (4, 40, 6, 80)
mock_get_limit.return_value = 100
res = limit.check_thresholds()
res = limit.check_thresholds()
assert res is False
assert limit._warnings == [u1]
assert limit._criticals == [u3]
assert mock_get_thresh.mock_calls == [call()]
assert mock_get_limit.mock_calls == [call(), call(), call()]

def test_pct_crit(self):
limit = AwsLimit('limitname', self.mock_svc, 100, 1, 2)
Expand All @@ -640,23 +650,33 @@ def test_pct_crit(self):
assert mock_get_limit.mock_calls == [call(), call(), call()]

def test_int_crit(self):
limit = AwsLimit('limitname', self.mock_svc, 100, 1, 2)
u1 = AwsLimitUsage(limit, 9, resource_id='foo4bar')
u2 = AwsLimitUsage(limit, 3, resource_id='foo3bar')
u3 = AwsLimitUsage(limit, 95, resource_id='foo2bar')
limit = AwsLimit(
name='limitname',
service=self.mock_svc,
default_limit=10,
def_warning_threshold=60,
def_critical_threshold=80,
)
u1 = AwsLimitUsage(
limit=limit,
value=9,
resource_id='foo4bar',
)
u2 = AwsLimitUsage(
limit=limit,
value=3,
resource_id='foo3bar',
)
u3 = AwsLimitUsage(
limit=limit,
value=95,
resource_id='foo2bar',
)
limit._current_usage = [u1, u2, u3]
with patch('awslimitchecker.limit.AwsLimit.'
'_get_thresholds') as mock_get_thresh:
with patch('awslimitchecker.limit.AwsLimit.get_'
'limit') as mock_get_limit:
mock_get_thresh.return_value = (6, 40, 8, 80)
mock_get_limit.return_value = 100
res = limit.check_thresholds()
res = limit.check_thresholds()
assert res is False
assert limit._warnings == []
assert limit._criticals == [u1, u3]
assert mock_get_thresh.mock_calls == [call()]
assert mock_get_limit.mock_calls == [call(), call(), call()]

def test_pct_warn_crit(self):
limit = AwsLimit('limitname', self.mock_svc, 100, 1, 2)
Expand Down
49 changes: 21 additions & 28 deletions awslimitchecker/tests/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -769,22 +769,18 @@ def test_default(self, capsys):
mock_checker = Mock(spec_set=AwsLimitChecker)
mock_checker.get_limits.return_value = limits
self.cls.checker = mock_checker
with patch('awslimitchecker.runner.dict2cols') as mock_d2c:
mock_d2c.return_value = 'd2cval'
with patch('awslimitchecker.runner.tabulate') as mock_tabulate:
self.cls.show_usage()
out, err = capsys.readouterr()
assert out == 'd2cval\n'
assert mock_checker.mock_calls == [
call.find_usage(service=None, use_ta=True),
call.get_limits(service=None, use_ta=True)
]
assert mock_d2c.mock_calls == [
call({
'SvcBar/bar limit2': '22',
'SvcBar/barlimit1': '11',
'SvcFoo/foo limit3': '33',
})
]
assert mock_checker.mock_calls == [
call.find_usage(service=None, use_ta=True),
call.get_limits(service=None, use_ta=True)
]
assert len(mock_tabulate.method_calls) == 1
assert mock_tabulate.method_calls[0].args == ([
['SvcBar/bar limit2', '-', '22', '-', '<unknown>'],
['SvcBar/barlimit1', '-', '11', '-', '<unknown>'],
['SvcFoo/foo limit3', '-', '33', '-', '<unknown>']
],)

def test_one_service(self, capsys):
limits = {
Expand All @@ -796,20 +792,17 @@ def test_one_service(self, capsys):
self.cls.checker = mock_checker
self.cls.service_name = ['SvcFoo']
self.cls.skip_ta = True
with patch('awslimitchecker.runner.dict2cols') as mock_d2c:
mock_d2c.return_value = 'd2cval'
with patch('awslimitchecker.runner.tabulate') as mock_tabulate:
self.cls.show_usage()
out, err = capsys.readouterr()
assert out == 'd2cval\n'
assert mock_checker.mock_calls == [
call.find_usage(service=['SvcFoo'], use_ta=False),
call.get_limits(service=['SvcFoo'], use_ta=False)
]
assert mock_d2c.mock_calls == [
call({
'SvcFoo/foo limit3': '33',
})
]
out, err = capsys.readouterr()
assert mock_checker.mock_calls == [
call.find_usage(service=['SvcFoo'], use_ta=False),
call.get_limits(service=['SvcFoo'], use_ta=False)
]
assert len(mock_tabulate.method_calls) == 1
assert mock_tabulate.method_calls[0].args == (
[['SvcFoo/foo limit3', '-', '33', '-', '<unknown>']],
)


class TestCheckThresholds(RunnerTester):
Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@
'python-dateutil',
'versionfinder>=0.1.1',
'pytz',
'urllib3'
'urllib3',
'tabulate>=0.9.0',
]

classifiers = [
Expand Down