Compare commits

..

40 Commits

Author SHA1 Message Date
18b1232db4 Update master for stable/2026.1
Add file to the reno documentation build to show release notes for
stable/2026.1.

Use pbr instruction to increment the minor version number
automatically so that master versions are higher than the versions on
stable/2026.1.

Sem-Ver: feature
Change-Id: Icaf974beefa4e54680fa161370a54ffd9487c0ca
Signed-off-by: OpenStack Release Bot <infra-root@openstack.org>
Generated-By: openstack/project-config:roles/copy-release-tools-scripts/files/release-tools/add_release_note_page.sh
2026-03-04 18:25:43 +00:00
Slawek Kaplonski
6e5eb4da33 [fwaas] Don't ignore missing fw related resources
Previously when fwaas osc plugin was going to look for firewall related
resources, like e.g. asking neutron for firewall group or policy was
done with ignore_missing=True which means that openstack SDK client
didn't raise exception when requested object was not found on the
server.
That led to the weird and unclear error message displayed by the
OpenStack client which said something about "'NoneType' object is not
subscriptable".

This patch adds "ignore_missing=True" to all those "find_*" methods used
in the fwaas osc plugin. That way proper exception is raised by the SDK
client and valid error message is displayed to the user by OSC.

Closes-bug: #2142458

Change-Id: I309a5dbf61c65d5837d4ea2b3235aa41269ae73d
Signed-off-by: Slawek Kaplonski <skaplons@redhat.com>
2026-02-26 11:04:47 +01:00
Slawek Kaplonski
f7c085005d [FWaaS] Remove client side protocol validation
There is no need to limit available choices for the firewall rule's
protocol on the client side. Neutron-fwaas plugin on the server side
will do the validation in the same way as for security group rules.
And for SG rules OSC is not validating nor limiting choices on the
client's side at all.

Closes-bug: #2142479

Change-Id: I8c02a2232601c2ab6655c458aa0365102b3b5e2d
Signed-off-by: Slawek Kaplonski <skaplons@redhat.com>
2026-02-23 16:57:58 +01:00
Takashi Kajinami
d9a3518f75 Bump flake8-import-order
The 1.18.2 release requires pkg_resources.

The dependency was removed in 1.19.0 .

Change-Id: I25106085e68dfc13a091af0e9e365287dac17308
Signed-off-by: Takashi Kajinami <kajinamit@oss.nttdata.com>
2026-02-21 00:18:54 +09:00
Zuul
efa0ccb944 Merge "Revert "Add Tap-as-a-Service client code"" 2025-12-12 17:29:15 +00:00
Zhan Zhang
8f72d77812 v2_0: Use 'bindings' when listing port bindings
This commit fixes a bug in v2_0 client's "list_port_bindings"
function, where it uses "port_bindings" to access Neutron's
response, instead of "bindings" [0].

[0]: https://docs.openstack.org/api-ref/network/v2/index.html#show-port-binding-of-a-port

Closes-Bug: #2130459
Change-Id: I32ef753ec212b55f698e3844e043f68b22992ead
Signed-off-by: Zhan Zhang <zzhang953@bloomberg.net>
2025-11-11 14:05:44 -05:00
Miro Tomaska
a991ac87c7 Revert "Add Tap-as-a-Service client code"
This reverts commit 01ffc4684a.

Reason for revert:
In the last PTG we decided that the best location for the stadium projects osc client code would be the openstackclient repo. A patch was proposed for tapaas, see depends-on link below. Other projects will follow

Change-Id: Iaad2080f0ef552a0c0a00635bea48130cfc327a4
Depends-On: https://review.opendev.org/c/openstack/python-openstackclient/+/963445
Signed-off-by: Miro Tomaska <mtomaska@redhat.com>
2025-11-06 21:39:01 +00:00
01d0553ca4 reno: Update master for unmaintained/2024.1
Update the 2024.1 release notes configuration to build from
unmaintained/2024.1.

Change-Id: Ic2592d22b36b22f3cf48a21d81bfb0b41b31ae86
Signed-off-by: OpenStack Release Bot <infra-root@openstack.org>
Generated-By: openstack/project-config:roles/copy-release-tools-scripts/files/release-tools/change_reno_branch_to_unmaintained.sh
2025-10-31 12:06:40 +00:00
Zuul
66ccb4569d Merge "Add Tap-as-a-Service client code" 2025-09-19 16:22:01 +00:00
Zuul
1aee34b246 Merge "Drop unused os-client-config" 2025-09-15 20:36:02 +00:00
Mohammed Naser
01ffc4684a Add Tap-as-a-Service client code
This commit adds the Tap-as-a-Service client code as-is based
on the discussion that it can now be included into the Neutron
client[1].

[1]: https://lists.openstack.org/archives/list/openstack-discuss@lists.openstack.org/message/PCITF3UPLEEVQB7EVJ2MB6FLAI3RFYSR/

Change-Id: I82b3229b3f9ac7ef57324d0a611527c77d26c3b6
Signed-off-by: Mohammed Naser <mnaser@vexxhost.com>
2025-09-12 11:37:06 -04:00
2f170ce6aa Update master for stable/2025.2
Add file to the reno documentation build to show release notes for
stable/2025.2.

Use pbr instruction to increment the minor version number
automatically so that master versions are higher than the versions on
stable/2025.2.

Sem-Ver: feature
Change-Id: I97f7bba4f875b98d98f03ba60ee394a1aa64a3fd
Signed-off-by: OpenStack Release Bot <infra-root@openstack.org>
Generated-By: openstack/project-config:roles/copy-release-tools-scripts/files/release-tools/add_release_note_page.sh
2025-09-04 13:44:40 +00:00
Takashi Kajinami
275924ecc8 Drop unused os-client-config
It was deprecated[1] after the code was merged into openstacksdk[2].
It's not actually used by any code in this repository.

[1] https://review.opendev.org/c/openstack/os-client-config/+/549307
[2] https://review.opendev.org/c/openstack/openstacksdk/+/518128

