Skip to content

Commit

Permalink
fixes #17 - VPC service
Browse files Browse the repository at this point in the history
  • Loading branch information
jantman committed Jun 20, 2015
1 parent c8bb60c commit 4fe1179
Show file tree
Hide file tree
Showing 10 changed files with 717 additions and 22 deletions.
1 change: 1 addition & 0 deletions awslimitchecker/services/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

from awslimitchecker.services.base import _AwsService
from awslimitchecker.services.ec2 import _Ec2Service
from awslimitchecker.services.vpc import _VpcService

# dynamically generate the service name to class dict
_services = {}
Expand Down
41 changes: 41 additions & 0 deletions awslimitchecker/services/addservice
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env python

import os
import sys
import argparse
import re

def service_from_template(sname, sname_lower):
svc_dir = os.path.dirname(os.path.abspath(__file__))
with open(os.path.join(svc_dir, 'newservice.py.example'), 'r') as fh:
tmpl = fh.read()
tmpl = tmpl.replace('XXnewserviceXX', sname_lower)
tmpl = tmpl.replace('XXNewServiceXX', sname)
fname = '{s}.py'.format(s=sname_lower)
print("Writing {f}".format(f=fname))
with open(os.path.join(svc_dir, fname), 'w') as fh:
fh.write(tmpl)

def test_from_template(sname, sname_lower):
test_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'tests', 'services')
with open(os.path.join(test_dir, 'test_newservice.py.example'), 'r') as fh:
tmpl = fh.read()
tmpl = tmpl.replace('XXnewserviceXX', sname_lower)
tmpl = tmpl.replace('XXNewServiceXX', sname)
fname = 'test_{s}.py'.format(s=sname_lower)
print("Writing {f}".format(f=fname))
with open(os.path.join(test_dir, fname), 'w') as fh:
fh.write(tmpl)

if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Add a new service to awslimitchecker')
parser.add_argument('service_name', type=str, help='The name of the AWS service, in CamelCase')
args = parser.parse_args()
name_re = r'^[A-Za-z_]+$'
if not re.match(name_re, args.service_name):
sys.stderr.write('ERROR: service_name must match {r}\n'.format(r=name_re))
raise SystemExit(1)
svc_name = args.service_name.capitalize()
svc_name_lower = svc_name.lower()
service_from_template(svc_name, svc_name_lower)
test_from_template(svc_name, svc_name_lower)
12 changes: 7 additions & 5 deletions awslimitchecker/services/newservice.py.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
awslimitchecker/services/NewService.py
awslimitchecker/services/XXnewserviceXX.py

The latest version of this package is available at:
<https://github.com/jantman/awslimitchecker>
Expand Down Expand Up @@ -47,16 +47,16 @@ from ..limit import AwsLimit
logger = logging.getLogger(__name__)


class _NewServiceService(_AwsService):
class _XXNewServiceXXService(_AwsService):

service_name = 'NewService'
service_name = 'XXNewServiceXX'

def connect(self):
if self.conn is None:
logger.debug("Connecting to {n}".format(
n=self.service_name))
# TODO: set this to the correct connection method:
self.conn = boto.connect_NewService()
self.conn = boto.connect_XXNewServiceXX()
logger.info("Connected to {n}".format(
n=self.service_name))

Expand All @@ -77,6 +77,7 @@ class _NewServiceService(_AwsService):
u_id = (resource id from AWS)
self.limits['Number of u']._add_current_usage(u, aws_type='U', id=u_id)
"""
self._have_usage = True
logger.debug("Done checking usage.")

def get_limits(self):
Expand All @@ -102,6 +103,7 @@ class _NewServiceService(_AwsService):
)

"""
self.limits = limits
return limits

