@@ -62,6 +62,17 @@ def _format_network_port_range(rule):
6262 return port_range
6363
6464
65+ def _format_remote_ip_prefix (rule ):
66+ remote_ip_prefix = rule ['remote_ip_prefix' ]
67+ if remote_ip_prefix is None :
68+ ethertype = rule ['ether_type' ]
69+ if ethertype == 'IPv4' :
70+ remote_ip_prefix = '0.0.0.0/0'
71+ elif ethertype == 'IPv6' :
72+ remote_ip_prefix = '::/0'
73+ return remote_ip_prefix
74+
75+
6576def _get_columns (item ):
6677 column_map = {
6778 'tenant_id' : 'project_id' ,
@@ -108,7 +119,8 @@ def update_parser_common(self, parser):
108119 "--remote-ip" ,
109120 metavar = "<ip-address>" ,
110121 help = _ ("Remote IP address block (may use CIDR notation; "
111- "default for IPv4 rule: 0.0.0.0/0)" ),
122+ "default for IPv4 rule: 0.0.0.0/0, "
123+ "default for IPv6 rule: ::/0)" ),
112124 )
113125 remote_group .add_argument (
114126 "--remote-group" ,
@@ -230,6 +242,14 @@ def _get_protocol(self, parsed_args, default_protocol='any'):
230242 protocol = None
231243 return protocol
232244
245+ def _get_ethertype (self , parsed_args , protocol ):
246+ ethertype = 'IPv4'
247+ if parsed_args .ethertype is not None :
248+ ethertype = parsed_args .ethertype
249+ elif self ._is_ipv6_protocol (protocol ):
250+ ethertype = 'IPv6'
251+ return ethertype
252+
233253 def _is_ipv6_protocol (self , protocol ):
234254 # NOTE(rtheis): Neutron has deprecated protocol icmpv6.
235255 # However, while the OSC CLI doesn't document the protocol,
@@ -264,12 +284,8 @@ def take_action_network(self, client, parsed_args):
264284
265285 # NOTE(rtheis): Use ethertype specified else default based
266286 # on IP protocol.
267- if parsed_args .ethertype :
268- attrs ['ethertype' ] = parsed_args .ethertype
269- elif self ._is_ipv6_protocol (attrs ['protocol' ]):
270- attrs ['ethertype' ] = 'IPv6'
271- else :
272- attrs ['ethertype' ] = 'IPv4'
287+ attrs ['ethertype' ] = self ._get_ethertype (parsed_args ,
288+ attrs ['protocol' ])
273289
274290 # NOTE(rtheis): Validate the port range and ICMP type and code.
275291 # It would be ideal if argparse could do this.
@@ -306,6 +322,8 @@ def take_action_network(self, client, parsed_args):
306322 attrs ['remote_ip_prefix' ] = parsed_args .remote_ip
307323 elif attrs ['ethertype' ] == 'IPv4' :
308324 attrs ['remote_ip_prefix' ] = '0.0.0.0/0'
325+ elif attrs ['ethertype' ] == 'IPv6' :
326+ attrs ['remote_ip_prefix' ] = '::/0'
309327 attrs ['security_group_id' ] = security_group_id
310328 if parsed_args .project is not None :
311329 identity_client = self .app .client_manager .identity
@@ -387,6 +405,7 @@ def _format_network_security_group_rule(self, rule):
387405 """
388406 rule = rule .to_dict ()
389407 rule ['port_range' ] = _format_network_port_range (rule )
408+ rule ['remote_ip_prefix' ] = _format_remote_ip_prefix (rule )
390409 return rule
391410
392411 def update_parser_common (self , parser ):
@@ -418,6 +437,12 @@ def update_parser_network(self, parser):
418437 "udp, udplite, vrrp and integer representations [0-255] "
419438 "or any; default: any (all protocols))" )
420439 )
440+ parser .add_argument (
441+ '--ethertype' ,
442+ metavar = '<ethertype>' ,
443+ type = _convert_to_lowercase ,
444+ help = _ ("List rules by the Ethertype (IPv4 or IPv6)" )
445+ )
421446 direction_group = parser .add_mutually_exclusive_group ()
422447 direction_group .add_argument (
423448 '--ingress' ,
@@ -458,11 +483,12 @@ def _get_column_headers(self, parsed_args):
458483 column_headers = (
459484 'ID' ,
460485 'IP Protocol' ,
486+ 'Ethertype' ,
461487 'IP Range' ,
462488 'Port Range' ,
463489 )
464490 if parsed_args .long :
465- column_headers = column_headers + ('Direction' , 'Ethertype' , )
491+ column_headers = column_headers + ('Direction' ,)
466492 column_headers = column_headers + ('Remote Security Group' ,)
467493 if parsed_args .group is None :
468494 column_headers = column_headers + ('Security Group' ,)
@@ -473,11 +499,12 @@ def take_action_network(self, client, parsed_args):
473499 columns = (
474500 'id' ,
475501 'protocol' ,
502+ 'ether_type' ,
476503 'remote_ip_prefix' ,
477504 'port_range' ,
478505 )
479506 if parsed_args .long :
480- columns = columns + ('direction' , 'ether_type' , )
507+ columns = columns + ('direction' ,)
481508 columns = columns + ('remote_group_id' ,)
482509
483510 # Get the security group rules using the requested query.
@@ -516,6 +543,7 @@ def take_action_compute(self, client, parsed_args):
516543 columns = (
517544 "ID" ,
518545 "IP Protocol" ,
546+ "Ethertype" ,
519547 "IP Range" ,
520548 "Port Range" ,
521549 "Remote Security Group" ,
@@ -564,6 +592,9 @@ def update_parser_common(self, parser):
564592 def take_action_network (self , client , parsed_args ):
565593 obj = client .find_security_group_rule (parsed_args .rule ,
566594 ignore_missing = False )
595+ # necessary for old rules that have None in this field
596+ if not obj ['remote_ip_prefix' ]:
597+ obj ['remote_ip_prefix' ] = _format_remote_ip_prefix (obj )
567598 display_columns , columns = _get_columns (obj )
568599 data = utils .get_item_properties (obj , columns )
569600 return (display_columns , data )
0 commit comments