Change-Id: Ia93d2952ca09fc70a970a85789775441ed114d49
Signed-off-by: Takashi Kajinami <kajinamit@oss.nttdata.com>
2025-07-02 23:23:28 +09:00
Zuul
5f7d102f0e Merge "Add warning for using the python bindings" 2025-06-13 01:25:15 +00:00
Takashi Kajinami
905be917fe Drop explicit dependency on python-subunit
It is no longer directly used by any test code in this repository since
we switched to stestr[1].

It is now installed as a dependency of stestr.

[1] 259c386d42

Change-Id: Iacbdd3477a9e0b2d2bae3e09d20867d794586673
2025-06-10 12:12:18 +00:00
elajkat
857b4b233c Add warning for using the python bindings
The deprecation of python-neutronclient bindings
was discussed on the 2025.2 (Flamingo) PTG:
https://etherpad.opendev.org/p/apr2025-ptg-neutron#L163

Change-Id: Ieb08fc0884d7f386dc94090dce9d284d786d1ec2
2025-04-30 13:35:14 +02:00
690bb97d9d Update master for stable/2025.1
Add file to the reno documentation build to show release notes for
stable/2025.1.

Use pbr instruction to increment the minor version number
automatically so that master versions are higher than the versions on
stable/2025.1.

Sem-Ver: feature
Change-Id: Ia1fb8c591c315404d4e758a657a4b35fe523dfff
2025-03-06 09:16:53 +00:00
Zuul
7d998d2525 Merge "Remove unnecessary direct dependency on iso8601" 2025-03-03 20:57:35 +00:00
Takashi Kajinami
370bd215c7 Remove unnecessary direct dependency on iso8601
Direct dependency on the library was removed by [1].

[1] 9c464ba53f

Change-Id: Id24f85b68c42977cb3f34c66934238a16e03a79c
2025-03-01 01:11:16 +09:00
Bodo Petermann
dc026cd3d6 vpnaas: add support for more ciphers (auth, encryption, pfs modes)
Extend the lists of choices for encryption algorithms, auth algorithms,
and PFS groups to include the additions made in neutron-vpnaas.

Encryption algorithms: add AES CCM mode and AES GCM mode variants
for 128/192/256 bit keys and 8/12/16 octet ICVs, add AES CTR modes
for 128/192/256 bit keys
Auth algorithms: add aes-xcbc and aes-cmac.
PFS: add Diffie Hellman groups 15 to 31.

Related-Bug: #1938284
Change-Id: I3fd17b93820da9d86b2fc4bc89058475d7629d5d
2025-02-26 16:02:25 +01:00
Zuul
1d7a13ab11 Merge "vpnaas: show external_vx_ip for vpn service show" 2024-11-20 17:34:37 +00:00
636ac764d3 reno: Update master for unmaintained/2023.1
Update the 2023.1 release notes configuration to build from
unmaintained/2023.1.

Change-Id: Id69fb2c2e197e91d679473c52f556e378fa3ba1e
2024-11-14 10:35:43 +00:00
elajkat
b2107dc867 vpnaas: show external_vx_ip for vpn service show
Closes-Bug: #2086144
Change-Id: Ic8ae85ee62e35991e8bb0096cdc6785a0b04e545
2024-11-08 09:02:34 +01:00
Zuul
75e112bc9b Merge "Drop unused tempest from test requirements" 2024-11-04 20:43:19 +00:00
Zuul
1befb3cd08 Merge "tox: Drop envdir" 2024-10-30 10:50:03 +00:00
Takashi Kajinami
f882f1ddb6 Remove Python 3.8 support
Python 3.8 was removed from the tested runtimes for 2024.2[1] and has
not been tested since then.

Also add a few newer versions which are part of the tested runtimes for
2025.1.

[1] https://governance.openstack.org/tc/reference/runtimes/2024.2.html

Change-Id: Ic0c05be1ce22dc2a5c67c6eb2b215d50d57ff116
2024-10-24 21:19:15 +09:00
Takashi Kajinami
8a2f07683b tox: Drop envdir
tox now always recreates an env although the env is shared using envdir
options.
~~~
$ tox -e genpolicy
genpolicy: recreate env because env type changed from
{'name': 'genconfig', 'type': 'VirtualEnvRunner'} to
{'name': 'genpolicy', 'type': 'VirtualEnvRunner'}
~~~

According to the maintainer of tox, this functionality is not intended
to be supported.
https://github.com/tox-dev/tox/issues/425#issuecomment-1011944293

Change-Id: I496d3ffe65be13df80c29ac4582596be0aa4d909
2024-10-13 01:30:39 +09:00
Takashi Kajinami
5438377b9c Drop unused tempest from test requirements
None of the tests implemented in this repository depend on tempest.

In addition testscenarios is not used either, and can be removed.

Change-Id: I642f8a5093a6e2b5528e446a798270734c4ed30d
2024-10-12 00:06:07 +09:00
d36a8a4a17 Update master for stable/2024.2
Add file to the reno documentation build to show release notes for
stable/2024.2.

Use pbr instruction to increment the minor version number
automatically so that master versions are higher than the versions on
stable/2024.2.

Sem-Ver: feature
Change-Id: I02c3547991a272afcc3a8902476949cd0bd1ce74
2024-09-05 16:02:19 +00:00
Zuul
a10390c62e Merge "Fix insert and remove rule from firewall policy" 2024-05-20 11:19:44 +00:00
Valentin Chassignol
cb9aae55c8 BGPVPN: Fix resource comparison
This patch updates the resource comparison to accurately differentiate
between the manipulation of networks, ports, and router associations.
Introduced in I84fe4bb45d24c2f4a7a0246e2b9fb50354a715e0, the previous
implementation contained incorrect variable names, leading to
inconsistent results. This fix ensures that each resource type is
properly identified during comparison.

Closes-Bug: #2064286
Change-Id: Ieb87174296240f8f76ec10b39007935545b1bd3f
2024-05-06 14:22:08 +00:00
fb8de782bc reno: Update master for unmaintained/zed
Update the zed release notes configuration to build from
unmaintained/zed.

