1616import six
1717
1818from openstackclient .common import exceptions
19+ from openstackclient .common import parseractions
1920from openstackclient .common import utils
2021from openstackclient .network import common
2122from openstackclient .network import utils as network_utils
@@ -34,6 +35,105 @@ def _get_columns(item):
3435 return tuple (sorted (columns ))
3536
3637
38+ def _convert_to_lowercase (string ):
39+ return string .lower ()
40+
41+
42+ class CreateSecurityGroupRule (common .NetworkAndComputeShowOne ):
43+ """Create a new security group rule"""
44+
45+ def update_parser_common (self , parser ):
46+ parser .add_argument (
47+ 'group' ,
48+ metavar = '<group>' ,
49+ help = 'Create rule in this security group (name or ID)' ,
50+ )
51+ # TODO(rtheis): Add support for additional protocols for network.
52+ # Until then, continue enforcing the compute choices.
53+ parser .add_argument (
54+ "--proto" ,
55+ metavar = "<proto>" ,
56+ default = "tcp" ,
57+ choices = ['icmp' , 'tcp' , 'udp' ],
58+ type = _convert_to_lowercase ,
59+ help = "IP protocol (icmp, tcp, udp; default: tcp)" ,
60+ )
61+ source_group = parser .add_mutually_exclusive_group ()
62+ source_group .add_argument (
63+ "--src-ip" ,
64+ metavar = "<ip-address>" ,
65+ default = "0.0.0.0/0" ,
66+ help = "Source IP address block (may use CIDR notation; default: "
67+ "0.0.0.0/0)" ,
68+ )
69+ source_group .add_argument (
70+ "--src-group" ,
71+ metavar = "<group>" ,
72+ help = "Source security group (ID only)" ,
73+ )
74+ parser .add_argument (
75+ "--dst-port" ,
76+ metavar = "<port-range>" ,
77+ default = (0 , 0 ),
78+ action = parseractions .RangeAction ,
79+ help = "Destination port, may be a single port or port range: "
80+ "137:139 (only required for IP protocols tcp and udp)" ,
81+ )
82+ return parser
83+
84+ def take_action_network (self , client , parsed_args ):
85+ # Get the security group ID to hold the rule.
86+ security_group_id = client .find_security_group (
87+ parsed_args .group ,
88+ ignore_missing = False
89+ ).id
90+
91+ # Build the create attributes.
92+ attrs = {}
93+ # TODO(rtheis): Add --direction option. Until then, continue
94+ # with the default of 'ingress'.
95+ attrs ['direction' ] = 'ingress'
96+ # TODO(rtheis): Add --ethertype option. Until then, continue
97+ # with the default of 'IPv4'
98+ attrs ['ethertype' ] = 'IPv4'
99+ # TODO(rtheis): Add port range support (type and code) for icmp
100+ # protocol. Until then, continue ignoring the port range.
101+ if parsed_args .proto != 'icmp' :
102+ attrs ['port_range_min' ] = parsed_args .dst_port [0 ]
103+ attrs ['port_range_max' ] = parsed_args .dst_port [1 ]
104+ attrs ['protocol' ] = parsed_args .proto
105+ if parsed_args .src_group is not None :
106+ attrs ['remote_group_id' ] = parsed_args .src_group
107+ else :
108+ attrs ['remote_ip_prefix' ] = parsed_args .src_ip
109+ attrs ['security_group_id' ] = security_group_id
110+
111+ # Create and show the security group rule.
112+ obj = client .create_security_group_rule (** attrs )
113+ columns = _get_columns (obj )
114+ data = utils .get_item_properties (obj , columns )
115+ return (columns , data )
116+
117+ def take_action_compute (self , client , parsed_args ):
118+ group = utils .find_resource (
119+ client .security_groups ,
120+ parsed_args .group ,
121+ )
122+ if parsed_args .proto == 'icmp' :
123+ from_port , to_port = - 1 , - 1
124+ else :
125+ from_port , to_port = parsed_args .dst_port
126+ obj = client .security_group_rules .create (
127+ group .id ,
128+ parsed_args .proto ,
129+ from_port ,
130+ to_port ,
131+ parsed_args .src_ip ,
132+ parsed_args .src_group ,
133+ )
134+ return _format_security_group_rule_show (obj ._info )
135+
136+
37137class DeleteSecurityGroupRule (common .NetworkAndComputeCommand ):
38138 """Delete a security group rule"""
39139
0 commit comments