Overall Program Flow

AwsLimitChecker provides the full and only public interface to this project; it’s used by the awslimitchecker command line script (entry point to runner) and should be the only portion directly used by external code.

Each AWS Service is represented by a subclass of the _AwsService abstract base class; these Service Classes are responsible for knowing which limits exist for the service they represent, what the default values for these limits are, querying current limits from the service’s API (if supported), and how to check the current usage via the AWS API (via boto). When the Service Classes are instantiated, they build a dict of all of their limits, correlating a string key (the “limit name”) with an AwsLimit object. The Service Class constructors must not make any network connections; connections are created lazily as needed and stored as a class attribute. This allows us to inspect the services, limits and default limit values without ever connecting to AWS (this is also used to generate the Supported Limits documentation automatically).

All calls to the AWS APIs should be made through boto_query_wrapper(). This function encapsulates both retrying queries with an exponential backoff when queries are throttled due to your account hitting the request rate limit (via invoke_with_throttling_retries()) and automatically paginating query responses that aren’t automatically handled by boto.

When AwsLimitChecker is instantiated, it imports services which in turn creates instances of all* classes and adds them to a dict mapping the string Service Name to the Service Class instance. These instances are used for all interaction with the services.

So, once an instance of AwsLimitChecker is created, we should have instant access to the services and limits without any connection to AWS. This is utilized by the --list-services and --list-defaults options for the command line client.

Trusted Advisor

When AwsLimitChecker is initialized, it also initializes an instance of TrustedAdvisor. In get_limits(), find_usage() and check_thresholds(), when called with use_ta == True (the default), update_limits() is called on the TrustedAdvisor instance.

update_limits() polls Trusted Advisor data is from the Support API via _poll(); this will retrieve the limits for all “flaggedResources” items in the Service Limits Trusted Advisor check result for the current AWS account. It then calls _update_services(), passing in the Trusted Advisor check results and the dict of _AwsService objects it was called with (from AwsLimitChecker).

_update_services() iterates over the Services in the Trusted Advisor check result and attempts to find a matching _AwsService (by string service name) in the dict passed in from AwsLimitChecker. If a match is found, it iterates over all limits for that service in the TA result and attempts to call the Service‘s _set_ta_limit() method. If a matching Service is not found, or if _set_ta_limit raises a ValueError (matching Limit not found for that Service), an error is logged.

Using this methodology, no additional code is needed to support new/additional Trusted Advisor limit checks; so long as the Service and Limit name strings match between the Trusted Advisor API response and their corresponding _AwsService and AwsLimit instances, the TA limits will be automatically added to the corresponding AwsLimit.

Service API Limit Information

Some services provide API calls to retrieve at least some of the current limits, such as the DescribeAccountAttributes API calls for RDS and EC2. Services that support such calls should make them in a _update_limits_from_api() method, which will be automatically called from get_limits(). The _update_limits_from_api() method should make the API call, and then update all relevant limits via the AwsLimit class’s _set_api_limit() method.

Limit Value Precedence

The value used for a limit is the first match in the following list:

  1. Limit Override (set at runtime)
  2. API Limit
  3. Trusted Advisor
  4. Hard-coded default