Change-Id: I73aa32050dfaa378dd7455846e994560851c0e54
2024-04-30 08:54:59 +00:00
Benjamin Reichel
2169b2bbab Fix insert and remove rule from firewall policy
This change fixes the incompatability with the openstacksdk
for inserting and removing rules from firewall policiese.

Closes-Bug: #2057816
Change-Id: I8db7b4cc61b810887b0a675efa562f089821e8ec
2024-04-12 10:42:12 +02:00
Zuul
111713fd62 Merge "reno: Update master for unmaintained/victoria" 2024-04-02 18:36:50 +00:00
Zuul
98d8d8b5cd Merge "reno: Update master for unmaintained/wallaby" 2024-04-02 18:36:08 +00:00
Zuul
1cdac483be Merge "reno: Update master for unmaintained/xena" 2024-04-02 18:34:58 +00:00
fe515adf35 Update master for stable/2024.1
Add file to the reno documentation build to show release notes for
stable/2024.1.

Use pbr instruction to increment the minor version number
automatically so that master versions are higher than the versions on
stable/2024.1.

Sem-Ver: feature
Change-Id: I074213d853338f1e087b59f14f3c66ea449e5536
2024-03-07 15:38:58 +00:00
41e7ea6e29 reno: Update master for unmaintained/xena
Update the xena release notes configuration to build from
unmaintained/xena.

Change-Id: I074395b7079588a5dd2f6188a04b5d48b10e124b
2024-03-06 12:21:58 +00:00
863c6031fc reno: Update master for unmaintained/wallaby
Update the wallaby release notes configuration to build from
unmaintained/wallaby.

Change-Id: Ia81995fae56aef0951004ab1c7340a38f24a66f0
2024-03-06 12:14:08 +00:00
750afa1777 reno: Update master for unmaintained/victoria
Update the victoria release notes configuration to build from
unmaintained/victoria.

Change-Id: I27ad08ec3327a9a9984223f7d9319129537040e4
2024-03-06 12:04:19 +00:00
30 changed files with 272 additions and 85 deletions

View File

@@ -31,7 +31,6 @@
- openstack/keystoneauth
- openstack/neutron
- openstack/neutron-lib
- openstack/os-client-config
- openstack/python-cinderclient
- openstack/python-glanceclient
- openstack/python-ironicclient

View File

@@ -20,6 +20,7 @@ provides a Python API (the ``neutronclient`` module).
.. note:: This project has been deprecated. The CLI code has been deleted
and is not accessible anymore. The Python bindings are still in use by
other projects but no new features will be added to this project.
All projects under Openstack governance migrating to use OpenstackSDK.
Any new feature should be proposed to OpenStack SDK and OpenStack
Client.

View File

@@ -129,19 +129,19 @@ def _get_common_attrs(client_manager, parsed_args, is_create=True):
if (parsed_args.ingress_firewall_policy and
parsed_args.no_ingress_firewall_policy):
attrs['ingress_firewall_policy_id'] = client.find_firewall_policy(
parsed_args.ingress_firewall_policy)['id']
parsed_args.ingress_firewall_policy, ignore_missing=False)['id']
elif parsed_args.ingress_firewall_policy:
attrs['ingress_firewall_policy_id'] = client.find_firewall_policy(
parsed_args.ingress_firewall_policy)['id']
parsed_args.ingress_firewall_policy, ignore_missing=False)['id']
elif parsed_args.no_ingress_firewall_policy:
attrs['ingress_firewall_policy_id'] = None
if (parsed_args.egress_firewall_policy and
parsed_args.no_egress_firewall_policy):
attrs['egress_firewall_policy_id'] = client.find_firewall_policy(
parsed_args.egress_firewall_policy)['id']
parsed_args.egress_firewall_policy, ignore_missing=False)['id']
elif parsed_args.egress_firewall_policy:
attrs['egress_firewall_policy_id'] = client.find_firewall_policy(
parsed_args.egress_firewall_policy)['id']
parsed_args.egress_firewall_policy, ignore_missing=False)['id']
elif parsed_args.no_egress_firewall_policy:
attrs['egress_firewall_policy_id'] = None
if parsed_args.share:
@@ -165,7 +165,7 @@ def _get_common_attrs(client_manager, parsed_args, is_create=True):
ports.append(client.find_port(p)['id'])
if not is_create:
ports += client.find_firewall_group(
parsed_args.firewall_group)['ports']
parsed_args.firewall_group, ignore_missing=False)['ports']
attrs['ports'] = sorted(set(ports))
elif parsed_args.no_port:
attrs['ports'] = []
@@ -220,7 +220,8 @@ class DeleteFirewallGroup(command.Command):
result = 0
for fwg in parsed_args.firewall_group:
try:
fwg_id = client.find_firewall_group(fwg)['id']
fwg_id = client.find_firewall_group(
fwg, ignore_missing=False)['id']
client.delete_firewall_group(fwg_id)
except Exception as e:
result += 1
@@ -281,7 +282,8 @@ class SetFirewallGroup(command.Command):
def take_action(self, parsed_args):
client = self.app.client_manager.network
fwg_id = client.find_firewall_group(parsed_args.firewall_group)['id']
fwg_id = client.find_firewall_group(
parsed_args.firewall_group, ignore_missing=False)['id']
attrs = _get_common_attrs(self.app.client_manager, parsed_args,
is_create=False)
try:
@@ -305,7 +307,8 @@ class ShowFirewallGroup(command.ShowOne):
def take_action(self, parsed_args):
client = self.app.client_manager.network
fwg_id = client.find_firewall_group(parsed_args.firewall_group)['id']
fwg_id = client.find_firewall_group(
parsed_args.firewall_group, ignore_missing=False)['id']
obj = client.get_firewall_group(fwg_id)
display_columns, columns = utils.get_osc_show_columns_for_sdk_resource(
obj, _attr_map_dict, ['location', 'tenant_id'])
@@ -366,7 +369,7 @@ class UnsetFirewallGroup(command.Command):
attrs['admin_state_up'] = False
if parsed_args.port:
old = client.find_firewall_group(
parsed_args.firewall_group)['ports']
parsed_args.firewall_group, ignore_missing=False)['ports']
new = [client.find_port(r)['id'] for r in parsed_args.port]
attrs['ports'] = sorted(list(set(old) - set(new)))
if parsed_args.all_port:
@@ -375,7 +378,8 @@ class UnsetFirewallGroup(command.Command):
def take_action(self, parsed_args):
client = self.app.client_manager.network
fwg_id = client.find_firewall_group(parsed_args.firewall_group)['id']
fwg_id = client.find_firewall_group(
parsed_args.firewall_group, ignore_missing=False)['id']
attrs = self._get_attrs(client, parsed_args)
try:
client.update_firewall_group(fwg_id, **attrs)

