diff --git a/0001-add-distributed-traffic-feature-support.patch b/0001-add-distributed-traffic-feature-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..c4e96c0e1a33aa44b6ada8342857cdfd9b523ce8 --- /dev/null +++ b/0001-add-distributed-traffic-feature-support.patch @@ -0,0 +1,454 @@ +Author: wangkuntian +Date: Tue Dec 5 14:10:00 2023 +0800 + + add distributed traffic feature +--- + network/v2/rg_port_forwarding.py | 340 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + network/v2/router.py | 51 +++++++++ + 2 files changed, 391 insertions(+) + +diff --git a/network/v2/rg_port_forwarding.py b/network/v2/rg_port_forwarding.py +new file mode 100644 +index 00000000..a1609d2c +--- /dev/null ++++ b/network/v2/rg_port_forwarding.py +@@ -0,0 +1,340 @@ ++# Copyright (c) 2023 UnionTech ++# 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. You may obtain ++# a copy of the License at ++# ++# http://www.apache.org/licenses/LICENSE-2.0 ++# ++# Unless required by applicable law or agreed to in writing, software ++# distributed under the License 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. ++ ++import logging ++from osc_lib import utils ++from osc_lib import exceptions ++from osc_lib.command import command ++from osc_lib.cli import format_columns ++ ++from openstackclient.i18n import _ ++from openstackclient.network import sdk_utils ++ ++LOG = logging.getLogger(__name__) ++ ++_formatters = { ++ 'location': format_columns.DictColumn, ++} ++ ++ ++def _get_columns(item): ++ return sdk_utils.get_osc_show_columns_for_sdk_resource( ++ item, dict(), invisible_columns=['name', 'location'] ++ ) ++ ++ ++class ListRGPortForwarding(command.Lister): ++ _description = _("List router gateway port forwarding") ++ ++ def get_parser(self, prog_name): ++ parser = super(ListRGPortForwarding, self).get_parser(prog_name) ++ parser.add_argument( ++ 'router', ++ metavar='', ++ help=_("Router that the port forwarding belongs to (ID / Name)") ++ ) ++ parser.add_argument( ++ '--port', ++ metavar='', ++ help=_("Filter the list result by the ID or name of " ++ "the internal network port") ++ ) ++ parser.add_argument( ++ '--external-protocol-port', ++ metavar='', ++ dest='external_protocol_port', ++ help=_("Filter the list result by the " ++ "protocol port number of the router gateway address") ++ ) ++ parser.add_argument( ++ '--protocol', ++ metavar='protocol', ++ help=_("Filter the list result by the port protocol") ++ ) ++ ++ return parser ++ ++ def take_action(self, parsed_args): ++ client = self.app.client_manager.network ++ ++ columns = ('id', ++ 'internal_port_id', ++ 'internal_ip_address', ++ 'internal_port', ++ 'gw_ip_address', ++ 'external_port', ++ 'protocol',) ++ headers = ('ID', ++ 'Internal Port ID', ++ 'Internal IP Address', ++ 'Internal Port', ++ 'Gateway IP Address', ++ 'External Port', ++ 'Protocol',) ++ ++ query = dict() ++ ++ if parsed_args.port: ++ port = client.find_port(parsed_args.port, ++ ignore_missing=False) ++ query['internal_port_id'] = port.id ++ if parsed_args.external_protocol_port is not None: ++ query['external_port'] = parsed_args.external_protocol_port ++ if parsed_args.protocol is not None: ++ query['protocol'] = parsed_args.protocol ++ ++ obj = client.find_router(parsed_args.router, ignore_missing=False) ++ ++ data = client.router_gateway_port_forwardings(obj, **query) ++ ++ return (headers, ++ (utils.get_item_properties(s, columns, formatters={}, ) ++ for s in data)) ++ ++ ++class ShowRGPortForwarding(command.ShowOne): ++ _description = _("Display router gateway port forwarding details") ++ ++ def get_parser(self, prog_name): ++ parser = super(ShowRGPortForwarding, self).get_parser(prog_name) ++ parser.add_argument( ++ 'router', ++ metavar='', ++ help=_("Router that the port forwarding belongs to (ID / Name)") ++ ) ++ parser.add_argument( ++ 'port_forwarding_id', ++ metavar="", ++ help=_("The ID of the router gateway port forwarding") ++ ) ++ return parser ++ ++ def take_action(self, parsed_args): ++ client = self.app.client_manager.network ++ router = client.find_router(parsed_args.router, ignore_missing=False) ++ obj = client.find_router_gateway_port_forwarding( ++ router, ++ parsed_args.port_forwarding_id, ++ ignore_missing=False, ++ ) ++ display_columns, columns = _get_columns(obj) ++ print(display_columns, columns) ++ data = utils.get_item_properties(obj, columns, formatters=_formatters) ++ return display_columns, data ++ ++ ++class CreateRGPortForwarding(command.ShowOne): ++ _description = _("Create router gateway port forwarding") ++ ++ def get_parser(self, prog_name): ++ parser = super(CreateRGPortForwarding, self).get_parser(prog_name) ++ parser.add_argument( ++ '--internal-ip-address', ++ required=True, ++ metavar='', ++ help=_("The fixed IPv4 address of the network " ++ "port associated to the router gateway port forwarding") ++ ) ++ parser.add_argument( ++ '--port', ++ metavar='', ++ required=True, ++ help=_("The name or ID of the network port associated " ++ "to the router gateway port forwarding") ++ ) ++ parser.add_argument( ++ '--internal-protocol-port', ++ type=int, ++ metavar='', ++ required=True, ++ help=_("The protocol port number " ++ "of the network port fixed IPv4 address " ++ "associated to the router gateway port forwarding") ++ ) ++ parser.add_argument( ++ '--external-protocol-port', ++ type=int, ++ metavar='', ++ required=True, ++ help=_("The protocol port number of " ++ "the port forwarding's router gateway address") ++ ) ++ parser.add_argument( ++ '--protocol', ++ metavar='', ++ required=True, ++ help=_("The protocol used in the router gateway " ++ "port forwarding, for instance: TCP, UDP") ++ ) ++ parser.add_argument( ++ 'router', ++ metavar='', ++ help=_("Router that the port forwarding belongs to (ID / Name)") ++ ) ++ return parser ++ ++ def take_action(self, parsed_args): ++ attrs = {} ++ client = self.app.client_manager.network ++ router = client.find_router(parsed_args.router, ignore_missing=False) ++ ++ if parsed_args.internal_protocol_port is not None: ++ if (parsed_args.internal_protocol_port <= 0 or ++ parsed_args.internal_protocol_port > 65535): ++ msg = _("The port number range is <1-65535>") ++ raise exceptions.CommandError(msg) ++ attrs['internal_port'] = parsed_args.internal_protocol_port ++ ++ if parsed_args.external_protocol_port is not None: ++ if (parsed_args.external_protocol_port <= 0 or ++ parsed_args.external_protocol_port > 65535): ++ msg = _("The port number range is <1-65535>") ++ raise exceptions.CommandError(msg) ++ attrs['external_port'] = parsed_args.external_protocol_port ++ ++ if parsed_args.port: ++ port = client.find_port(parsed_args.port, ignore_missing=False) ++ attrs['internal_port_id'] = port.id ++ attrs['internal_ip_address'] = parsed_args.internal_ip_address ++ attrs['protocol'] = parsed_args.protocol ++ ++ obj = client.create_router_gateway_port_forwarding(router.id, **attrs) ++ display_columns, columns = _get_columns(obj) ++ data = utils.get_item_properties(obj, columns) ++ return display_columns, data ++ ++ ++class DeleteRGPortForwarding(command.Command): ++ _description = _("Delete router gateway port forwarding") ++ ++ def get_parser(self, prog_name): ++ parser = super(DeleteRGPortForwarding, self).get_parser(prog_name) ++ parser.add_argument( ++ 'router', ++ metavar='', ++ help=_("Router that the port forwarding belongs to (ID / Name)") ++ ) ++ parser.add_argument( ++ 'port_forwarding_id', ++ nargs="+", ++ metavar="", ++ help=_("The ID of the router gateway port forwarding") ++ ) ++ return parser ++ ++ def take_action(self, parsed_args): ++ client = self.app.client_manager.network ++ router = client.find_router(parsed_args.router, ignore_missing=False) ++ result = 0 ++ ++ for port_forwarding_id in parsed_args.port_forwarding_id: ++ try: ++ client.delete_router_gateway_port_forwarding( ++ router.id, port_forwarding_id, ignore_missing=False, ++ ) ++ except Exception as e: ++ result += 1 ++ LOG.error(_("Failed to delete router gateway port forwarding " ++ "'%(port_forwarding_id)s': %(e)s"), ++ {'port_forwarding_id': port_forwarding_id, 'e': e}) ++ if result > 0: ++ total = len(parsed_args.port_forwarding_id) ++ msg = (_("%(result)s of %(total)s Port forwarding failed " ++ "to delete.") % {'result': result, 'total': total}) ++ raise exceptions.CommandError(msg) ++ ++ ++class SetRGPortForwarding(command.Command): ++ _description = _("Set router gateway Port Forwarding Properties") ++ ++ def get_parser(self, prog_name): ++ parser = super(SetRGPortForwarding, self).get_parser(prog_name) ++ parser.add_argument( ++ 'router', ++ metavar='', ++ help=_("Router that the port forwarding belongs to (ID / Name)") ++ ) ++ parser.add_argument( ++ 'port_forwarding_id', ++ metavar="", ++ help=_("The ID of the router gateway port forwarding") ++ ) ++ parser.add_argument( ++ '--port', ++ metavar='', ++ help=_("The ID of the network port associated to " ++ "the router gateway port forwarding") ++ ) ++ parser.add_argument( ++ '--internal-ip-address', ++ metavar='', ++ help=_("The fixed IPv4 address of the network port " ++ "associated to the router gateway port forwarding") ++ ) ++ parser.add_argument( ++ '--internal-protocol-port', ++ metavar='', ++ type=int, ++ help=_("The TCP/UDP/other protocol port number of the " ++ "network port fixed IPv4 address associated to " ++ "the router gateway port forwarding") ++ ) ++ parser.add_argument( ++ '--external-protocol-port', ++ type=int, ++ metavar='', ++ help=_("The TCP/UDP/other protocol port number of the " ++ "port forwarding's router gateway address") ++ ) ++ parser.add_argument( ++ '--protocol', ++ metavar='', ++ choices=['tcp', 'udp'], ++ help=_("The IP protocol used in the " ++ "router gateway port forwarding") ++ ) ++ return parser ++ ++ def take_action(self, parsed_args): ++ client = self.app.client_manager.network ++ router = client.find_router(parsed_args.router, ignore_missing=False) ++ ++ attrs = {} ++ if parsed_args.port: ++ port = client.find_port(parsed_args.port, ignore_missing=False) ++ attrs['internal_port_id'] = port.id ++ ++ if parsed_args.internal_ip_address: ++ attrs['internal_ip_address'] = parsed_args.internal_ip_address ++ if parsed_args.internal_protocol_port is not None: ++ if (parsed_args.internal_protocol_port <= 0 or ++ parsed_args.internal_protocol_port > 65535): ++ msg = _("The port number range is <1-65535>") ++ raise exceptions.CommandError(msg) ++ attrs['internal_port'] = parsed_args.internal_protocol_port ++ ++ if parsed_args.external_protocol_port is not None: ++ if (parsed_args.external_protocol_port <= 0 or ++ parsed_args.external_protocol_port > 65535): ++ msg = _("The port number range is <1-65535>") ++ raise exceptions.CommandError(msg) ++ attrs['external_port'] = parsed_args.external_protocol_port ++ ++ if parsed_args.protocol: ++ attrs['protocol'] = parsed_args.protocol ++ ++ client.update_router_gateway_port_forwarding( ++ router.id, parsed_args.port_forwarding_id, **attrs ++ ) +diff --git a/network/v2/router.py b/network/v2/router.py +index 5d85e485..e7df6502 100644 +--- a/network/v2/router.py ++++ b/network/v2/router.py +@@ -64,6 +64,7 @@ _formatters = { + 'location': format_columns.DictColumn, + 'routes': RoutesColumn, + 'tags': format_columns.ListColumn, ++ 'configurations': format_columns.DictColumn + } + + +@@ -76,6 +77,8 @@ def _get_columns(item): + } + if hasattr(item, 'interfaces_info'): + column_map['interfaces_info'] = 'interfaces_info' ++ if hasattr(item, 'configurations'): ++ column_map['configurations'] = 'configurations' + invisible_columns = [] + if item.is_ha is None: + invisible_columns.append('is_ha') +@@ -219,6 +222,19 @@ class CreateRouter(command.ShowOne): + metavar='', + help=_("Set router description") + ) ++ parser.add_argument( ++ '--preferred-agent', ++ help=_("Set the preferred agent of router (legacy router only)") ++ ) ++ parser.add_argument( ++ '--master-agent', ++ help=_("Set the master agent of router (ha router only)") ++ ) ++ parser.add_argument( ++ '--slave-agents', ++ type=str, ++ help=_("Set the slave agents of router (ha router only)") ++ ) + parser.add_argument( + '--project', + metavar='', +@@ -244,8 +260,17 @@ class CreateRouter(command.ShowOne): + attrs = _get_attrs(self.app.client_manager, parsed_args) + if parsed_args.ha: + attrs['ha'] = True ++ if parsed_args.master_agent and parsed_args.slave_agents: ++ configurations = dict( ++ master_agent=parsed_args.master_agent, ++ slave_agents=parsed_args.slave_agents.split(',') ++ ) ++ attrs['configurations'] = configurations + if parsed_args.no_ha: + attrs['ha'] = False ++ if parsed_args.prefrred_agent: ++ configurations = dict(prefrred_agent=parsed_args.prefrred_agent) ++ attrs['configurations'] = configurations + obj = client.create_router(**attrs) + # tags cannot be set when created, so tags need to be set later. + _tag.update_tags_for_set(client, obj, parsed_args) +@@ -565,6 +590,19 @@ class SetRouter(command.Command): + help=_("Clear high availability attribute of the router " + "(disabled router only)") + ) ++ parser.add_argument( ++ '--preferred-agent', ++ help=_("Set the preferred agent of router (disabled router only)") ++ ) ++ parser.add_argument( ++ '--master-agent', ++ help=_("Set the master agent of router (disabled router only)") ++ ) ++ parser.add_argument( ++ '--slave-agents', ++ type=str, ++ help=_("Set the slave agents of router (disabled router only)") ++ ) + parser.add_argument( + '--external-gateway', + metavar="", +@@ -618,6 +656,19 @@ class SetRouter(command.Command): + elif parsed_args.no_ha: + attrs['ha'] = False + ++ if parsed_args.master_agent or parsed_args.slave_agents: ++ configurations = dict() ++ if parsed_args.master_agent: ++ configurations['master_agent'] = parsed_args.master_agent ++ if parsed_args.slave_agents: ++ slave_agents = parsed_args.slave_agents.split(',') ++ configurations['slave_agents'] = slave_agents ++ attrs['configurations'] = configurations ++ ++ if parsed_args.prefrred_agent: ++ configurations = dict(prefrred_agent=parsed_args.prefrred_agent) ++ attrs['configurations'] = configurations ++ + if parsed_args.routes is not None: + for route in parsed_args.routes: + route['nexthop'] = route.pop('gateway') diff --git a/python-openstackclient.spec b/python-openstackclient.spec index 3a6ca064535e81b64c68fec83deab45e27ac6a49..e23009dbe05f9aa41b5ddd9dc979202fc7ac0ff6 100644 --- a/python-openstackclient.spec +++ b/python-openstackclient.spec @@ -1,14 +1,27 @@ +%define gitPatch() \ +cd %1; \ +git init && git config user.name "openstack-plugin" && git config user.email "openstack-plugin"; \ +git add . && git commit -m "openstack-plugin init"; \ +git apply --check %2 || exit 1 && git apply %2; \ +git add . && git commit -m "openstack-plugin patch" + +%define gitUnPatch() \ +cd %1;\ +git reset --hard HEAD~;\ +rm -rf %1/.git + %{!?upstream_version: %global upstream_version %{version}%{?milestone}} %global with_doc 1 Name: python-openstackclient Version: 4.0.2 -Release: 1 +Release: 2 Summary: OpenStack Command-line Client License: Apache-2.0 URL: http://launchpad.net/%{name} Source0: https://tarballs.openstack.org/%{name}/%{name}-%{upstream_version}.tar.gz +Source1: 0001-add-distributed-traffic-feature-support.patch BuildArch: noarch BuildRequires: git @@ -81,6 +94,16 @@ Summary: Translation files for Openstackclient %description -n python3-openstackclient-lang Translation files for Openstackclient +%package -n python3-openstackclient-distributed-traffic +Summary: The plug-in package of python3-openstackclient for distributed traffic feature +Requires: git +Requires: python3-crudini +Requires: python3-openstackclient + +%description -n python3-openstackclient-distributed-traffic +The plug-in package of python3-openstackclient for distributed traffic feature + + %prep %autosetup -n %{name}-%{upstream_version} @@ -112,12 +135,33 @@ rm -f %{buildroot}%{python3_sitelib}/openstackclient/locale/*pot mv %{buildroot}%{python3_sitelib}/openstackclient/locale %{buildroot}%{_datadir}/locale rm -rf %{buildroot}%{python3_sitelib}/openstackclient/locale +# Install distributed traffic feature patch +install -D -p -m 644 %{SOURCE1} %{buildroot}%{python3_sitelib}/openstack-plugin/python-openstackclient/$(basename %{SOURCE1}) + %find_lang openstackclient --all-name %check export PYTHON=%{__python3} stestr run +%post -n python3-openstackclient-distributed-traffic +export patch_name=$(basename %{SOURCE1}) +%gitPatch %{python3_sitelib}/openstackclient %{python3_sitelib}/openstack-plugin/python-openstackclient/$patch_name +crudini --set %{python3_sitelib}/python_openstackclient-*.egg-info/entry_points.txt openstack.network.v2 router_gateway_port_forwarding_set openstackclient.network.v2.rg_port_forwarding:SetRGPortForwarding +crudini --set %{python3_sitelib}/python_openstackclient-*.egg-info/entry_points.txt openstack.network.v2 router_gateway_port_forwarding_show openstackclient.network.v2.rg_port_forwarding:ShowRGPortForwarding +crudini --set %{python3_sitelib}/python_openstackclient-*.egg-info/entry_points.txt openstack.network.v2 router_gateway_port_forwarding_create openstackclient.network.v2.rg_port_forwarding:CreateRGPortForwarding +crudini --set %{python3_sitelib}/python_openstackclient-*.egg-info/entry_points.txt openstack.network.v2 router_gateway_port_forwarding_delete openstackclient.network.v2.rg_port_forwarding:DeleteRGPortForwarding + + + +%preun -n python3-openstackclient-distributed-traffic +%gitUnPatch %{python3_sitelib}/openstackclient +crudini --del %{python3_sitelib}/python_openstackclient-*.egg-info/entry_points.txt openstack.network.v2 router_gateway_port_forwarding_set +crudini --del %{python3_sitelib}/python_openstackclient-*.egg-info/entry_points.txt openstack.network.v2 router_gateway_port_forwarding_show +crudini --del %{python3_sitelib}/python_openstackclient-*.egg-info/entry_points.txt openstack.network.v2 router_gateway_port_forwarding_create +crudini --del %{python3_sitelib}/python_openstackclient-*.egg-info/entry_points.txt openstack.network.v2 router_gateway_port_forwarding_delete + + %files -n python3-openstackclient %license LICENSE %doc README.rst @@ -136,6 +180,12 @@ stestr run %files -n python3-openstackclient-lang -f openstackclient.lang %license LICENSE +%files -n python3-openstackclient-distributed-traffic +%{python3_sitelib}/openstack-plugin/python-openstackclient/%{basename %{SOURCE1}} + %changelog +* Tue Dec 5 2023 wangkuntian - 4.0.2-2 +- Add distributed traffic feature patch + * Mon Nov 8 2021 huangtianhua 4.0.2-1 - Init python-openstackclient with 4.0.2