diff options
| author | Eric Fried <openstack@fried.cc> | 2019-10-28 17:27:38 -0500 |
|---|---|---|
| committer | Eric Fried <openstack@fried.cc> | 2019-11-01 14:24:30 -0500 |
| commit | cd6c285cc6c2274e6b42cc452ba4a61a3487ca23 (patch) | |
| tree | 334eddf792c9287511a8d419e82c2e6777fd63b2 /openstackclient | |
| parent | 61ad83b57580c76a1c448e03064c4df6bcc01e87 (diff) | |
| download | python-openstackclient-cd6c285cc6c2274e6b42cc452ba4a61a3487ca23.tar.gz | |
neutron: autogenerate docs
$namespace = openstack.network.v2
The subcommand documents for $namespace were hardcoded and thus prone to
drift over time. This commit removes the hardcoded content and uses the
autoprogram-cliff directive to generate them automatically from the
subcommand configuration classes.
This one turned out to be quite involved, because we support both
neutron and nova-network. When running in a real cloud, the command
classes detect whether the neutron service is present, assume
nova-network if that service is not found, and only add parser options
relevant to the detected service. But the docs need to present both sets
of options. This was easy enough when they were hardcoded, but required
a bit of additional infrastructure for generated docs.
Change-Id: I426261eb1d86bcc68656aabd61f10b7f082da402
Diffstat (limited to 'openstackclient')
| -rw-r--r-- | openstackclient/identity/common.py | 8 | ||||
| -rw-r--r-- | openstackclient/network/common.py | 199 | ||||
| -rw-r--r-- | openstackclient/network/v2/_tag.py | 46 | ||||
| -rw-r--r-- | openstackclient/network/v2/floating_ip.py | 74 | ||||
| -rw-r--r-- | openstackclient/network/v2/network.py | 109 | ||||
| -rw-r--r-- | openstackclient/network/v2/security_group.py | 46 | ||||
| -rw-r--r-- | openstackclient/network/v2/security_group_rule.py | 205 |
7 files changed, 385 insertions, 302 deletions
diff --git a/openstackclient/identity/common.py b/openstackclient/identity/common.py index d125d285..7be2a17b 100644 --- a/openstackclient/identity/common.py +++ b/openstackclient/identity/common.py @@ -233,13 +233,13 @@ def add_group_domain_option_to_parser(parser): ) -def add_project_domain_option_to_parser(parser): +def add_project_domain_option_to_parser(parser, enhance_help=lambda _h: _h): parser.add_argument( '--project-domain', metavar='<project-domain>', - help=_('Domain the project belongs to (name or ID). ' - 'This can be used in case collisions between project names ' - 'exist.'), + help=enhance_help(_('Domain the project belongs to (name or ID). This ' + 'can be used in case collisions between project ' + 'names exist.')), ) diff --git a/openstackclient/network/common.py b/openstackclient/network/common.py index d22b2caa..e68628b3 100644 --- a/openstackclient/network/common.py +++ b/openstackclient/network/common.py @@ -34,6 +34,10 @@ _required_opt_extensions_map = { 'security_groups': 'security-groups', } +_NET_TYPE_NEUTRON = 'neutron' +_NET_TYPE_COMPUTE = 'nova-network' +_QUALIFIER_FMT = "%s\n\n*%s*" + @contextlib.contextmanager def check_missing_extension_if_error(client_manager, attrs): @@ -51,35 +55,87 @@ def check_missing_extension_if_error(client_manager, attrs): @six.add_metaclass(abc.ABCMeta) -class NetworkAndComputeCommand(command.Command): - """Network and Compute Command +class NetDetectionMixin(object): + """Convenience methods for nova-network vs. neutron decisions. - Command class for commands that support implementation via - the network or compute endpoint. Such commands have different - implementations for take_action() and may even have different - arguments. - """ + A live environment detects which network type it is running and creates its + parser with only the options relevant to that network type. - def take_action(self, parsed_args): - if self.app.client_manager.is_network_endpoint_enabled(): - return self.take_action_network(self.app.client_manager.network, - parsed_args) - else: - return self.take_action_compute(self.app.client_manager.compute, - parsed_args) + But the command classes are used for docs builds as well, and docs must + present the options for both network types, often qualified accordingly. + """ + @property + def _network_type(self): + """Discover whether the running cloud is using neutron or nova-network. + + :return: + * ``NET_TYPE_NEUTRON`` if neutron is detected + * ``NET_TYPE_COMPUTE`` if running in a cloud but neutron is not + detected. + * ``None`` if not running in a cloud, which hopefully means we're + building docs. + """ + # Have we set it up yet for this command? + if not hasattr(self, '_net_type'): + # import pdb; pdb.set_trace() + try: + if self.app.client_manager.is_network_endpoint_enabled(): + net_type = _NET_TYPE_NEUTRON + else: + net_type = _NET_TYPE_COMPUTE + except AttributeError: + LOG.warning( + "%s: Could not detect a network type. Assuming we are " + "building docs.", self.__class__.__name__) + net_type = None + self._net_type = net_type + return self._net_type + + @property + def is_neutron(self): + return self._network_type is _NET_TYPE_NEUTRON + + @property + def is_nova_network(self): + return self._network_type is _NET_TYPE_COMPUTE + + @property + def is_docs_build(self): + return self._network_type is None + + def enhance_help_neutron(self, _help): + if self.is_docs_build: + # Why can't we say 'neutron'? + return _QUALIFIER_FMT % (_help, _("Network version 2 only")) + return _help + + def enhance_help_nova_network(self, _help): + if self.is_docs_build: + # Why can't we say 'nova-network'? + return _QUALIFIER_FMT % (_help, _("Compute version 2 only")) + return _help + + @staticmethod + def split_help(network_help, compute_help): + return ( + "*%(network_qualifier)s:*\n %(network_help)s\n\n" + "*%(compute_qualifier)s:*\n %(compute_help)s" % dict( + network_qualifier=_("Network version 2"), + network_help=network_help, + compute_qualifier=_("Compute version 2"), + compute_help=compute_help)) def get_parser(self, prog_name): LOG.debug('get_parser(%s)', prog_name) - parser = super(NetworkAndComputeCommand, self).get_parser(prog_name) + parser = super(NetDetectionMixin, self).get_parser(prog_name) parser = self.update_parser_common(parser) LOG.debug('common parser: %s', parser) - if ( - self.app is None or - self.app.client_manager.is_network_endpoint_enabled() - ): - return self.update_parser_network(parser) - else: - return self.update_parser_compute(parser) + if self.is_neutron or self.is_docs_build: + parser = self.update_parser_network(parser) + if self.is_nova_network or self.is_docs_build: + # Add nova-net options if running nova-network or building docs + parser = self.update_parser_compute(parser) + return parser def update_parser_common(self, parser): """Default is no updates to parser.""" @@ -93,18 +149,36 @@ class NetworkAndComputeCommand(command.Command): """Default is no updates to parser.""" return parser - @abc.abstractmethod + def take_action(self, parsed_args): + if self.is_neutron: + return self.take_action_network(self.app.client_manager.network, + parsed_args) + elif self.is_nova_network: + return self.take_action_compute(self.app.client_manager.compute, + parsed_args) + def take_action_network(self, client, parsed_args): """Override to do something useful.""" pass - @abc.abstractmethod def take_action_compute(self, client, parsed_args): """Override to do something useful.""" pass @six.add_metaclass(abc.ABCMeta) +class NetworkAndComputeCommand(NetDetectionMixin, command.Command): + """Network and Compute Command + + Command class for commands that support implementation via + the network or compute endpoint. Such commands have different + implementations for take_action() and may even have different + arguments. + """ + pass + + +@six.add_metaclass(abc.ABCMeta) class NetworkAndComputeDelete(NetworkAndComputeCommand): """Network and Compute Delete @@ -149,7 +223,7 @@ class NetworkAndComputeDelete(NetworkAndComputeCommand): @six.add_metaclass(abc.ABCMeta) -class NetworkAndComputeLister(command.Lister): +class NetworkAndComputeLister(NetDetectionMixin, command.Lister): """Network and Compute Lister Lister class for commands that support implementation via @@ -157,50 +231,11 @@ class NetworkAndComputeLister(command.Lister): implementations for take_action() and may even have different arguments. """ - - def take_action(self, parsed_args): - if self.app.client_manager.is_network_endpoint_enabled(): - return self.take_action_network(self.app.client_manager.network, - parsed_args) - else: - return self.take_action_compute(self.app.client_manager.compute, - parsed_args) - - def get_parser(self, prog_name): - LOG.debug('get_parser(%s)', prog_name) - parser = super(NetworkAndComputeLister, self).get_parser(prog_name) - parser = self.update_parser_common(parser) - LOG.debug('common parser: %s', parser) - if self.app.client_manager.is_network_endpoint_enabled(): - return self.update_parser_network(parser) - else: - return self.update_parser_compute(parser) - - def update_parser_common(self, parser): - """Default is no updates to parser.""" - return parser - - def update_parser_network(self, parser): - """Default is no updates to parser.""" - return parser - - def update_parser_compute(self, parser): - """Default is no updates to parser.""" - return parser - - @abc.abstractmethod - def take_action_network(self, client, parsed_args): - """Override to do something useful.""" - pass - - @abc.abstractmethod - def take_action_compute(self, client, parsed_args): - """Override to do something useful.""" - pass + pass @six.add_metaclass(abc.ABCMeta) -class NetworkAndComputeShowOne(command.ShowOne): +class NetworkAndComputeShowOne(NetDetectionMixin, command.ShowOne): """Network and Compute ShowOne ShowOne class for commands that support implementation via @@ -222,35 +257,3 @@ class NetworkAndComputeShowOne(command.ShowOne): if exc.details: msg += ", " + six.text_type(exc.details) raise exceptions.CommandError(msg) - - def get_parser(self, prog_name): - LOG.debug('get_parser(%s)', prog_name) - parser = super(NetworkAndComputeShowOne, self).get_parser(prog_name) - parser = self.update_parser_common(parser) - LOG.debug('common parser: %s', parser) - if self.app.client_manager.is_network_endpoint_enabled(): - return self.update_parser_network(parser) - else: - return self.update_parser_compute(parser) - - def update_parser_common(self, parser): - """Default is no updates to parser.""" - return parser - - def update_parser_network(self, parser): - """Default is no updates to parser.""" - return parser - - def update_parser_compute(self, parser): - """Default is no updates to parser.""" - return parser - - @abc.abstractmethod - def take_action_network(self, client, parsed_args): - """Override to do something useful.""" - pass - - @abc.abstractmethod - def take_action_compute(self, client, parsed_args): - """Override to do something useful.""" - pass diff --git a/openstackclient/network/v2/_tag.py b/openstackclient/network/v2/_tag.py index ce39f35e..e1cba22e 100644 --- a/openstackclient/network/v2/_tag.py +++ b/openstackclient/network/v2/_tag.py @@ -22,34 +22,39 @@ class _CommaListAction(argparse.Action): setattr(namespace, self.dest, values.split(',')) -def add_tag_filtering_option_to_parser(parser, collection_name): +def add_tag_filtering_option_to_parser(parser, collection_name, + enhance_help=lambda _h: _h): parser.add_argument( '--tags', metavar='<tag>[,<tag>,...]', action=_CommaListAction, - help=_('List %s which have all given tag(s) ' - '(Comma-separated list of tags)') % collection_name + help=enhance_help( + _('List %s which have all given tag(s) (Comma-separated list of ' + 'tags)') % collection_name) ) parser.add_argument( '--any-tags', metavar='<tag>[,<tag>,...]', action=_CommaListAction, - help=_('List %s which have any given tag(s) ' - '(Comma-separated list of tags)') % collection_name + help=enhance_help( + _('List %s which have any given tag(s) (Comma-separated list of ' + 'tags)') % collection_name) ) parser.add_argument( '--not-tags', metavar='<tag>[,<tag>,...]', action=_CommaListAction, - help=_('Exclude %s which have all given tag(s) ' - '(Comma-separated list of tags)') % collection_name + help=enhance_help( + _('Exclude %s which have all given tag(s) (Comma-separated list ' + 'of tags)') % collection_name) ) parser.add_argument( '--not-any-tags', metavar='<tag>[,<tag>,...]', action=_CommaListAction, - help=_('Exclude %s which have any given tag(s) ' - '(Comma-separated list of tags)') % collection_name + help=enhance_help( + _('Exclude %s which have any given tag(s) (Comma-separated list ' + 'of tags)') % collection_name) ) @@ -64,37 +69,42 @@ def get_tag_filtering_args(parsed_args, args): args['not_any_tags'] = ','.join(parsed_args.not_any_tags) -def add_tag_option_to_parser_for_create(parser, resource_name): +def add_tag_option_to_parser_for_create(parser, resource_name, + enhance_help=lambda _h: _h): tag_group = parser.add_mutually_exclusive_group() tag_group.add_argument( '--tag', action='append', dest='tags', metavar='<tag>', - help=_("Tag to be added to the %s " - "(repeat option to set multiple tags)") % resource_name + help=enhance_help( + _("Tag to be added to the %s " + "(repeat option to set multiple tags)") % resource_name) ) tag_group.add_argument( '--no-tag', action='store_true', - help=_("No tags associated with the %s") % resource_name + help=enhance_help(_("No tags associated with the %s") % resource_name) ) -def add_tag_option_to_parser_for_set(parser, resource_name): +def add_tag_option_to_parser_for_set(parser, resource_name, + enhance_help=lambda _h: _h): parser.add_argument( '--tag', action='append', dest='tags', metavar='<tag>', - help=_("Tag to be added to the %s " - "(repeat option to set multiple tags)") % resource_name + help=enhance_help( + _("Tag to be added to the %s (repeat option to set multiple " + "tags)") % resource_name) ) parser.add_argument( '--no-tag', action='store_true', - help=_("Clear tags associated with the %s. Specify both " - "--tag and --no-tag to overwrite current tags") % resource_name + help=enhance_help( + _("Clear tags associated with the %s. Specify both --tag and " + "--no-tag to overwrite current tags") % resource_name) ) diff --git a/openstackclient/network/v2/floating_ip.py b/openstackclient/network/v2/floating_ip.py index e0aa0435..bd43379a 100644 --- a/openstackclient/network/v2/floating_ip.py +++ b/openstackclient/network/v2/floating_ip.py @@ -114,57 +114,65 @@ class CreateFloatingIP(common.NetworkAndComputeShowOne): parser.add_argument( '--subnet', metavar='<subnet>', - help=_("Subnet on which you want to create the floating IP " - "(name or ID)") + help=self.enhance_help_neutron( + _("Subnet on which you want to create the floating IP " + "(name or ID)")) ) parser.add_argument( '--port', metavar='<port>', - help=_("Port to be associated with the floating IP " - "(name or ID)") + help=self.enhance_help_neutron( + _("Port to be associated with the floating IP " + "(name or ID)")) ) parser.add_argument( '--floating-ip-address', metavar='<ip-address>', dest='floating_ip_address', - help=_("Floating IP address") + help=self.enhance_help_neutron(_("Floating IP address")) ) parser.add_argument( '--fixed-ip-address', metavar='<ip-address>', dest='fixed_ip_address', - help=_("Fixed IP address mapped to the floating IP") + help=self.enhance_help_neutron( + _("Fixed IP address mapped to the floating IP")) ) parser.add_argument( '--qos-policy', metavar='<qos-policy>', - help=_("Attach QoS policy to the floating IP (name or ID)") + help=self.enhance_help_neutron( + _("Attach QoS policy to the floating IP (name or ID)")) ) parser.add_argument( '--description', metavar='<description>', - help=_('Set floating IP description') + help=self.enhance_help_neutron(_('Set floating IP description')) ) parser.add_argument( '--project', metavar='<project>', - help=_("Owner's project (name or ID)") + help=self.enhance_help_neutron(_("Owner's project (name or ID)")) ) parser.add_argument( '--dns-domain', metavar='<dns-domain>', dest='dns_domain', - help=_("Set DNS domain for this floating IP") + help=self.enhance_help_neutron( + _("Set DNS domain for this floating IP")) ) parser.add_argument( '--dns-name', metavar='<dns-name>', dest='dns_name', - help=_("Set DNS name for this floating IP") + help=self.enhance_help_neutron( + _("Set DNS name for this floating IP")) ) - identity_common.add_project_domain_option_to_parser(parser) - _tag.add_tag_option_to_parser_for_create(parser, _('floating IP')) + identity_common.add_project_domain_option_to_parser( + parser, enhance_help=self.enhance_help_neutron) + _tag.add_tag_option_to_parser_for_create( + parser, _('floating IP'), enhance_help=self.enhance_help_neutron) return parser def take_action_network(self, client, parsed_args): @@ -217,60 +225,68 @@ class DeleteFloatingIP(common.NetworkAndComputeDelete): class ListFloatingIP(common.NetworkAndComputeLister): # TODO(songminglong): Use SDK resource mapped attribute names once # the OSC minimum requirements include SDK 1.0 + _description = _("List floating IP(s)") def update_parser_network(self, parser): parser.add_argument( '--network', metavar='<network>', - help=_("List floating IP(s) according to " - "given network (name or ID)") + help=self.enhance_help_neutron( + _("List floating IP(s) according to " + "given network (name or ID)")) ) parser.add_argument( '--port', metavar='<port>', - help=_("List floating IP(s) according to " - "given port (name or ID)") + help=self.enhance_help_neutron( + _("List floating IP(s) according to given port (name or ID)")) ) parser.add_argument( '--fixed-ip-address', metavar='<ip-address>', - help=_("List floating IP(s) according to " - "given fixed IP address") + help=self.enhance_help_neutron( + _("List floating IP(s) according to given fixed IP address")) ) parser.add_argument( '--floating-ip-address', metavar='<ip-address>', - help=_("List floating IP(s) according to " - "given floating IP address") + help=self.enhance_help_neutron( + _("List floating IP(s) according to given floating IP " + "address")) ) parser.add_argument( '--long', action='store_true', default=False, - help=_("List additional fields in output") + help=self.enhance_help_neutron( + _("List additional fields in output")) ) parser.add_argument( '--status', metavar='<status>', choices=['ACTIVE', 'DOWN'], - help=_("List floating IP(s) according to " - "given status ('ACTIVE', 'DOWN')") + help=self.enhance_help_neutron( + _("List floating IP(s) according to given status ('ACTIVE', " + "'DOWN')")) ) parser.add_argument( '--project', metavar='<project>', - help=_("List floating IP(s) according to " - "given project (name or ID)") + help=self.enhance_help_neutron( + _("List floating IP(s) according to given project (name or " + "ID)")) ) identity_common.add_project_domain_option_to_parser(parser) parser.add_argument( '--router', metavar='<router>', - help=_("List floating IP(s) according to " - "given router (name or ID)") + help=self.enhance_help_neutron( + _("List floating IP(s) according to given router (name or " + "ID)")) ) - _tag.add_tag_filtering_option_to_parser(parser, _('floating IP')) + _tag.add_tag_filtering_option_to_parser( + parser, _('floating IP'), enhance_help=self.enhance_help_neutron) return parser diff --git a/openstackclient/network/v2/network.py b/openstackclient/network/v2/network.py index 09f3556c..e7031266 100644 --- a/openstackclient/network/v2/network.py +++ b/openstackclient/network/v2/network.py @@ -219,27 +219,27 @@ class CreateNetwork(common.NetworkAndComputeShowOne): '--enable', action='store_true', default=True, - help=_("Enable network (default)") + help=self.enhance_help_neutron(_("Enable network (default)")) ) admin_group.add_argument( '--disable', action='store_true', - help=_("Disable network") + help=self.enhance_help_neutron(_("Disable network")) ) parser.add_argument( '--project', metavar='<project>', - help=_("Owner's project (name or ID)") + help=self.enhance_help_neutron(_("Owner's project (name or ID)")) ) parser.add_argument( '--description', metavar='<description>', - help=_("Set network description") + help=self.enhance_help_neutron(_("Set network description")) ) parser.add_argument( '--mtu', metavar='<mtu>', - help=_("Set network mtu") + help=self.enhance_help_neutron(_("Set network mtu")) ) identity_common.add_project_domain_option_to_parser(parser) parser.add_argument( @@ -247,65 +247,76 @@ class CreateNetwork(common.NetworkAndComputeShowOne): action='append', dest='availability_zone_hints', metavar='<availability-zone>', - help=_("Availability Zone in which to create this network " - "(Network Availability Zone extension required, " - "repeat option to set multiple availability zones)") + help=self.enhance_help_neutron( + _("Availability Zone in which to create this network " + "(Network Availability Zone extension required, " + "repeat option to set multiple availability zones)")) ) port_security_group = parser.add_mutually_exclusive_group() port_security_group.add_argument( '--enable-port-security', action='store_true', - help=_("Enable port security by default for ports created on " - "this network (default)") + help=self.enhance_help_neutron( + _("Enable port security by default for ports created on " + "this network (default)")) ) port_security_group.add_argument( '--disable-port-security', action='store_true', - help=_("Disable port security by default for ports created on " - "this network") + help=self.enhance_help_neutron( + _("Disable port security by default for ports created on " + "this network")) ) external_router_grp = parser.add_mutually_exclusive_group() external_router_grp.add_argument( '--external', action='store_true', - help=_("Set this network as an external network " - "(external-net extension required)") + help=self.enhance_help_neutron( + _("Set this network as an external network " + "(external-net extension required)")) ) external_router_grp.add_argument( '--internal', action='store_true', - help=_("Set this network as an internal network (default)") + help=self.enhance_help_neutron( + _("Set this network as an internal network (default)")) ) default_router_grp = parser.add_mutually_exclusive_group() default_router_grp.add_argument( '--default', action='store_true', - help=_("Specify if this network should be used as " - "the default external network") + help=self.enhance_help_neutron( + _("Specify if this network should be used as the default " + "external network")) ) default_router_grp.add_argument( '--no-default', action='store_true', - help=_("Do not use the network as the default external network " - "(default)") + help=self.enhance_help_neutron( + _("Do not use the network as the default external network " + "(default)")) ) parser.add_argument( '--qos-policy', metavar='<qos-policy>', - help=_("QoS policy to attach to this network (name or ID)") + help=self.enhance_help_neutron( + _("QoS policy to attach to this network (name or ID)")) ) vlan_transparent_grp = parser.add_mutually_exclusive_group() vlan_transparent_grp.add_argument( '--transparent-vlan', action='store_true', - help=_("Make the network VLAN transparent")) + help=self.enhance_help_neutron( + _("Make the network VLAN transparent"))) vlan_transparent_grp.add_argument( '--no-transparent-vlan', action='store_true', - help=_("Do not make the network VLAN transparent")) + help=self.enhance_help_neutron( + _("Do not make the network VLAN transparent"))) _add_additional_network_options(parser) - _tag.add_tag_option_to_parser_for_create(parser, _('network')) + _tag.add_tag_option_to_parser_for_create( + parser, _('network'), enhance_help=self.enhance_help_neutron) return parser def update_parser_compute(self, parser): @@ -313,7 +324,8 @@ class CreateNetwork(common.NetworkAndComputeShowOne): '--subnet', metavar='<subnet>', required=True, - help=_("IPv4 subnet for fixed IPs (in CIDR notation)") + help=self.enhance_help_nova_network( + _("IPv4 subnet for fixed IPs (in CIDR notation)")) ) return parser @@ -376,87 +388,98 @@ class ListNetwork(common.NetworkAndComputeLister): router_ext_group.add_argument( '--external', action='store_true', - help=_("List external networks") + help=self.enhance_help_neutron(_("List external networks")) ) router_ext_group.add_argument( '--internal', action='store_true', - help=_("List internal networks") + help=self.enhance_help_neutron(_("List internal networks")) ) parser.add_argument( '--long', action='store_true', - help=_("List additional fields in output") + help=self.enhance_help_neutron( + _("List additional fields in output")) ) parser.add_argument( '--name', metavar='<name>', - help=_("List networks according to their name") + help=self.enhance_help_neutron( + _("List networks according to their name")) ) admin_state_group = parser.add_mutually_exclusive_group() admin_state_group.add_argument( '--enable', action='store_true', - help=_("List enabled networks") + help=self.enhance_help_neutron(_("List enabled networks")) ) admin_state_group.add_argument( '--disable', action='store_true', - help=_("List disabled networks") + help=self.enhance_help_neutron(_("List disabled networks")) ) parser.add_argument( '--project', metavar='<project>', help=_("List networks according to their project (name or ID)") ) - identity_common.add_project_domain_option_to_parser(parser) + identity_common.add_project_domain_option_to_parser( + parser, enhance_help=self.enhance_help_neutron) shared_group = parser.add_mutually_exclusive_group() shared_group.add_argument( '--share', action='store_true', - help=_("List networks shared between projects") + help=self.enhance_help_neutron( + _("List networks shared between projects")) ) shared_group.add_argument( '--no-share', action='store_true', - help=_("List networks not shared between projects") + help=self.enhance_help_neutron( + _("List networks not shared between projects")) ) parser.add_argument( '--status', metavar='<status>', choices=['ACTIVE', 'BUILD', 'DOWN', 'ERROR'], - help=_("List networks according to their status " - "('ACTIVE', 'BUILD', 'DOWN', 'ERROR')") + help=self.enhance_help_neutron( + _("List networks according to their status " + "('ACTIVE', 'BUILD', 'DOWN', 'ERROR')")) ) parser.add_argument( '--provider-network-type', metavar='<provider-network-type>', choices=['flat', 'geneve', 'gre', 'local', 'vlan', 'vxlan'], - help=_("List networks according to their physical mechanisms. " - "The supported options are: flat, geneve, gre, local, " - "vlan, vxlan.") + help=self.enhance_help_neutron( + _("List networks according to their physical mechanisms. The " + "supported options are: flat, geneve, gre, local, vlan, " + "vxlan.")) ) parser.add_argument( '--provider-physical-network', metavar='<provider-physical-network>', dest='physical_network', - help=_("List networks according to name of the physical network") + help=self.enhance_help_neutron( + _("List networks according to name of the physical network")) ) parser.add_argument( '--provider-segment', metavar='<provider-segment>', dest='segmentation_id', - help=_("List networks according to VLAN ID for VLAN networks " - "or Tunnel ID for GENEVE/GRE/VXLAN networks") + help=self.enhance_help_neutron( + _("List networks according to VLAN ID for VLAN networks or " + "Tunnel ID for GENEVE/GRE/VXLAN networks")) ) parser.add_argument( '--agent', metavar='<agent-id>', dest='agent_id', - help=_('List networks hosted by agent (ID only)') + help=self.enhance_help_neutron( + _('List networks hosted by agent (ID only)')) ) - _tag.add_tag_filtering_option_to_parser(parser, _('networks')) + _tag.add_tag_filtering_option_to_parser( + parser, _('networks'), enhance_help=self.enhance_help_neutron) return parser def take_action_network(self, client, parsed_args): diff --git a/openstackclient/network/v2/security_group.py b/openstackclient/network/v2/security_group.py index 38b4e97a..9f0ca0a1 100644 --- a/openstackclient/network/v2/security_group.py +++ b/openstackclient/network/v2/security_group.py @@ -119,10 +119,13 @@ class CreateSecurityGroup(common.NetworkAndComputeShowOne): parser.add_argument( '--project', metavar='<project>', - help=_("Owner's project (name or ID)") + help=self.enhance_help_neutron(_("Owner's project (name or ID)")) ) - identity_common.add_project_domain_option_to_parser(parser) - _tag.add_tag_option_to_parser_for_create(parser, _('security group')) + identity_common.add_project_domain_option_to_parser( + parser, enhance_help=self.enhance_help_neutron) + _tag.add_tag_option_to_parser_for_create( + parser, _('security group'), + enhance_help=self.enhance_help_neutron) return parser def _get_description(self, parsed_args): @@ -202,22 +205,28 @@ class ListSecurityGroup(common.NetworkAndComputeLister): _description = _("List security groups") def update_parser_network(self, parser): - # Maintain and hide the argument for backwards compatibility. - # Network will always return all projects for an admin. - parser.add_argument( - '--all-projects', - action='store_true', - default=False, - help=argparse.SUPPRESS, - ) + if not self.is_docs_build: + # Maintain and hide the argument for backwards compatibility. + # Network will always return all projects for an admin. + parser.add_argument( + '--all-projects', + action='store_true', + default=False, + help=argparse.SUPPRESS, + ) + parser.add_argument( '--project', metavar='<project>', - help=_("List security groups according to the project " - "(name or ID)") + help=self.enhance_help_neutron( + _("List security groups according to the project (name or " + "ID)")) ) - identity_common.add_project_domain_option_to_parser(parser) - _tag.add_tag_filtering_option_to_parser(parser, _('security group')) + identity_common.add_project_domain_option_to_parser( + parser, enhance_help=self.enhance_help_neutron) + _tag.add_tag_filtering_option_to_parser( + parser, _('security group'), + enhance_help=self.enhance_help_neutron) return parser def update_parser_compute(self, parser): @@ -225,7 +234,8 @@ class ListSecurityGroup(common.NetworkAndComputeLister): '--all-projects', action='store_true', default=False, - help=_("Display information from all projects (admin only)") + help=self.enhance_help_nova_network( + _("Display information from all projects (admin only)")) ) return parser @@ -307,7 +317,9 @@ class SetSecurityGroup(common.NetworkAndComputeCommand): return parser def update_parser_network(self, parser): - _tag.add_tag_option_to_parser_for_set(parser, _('security group')) + _tag.add_tag_option_to_parser_for_set( + parser, _('security group'), + enhance_help=self.enhance_help_neutron) return parser def take_action_network(self, client, parsed_args): diff --git a/openstackclient/network/v2/security_group_rule.py b/openstackclient/network/v2/security_group_rule.py index 15f099b1..a38587fa 100644 --- a/openstackclient/network/v2/security_group_rule.py +++ b/openstackclient/network/v2/security_group_rule.py @@ -133,109 +133,120 @@ class CreateSecurityGroupRule(common.NetworkAndComputeShowOne): metavar="<group>", help=_("Remote security group (name or ID)"), ) - return parser - def update_parser_network(self, parser): - parser.add_argument( - '--description', - metavar='<description>', - help=_("Set security group rule description") - ) + # NOTE(efried): The --dst-port, --protocol, and --proto options exist + # for both nova-network and neutron, but differ slightly. For the sake + # of the docs build, which has to account for both variants, but only + # add each to the parser once, they are handled here rather than in the + # _network- or _compute-specific methods below. + + # --dst-port has a default for nova-net only + if self.is_nova_network: + dst_port_default = dict(default=(0, 0)) + else: + dst_port_default = {} parser.add_argument( '--dst-port', metavar='<port-range>', action=parseractions.RangeAction, help=_("Destination port, may be a single port or a starting and " "ending port range: 137:139. Required for IP protocols TCP " - "and UDP. Ignored for ICMP IP protocols.") - ) - parser.add_argument( - '--icmp-type', - metavar='<icmp-type>', - type=int, - help=_("ICMP type for ICMP IP protocols") - ) - parser.add_argument( - '--icmp-code', - metavar='<icmp-code>', - type=int, - help=_("ICMP code for ICMP IP protocols") + "and UDP. Ignored for ICMP IP protocols."), + **dst_port_default ) + # NOTE(rtheis): Support either protocol option name for now. # However, consider deprecating and then removing --proto in # a future release. protocol_group = parser.add_mutually_exclusive_group() + # --proto[col] has choices for nova-network only + if self.is_nova_network: + proto_choices = dict(choices=['icmp', 'tcp', 'udp']) + else: + proto_choices = {} + protocol_help_compute = _("IP protocol (icmp, tcp, udp; default: tcp)") + protocol_help_network = _( + "IP protocol (ah, dccp, egp, esp, gre, icmp, igmp, ipv6-encap, " + "ipv6-frag, ipv6-icmp, ipv6-nonxt, ipv6-opts, ipv6-route, ospf, " + "pgm, rsvp, sctp, tcp, udp, udplite, vrrp and integer " + "representations [0-255] or any; default: any (all protocols))") + if self.is_nova_network: + protocol_help = protocol_help_compute + elif self.is_neutron: + protocol_help = protocol_help_network + else: + # Docs build: compose help for both nova-network and neutron + protocol_help = self.split_help( + protocol_help_network, protocol_help_compute) + protocol_group.add_argument( '--protocol', metavar='<protocol>', type=_convert_to_lowercase, - help=_("IP protocol (ah, dccp, egp, esp, gre, icmp, igmp, " - "ipv6-encap, ipv6-frag, ipv6-icmp, ipv6-nonxt, " - "ipv6-opts, ipv6-route, ospf, pgm, rsvp, sctp, tcp, " - "udp, udplite, vrrp and integer representations [0-255] " - "or any; default: any (all protocols))") + help=protocol_help, + **proto_choices ) - protocol_group.add_argument( - '--proto', - metavar='<proto>', - type=_convert_to_lowercase, - help=argparse.SUPPRESS + if not self.is_docs_build: + protocol_group.add_argument( + '--proto', + metavar='<proto>', + type=_convert_to_lowercase, + help=argparse.SUPPRESS, + **proto_choices + ) + + return parser + + def update_parser_network(self, parser): + parser.add_argument( + '--description', + metavar='<description>', + help=self.enhance_help_neutron( + _("Set security group rule description")) + ) + parser.add_argument( + '--icmp-type', + metavar='<icmp-type>', + type=int, + help=self.enhance_help_neutron( + _("ICMP type for ICMP IP protocols")) + ) + parser.add_argument( + '--icmp-code', + metavar='<icmp-code>', + type=int, + help=self.enhance_help_neutron( + _("ICMP code for ICMP IP protocols")) ) direction_group = parser.add_mutually_exclusive_group() direction_group.add_argument( '--ingress', action='store_true', - help=_("Rule applies to incoming network traffic (default)") + help=self.enhance_help_neutron( + _("Rule applies to incoming network traffic (default)")) ) direction_group.add_argument( '--egress', action='store_true', - help=_("Rule applies to outgoing network traffic") + help=self.enhance_help_neutron( + _("Rule applies to outgoing network traffic")) ) parser.add_argument( '--ethertype', metavar='<ethertype>', choices=['IPv4', 'IPv6'], type=_convert_ipvx_case, - help=_("Ethertype of network traffic " - "(IPv4, IPv6; default: based on IP protocol)") + help=self.enhance_help_neutron( + _("Ethertype of network traffic " + "(IPv4, IPv6; default: based on IP protocol)")) ) parser.add_argument( '--project', metavar='<project>', - help=_("Owner's project (name or ID)") - ) - identity_common.add_project_domain_option_to_parser(parser) - return parser - - def update_parser_compute(self, parser): - parser.add_argument( - '--dst-port', - metavar='<port-range>', - default=(0, 0), - action=parseractions.RangeAction, - help=_("Destination port, may be a single port or a starting and " - "ending port range: 137:139. Required for IP protocols TCP " - "and UDP. Ignored for ICMP IP protocols.") - ) - # NOTE(rtheis): Support either protocol option name for now. - # However, consider deprecating and then removing --proto in - # a future release. - protocol_group = parser.add_mutually_exclusive_group() - protocol_group.add_argument( - '--protocol', - metavar='<protocol>', - choices=['icmp', 'tcp', 'udp'], - type=_convert_to_lowercase, - help=_("IP protocol (icmp, tcp, udp; default: tcp)") - ) - protocol_group.add_argument( - '--proto', - metavar='<proto>', - choices=['icmp', 'tcp', 'udp'], - type=_convert_to_lowercase, - help=argparse.SUPPRESS + help=self.enhance_help_neutron(_("Owner's project (name or ID)")) ) + identity_common.add_project_domain_option_to_parser( + parser, enhance_help=self.enhance_help_neutron) return parser def _get_protocol(self, parsed_args, default_protocol='any'): @@ -424,47 +435,53 @@ class ListSecurityGroupRule(common.NetworkAndComputeLister): return parser def update_parser_network(self, parser): - # Accept but hide the argument for consistency with compute. - # Network will always return all projects for an admin. - parser.add_argument( - '--all-projects', - action='store_true', - default=False, - help=argparse.SUPPRESS - ) + if not self.is_docs_build: + # Accept but hide the argument for consistency with compute. + # Network will always return all projects for an admin. + parser.add_argument( + '--all-projects', + action='store_true', + default=False, + help=argparse.SUPPRESS + ) + parser.add_argument( '--protocol', metavar='<protocol>', type=_convert_to_lowercase, - help=_("List rules by the IP protocol (" - "ah, dhcp, egp, esp, gre, icmp, igmp, " - "ipv6-encap, ipv6-frag, ipv6-icmp, ipv6-nonxt, " - "ipv6-opts, ipv6-route, ospf, pgm, rsvp, sctp, tcp, " - "udp, udplite, vrrp and integer representations [0-255] " - "or any; default: any (all protocols))") + help=self.enhance_help_neutron( + _("List rules by the IP protocol (ah, dhcp, egp, esp, gre, " + "icmp, igmp, ipv6-encap, ipv6-frag, ipv6-icmp, ipv6-nonxt, " + "ipv6-opts, ipv6-route, ospf, pgm, rsvp, sctp, tcp, udp, " + "udplite, vrrp and integer representations [0-255] or any; " + "default: any (all protocols))")) ) parser.add_argument( '--ethertype', metavar='<ethertype>', type=_convert_to_lowercase, - help=_("List rules by the Ethertype (IPv4 or IPv6)") + help=self.enhance_help_neutron( + _("List rules by the Ethertype (IPv4 or IPv6)")) ) direction_group = parser.add_mutually_exclusive_group() direction_group.add_argument( '--ingress', action='store_true', - help=_("List rules applied to incoming network traffic") + help=self.enhance_help_neutron( + _("List rules applied to incoming network traffic")) ) direction_group.add_argument( '--egress', action='store_true', - help=_("List rules applied to outgoing network traffic") + help=self.enhance_help_neutron( + _("List rules applied to outgoing network traffic")) ) parser.add_argument( '--long', action='store_true', default=False, - help=_("List additional fields in output") + help=self.enhance_help_neutron( + _("List additional fields in output")) ) return parser @@ -473,16 +490,18 @@ class ListSecurityGroupRule(common.NetworkAndComputeLister): '--all-projects', action='store_true', default=False, - help=_("Display information from all projects (admin only)") - ) - # Accept but hide the argument for consistency with network. - # There are no additional fields to display at this time. - parser.add_argument( - '--long', - action='store_false', - default=False, - help=argparse.SUPPRESS + help=self.enhance_help_nova_network( + _("Display information from all projects (admin only)")) ) + if not self.is_docs_build: + # Accept but hide the argument for consistency with network. + # There are no additional fields to display at this time. + parser.add_argument( + '--long', + action='store_false', + default=False, + help=argparse.SUPPRESS + ) return parser def _get_column_headers(self, parsed_args): |
