Skip to content

Commit

Permalink
Adding simple, scalar parameters for authorize/revoke operations that…
Browse files Browse the repository at this point in the history
… mimic the legacy CLI.
  • Loading branch information
garnaat committed Aug 5, 2013
1 parent d15015a commit d07ac23
Show file tree
Hide file tree
Showing 4 changed files with 278 additions and 0 deletions.
40 changes: 40 additions & 0 deletions awscli/customizations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,43 @@
all customizations and register them without having to manually edit
``handlers.py`` each time.
"""
from awscli.clidriver import BaseCLIArgument


class CustomArgument(BaseCLIArgument):

Documentation = 'Documentation goes here'

def __init__(self, operation, name, cli_type_name='string',
documentation=None, default=None):
super(CustomArgument, self).__init__(
name, argument_object=None)
self._operation = operation
self._name = name
self._cli_type_name = cli_type_name
self._documentation = documentation
self._default = default

@property
def cli_name(self):
return '--' + self._name

@property
def cli_type_name(self):
return self._cli_type_name

@property
def required(self):
return False

@property
def documentation(self):
return self._documentation

def add_to_parser(self, parser, cli_name=None):
parser.add_argument(self.cli_name, dest=self._name,
default=self._default)

def add_to_params(self, parameters, value):
pass

150 changes: 150 additions & 0 deletions awscli/customizations/ec2secgroupsimplify.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file 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.
"""
This customization adds the following scalar parameters to the
authorize operations:
* --protocol: tcp | udp | icmp or any protocol number
* --port: A single integer or a range (min-max). You can specify ``all``
to mean all ports (for example, port range 0-65535)
* --source-group-name
* --source-group-id
* --cidr - The CIDR range. Cannot be used when specifying a source or
destination security group.
"""
import logging

from awscli.customizations import CustomArgument


logger = logging.getLogger(__name__)

EVENTS = [
'building-argument-table.ec2.AuthorizeSecurityGroupIngress',
'building-argument-table.ec2.AuthorizeSecurityGroupEgress',
'building-argument-table.ec2.RevokeSecurityGroupIngress',
'building-argument-table.ec2.RevokeSecurityGroupEgress'
]
PROTOCOL_DOCS = ('<p>The IP protocol of this permission.</p>'
'<p>Valid protocol values: <code>tcp</code>, '
'<code>udp</code>, <code>icmp</code></p>')
PORT_DOCS = ('<p>For TCP or UDP: The range of ports to allow.'
' A single integer or a range (min-max). You can '
'specify <code>all</code> to mean all ports</p>')
CIDR_DOCS = '<p>The CIDR IP range.</p>'
SOURCEGROUP_DOCS = ('<p>The name of the source security group. '
'Cannot be used when specifying a CIDR IP address.')
GROUPOWNER_DOCS = ('<p>The AWS account ID that owns the source security '
'group. Cannot be used when specifying a CIDR IP '
'address.</p>')

def register_secgroup(event_handler):
for event in EVENTS:
event_handler.register(event, _add_params)


def _build_ip_permissions(params, key, value):
logger.debug('_build_ip_permissions: %s=%s', key, value)
if 'ip_permissions' not in params:
params['ip_permissions'] = [{}]
if key == 'CidrIp':
if 'IpRanges' not in params['ip_permissions'][0]:
params['ip_permissions'][0]['IpRanges'] = []
params['ip_permissions'][0]['IpRanges'].append(value)
elif key in ('GroupId', 'GroupName', 'UserId'):
if 'UserIdGroupPairs' not in params['ip_permissions'][0]:
params['ip_permissions'][0]['UserIdGroupPairs'] = [{}]
params['ip_permissions'][0]['UserIdGroupPairs'][0][key] = value
else:
params['ip_permissions'][0][key] = value


def _add_params(argument_table, operation, **kwargs):
arg = ProtocolArgument(operation, 'protocol',
documentation=PROTOCOL_DOCS)
argument_table['protocol'] = arg
arg = PortArgument(operation, 'port', documentation=PORT_DOCS)
argument_table['port'] = arg
arg = CidrArgument(operation, 'cidr', documentation=CIDR_DOCS)
argument_table['cidr'] = arg
arg = SourceGroupArgument(operation, 'source-group',
documentation=SOURCEGROUP_DOCS)
argument_table['source-group'] = arg
arg = GroupOwnerArgument(operation, 'group-owner',
documentation=GROUPOWNER_DOCS)
argument_table['group-owner'] = arg


class ProtocolArgument(CustomArgument):

def add_to_params(self, parameters, value):
if value:
try:
int_value = int(value)
if int_value < 0 or int_value > 255:
msg = ('protocol numbers must be in the range 0-255')
raise ValueError(msg)
except ValueError:
if value not in ('tcp', 'udp', 'icmp'):
msg = ('protocol parameter should be one of: '
'tcp|udp|icmp or any valid protocol number.')
raise ValueError(msg)
_build_ip_permissions(parameters, 'IpProtocol', value)


class PortArgument(CustomArgument):

def add_to_params(self, parameters, value):
logger.debug('PortArgument value=%s', value)
if value:
try:
if value == '-1' or value == 'all':
fromstr = '-1'
tostr = '-1'
elif '-' in value:
fromstr, tostr = value.split('-')
else:
fromstr, tostr = (value, value)
_build_ip_permissions(parameters, 'FromPort', int(fromstr))
_build_ip_permissions(parameters, 'ToPort', int(tostr))
except ValueError:
msg = ('port parameter should be of '
'form from[-to] (e.g. 22 or 22-25)')
raise ValueError(msg)


class CidrArgument(CustomArgument):

def add_to_params(self, parameters, value):
if value:
value = [{'CidrIp': value}]
_build_ip_permissions(parameters, 'IpRanges', value)


class SourceGroupArgument(CustomArgument):

def add_to_params(self, parameters, value):
if value:
if value.startswith('sg-'):
_build_ip_permissions(parameters, 'GroupId', value)
else:
_build_ip_permissions(parameters, 'GroupName', value)


class GroupOwnerArgument(CustomArgument):

def add_to_params(self, parameters, value):
if value:
_build_ip_permissions(parameters, 'UserId', value)


2 changes: 2 additions & 0 deletions awscli/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from awscli.customizations.ec2addcount import ec2_add_count
from awscli.customizations.paginate import unify_paging_params
from awscli.customizations.ec2decryptpassword import ec2_add_priv_launch_key
from awscli.customizations.ec2secgroupsimplify import register_secgroup


def awscli_initialize(event_handlers):
Expand All @@ -47,4 +48,5 @@ def awscli_initialize(event_handlers):
unify_paging_params)
event_handlers.register('building-argument-table.ec2.GetPasswordData',
ec2_add_priv_launch_key)
register_secgroup(event_handlers)
register_removals(event_handlers)
86 changes: 86 additions & 0 deletions tests/unit/ec2/test_security_group_operations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#!/usr/bin/env python
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file 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 tests.unit import BaseAWSCommandParamsTest


class TestAuthorizeSecurityGroupIngress(BaseAWSCommandParamsTest):

prefix = 'ec2 authorize-security-group-ingress'

def test_simple_cidr(self):
args = ' --group-name foobar --protocol tcp --port 22-25 --cidr 0.0.0.0/0'
args_list = (self.prefix + args).split()
result = {'GroupName': 'foobar',
'IpPermissions.1.FromPort': '22',
'IpPermissions.1.ToPort': '25',
'IpPermissions.1.IpProtocol': 'tcp',
'IpPermissions.1.IpRanges.1.CidrIp': '0.0.0.0/0'}
self.assert_params_for_cmd(args_list, result)

def test_all_port(self):
args = ' --group-name foobar --protocol tcp --port all --cidr 0.0.0.0/0'
args_list = (self.prefix + args).split()
result = {'GroupName': 'foobar',
'IpPermissions.1.FromPort': '-1',
'IpPermissions.1.ToPort': '-1',
'IpPermissions.1.IpProtocol': 'tcp',
'IpPermissions.1.IpRanges.1.CidrIp': '0.0.0.0/0'}
self.assert_params_for_cmd(args_list, result)

def test_classic_group(self):
args = ' --group-name foobar --protocol udp --source-group fiebaz --group-owner 11111111'
args_list = (self.prefix + args).split()
result = {'GroupName': 'foobar',
'IpPermissions.1.Groups.1.GroupName': 'fiebaz',
'IpPermissions.1.IpProtocol': 'udp',
'IpPermissions.1.Groups.1.UserId': '11111111'}
self.assert_params_for_cmd(args_list, result)

def test_vpc_group(self):
args = ' --group-name foobar --protocol icmp --source-group sg-12345678'
args_list = (self.prefix + args).split()
result = {'GroupName': 'foobar',
'IpPermissions.1.Groups.1.GroupId': 'sg-12345678',
'IpPermissions.1.IpProtocol': 'icmp'}
self.assert_params_for_cmd(args_list, result)

def test_ip_permissions(self):
json = """[{"FromPort":8000,"ToPort":9000,"IpProtocol":"tcp","IpRanges":[{"CidrIp":"192.168.100.0/24"}]}]"""
args = ' --group-name foobar --ip-permissions %s' % json
args_list = (self.prefix + args).split()
result = {'GroupName': 'foobar',
'IpPermissions.1.FromPort': '8000',
'IpPermissions.1.ToPort': '9000',
'IpPermissions.1.IpProtocol': 'tcp',
'IpPermissions.1.IpRanges.1.CidrIp': '192.168.100.0/24'}
self.assert_params_for_cmd(args_list, result)


class TestAuthorizeSecurityGroupEgress(BaseAWSCommandParamsTest):

prefix = 'ec2 authorize-security-group-egress'


class TestRevokeSecurityGroupIngress(BaseAWSCommandParamsTest):

prefix = 'ec2 revoke-security-group-ingress'


class TestRevokeSecurityGroupEgress(BaseAWSCommandParamsTest):

prefix = 'ec2 revoke-security-group-egress'


if __name__ == "__main__":
unittest.main()

0 comments on commit d07ac23

Please sign in to comment.