def required_iam_permissions(self):
Expand All @@ -115,5 +117,5 @@ class _NewServiceService(_AwsService):
"""
# TODO: update this to be all IAM permissions required for find_usage() to work
return [
"NewService:SomeAction",
"XXNewServiceXX:SomeAction",
]
219 changes: 219 additions & 0 deletions awslimitchecker/services/vpc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
"""
awslimitchecker/services/vpc.py
The latest version of this package is available at:
<https://github.com/jantman/awslimitchecker>
################################################################################
Copyright 2015 Jason Antman <jason@jasonantman.com> <http://www.jasonantman.com>
This file is part of awslimitchecker, also known as awslimitchecker.
awslimitchecker is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
awslimitchecker is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with awslimitchecker. If not, see <http://www.gnu.org/licenses/>.
The Copyright and Authors attributions contained herein may not be removed or
otherwise altered, except to add the Author attribution of a contributor to
this work. (Additional Terms pursuant to Section 7b of the AGPL v3)
################################################################################
While not legally required, I sincerely request that anyone who finds
bugs please submit them at <https://github.com/jantman/awslimitchecker> or
to me via email, and that you send any contributions or improvements
either as a pull request on GitHub, or to me via email.
################################################################################
AUTHORS:
Jason Antman <jason@jasonantman.com> <http://www.jasonantman.com>
################################################################################
"""

import abc # noqa
import boto
import logging
from collections import defaultdict

from .base import _AwsService
from ..limit import AwsLimit

logger = logging.getLogger(__name__)


class _VpcService(_AwsService):

service_name = 'VPC'

def connect(self):
if self.conn is None:
logger.debug("Connecting to {n}".format(
n=self.service_name))
self.conn = boto.connect_vpc()
logger.info("Connected to {n}".format(
n=self.service_name))

def find_usage(self):
"""
Determine the current usage for each limit of this service,
and update corresponding Limit via
:py:meth:`~.AwsLimit._add_current_usage`.
"""
logger.debug("Checking usage for service {n}".format(
n=self.service_name))
self.connect()
for lim in self.limits.values():
lim._reset_usage()

# overall number of VPCs
vpcs = self.conn.get_all_vpcs()
self.limits['VPCs']._add_current_usage(
len(vpcs),
aws_type='AWS::EC2::VPC'
)

# subnets per VPC
subnets = defaultdict(int)
for subnet in self.conn.get_all_subnets():
# boto.vpc.subnet.Subnet
subnets[subnet.vpc_id] += 1
for vpc_id in subnets:
self.limits['Subnets per VPC']._add_current_usage(
subnets[vpc_id],
aws_type='AWS::EC2::VPC',
id=vpc_id
)

# Network ACLs per VPC
acls = defaultdict(int)
for acl in self.conn.get_all_network_acls():
# boto.vpc.networkacl.NetworkAcl
acls[acl.vpc_id] += 1
# Rules per network ACL
self.limits['Rules per network ACL']._add_current_usage(
len(acl.network_acl_entries),
aws_type='AWS::EC2::NetworkAcl',
id=acl.id
)
for vpc_id in acls:
self.limits['Network ACLs per VPC']._add_current_usage(
acls[vpc_id],
aws_type='AWS::EC2::VPC',
id=vpc_id,
)

# Route tables per VPC
tables = defaultdict(int)
for table in self.conn.get_all_route_tables():
# boto.vpc.routetable.RouteTable
tables[table.vpc_id] += 1
# Entries per route table
self.limits['Entries per route table']._add_current_usage(
len(table.routes),
aws_type='AWS::EC2::RouteTable',
id=table.id
)
for vpc_id in tables:
self.limits['Route tables per VPC']._add_current_usage(
tables[vpc_id],
aws_type='AWS::EC2::VPC',
id=vpc_id,
)
self._have_usage = True
logger.debug("Done checking usage.")

def get_limits(self):
"""
Return all known limits for this service, as a dict of their names
to :py:class:`~.AwsLimit` objects.
:returns: dict of limit names to :py:class:`~.AwsLimit` objects
:rtype: dict
"""
if self.limits != {}:
return self.limits
limits = {}

limits['VPCs'] = AwsLimit(
'VPCs',
self,
5,
self.warning_threshold,
self.critical_threshold,
limit_type='AWS::EC2::VPC',
)

limits['Subnets per VPC'] = AwsLimit(
'Subnets per VPC',
self,
200,
self.warning_threshold,
self.critical_threshold,
limit_type='AWS::EC2::Subnet',
limit_subtype='AWS::EC2::VPC',
)

limits['Network ACLs per VPC'] = AwsLimit(
'Network ACLs per VPC',
self,
200,
self.warning_threshold,
self.critical_threshold,
limit_type='AWS::EC2::NetworkAcl',
limit_subtype='AWS::EC2::VPC',
)

limits['Rules per network ACL'] = AwsLimit(
'Rules per network ACL',
self,
20,
self.warning_threshold,
self.critical_threshold,
limit_type='AWS::EC2::NetworkAclEntry',
limit_subtype='AWS::EC2::NetworkAcl',
)

limits['Route tables per VPC'] = AwsLimit(
'Route tables per VPC',
self,
200,
self.warning_threshold,
self.critical_threshold,
limit_type='AWS::EC2::RouteTable',
limit_subtype='AWS::EC2::VPC',
)

limits['Entries per route table'] = AwsLimit(
'Entries per route table',
self,
50,
self.warning_threshold,
self.critical_threshold,
limit_type='AWS::EC2::Route',
limit_subtype='AWS::EC2::RouteTable',
)
self.limits = limits
return limits

def required_iam_permissions(self):
"""
Return a list of IAM Actions required for this Service to function
properly. All Actions will be shown with an Effect of "Allow"
and a Resource of "*".
:returns: list of IAM Action strings
:rtype: list
"""
return [
'ec2:DescribeNetworkAcls',
'ec2:DescribeRouteTables',
'ec2:DescribeSubnets',
'ec2:DescribeVpcs',
]

0 comments on commit 4fe1179

Please sign in to comment.