View File

@@ -67,16 +67,18 @@ def _get_common_attrs(client_manager, parsed_args, is_create=True):
if parsed_args.firewall_rule and parsed_args.no_firewall_rule:
_firewall_rules = []
for f in parsed_args.firewall_rule:
_firewall_rules.append(client.find_firewall_rule(f)['id'])
_firewall_rules.append(
client.find_firewall_rule(f, ignore_missing=False)['id'])
attrs[const.FWRS] = _firewall_rules
elif parsed_args.firewall_rule:
rules = []
if not is_create:
foobar = client.find_firewall_policy(
parsed_args.firewall_policy)
parsed_args.firewall_policy, ignore_missing=False)
rules += foobar[const.FWRS]
for f in parsed_args.firewall_rule:
rules.append(client.find_firewall_rule(f)['id'])
rules.append(
client.find_firewall_rule(f, ignore_missing=False)['id'])
attrs[const.FWRS] = rules
elif parsed_args.no_firewall_rule:
attrs[const.FWRS] = []
@@ -173,7 +175,8 @@ class DeleteFirewallPolicy(command.Command):
result = 0
for fwp in parsed_args.firewall_policy:
try:
fwp_id = client.find_firewall_policy(fwp)['id']
fwp_id = client.find_firewall_policy(
fwp, ignore_missing=False)['id']
client.delete_firewall_policy(fwp_id)
except Exception as e:
result += 1
@@ -220,12 +223,12 @@ class FirewallPolicyInsertRule(command.Command):
if 'insert_before' in parsed_args:
if parsed_args.insert_before:
_insert_before = client.find_firewall_rule(
parsed_args.insert_before)['id']
parsed_args.insert_before, ignore_missing=False)['id']
_insert_after = ''
if 'insert_after' in parsed_args:
if parsed_args.insert_after:
_insert_after = client.find_firewall_rule(
parsed_args.insert_after)['id']
parsed_args.insert_after, ignore_missing=False)['id']
return {'firewall_rule_id': _rule_id,
'insert_before': _insert_before,
'insert_after': _insert_after}
@@ -233,9 +236,9 @@ class FirewallPolicyInsertRule(command.Command):
def take_action(self, parsed_args):
client = self.app.client_manager.network
policy_id = client.find_firewall_policy(
parsed_args.firewall_policy)['id']
parsed_args.firewall_policy, ignore_missing=False)['id']
body = self.args2body(parsed_args)
client.insert_rule_into_policy(policy_id, body)
client.insert_rule_into_policy(policy_id, **body)
rule_id = body['firewall_rule_id']
policy = parsed_args.firewall_policy
print((_('Inserted firewall rule %(rule)s in firewall policy '
@@ -261,10 +264,10 @@ class FirewallPolicyRemoveRule(command.Command):
def take_action(self, parsed_args):
client = self.app.client_manager.network
policy_id = client.find_firewall_policy(
parsed_args.firewall_policy)['id']
parsed_args.firewall_policy, ignore_missing=False)['id']
fwr_id = _get_required_firewall_rule(client, parsed_args)
body = {'firewall_rule_id': fwr_id}
client.remove_rule_from_policy(policy_id, body)
client.remove_rule_from_policy(policy_id, **body)
rule_id = body['firewall_rule_id']
policy = parsed_args.firewall_policy
print((_('Removed firewall rule %(rule)s from firewall policy '
@@ -322,7 +325,7 @@ class SetFirewallPolicy(command.Command):
def take_action(self, parsed_args):
client = self.app.client_manager.network
fwp_id = client.find_firewall_policy(
parsed_args.firewall_policy)['id']
parsed_args.firewall_policy, ignore_missing=False)['id']
attrs = _get_common_attrs(self.app.client_manager,
parsed_args, is_create=False)
try:
@@ -347,7 +350,7 @@ class ShowFirewallPolicy(command.ShowOne):
def take_action(self, parsed_args):
client = self.app.client_manager.network
fwp_id = client.find_firewall_policy(
parsed_args.firewall_policy)['id']
parsed_args.firewall_policy, ignore_missing=False)['id']
obj = client.get_firewall_policy(fwp_id)
display_columns, columns = utils.get_osc_show_columns_for_sdk_resource(
obj, _attr_map_dict, ['location', 'tenant_id'])
@@ -359,7 +362,8 @@ def _get_required_firewall_rule(client, parsed_args):
if not parsed_args.firewall_rule:
msg = (_("Firewall rule (name or ID) is required."))
raise exceptions.CommandError(msg)
return client.find_firewall_rule(parsed_args.firewall_rule)['id']
return client.find_firewall_rule(
parsed_args.firewall_rule, ignore_missing=False)['id']
class UnsetFirewallPolicy(command.Command):
@@ -399,10 +403,11 @@ class UnsetFirewallPolicy(command.Command):
if parsed_args.firewall_rule:
current = client.find_firewall_policy(
parsed_args.firewall_policy)[const.FWRS]
parsed_args.firewall_policy, ignore_missing=False)[const.FWRS]
removed = []
for f in set(parsed_args.firewall_rule):
removed.append(client.find_firewall_rule(f)['id'])
removed.append(
client.find_firewall_rule(f, ignore_missing=False)['id'])
attrs[const.FWRS] = [r for r in current if r not in removed]
if parsed_args.all_firewall_rule:
attrs[const.FWRS] = []
@@ -415,7 +420,7 @@ class UnsetFirewallPolicy(command.Command):
def take_action(self, parsed_args):
client = self.app.client_manager.network
fwp_id = client.find_firewall_policy(
parsed_args.firewall_policy)['id']
parsed_args.firewall_policy, ignore_missing=False)['id']
attrs = self._get_attrs(self.app.client_manager, parsed_args)
try:
client.update_firewall_policy(fwp_id, **attrs)

View File

@@ -86,9 +86,12 @@ def _get_common_parser(parser):
help=_('Description of the firewall rule'))
parser.add_argument(
'--protocol',
choices=['tcp', 'udp', 'icmp', 'any'],
type=nc_utils.convert_to_lowercase,
help=_('Protocol for the firewall rule'))
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))'))
parser.add_argument(
'--action',
choices=['allow', 'deny', 'reject'],
@@ -226,12 +229,12 @@ def _get_common_attrs(client_manager, parsed_args, is_create=True):
attrs['shared'] = False
if parsed_args.source_firewall_group:
attrs['source_firewall_group_id'] = client.find_firewall_group(
parsed_args.source_firewall_group)['id']
parsed_args.source_firewall_group, ignore_missing=False)['id']
if parsed_args.no_source_firewall_group:
attrs['source_firewall_group_id'] = None
if parsed_args.destination_firewall_group:
attrs['destination_firewall_group_id'] = client.find_firewall_group(
parsed_args.destination_firewall_group)['id']
parsed_args.destination_firewall_group, ignore_missing=False)['id']
if parsed_args.no_destination_firewall_group:
attrs['destination_firewall_group_id'] = None
return attrs
@@ -281,7 +284,8 @@ class DeleteFirewallRule(command.Command):
result = 0
for fwr in parsed_args.firewall_rule:
try:
fwr_id = client.find_firewall_rule(fwr)['id']
fwr_id = client.find_firewall_rule(
fwr, ignore_missing=False)['id']
client.delete_firewall_rule(fwr_id)
except Exception as e:
result += 1
@@ -358,7 +362,8 @@ class SetFirewallRule(command.Command):
client = self.app.client_manager.network
attrs = _get_common_attrs(self.app.client_manager,
parsed_args, is_create=False)
fwr_id = client.find_firewall_rule(parsed_args.firewall_rule)['id']
fwr_id = client.find_firewall_rule(
parsed_args.firewall_rule, ignore_missing=False)['id']
try:
client.update_firewall_rule(fwr_id, **attrs)
except Exception as e:
@@ -380,7 +385,8 @@ class ShowFirewallRule(command.ShowOne):
def take_action(self, parsed_args):
client = self.app.client_manager.network
fwr_id = client.find_firewall_rule(parsed_args.firewall_rule)['id']
fwr_id = client.find_firewall_rule(
parsed_args.firewall_rule, ignore_missing=False)['id']
obj = client.get_firewall_rule(fwr_id)
display_columns, columns = utils.get_osc_show_columns_for_sdk_resource(
obj, _attr_map_dict, ['location', 'tenant_id'])
@@ -458,7 +464,8 @@ class UnsetFirewallRule(command.Command):
def take_action(self, parsed_args):
client = self.app.client_manager.network
attrs = self._get_attrs(self.app.client_manager, parsed_args)
fwr_id = client.find_firewall_rule(parsed_args.firewall_rule)['id']
fwr_id = client.find_firewall_rule(
parsed_args.firewall_rule, ignore_missing=False)['id']
try:
client.update_firewall_rule(fwr_id, **attrs)
except Exception as e:

View File

@@ -75,10 +75,10 @@ class CreateBgpvpnResAssoc(command.ShowOne):
body.update(
arg2body(bgpvpn['id'], parsed_args))
if self._assoc_res_name == constants.NETWORK_ASSOC:
if self._resource == constants.NETWORK_ASSOC:
obj = client.create_bgpvpn_network_association(
bgpvpn['id'], **body)
elif self._assoc_res_name == constants.PORT_ASSOCS:
elif self._resource == constants.PORT_ASSOC:
obj = client.create_bgpvpn_port_association(bgpvpn['id'], **body)
else:
obj = client.create_bgpvpn_router_association(
@@ -123,10 +123,10 @@ class SetBgpvpnResAssoc(command.Command):
arg2body = getattr(self, '_args2body', None)
if callable(arg2body):
body = arg2body(bgpvpn['id'], parsed_args)
if self._assoc_res_name == constants.NETWORK_ASSOC:
if self._resource == constants.NETWORK_ASSOC:
client.update_bgpvpn_network_association(
bgpvpn['id'], parsed_args.resource_association_id, **body)
elif self._assoc_res_name == constants.PORT_ASSOCS:
elif self._resource == constants.PORT_ASSOC:
client.update_bgpvpn_port_association(
bgpvpn['id'], parsed_args.resource_association_id, **body)
else:
@@ -165,9 +165,9 @@ class DeleteBgpvpnResAssoc(command.Command):
fails = 0
for id in parsed_args.resource_association_ids:
try:
if self._assoc_res_name == constants.NETWORK_ASSOC:
if self._resource == constants.NETWORK_ASSOC:
client.delete_bgpvpn_network_association(bgpvpn['id'], id)
elif self._assoc_res_name == constants.PORT_ASSOCS:
elif self._resource == constants.PORT_ASSOC:
client.delete_bgpvpn_port_association(bgpvpn['id'], id)
else:
client.delete_bgpvpn_router_association(bgpvpn['id'], id)
@@ -221,10 +221,10 @@ class ListBgpvpnResAssoc(command.Lister):
params = {}
if parsed_args.property:
params.update(parsed_args.property)
if self._assoc_res_name == constants.NETWORK_ASSOC:
if self._resource == constants.NETWORK_ASSOC:
objs = client.bgpvpn_network_associations(
bgpvpn['id'], retrieve_all=True, **params)
elif self._assoc_res_name == constants.PORT_ASSOCS:
elif self._resource == constants.PORT_ASSOC:
objs = client.bgpvpn_port_associations(
bgpvpn['id'], retrieve_all=True, **params)
else:
@@ -265,10 +265,10 @@ class ShowBgpvpnResAssoc(command.ShowOne):
def take_action(self, parsed_args):
client = self.app.client_manager.network
bgpvpn = client.find_bgpvpn(parsed_args.bgpvpn)
if self._assoc_res_name == constants.NETWORK_ASSOC:
if self._resource == constants.NETWORK_ASSOC:
obj = client.get_bgpvpn_network_association(
bgpvpn['id'], parsed_args.resource_association_id)
elif self._assoc_res_name == constants.PORT_ASSOCS:
elif self._resource == constants.PORT_ASSOC:
obj = client.get_bgpvpn_port_association(
bgpvpn['id'], parsed_args.resource_association_id)
else:

View File

@@ -56,6 +56,66 @@ _attr_map_dict = {
'project_id': 'Project',
}
_auth_algorithms = [
'sha1',
'sha256',
'sha384',
'sha512',
'aes-xcbc',
'aes-cmac',
]
_encryption_algorithms = [
'3des',
'aes-128',
'aes-192',
'aes-256',
'aes-128-ccm-8',
'aes-192-ccm-8',
'aes-256-ccm-8',
'aes-128-ccm-12',
'aes-192-ccm-12',
'aes-256-ccm-12',
'aes-128-ccm-16',
'aes-192-ccm-16',
'aes-256-ccm-16',
'aes-128-gcm-8',
'aes-192-gcm-8',
'aes-256-gcm-8',
'aes-128-gcm-12',
'aes-192-gcm-12',
'aes-256-gcm-12',
'aes-128-gcm-16',
'aes-192-gcm-16',
'aes-256-gcm-16',
'aes-128-ctr',
'aes-192-ctr',
'aes-256-ctr',
]
_pfs_groups = [
'group2',
'group5',
'group14',
'group15',
'group16',
'group17',
'group18',
'group19',
'group20',
'group21',
'group22',
'group23',
'group24',
'group25',
'group26',
'group27',
'group28',
'group29',
'group30',
'group31',
]
def _convert_to_lowercase(string):
return string.lower()
@@ -68,12 +128,12 @@ def _get_common_parser(parser):
help=_('Description of the IKE policy'))
parser.add_argument(
'--auth-algorithm',
choices=['sha1', 'sha256', 'sha384', 'sha512'],
choices=_auth_algorithms,
type=_convert_to_lowercase,
help=_('Authentication algorithm'))
parser.add_argument(
'--encryption-algorithm',
choices=['aes-128', '3des', 'aes-192', 'aes-256'],
choices=_encryption_algorithms,
type=_convert_to_lowercase,
help=_('Encryption algorithm'))
parser.add_argument(
@@ -88,7 +148,7 @@ def _get_common_parser(parser):
help=_('IKE version for the policy'))
parser.add_argument(
'--pfs',
choices=['group5', 'group2', 'group14'],
choices=_pfs_groups,
type=_convert_to_lowercase,
help=_('Perfect Forward Secrecy'))
parser.add_argument(

View File

@@ -54,6 +54,66 @@ _attr_map_dict = {
'project_id': 'Project',
}
_auth_algorithms = [
'sha1',
'sha256',
'sha384',
'sha512',
'aes-xcbc',
'aes-cmac',
]
_encryption_algorithms = [
'3des',
'aes-128',
'aes-192',
'aes-256',
'aes-128-ccm-8',
'aes-192-ccm-8',
'aes-256-ccm-8',
'aes-128-ccm-12',
'aes-192-ccm-12',
'aes-256-ccm-12',
'aes-128-ccm-16',
'aes-192-ccm-16',
'aes-256-ccm-16',
'aes-128-gcm-8',
'aes-192-gcm-8',
'aes-256-gcm-8',
'aes-128-gcm-12',
'aes-192-gcm-12',
'aes-256-gcm-12',
'aes-128-gcm-16',
'aes-192-gcm-16',
'aes-256-gcm-16',
'aes-128-ctr',
'aes-192-ctr',
'aes-256-ctr',
]
_pfs_groups = [
'group2',
'group5',
'group14',
'group15',
'group16',
'group17',
'group18',
'group19',
'group20',
'group21',
'group22',
'group23',
'group24',
'group25',
'group26',
'group27',
'group28',
'group29',
'group30',
'group31',
]
def _convert_to_lowercase(string):
return string.lower()
@@ -66,7 +126,7 @@ def _get_common_parser(parser):
help=_('Description of the IPsec policy'))
parser.add_argument(
'--auth-algorithm',
choices=['sha1', 'sha256', 'sha384', 'sha512'],
choices=_auth_algorithms,
type=_convert_to_lowercase,
help=_('Authentication algorithm for IPsec policy'))
parser.add_argument(
@@ -76,7 +136,7 @@ def _get_common_parser(parser):
help=_('Encapsulation mode for IPsec policy'))
parser.add_argument(
'--encryption-algorithm',
choices=['3des', 'aes-128', 'aes-192', 'aes-256'],
choices=_encryption_algorithms,
type=_convert_to_lowercase,
help=_('Encryption algorithm for IPsec policy'))
parser.add_argument(
@@ -86,7 +146,7 @@ def _get_common_parser(parser):
help=vpn_utils.lifetime_help("IPsec"))
parser.add_argument(
'--pfs',
choices=['group2', 'group5', 'group14'],
choices=_pfs_groups,
type=_convert_to_lowercase,
help=_('Perfect Forward Secrecy for IPsec policy'))
parser.add_argument(

View File

@@ -36,6 +36,8 @@ _attr_map = (
('status', 'Status', column_util.LIST_BOTH),
('description', 'Description', column_util.LIST_LONG_ONLY),
('project_id', 'Project', column_util.LIST_LONG_ONLY),
('external_v4_ip', 'Ext v4 IP', column_util.LIST_LONG_ONLY),
('external_v6_ip', 'Ext v6 IP', column_util.LIST_LONG_ONLY),
)
_attr_map_dict = {
@@ -48,6 +50,8 @@ _attr_map_dict = {
'status': 'Status',
'description': 'Description',
'project_id': 'Project',
'external_v4_ip': 'Ext v4 IP',
'external_v6_ip': 'Ext v6 IP',
}
@@ -135,8 +139,7 @@ class CreateVPNService(command.ShowOne):
attrs['router_id'] = _router_id
obj = client.create_vpn_service(**attrs)
display_columns, columns = utils.get_osc_show_columns_for_sdk_resource(
obj, _attr_map_dict, ['location', 'tenant_id', 'external_v4_ip',
'external_v6_ip'])
obj, _attr_map_dict, ['location', 'tenant_id'])
data = utils.get_dict_properties(obj, columns)
return display_columns, data
@@ -244,7 +247,6 @@ class ShowVPNService(command.ShowOne):
ignore_missing=False)['id']
obj = client.get_vpn_service(vpn_id)
display_columns, columns = utils.get_osc_show_columns_for_sdk_resource(
obj, _attr_map_dict, ['location', 'tenant_id', 'external_v4_ip',
'external_v6_ip'])
obj, _attr_map_dict, ['location', 'tenant_id'])
data = utils.get_dict_properties(obj, columns)
return (display_columns, data)

