Skip to content
This repository has been archived by the owner on Feb 2, 2021. It is now read-only.

Commit

Permalink
Merge pull request #27 from ZuzanaLietavcova/my_sgmanager
Browse files Browse the repository at this point in the history
PAAS-11126 Add sgmanager-config PR check
  • Loading branch information
Petr Benas authored Aug 31, 2017
2 parents 63a8f4d + f6ca03e commit c0efc53
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 32 deletions.
11 changes: 8 additions & 3 deletions sgmanager/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class ThresholdException(Exception):
friendly = True
pass


class SGManager(object):
def __init__(self, ec2_connection=None, vpc=False, only_groups=[]):
"""
Expand All @@ -27,16 +28,19 @@ def __init__(self, ec2_connection=None, vpc=False, only_groups=[]):
"""
global ec2

if not ec2_connection:
if isinstance(ec2_connection, boto.ec2.connection.EC2Connection):
# Use supplied connection
ec2 = ec2_connection
elif ec2_connection:
# Try to connect on our own
try:
ec2 = boto.connect_ec2()
except boto.exception.NoAuthHandlerFound as e:
e.friendly = True
raise
else:
# Try to connect on our own
ec2 = ec2_connection
# Continue without connection
ec2 = None

if vpc:
lg.debug("Working only with VPC security groups")
Expand Down Expand Up @@ -89,6 +93,7 @@ def load_local_groups(self, config, mode):
"""
self.local = SecurityGroups(vpc=self.vpc, only_groups=self.only_groups)
self.local.load_local_groups(config, mode)
self.local.check_validity()
return self.local

def dump_remote_groups(self):
Expand Down
51 changes: 31 additions & 20 deletions sgmanager/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import boto

from sgmanager import SGManager
from sgmanager.exceptions import InvalidConfiguration
import sgmanager.logger

lg_root = sgmanager.logger.init(name='', syslog=False)
Expand Down Expand Up @@ -38,7 +39,7 @@ def cli():
Main CLI entrance
"""
parser = argparse.ArgumentParser(description='Security groups management tool')
parser.add_argument('-c', '--config', help='Config file to use')
parser.add_argument('-c', '--config', help='Config file to use', required=True)
parser.add_argument('--vpc', action='store_true', help='Work with VPC groups, otherwise only non-VPC')
parser.add_argument('--dump', action='store_true', help='Dump remote groups and exit')
parser.add_argument('--unused', action='store_true', help='Dump groups not used by any instance')
Expand All @@ -58,6 +59,7 @@ def cli():
parser.add_argument('--insecure', action='store_true', help='Do not validate SSL certs')
parser.add_argument('--threshold', help='Maximum threshold to use for add/rm of groups/rules in percentage (default: 15)', default=15)
parser.add_argument('--cert', help='Path to CA certificates (eg. /etc/pki/cacert.pem)')
parser.add_argument('--validate', action='store_true', help='Dry-run, validates the config file')
args = parser.parse_args()

if args.quiet:
Expand All @@ -71,9 +73,36 @@ def cli():
lg.setLevel(logging.DEBUG)
lg_root.setLevel(logging.DEBUG)

mode = None
if args.mode in ('a', 'ascii'):
mode = 'ascii'
elif args.mode in ('s', 'strict'):
mode = 'strict'
elif args.mode in ('v', 'vpc') or args.vpc:
mode = 'vpc'

if not mode:
lg.error('Invalid mode "%s" selected' % args.mode)
sys.exit(1)

# Initialize SGManager
ec2 = connect_ec2(args)
if not args.validate:
ec2 = connect_ec2(args)
else:
ec2 = None
args.only_groups = None

manager = SGManager(ec2, vpc=args.vpc, only_groups=args.only_groups)

try:
manager.load_local_groups(args.config, mode)
except InvalidConfiguration as e:
lg.error("Invalid config file: %s" %e)
sys.exit(1)

if args.validate:
sys.exit(0)

manager.load_remote_groups()

if args.dump:
Expand All @@ -91,24 +120,6 @@ def cli():
manager.remove_unused_groups(dry=not args.force)
sys.exit(0)

if not args.config:
lg.error('No config file supplied')
sys.exit(1)

mode = False
if args.mode in ('a', 'ascii'):
mode = 'ascii'
if args.mode in ('s', 'strict'):
mode = 'strict'
if args.mode in ('v', 'vpc') or args.vpc:
mode = 'vpc'

if not mode:
lg.error('Invalid mode "%s" selected' % args.mode)
sys.exit(1)

manager.load_local_groups(args.config, mode)

# Parameters for manager.apply_diff()
params = {
'dry' : not args.force,
Expand Down
45 changes: 36 additions & 9 deletions sgmanager/securitygroups/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,14 @@ def __init__(self, vpc=False, only_groups=[]):

self.groups = {}
self.config = None
try:
self.owner_id = ec2.get_all_security_groups('default')[0].owner_id
lg.debug("Default owner id: %s" % self.owner_id)
except Exception as e:
lg.error("Can't load default security group to lookup owner id: %s" % e)
self.owner_id = None
if ec2:
try:
self.owner_id = ec2.get_all_security_groups('default')[0].owner_id
lg.debug("Default owner id: %s" % self.owner_id)
except Exception as e:
lg.error("Can't load default security group to lookup"
"owner id: %s" % e)

def load_remote_groups(self):
"""
Expand Down Expand Up @@ -133,15 +136,19 @@ def load_local_groups(self, config, mode):
raise InvalidConfiguration("Can't parse config file %s: error at line %s, column %s" % (config, mark.line+1, mark.column+1))
else:
raise InvalidConfiguration("Can't parse config file %s: %s" % (config, e))
# Empty config file is considered invalid
if not conf:
raise InvalidConfiguration("Config file %s is empty" % config)

# Remove include keys
conf = self._fix_include(conf)

lg.debug("Loading local groups")
for name, group in conf.iteritems():
if not self.only_groups or name in self.only_groups:
# Initialize SGroup object
self.groups[name] = self._load_sgroup(name, group, check_mode=mode)
if isinstance(conf, dict):
for name, group in conf.iteritems():
if not self.only_groups or name in self.only_groups:
# Initialize SGroup object
self.groups[name] = self._load_sgroup(name, group, check_mode=mode)

return self.groups

Expand Down Expand Up @@ -365,6 +372,26 @@ def compare(self, other):

return added, removed, updated, unchanged

def check_validity(self):
"""
Checks if groups mentioned in the rules are defined
and if ip address is in the correct format (including mask)
"""
for name, ref in self.groups.iteritems():
for rule in ref.rules:
for group in rule.groups:
if not self.has_group(group['name']):
raise InvalidConfiguration("Group %s referenced by "
"group %s does not exist in the config file"
% (group['name'], name))
if rule.cidr:
for ip in rule.cidr:
if not re.match('^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.'
'([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.'
'([01]?\\d\\d?|2[0-4]\\d|25[0-5])\/(\\d|[1-2]\\d|3[0-2])$', ip):
raise InvalidConfiguration("Wrong format of ip address '%s' "
"in the config file" % ip)


class YamlDumper(yaml.SafeDumper):
"""
Expand Down

0 comments on commit c0efc53

Please sign in to comment.