View File

@@ -215,7 +215,7 @@ class TestCreateFirewallGroup(TestFirewallGroup, common.TestCreateFWaaS):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
headers, data = self.cmd.take_action(parsed_args)
self.networkclient.find_firewall_policy.assert_called_once_with(
ingress_policy)
ingress_policy, ignore_missing=False)
self.check_results(headers, data, request)
@@ -236,7 +236,7 @@ class TestCreateFirewallGroup(TestFirewallGroup, common.TestCreateFWaaS):
headers, data = self.cmd.take_action(parsed_args)
self.networkclient.find_firewall_policy.assert_called_once_with(
egress_policy)
egress_policy, ignore_missing=False)
self.check_results(headers, data, request)
def test_create_with_all_params(self):
@@ -398,15 +398,15 @@ class TestSetFirewallGroup(TestFirewallGroup, common.TestSetFWaaS):
# 1. Find specified firewall_group
if self.networkclient.find_firewall_group.call_count == 1:
self.networkclient.find_firewall_group.assert_called_with(
target)
target, ignore_missing=False)
# 2. Find specified 'ingress_firewall_policy'
if self.networkclient.find_firewall_policy.call_count == 1:
self.networkclient.find_firewall_policy.assert_called_with(
ingress_policy)
ingress_policy, ignore_missing=False)
# 3. Find specified 'ingress_firewall_policy'
if self.networkclient.find_firewall_policy.call_count == 2:
self.networkclient.find_firewall_policy.assert_called_with(
egress_policy)
egress_policy, ignore_missing=False)
return {'id': args[0]}
self.networkclient.find_firewall_group.side_effect = _mock_fwg_policy
@@ -439,7 +439,7 @@ class TestSetFirewallGroup(TestFirewallGroup, common.TestSetFWaaS):
# 1. Find specified firewall_group
if self.networkclient.find_firewall_group.call_count in [1, 2]:
self.networkclient.find_firewall_group.assert_called_with(
target)
target, ignore_missing=False)
return {'id': args[0], 'ports': _fwg['ports']}
# 2. Find specified 'port' #1
if self.networkclient.find_port.call_count == 1:
@@ -687,7 +687,7 @@ class TestUnsetFirewallGroup(TestFirewallGroup, common.TestUnsetFWaaS):
# 1. Find specified firewall_group
if self.networkclient.find_firewall_group.call_count in [1, 2]:
self.networkclient.find_firewall_group.assert_called_with(
target)
target, ignore_missing=False)
return {'id': args[0], 'ports': _fwg['ports']}
# 2. Find specified firewall_group and refer 'ports' attribute
if self.networkclient.find_port.call_count == 2:

View File

@@ -507,12 +507,12 @@ class TestFirewallPolicyInsertRule(TestFirewallPolicy):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.mocked.assert_called_once_with(
target, {
'firewall_rule_id': rule,
'insert_before': before,
'insert_after': after
})
body = {
'firewall_rule_id': rule,
'insert_before': before,
'insert_after': after
}
self.mocked.assert_called_once_with(target, **body)
self.assertIsNone(result)
self.assertEqual(1, self.networkclient.find_firewall_policy.call_count)
self.assertEqual(3, self.networkclient.find_firewall_rule.call_count)
@@ -560,8 +560,8 @@ class TestFirewallPolicyRemoveRule(TestFirewallPolicy):
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.mocked.assert_called_once_with(
target, {'firewall_rule_id': rule})
body = {'firewall_rule_id': rule}
self.mocked.assert_called_once_with(target, **body)
self.assertIsNone(result)
self.assertEqual(1, self.networkclient.find_firewall_policy.call_count)
self.assertEqual(1, self.networkclient.find_firewall_rule.call_count)

View File

@@ -125,6 +125,8 @@ class VPNService(FakeVPNaaS):
('status', 'ACTIVE'),
('description', 'my-desc-' + uuid.uuid4().hex),
('project_id', 'project-id-' + uuid.uuid4().hex),
('external_v4_ip', '192.0.2.42'),
('external_v6_ip', '2001:0db8:207a:4a3a:053b:6fab:7df9:1afd'),
))

View File

@@ -106,10 +106,14 @@ class TestVPNService(test_fakes.TestNeutronClientOSCV2):
'Status',
'Description',
'Project',
'Ext v4 IP',
'Ext v6 IP',
)
self.data = _generate_data()
self.ordered_headers = (
'Description',
'Ext v4 IP',
'Ext v6 IP',
'Flavor',
'ID',
'Name',
@@ -121,6 +125,8 @@ class TestVPNService(test_fakes.TestNeutronClientOSCV2):
)
self.ordered_data = (
_vpnservice['description'],
_vpnservice['external_v4_ip'],
_vpnservice['external_v6_ip'],
_vpnservice['flavor_id'],
_vpnservice['id'],
_vpnservice['name'],
@@ -132,6 +138,8 @@ class TestVPNService(test_fakes.TestNeutronClientOSCV2):
)
self.ordered_columns = (
'description',
'external_v4_ip',
'external_v6_ip',
'flavor_id',
'id',
'name',

View File

@@ -250,6 +250,9 @@ class ClientBase(object):
def __init__(self, **kwargs):
"""Initialize a new client for the Neutron v2.0 API."""
super(ClientBase, self).__init__()
_logger.warning("The python binding code in neutronclient is "
"deprecated in favor of OpenstackSDK, please use "
"that as this will be removed in a future release.")
self.retries = kwargs.pop('retries', 0)
self.raise_errors = kwargs.pop('raise_errors', True)
self.httpclient = client.construct_http_client(**kwargs)
@@ -847,7 +850,7 @@ class Client(ClientBase):
def list_port_bindings(self, port_id, retrieve_all=True, **_params):
"""Fetches a list of all bindings for a certain port."""
return self.list('port_bindings', self.port_bindings_path % port_id,
return self.list('bindings', self.port_bindings_path % port_id,
retrieve_all, **_params)
def activate_port_binding(self, port_id, host_id):

View File

@@ -0,0 +1,5 @@
---
upgrade:
- |
Python 3.8 support was dropped. The minimum version of Python now supported
is Python 3.9.

View File

@@ -3,4 +3,4 @@
===========================
.. release-notes::
:branch: stable/2023.1
:branch: unmaintained/2023.1

View File

@@ -0,0 +1,6 @@
===========================
2024.1 Series Release Notes
===========================
.. release-notes::
:branch: unmaintained/2024.1

View File

@@ -0,0 +1,6 @@
===========================
2024.2 Series Release Notes
===========================
.. release-notes::
:branch: stable/2024.2

View File

@@ -0,0 +1,6 @@
===========================
2025.1 Series Release Notes
===========================
.. release-notes::
:branch: stable/2025.1

View File

@@ -0,0 +1,6 @@
===========================
2025.2 Series Release Notes
===========================
.. release-notes::
:branch: stable/2025.2

View File

@@ -0,0 +1,6 @@
===========================
2026.1 Series Release Notes
===========================
.. release-notes::
:branch: stable/2026.1

View File

@@ -6,6 +6,11 @@
:maxdepth: 1
unreleased
2026.1
2025.2
2025.1
2024.2
2024.1
2023.2
2023.1
zed

View File

@@ -3,4 +3,4 @@ Victoria Series Release Notes
=============================
.. release-notes::
:branch: stable/victoria
:branch: unmaintained/victoria

View File

@@ -3,4 +3,4 @@ Wallaby Series Release Notes
============================
.. release-notes::
:branch: stable/wallaby
:branch: unmaintained/wallaby

View File

@@ -3,4 +3,4 @@ Xena Series Release Notes
=========================
.. release-notes::
:branch: stable/xena
:branch: unmaintained/xena

View File

@@ -3,4 +3,4 @@ Zed Series Release Notes
========================
.. release-notes::
:branch: stable/zed
:branch: unmaintained/zed

View File

@@ -4,7 +4,6 @@
pbr!=2.1.0,>=2.0.0 # Apache-2.0
cliff>=3.4.0 # Apache-2.0
debtcollector>=1.2.0 # Apache-2.0
iso8601>=0.1.11 # MIT
netaddr>=0.7.18 # BSD
openstacksdk>=1.5.0 # Apache-2.0
osc-lib>=1.12.0 # Apache-2.0
@@ -12,7 +11,6 @@ oslo.i18n>=3.15.3 # Apache-2.0
oslo.log>=3.36.0 # Apache-2.0
oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
oslo.utils>=3.33.0 # Apache-2.0
os-client-config>=1.28.0 # Apache-2.0
keystoneauth1>=3.8.0 # Apache-2.0
# keystoneclient is used only by neutronclient.osc.utils
# TODO(amotoki): Drop this after osc.utils has no dependency on keystoneclient

View File

@@ -6,7 +6,7 @@ description_file =
author = OpenStack Networking Project
author_email = openstack-discuss@lists.openstack.org
home_page = https://docs.openstack.org/python-neutronclient/latest/
python_requires = >=3.8
python_requires = >=3.9
classifier =
Environment :: OpenStack
Intended Audience :: Developers
@@ -18,8 +18,10 @@ classifier =
Programming Language :: Python :: Implementation :: CPython
Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: 3
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Programming Language :: Python :: 3.12
[files]
packages =

View File

@@ -3,13 +3,10 @@ hacking>=6.1.0,<6.2.0 # Apache-2.0
bandit!=1.6.0,>=1.1.0 # Apache-2.0
coverage!=4.4,>=4.0 # Apache-2.0
fixtures>=3.0.0 # Apache-2.0/BSD
flake8-import-order>=0.18.0,<0.19.0 # LGPLv3
flake8-import-order>=0.19.0,<0.20.0 # LGPLv3
oslotest>=3.2.0 # Apache-2.0
osprofiler>=2.3.0 # Apache-2.0
python-openstackclient>=3.12.0 # Apache-2.0
python-subunit>=1.0.0 # Apache-2.0/BSD
requests-mock>=1.2.0 # Apache-2.0
stestr>=2.0.0 # Apache-2.0
testtools>=2.2.0 # MIT
testscenarios>=0.4 # Apache-2.0/BSD
tempest>=17.1.0 # Apache-2.0

View File

@@ -51,7 +51,6 @@ deps =
commands = sphinx-build -W -b html doc/source doc/build/html
[testenv:pdf-docs]
envdir = {toxworkdir}/docs
deps = {[testenv:docs]deps}
allowlist_externals =
make