python-openstackclient 8.3.0__py3-none-any.whl → 10.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openstackclient/__init__.py +2 -6
- openstackclient/api/api.py +41 -23
- openstackclient/api/compute_v2.py +44 -25
- openstackclient/api/object_store_v1.py +75 -97
- openstackclient/api/volume_v2.py +2 -1
- openstackclient/api/volume_v3.py +2 -1
- openstackclient/common/availability_zone.py +58 -42
- openstackclient/common/clientmanager.py +56 -29
- openstackclient/common/configuration.py +10 -3
- openstackclient/common/envvars.py +2 -2
- openstackclient/common/extension.py +14 -5
- openstackclient/common/limits.py +10 -5
- openstackclient/common/module.py +14 -6
- openstackclient/common/pagination.py +8 -2
- openstackclient/common/progressbar.py +7 -6
- openstackclient/common/project_cleanup.py +13 -7
- openstackclient/common/quota.py +126 -114
- openstackclient/common/versions.py +8 -2
- openstackclient/compute/client.py +7 -3
- openstackclient/compute/v2/agent.py +17 -10
- openstackclient/compute/v2/aggregate.py +36 -22
- openstackclient/compute/v2/console.py +14 -8
- openstackclient/compute/v2/console_connection.py +11 -3
- openstackclient/compute/v2/flavor.py +39 -21
- openstackclient/compute/v2/host.py +14 -6
- openstackclient/compute/v2/hypervisor.py +14 -5
- openstackclient/compute/v2/hypervisor_stats.py +10 -2
- openstackclient/compute/v2/keypair.py +29 -14
- openstackclient/compute/v2/server.py +251 -171
- openstackclient/compute/v2/server_backup.py +10 -4
- openstackclient/compute/v2/server_event.py +21 -12
- openstackclient/compute/v2/server_group.py +21 -11
- openstackclient/compute/v2/server_image.py +19 -10
- openstackclient/compute/v2/server_migration.py +24 -10
- openstackclient/compute/v2/server_share.py +274 -0
- openstackclient/compute/v2/server_volume.py +10 -4
- openstackclient/compute/v2/service.py +14 -7
- openstackclient/compute/v2/usage.py +26 -21
- openstackclient/identity/client.py +8 -3
- openstackclient/identity/common.py +103 -41
- openstackclient/identity/v2_0/catalog.py +14 -7
- openstackclient/identity/v2_0/ec2creds.py +21 -10
- openstackclient/identity/v2_0/endpoint.py +23 -11
- openstackclient/identity/v2_0/project.py +25 -14
- openstackclient/identity/v2_0/role.py +28 -14
- openstackclient/identity/v2_0/role_assignment.py +9 -3
- openstackclient/identity/v2_0/service.py +26 -12
- openstackclient/identity/v2_0/token.py +12 -5
- openstackclient/identity/v2_0/user.py +26 -15
- openstackclient/identity/v3/access_rule.py +26 -12
- openstackclient/identity/v3/application_credential.py +59 -24
- openstackclient/identity/v3/catalog.py +14 -7
- openstackclient/identity/v3/consumer.py +22 -11
- openstackclient/identity/v3/credential.py +36 -16
- openstackclient/identity/v3/domain.py +37 -18
- openstackclient/identity/v3/ec2creds.py +25 -12
- openstackclient/identity/v3/endpoint.py +42 -20
- openstackclient/identity/v3/endpoint_group.py +28 -17
- openstackclient/identity/v3/federation_protocol.py +71 -50
- openstackclient/identity/v3/group.py +55 -32
- openstackclient/identity/v3/identity_provider.py +92 -57
- openstackclient/identity/v3/implied_role.py +21 -9
- openstackclient/identity/v3/limit.py +115 -92
- openstackclient/identity/v3/mapping.py +26 -13
- openstackclient/identity/v3/policy.py +23 -12
- openstackclient/identity/v3/project.py +211 -122
- openstackclient/identity/v3/region.py +36 -16
- openstackclient/identity/v3/registered_limit.py +116 -109
- openstackclient/identity/v3/role.py +61 -31
- openstackclient/identity/v3/role_assignment.py +23 -6
- openstackclient/identity/v3/service.py +36 -16
- openstackclient/identity/v3/service_provider.py +37 -15
- openstackclient/identity/v3/tag.py +23 -17
- openstackclient/identity/v3/token.py +30 -14
- openstackclient/identity/v3/trust.py +32 -14
- openstackclient/identity/v3/unscoped_saml.py +10 -2
- openstackclient/identity/v3/user.py +49 -26
- openstackclient/image/client.py +7 -3
- openstackclient/image/v1/image.py +33 -26
- openstackclient/image/v2/cache.py +14 -9
- openstackclient/image/v2/image.py +76 -49
- openstackclient/image/v2/info.py +7 -1
- openstackclient/image/v2/metadef_namespaces.py +109 -13
- openstackclient/image/v2/metadef_objects.py +28 -15
- openstackclient/image/v2/metadef_properties.py +24 -13
- openstackclient/image/v2/metadef_resource_type_association.py +14 -7
- openstackclient/image/v2/metadef_resource_types.py +7 -1
- openstackclient/image/v2/task.py +15 -6
- openstackclient/locale/tr_TR/LC_MESSAGES/openstackclient.po +7 -192
- openstackclient/network/client.py +7 -2
- openstackclient/network/common.py +16 -241
- openstackclient/network/utils.py +36 -22
- openstackclient/network/v2/address_group.py +27 -16
- openstackclient/network/v2/address_scope.py +24 -13
- openstackclient/network/v2/bgpvpn/bgpvpn.py +463 -0
- openstackclient/network/v2/bgpvpn/constants.py +30 -0
- openstackclient/network/v2/bgpvpn/network_association.py +214 -0
- openstackclient/network/v2/bgpvpn/port_association.py +490 -0
- openstackclient/network/v2/bgpvpn/router_association.py +288 -0
- openstackclient/network/v2/default_security_group_rule.py +19 -10
- openstackclient/network/v2/floating_ip.py +110 -159
- openstackclient/network/v2/floating_ip_port_forwarding.py +30 -18
- openstackclient/network/v2/fwaas/__init__.py +0 -0
- openstackclient/network/v2/fwaas/group.py +466 -0
- openstackclient/network/v2/fwaas/policy.py +518 -0
- openstackclient/network/v2/fwaas/rule.py +574 -0
- openstackclient/network/v2/ip_availability.py +13 -5
- openstackclient/network/v2/l3_conntrack_helper.py +22 -13
- openstackclient/network/v2/local_ip.py +24 -13
- openstackclient/network/v2/local_ip_association.py +14 -7
- openstackclient/network/v2/ndp_proxy.py +20 -11
- openstackclient/network/v2/network.py +129 -196
- openstackclient/network/v2/network_agent.py +46 -25
- openstackclient/network/v2/network_auto_allocated_topology.py +22 -11
- openstackclient/network/v2/network_flavor.py +27 -16
- openstackclient/network/v2/network_flavor_profile.py +23 -12
- openstackclient/network/v2/network_meter.py +21 -10
- openstackclient/network/v2/network_meter_rule.py +21 -11
- openstackclient/network/v2/network_qos_policy.py +25 -15
- openstackclient/network/v2/network_qos_rule.py +32 -17
- openstackclient/network/v2/network_qos_rule_type.py +13 -5
- openstackclient/network/v2/network_rbac.py +23 -12
- openstackclient/network/v2/network_segment.py +20 -11
- openstackclient/network/v2/network_segment_range.py +56 -29
- openstackclient/network/v2/network_service_provider.py +7 -1
- openstackclient/network/v2/network_trunk.py +38 -22
- openstackclient/network/v2/port.py +54 -29
- openstackclient/network/v2/router.py +75 -52
- openstackclient/network/v2/security_group.py +87 -157
- openstackclient/network/v2/security_group_rule.py +100 -280
- openstackclient/network/v2/subnet.py +49 -28
- openstackclient/network/v2/subnet_pool.py +30 -17
- openstackclient/network/v2/taas/tap_flow.py +22 -11
- openstackclient/network/v2/taas/tap_mirror.py +22 -11
- openstackclient/network/v2/taas/tap_service.py +23 -12
- openstackclient/object/client.py +7 -2
- openstackclient/object/v1/account.py +13 -6
- openstackclient/object/v1/container.py +25 -15
- openstackclient/object/v1/object.py +25 -15
- openstackclient/py.typed +0 -0
- openstackclient/shell.py +46 -10
- openstackclient/tests/functional/base.py +55 -20
- openstackclient/tests/functional/common/test_extension.py +4 -0
- openstackclient/tests/functional/common/test_quota.py +3 -1
- openstackclient/tests/functional/compute/v2/common.py +14 -13
- openstackclient/tests/functional/compute/v2/test_flavor.py +3 -1
- openstackclient/tests/functional/compute/v2/test_server.py +3 -0
- openstackclient/tests/functional/identity/v2/common.py +10 -6
- openstackclient/tests/functional/identity/v2/test_role.py +4 -4
- openstackclient/tests/functional/identity/v3/common.py +25 -19
- openstackclient/tests/functional/identity/v3/test_group.py +20 -20
- openstackclient/tests/functional/identity/v3/test_idp.py +3 -1
- openstackclient/tests/functional/identity/v3/test_limit.py +47 -0
- openstackclient/tests/functional/identity/v3/test_project.py +10 -10
- openstackclient/tests/functional/identity/v3/test_role.py +18 -18
- openstackclient/tests/functional/identity/v3/test_role_assignment.py +12 -12
- openstackclient/tests/functional/identity/v3/test_user.py +8 -8
- openstackclient/tests/functional/image/base.py +1 -6
- openstackclient/tests/functional/image/v2/test_metadef_objects.py +69 -0
- openstackclient/tests/functional/network/v2/common.py +5 -2
- openstackclient/tests/functional/network/v2/test_floating_ip.py +10 -4
- openstackclient/tests/functional/network/v2/test_ip_availability.py +4 -0
- openstackclient/tests/functional/network/v2/test_network_meter_rule.py +3 -2
- openstackclient/tests/functional/network/v2/test_network_segment.py +5 -0
- openstackclient/tests/functional/network/v2/test_subnet.py +13 -9
- openstackclient/tests/functional/object/v1/common.py +4 -0
- openstackclient/tests/functional/volume/v2/common.py +4 -0
- openstackclient/tests/functional/volume/v2/test_volume_snapshot.py +27 -11
- openstackclient/tests/functional/volume/v2/test_volume_type.py +2 -2
- openstackclient/tests/functional/volume/v3/common.py +4 -0
- openstackclient/tests/functional/volume/v3/test_volume_snapshot.py +56 -138
- openstackclient/tests/functional/volume/v3/test_volume_type.py +2 -2
- openstackclient/tests/unit/common/test_availability_zone.py +35 -49
- openstackclient/tests/unit/common/test_extension.py +2 -2
- openstackclient/tests/unit/common/test_module.py +12 -7
- openstackclient/tests/unit/common/test_project_cleanup.py +3 -1
- openstackclient/tests/unit/common/test_quota.py +62 -23
- openstackclient/tests/unit/compute/v2/fakes.py +25 -0
- openstackclient/tests/unit/compute/v2/test_flavor.py +28 -2
- openstackclient/tests/unit/compute/v2/test_keypair.py +6 -6
- openstackclient/tests/unit/compute/v2/test_server.py +17 -104
- openstackclient/tests/unit/compute/v2/test_server_share.py +287 -0
- openstackclient/tests/unit/identity/v3/fakes.py +3 -0
- openstackclient/tests/unit/identity/v3/test_group.py +4 -14
- openstackclient/tests/unit/identity/v3/test_identity_provider.py +303 -299
- openstackclient/tests/unit/identity/v3/test_limit.py +197 -145
- openstackclient/tests/unit/identity/v3/test_project.py +831 -512
- openstackclient/tests/unit/identity/v3/test_protocol.py +97 -88
- openstackclient/tests/unit/identity/v3/test_registered_limit.py +355 -220
- openstackclient/tests/unit/identity/v3/test_user.py +4 -4
- openstackclient/tests/unit/image/v2/test_image.py +16 -16
- openstackclient/tests/unit/image/v2/test_metadef_namespaces.py +105 -6
- openstackclient/tests/unit/network/test_common.py +0 -155
- openstackclient/tests/unit/network/v2/bgpvpn/__init__.py +0 -0
- openstackclient/tests/unit/network/v2/bgpvpn/fakes.py +179 -0
- openstackclient/tests/unit/network/v2/bgpvpn/test_bgpvpn.py +584 -0
- openstackclient/tests/unit/network/v2/bgpvpn/test_network_association.py +285 -0
- openstackclient/tests/unit/network/v2/bgpvpn/test_port_association.py +384 -0
- openstackclient/tests/unit/network/v2/bgpvpn/test_router_association.py +297 -0
- openstackclient/tests/unit/network/v2/fwaas/__init__.py +0 -0
- openstackclient/tests/unit/network/v2/fwaas/test_group.py +897 -0
- openstackclient/tests/unit/network/v2/fwaas/test_policy.py +869 -0
- openstackclient/tests/unit/network/v2/fwaas/test_rule.py +980 -0
- openstackclient/tests/unit/network/v2/taas/{test_osc_tap_flow.py → test_tap_flow.py} +18 -25
- openstackclient/tests/unit/network/v2/taas/{test_osc_tap_mirror.py → test_tap_mirror.py} +19 -29
- openstackclient/tests/unit/network/v2/taas/{test_osc_tap_service.py → test_tap_service.py} +19 -29
- openstackclient/tests/unit/network/v2/test_address_group.py +2 -2
- openstackclient/tests/unit/network/v2/{test_floating_ip_network.py → test_floating_ip.py} +3 -2
- openstackclient/tests/unit/network/v2/test_floating_ip_port_forwarding.py +13 -13
- openstackclient/tests/unit/network/v2/test_network_agent.py +8 -4
- openstackclient/tests/unit/network/v2/test_network_auto_allocated_topology.py +3 -3
- openstackclient/tests/unit/network/v2/test_network_flavor.py +2 -2
- openstackclient/tests/unit/network/v2/test_network_qos_policy.py +1 -1
- openstackclient/tests/unit/network/v2/test_network_qos_rule.py +2 -2
- openstackclient/tests/unit/network/v2/test_network_rbac.py +1 -1
- openstackclient/tests/unit/network/v2/test_network_segment.py +1 -1
- openstackclient/tests/unit/network/v2/test_network_segment_range.py +7 -10
- openstackclient/tests/unit/network/v2/test_network_trunk.py +1 -1
- openstackclient/tests/unit/network/v2/test_router.py +8 -9
- openstackclient/tests/unit/network/v2/{test_security_group_network.py → test_security_group.py} +1 -20
- openstackclient/tests/unit/network/v2/{test_security_group_rule_network.py → test_security_group_rule.py} +7 -41
- openstackclient/tests/unit/network/v2/test_subnet.py +2 -1
- openstackclient/tests/unit/network/v2/test_subnet_pool.py +2 -1
- openstackclient/tests/unit/object/v1/fakes.py +8 -7
- openstackclient/tests/unit/object/v1/test_container.py +65 -101
- openstackclient/tests/unit/object/v1/test_container_all.py +8 -1
- openstackclient/tests/unit/object/v1/test_object.py +44 -84
- openstackclient/tests/unit/object/v1/test_object_all.py +8 -1
- openstackclient/tests/unit/test_hacking.py +108 -0
- openstackclient/tests/unit/volume/v2/fakes.py +1 -0
- openstackclient/tests/unit/volume/v2/test_consistency_group.py +8 -2
- openstackclient/tests/unit/volume/v2/test_volume.py +7 -6
- openstackclient/tests/unit/volume/v2/test_volume_backup.py +1 -5
- openstackclient/tests/unit/volume/v2/test_volume_snapshot.py +2 -1
- openstackclient/tests/unit/volume/v2/test_volume_type.py +2 -4
- openstackclient/tests/unit/volume/v3/fakes.py +1 -0
- openstackclient/tests/unit/volume/v3/test_volume.py +94 -15
- openstackclient/tests/unit/volume/v3/test_volume_attachment.py +1 -1
- openstackclient/tests/unit/volume/v3/test_volume_backup.py +1 -5
- openstackclient/tests/unit/volume/v3/test_volume_snapshot.py +55 -1
- openstackclient/tests/unit/volume/v3/test_volume_type.py +2 -4
- openstackclient/volume/client.py +7 -3
- openstackclient/volume/v2/backup_record.py +15 -6
- openstackclient/volume/v2/consistency_group.py +37 -25
- openstackclient/volume/v2/consistency_group_snapshot.py +27 -12
- openstackclient/volume/v2/qos_specs.py +30 -19
- openstackclient/volume/v2/service.py +17 -6
- openstackclient/volume/v2/volume.py +69 -34
- openstackclient/volume/v2/volume_backend.py +19 -6
- openstackclient/volume/v2/volume_backup.py +48 -22
- openstackclient/volume/v2/volume_host.py +6 -4
- openstackclient/volume/v2/volume_snapshot.py +52 -26
- openstackclient/volume/v2/volume_transfer_request.py +33 -15
- openstackclient/volume/v2/volume_type.py +46 -27
- openstackclient/volume/v3/block_storage_cleanup.py +11 -3
- openstackclient/volume/v3/block_storage_cluster.py +19 -7
- openstackclient/volume/v3/block_storage_log_level.py +15 -6
- openstackclient/volume/v3/block_storage_manage.py +10 -4
- openstackclient/volume/v3/block_storage_resource_filter.py +17 -5
- openstackclient/volume/v3/service.py +16 -6
- openstackclient/volume/v3/volume.py +103 -46
- openstackclient/volume/v3/volume_attachment.py +43 -21
- openstackclient/volume/v3/volume_backup.py +55 -26
- openstackclient/volume/v3/volume_group.py +23 -13
- openstackclient/volume/v3/volume_group_snapshot.py +32 -13
- openstackclient/volume/v3/volume_group_type.py +26 -13
- openstackclient/volume/v3/volume_message.py +15 -7
- openstackclient/volume/v3/volume_snapshot.py +71 -34
- openstackclient/volume/v3/volume_transfer_request.py +33 -15
- openstackclient/volume/v3/volume_type.py +45 -27
- {python_openstackclient-8.3.0.dist-info → python_openstackclient-10.0.0.dist-info}/METADATA +6 -6
- {python_openstackclient-8.3.0.dist-info → python_openstackclient-10.0.0.dist-info}/RECORD +279 -267
- {python_openstackclient-8.3.0.dist-info → python_openstackclient-10.0.0.dist-info}/WHEEL +1 -1
- {python_openstackclient-8.3.0.dist-info → python_openstackclient-10.0.0.dist-info}/entry_points.txt +53 -1
- {python_openstackclient-8.3.0.dist-info → python_openstackclient-10.0.0.dist-info}/licenses/AUTHORS +9 -0
- python_openstackclient-10.0.0.dist-info/pbr.json +1 -0
- openstackclient/api/image_v1.py +0 -69
- openstackclient/api/image_v2.py +0 -79
- openstackclient/network/v2/floating_ip_pool.py +0 -38
- openstackclient/tests/functional/image/v1/test_image.py +0 -97
- openstackclient/tests/unit/api/test_image_v1.py +0 -96
- openstackclient/tests/unit/api/test_image_v2.py +0 -96
- openstackclient/tests/unit/network/v2/test_floating_ip_compute.py +0 -248
- openstackclient/tests/unit/network/v2/test_floating_ip_pool_compute.py +0 -49
- openstackclient/tests/unit/network/v2/test_floating_ip_pool_network.py +0 -39
- openstackclient/tests/unit/network/v2/test_network_compute.py +0 -404
- openstackclient/tests/unit/network/v2/test_security_group_compute.py +0 -392
- openstackclient/tests/unit/network/v2/test_security_group_rule_compute.py +0 -555
- python_openstackclient-8.3.0.dist-info/pbr.json +0 -1
- /openstackclient/{tests/functional/image/v1 → network/v2/bgpvpn}/__init__.py +0 -0
- {python_openstackclient-8.3.0.dist-info → python_openstackclient-10.0.0.dist-info}/licenses/LICENSE +0 -0
- {python_openstackclient-8.3.0.dist-info → python_openstackclient-10.0.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# Copyright (c) 2016 Juniper Networks Inc.
|
|
2
|
+
# All Rights Reserved.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
5
|
+
# not use this file except in compliance with the License. You may obtain
|
|
6
|
+
# a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
13
|
+
# License for the specific language governing permissions and limitations
|
|
14
|
+
# under the License.
|
|
15
|
+
#
|
|
16
|
+
|
|
17
|
+
import logging
|
|
18
|
+
import typing as ty
|
|
19
|
+
|
|
20
|
+
from osc_lib.cli import identity as osc_id
|
|
21
|
+
from osc_lib.cli import parseractions
|
|
22
|
+
from osc_lib import exceptions
|
|
23
|
+
from osc_lib import utils as osc_utils
|
|
24
|
+
from osc_lib.utils import columns as column_util
|
|
25
|
+
|
|
26
|
+
from openstackclient import command
|
|
27
|
+
from openstackclient.i18n import _
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
LOG = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
_attr_map = (
|
|
33
|
+
('id', 'ID', column_util.LIST_BOTH),
|
|
34
|
+
('project_id', 'Project', column_util.LIST_LONG_ONLY),
|
|
35
|
+
('network_id', 'Network ID', column_util.LIST_BOTH),
|
|
36
|
+
)
|
|
37
|
+
_formatters: dict[str, ty.Any] = {}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _get_columns(item):
|
|
41
|
+
column_map: dict[str, str] = {}
|
|
42
|
+
hidden_columns = ['location', 'name', 'tenant_id']
|
|
43
|
+
return osc_utils.get_osc_show_columns_for_sdk_resource(
|
|
44
|
+
item, column_map, hidden_columns
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class CreateBgpvpnNetAssoc(command.ShowOne):
|
|
49
|
+
_description = _("Create a BGP VPN network association")
|
|
50
|
+
|
|
51
|
+
def get_parser(self, prog_name):
|
|
52
|
+
parser = super().get_parser(prog_name)
|
|
53
|
+
osc_id.add_project_owner_option_to_parser(parser)
|
|
54
|
+
parser.add_argument(
|
|
55
|
+
'bgpvpn',
|
|
56
|
+
metavar="<bgpvpn>",
|
|
57
|
+
help=_("BGP VPN to apply the network association (name or ID)"),
|
|
58
|
+
)
|
|
59
|
+
parser.add_argument(
|
|
60
|
+
'resource',
|
|
61
|
+
metavar="<network>",
|
|
62
|
+
help=_("Network to associate the BGP VPN (name or ID)"),
|
|
63
|
+
)
|
|
64
|
+
return parser
|
|
65
|
+
|
|
66
|
+
def take_action(self, parsed_args):
|
|
67
|
+
client = self.app.client_manager.network
|
|
68
|
+
bgpvpn = client.find_bgpvpn(parsed_args.bgpvpn, ignore_missing=False)
|
|
69
|
+
network = client.find_network(
|
|
70
|
+
parsed_args.resource, ignore_missing=False
|
|
71
|
+
)
|
|
72
|
+
body: dict[str, ty.Any] = {'network_id': network['id']}
|
|
73
|
+
if 'project' in parsed_args and parsed_args.project is not None:
|
|
74
|
+
project_id = osc_id.find_project(
|
|
75
|
+
self.app.client_manager.sdk_connection,
|
|
76
|
+
parsed_args.project,
|
|
77
|
+
parsed_args.project_domain,
|
|
78
|
+
).id
|
|
79
|
+
body['project_id'] = project_id
|
|
80
|
+
|
|
81
|
+
obj = client.create_bgpvpn_network_association(bgpvpn['id'], **body)
|
|
82
|
+
display_columns, columns = _get_columns(obj)
|
|
83
|
+
data = osc_utils.get_dict_properties(
|
|
84
|
+
obj, columns, formatters=_formatters
|
|
85
|
+
)
|
|
86
|
+
return display_columns, data
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class DeleteBgpvpnNetAssoc(command.Command):
|
|
90
|
+
_description = _(
|
|
91
|
+
"Delete a BGP VPN network association(s) for a given BGP VPN"
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
def get_parser(self, prog_name):
|
|
95
|
+
parser = super().get_parser(prog_name)
|
|
96
|
+
parser.add_argument(
|
|
97
|
+
'resource_association_ids',
|
|
98
|
+
metavar="<network association ID>",
|
|
99
|
+
nargs="+",
|
|
100
|
+
help=_("Network association ID(s) to remove"),
|
|
101
|
+
)
|
|
102
|
+
parser.add_argument(
|
|
103
|
+
'bgpvpn',
|
|
104
|
+
metavar="<bgpvpn>",
|
|
105
|
+
help=_("BGP VPN the network association belongs to (name or ID)"),
|
|
106
|
+
)
|
|
107
|
+
return parser
|
|
108
|
+
|
|
109
|
+
def take_action(self, parsed_args):
|
|
110
|
+
client = self.app.client_manager.network
|
|
111
|
+
bgpvpn = client.find_bgpvpn(parsed_args.bgpvpn, ignore_missing=False)
|
|
112
|
+
fails = 0
|
|
113
|
+
for id in parsed_args.resource_association_ids:
|
|
114
|
+
try:
|
|
115
|
+
client.delete_bgpvpn_network_association(bgpvpn['id'], id)
|
|
116
|
+
LOG.warning(
|
|
117
|
+
"Network association %(id)s deleted",
|
|
118
|
+
{'id': id},
|
|
119
|
+
)
|
|
120
|
+
except Exception as e:
|
|
121
|
+
fails += 1
|
|
122
|
+
LOG.error(
|
|
123
|
+
"Failed to delete network "
|
|
124
|
+
"association with ID '%(id)s': %(e)s",
|
|
125
|
+
{'id': id, 'e': e},
|
|
126
|
+
)
|
|
127
|
+
if fails > 0:
|
|
128
|
+
msg = _(
|
|
129
|
+
"Failed to delete %(fails)s of %(total)s "
|
|
130
|
+
"network BGP VPN association(s)."
|
|
131
|
+
) % {
|
|
132
|
+
'fails': fails,
|
|
133
|
+
'total': len(parsed_args.resource_association_ids),
|
|
134
|
+
}
|
|
135
|
+
raise exceptions.CommandError(msg)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class ListBgpvpnNetAssoc(command.Lister):
|
|
139
|
+
_description = _("List BGP VPN network associations for a given BGP VPN")
|
|
140
|
+
|
|
141
|
+
def get_parser(self, prog_name):
|
|
142
|
+
parser = super().get_parser(prog_name)
|
|
143
|
+
parser.add_argument(
|
|
144
|
+
'bgpvpn',
|
|
145
|
+
metavar="<bgpvpn>",
|
|
146
|
+
help=_("BGP VPN listed associations belong to (name or ID)"),
|
|
147
|
+
)
|
|
148
|
+
parser.add_argument(
|
|
149
|
+
'--long',
|
|
150
|
+
action='store_true',
|
|
151
|
+
help=_("List additional fields in output"),
|
|
152
|
+
)
|
|
153
|
+
parser.add_argument(
|
|
154
|
+
'--property',
|
|
155
|
+
metavar="<key=value>",
|
|
156
|
+
help=_(
|
|
157
|
+
"Filter property to apply on returned BGP VPNs (repeat to "
|
|
158
|
+
"filter on multiple properties)"
|
|
159
|
+
),
|
|
160
|
+
action=parseractions.KeyValueAction,
|
|
161
|
+
)
|
|
162
|
+
return parser
|
|
163
|
+
|
|
164
|
+
def take_action(self, parsed_args):
|
|
165
|
+
client = self.app.client_manager.network
|
|
166
|
+
bgpvpn = client.find_bgpvpn(parsed_args.bgpvpn, ignore_missing=False)
|
|
167
|
+
params = {}
|
|
168
|
+
if parsed_args.property:
|
|
169
|
+
params.update(parsed_args.property)
|
|
170
|
+
objs = client.bgpvpn_network_associations(
|
|
171
|
+
bgpvpn['id'], retrieve_all=True, **params
|
|
172
|
+
)
|
|
173
|
+
headers, columns = column_util.get_column_definitions(
|
|
174
|
+
list(_attr_map), long_listing=parsed_args.long
|
|
175
|
+
)
|
|
176
|
+
return (
|
|
177
|
+
headers,
|
|
178
|
+
(
|
|
179
|
+
osc_utils.get_dict_properties(
|
|
180
|
+
s, columns, formatters=_formatters
|
|
181
|
+
)
|
|
182
|
+
for s in objs
|
|
183
|
+
),
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class ShowBgpvpnNetAssoc(command.ShowOne):
|
|
188
|
+
_description = _("Show information of a given BGP VPN network association")
|
|
189
|
+
|
|
190
|
+
def get_parser(self, prog_name):
|
|
191
|
+
parser = super().get_parser(prog_name)
|
|
192
|
+
parser.add_argument(
|
|
193
|
+
'resource_association_id',
|
|
194
|
+
metavar="<network association ID>",
|
|
195
|
+
help=_("Network association ID to look up"),
|
|
196
|
+
)
|
|
197
|
+
parser.add_argument(
|
|
198
|
+
'bgpvpn',
|
|
199
|
+
metavar="<bgpvpn>",
|
|
200
|
+
help=_("BGP VPN the association belongs to (name or ID)"),
|
|
201
|
+
)
|
|
202
|
+
return parser
|
|
203
|
+
|
|
204
|
+
def take_action(self, parsed_args):
|
|
205
|
+
client = self.app.client_manager.network
|
|
206
|
+
bgpvpn = client.find_bgpvpn(parsed_args.bgpvpn, ignore_missing=False)
|
|
207
|
+
obj = client.get_bgpvpn_network_association(
|
|
208
|
+
bgpvpn['id'], parsed_args.resource_association_id
|
|
209
|
+
)
|
|
210
|
+
display_columns, columns = _get_columns(obj)
|
|
211
|
+
data = osc_utils.get_dict_properties(
|
|
212
|
+
obj, columns, formatters=_formatters
|
|
213
|
+
)
|
|
214
|
+
return display_columns, data
|
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
# Copyright (c) 2017 Juniper networks Inc.
|
|
2
|
+
# All Rights Reserved.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
5
|
+
# not use this file except in compliance with the License. You may obtain
|
|
6
|
+
# a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
13
|
+
# License for the specific language governing permissions and limitations
|
|
14
|
+
# under the License.
|
|
15
|
+
#
|
|
16
|
+
|
|
17
|
+
import logging
|
|
18
|
+
import typing as ty
|
|
19
|
+
|
|
20
|
+
from osc_lib.cli import format_columns
|
|
21
|
+
from osc_lib.cli import identity as osc_id
|
|
22
|
+
from osc_lib.cli import parseractions
|
|
23
|
+
from osc_lib import exceptions
|
|
24
|
+
from osc_lib import utils as osc_utils
|
|
25
|
+
from osc_lib.utils import columns as column_util
|
|
26
|
+
|
|
27
|
+
from openstackclient import command
|
|
28
|
+
from openstackclient.i18n import _
|
|
29
|
+
|
|
30
|
+
LOG = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
_attr_map = (
|
|
33
|
+
('id', 'ID', column_util.LIST_BOTH),
|
|
34
|
+
('project_id', 'Project', column_util.LIST_LONG_ONLY),
|
|
35
|
+
('port_id', 'Port ID', column_util.LIST_BOTH),
|
|
36
|
+
(
|
|
37
|
+
'prefix_routes',
|
|
38
|
+
'Prefix Routes (BGP LOCAL_PREF)',
|
|
39
|
+
column_util.LIST_LONG_ONLY,
|
|
40
|
+
),
|
|
41
|
+
(
|
|
42
|
+
'bgpvpn_routes',
|
|
43
|
+
'BGP VPN Routes (BGP LOCAL_PREF)',
|
|
44
|
+
column_util.LIST_LONG_ONLY,
|
|
45
|
+
),
|
|
46
|
+
(
|
|
47
|
+
'advertise_fixed_ips',
|
|
48
|
+
"Advertise Port's Fixed IPs",
|
|
49
|
+
column_util.LIST_LONG_ONLY,
|
|
50
|
+
),
|
|
51
|
+
)
|
|
52
|
+
_formatters = {
|
|
53
|
+
'prefix_routes': format_columns.ListColumn,
|
|
54
|
+
'bgpvpn_routes': format_columns.ListColumn,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _get_columns(item):
|
|
59
|
+
column_map: dict[str, str] = {}
|
|
60
|
+
hidden_columns = ['location', 'name', 'tenant_id']
|
|
61
|
+
return osc_utils.get_osc_show_columns_for_sdk_resource(
|
|
62
|
+
item, column_map, hidden_columns
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _transform_resource(data):
|
|
67
|
+
"""Transforms BGP VPN port association routes property.
|
|
68
|
+
|
|
69
|
+
Separates the two route types and formats them with ListColumn.
|
|
70
|
+
|
|
71
|
+
{'routes':
|
|
72
|
+
[
|
|
73
|
+
{'type': 'prefix', 'local_pref': 100, 'prefix': '8.8.8.0/27'},
|
|
74
|
+
{'type': 'bgpvpn', 'local_pref': 50,
|
|
75
|
+
'bgpvpn': '157d72a9-9968-48e7-8087-6c9a9bc7a181'},
|
|
76
|
+
],
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
to
|
|
80
|
+
|
|
81
|
+
{
|
|
82
|
+
'prefix_routes': ['8.8.8.0/27 (100)'],
|
|
83
|
+
'bgpvpn_routes': ['157d72a9-9968-48e7-8087-6c9a9bc7a181 (50)'],
|
|
84
|
+
}
|
|
85
|
+
"""
|
|
86
|
+
for route in data.get('routes', []):
|
|
87
|
+
local_pref = ''
|
|
88
|
+
if route.get('local_pref'):
|
|
89
|
+
local_pref = ' ({local_pref})'
|
|
90
|
+
if route['type'] == 'prefix':
|
|
91
|
+
data.setdefault('prefix_routes', []).append(
|
|
92
|
+
'{}{}'.format(route['prefix'], local_pref)
|
|
93
|
+
)
|
|
94
|
+
elif route['type'] == 'bgpvpn':
|
|
95
|
+
data.setdefault('bgpvpn_routes', []).append(
|
|
96
|
+
'{}{}'.format(route['bgpvpn_id'], local_pref)
|
|
97
|
+
)
|
|
98
|
+
else:
|
|
99
|
+
LOG.warning("Unknown route type %s (%s).", route['type'], route)
|
|
100
|
+
data.pop('routes', None)
|
|
101
|
+
return data
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _get_common_parser(parser, action):
|
|
105
|
+
"""Adds to parser arguments common to create, set and unset commands.
|
|
106
|
+
|
|
107
|
+
:params ArgumentParser parser: argparse object contains all command's
|
|
108
|
+
arguments
|
|
109
|
+
:params string action: 'create', 'set' or 'unset'
|
|
110
|
+
"""
|
|
111
|
+
ADVERTISE_ROUTE = _(
|
|
112
|
+
"Fixed IPs of the port will be advertised to the BGP VPN%s"
|
|
113
|
+
) % (_(' (default)') if action == 'create' else "")
|
|
114
|
+
NOT_ADVERTISE_ROUTE = _(
|
|
115
|
+
"Fixed IPs of the port will not be advertised to the BGP VPN"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
LOCAL_PREF_VALUE = _(
|
|
119
|
+
". Optionally, can control the value of the BGP "
|
|
120
|
+
"LOCAL_PREF of the routes that will be "
|
|
121
|
+
"advertised"
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
ADD_PREFIX_ROUTE = (
|
|
125
|
+
_("Add prefix route in CIDR notation%s") % LOCAL_PREF_VALUE
|
|
126
|
+
)
|
|
127
|
+
REMOVE_PREFIX_ROUTE = _("Remove prefix route in CIDR notation")
|
|
128
|
+
REPEAT_PREFIX_ROUTE = _("repeat option for multiple prefix routes")
|
|
129
|
+
|
|
130
|
+
ADD_BGVPVPN_ROUTE = (
|
|
131
|
+
_("Add BGP VPN route for route leaking%s") % LOCAL_PREF_VALUE
|
|
132
|
+
)
|
|
133
|
+
REMOVE_BGPVPN_ROUTE = _("Remove BGP VPN route")
|
|
134
|
+
REPEAT_BGPVPN_ROUTE = _("repeat option for multiple BGP VPN routes")
|
|
135
|
+
|
|
136
|
+
group_advertise_fixed_ips = parser.add_mutually_exclusive_group()
|
|
137
|
+
group_advertise_fixed_ips.add_argument(
|
|
138
|
+
'--advertise-fixed-ips',
|
|
139
|
+
action='store_true',
|
|
140
|
+
help=NOT_ADVERTISE_ROUTE if action == 'unset' else ADVERTISE_ROUTE,
|
|
141
|
+
)
|
|
142
|
+
group_advertise_fixed_ips.add_argument(
|
|
143
|
+
'--no-advertise-fixed-ips',
|
|
144
|
+
action='store_true',
|
|
145
|
+
help=ADVERTISE_ROUTE if action == 'unset' else NOT_ADVERTISE_ROUTE,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
if action in ['create', 'set']:
|
|
149
|
+
parser.add_argument(
|
|
150
|
+
'--prefix-route',
|
|
151
|
+
metavar="prefix=<cidr>[,local_pref=<integer>]",
|
|
152
|
+
dest='prefix_routes',
|
|
153
|
+
action=parseractions.MultiKeyValueAction,
|
|
154
|
+
required_keys=['prefix'],
|
|
155
|
+
optional_keys=['local_pref'],
|
|
156
|
+
help=f"{ADD_PREFIX_ROUTE} ({REPEAT_PREFIX_ROUTE})",
|
|
157
|
+
)
|
|
158
|
+
parser.add_argument(
|
|
159
|
+
'--bgpvpn-route',
|
|
160
|
+
metavar="bgpvpn=<BGP VPN ID or name>[,local_pref=<integer>]",
|
|
161
|
+
dest='bgpvpn_routes',
|
|
162
|
+
action=parseractions.MultiKeyValueAction,
|
|
163
|
+
required_keys=['bgpvpn'],
|
|
164
|
+
optional_keys=['local_pref'],
|
|
165
|
+
help=f"{ADD_BGVPVPN_ROUTE} ({REPEAT_BGPVPN_ROUTE})",
|
|
166
|
+
)
|
|
167
|
+
else:
|
|
168
|
+
parser.add_argument(
|
|
169
|
+
'--prefix-route',
|
|
170
|
+
metavar="<cidr>",
|
|
171
|
+
dest='prefix_routes',
|
|
172
|
+
action='append',
|
|
173
|
+
help=f"{REMOVE_PREFIX_ROUTE} ({REPEAT_PREFIX_ROUTE})",
|
|
174
|
+
)
|
|
175
|
+
parser.add_argument(
|
|
176
|
+
'--bgpvpn-route',
|
|
177
|
+
metavar="<BGP VPN ID or name>",
|
|
178
|
+
dest='bgpvpn_routes',
|
|
179
|
+
action='append',
|
|
180
|
+
help=f"{REMOVE_BGPVPN_ROUTE} ({REPEAT_BGPVPN_ROUTE})",
|
|
181
|
+
)
|
|
182
|
+
if action != 'create':
|
|
183
|
+
parser.add_argument(
|
|
184
|
+
'--no-prefix-route' if action == 'set' else '--all-prefix-routes',
|
|
185
|
+
dest='purge_prefix_route',
|
|
186
|
+
action='store_true',
|
|
187
|
+
help=_('Empty prefix route list'),
|
|
188
|
+
)
|
|
189
|
+
parser.add_argument(
|
|
190
|
+
'--no-bgpvpn-route' if action == 'set' else '--all-bgpvpn-routes',
|
|
191
|
+
dest='purge_bgpvpn_route',
|
|
192
|
+
action='store_true',
|
|
193
|
+
help=_('Empty BGP VPN route list'),
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _args2body(client, action, bgpvpn_id, args):
|
|
198
|
+
attrs: dict[str, ty.Any] = {}
|
|
199
|
+
|
|
200
|
+
if action != 'create':
|
|
201
|
+
assoc = client.find_bgpvpn_port_association(
|
|
202
|
+
args.port_association_id,
|
|
203
|
+
bgpvpn_id=bgpvpn_id,
|
|
204
|
+
ignore_missing=False,
|
|
205
|
+
)
|
|
206
|
+
else:
|
|
207
|
+
assoc = {'routes': []}
|
|
208
|
+
|
|
209
|
+
if args.advertise_fixed_ips:
|
|
210
|
+
attrs['advertise_fixed_ips'] = action != 'unset'
|
|
211
|
+
elif args.no_advertise_fixed_ips:
|
|
212
|
+
attrs['advertise_fixed_ips'] = action == 'unset'
|
|
213
|
+
|
|
214
|
+
prefix_routes: dict[str, ty.Any] | None = None
|
|
215
|
+
if 'purge_prefix_route' in args and args.purge_prefix_route:
|
|
216
|
+
prefix_routes = {}
|
|
217
|
+
else:
|
|
218
|
+
prefix_routes = {
|
|
219
|
+
r['prefix']: r.get('local_pref')
|
|
220
|
+
for r in assoc['routes']
|
|
221
|
+
if r['type'] == 'prefix'
|
|
222
|
+
}
|
|
223
|
+
if args.prefix_routes:
|
|
224
|
+
if action in ['create', 'set']:
|
|
225
|
+
prefix_routes.update(
|
|
226
|
+
{
|
|
227
|
+
r['prefix']: r.get('local_pref')
|
|
228
|
+
for r in args.prefix_routes
|
|
229
|
+
}
|
|
230
|
+
)
|
|
231
|
+
elif action == 'unset':
|
|
232
|
+
for prefix in args.prefix_routes:
|
|
233
|
+
prefix_routes.pop(prefix, None)
|
|
234
|
+
|
|
235
|
+
bgpvpn_routes: dict[str, ty.Any] | None = None
|
|
236
|
+
if 'purge_bgpvpn_route' in args and args.purge_bgpvpn_route:
|
|
237
|
+
bgpvpn_routes = {}
|
|
238
|
+
else:
|
|
239
|
+
bgpvpn_routes = {
|
|
240
|
+
r['bgpvpn_id']: r.get('local_pref')
|
|
241
|
+
for r in assoc['routes']
|
|
242
|
+
if r['type'] == 'bgpvpn'
|
|
243
|
+
}
|
|
244
|
+
if args.bgpvpn_routes:
|
|
245
|
+
if action == 'unset':
|
|
246
|
+
routes = [{'bgpvpn': bgpvpn} for bgpvpn in args.bgpvpn_routes]
|
|
247
|
+
else:
|
|
248
|
+
routes = args.bgpvpn_routes
|
|
249
|
+
args_bgpvpn_routes = {
|
|
250
|
+
client.find_bgpvpn(
|
|
251
|
+
r['bgpvpn'], ignore_missing=False
|
|
252
|
+
).id: r.get('local_pref')
|
|
253
|
+
for r in routes
|
|
254
|
+
}
|
|
255
|
+
if action in ['create', 'set']:
|
|
256
|
+
bgpvpn_routes.update(args_bgpvpn_routes)
|
|
257
|
+
elif action == 'unset':
|
|
258
|
+
for bgpvpn_id in args_bgpvpn_routes:
|
|
259
|
+
bgpvpn_routes.pop(bgpvpn_id, None)
|
|
260
|
+
|
|
261
|
+
if prefix_routes is not None and not prefix_routes:
|
|
262
|
+
attrs.setdefault('routes', [])
|
|
263
|
+
elif prefix_routes is not None:
|
|
264
|
+
for prefix, local_pref in prefix_routes.items():
|
|
265
|
+
route: dict[str, ty.Any] = {
|
|
266
|
+
'type': 'prefix',
|
|
267
|
+
'prefix': prefix,
|
|
268
|
+
}
|
|
269
|
+
if local_pref:
|
|
270
|
+
route['local_pref'] = int(local_pref)
|
|
271
|
+
attrs.setdefault('routes', []).append(route)
|
|
272
|
+
if bgpvpn_routes is not None and not bgpvpn_routes:
|
|
273
|
+
attrs.setdefault('routes', [])
|
|
274
|
+
elif bgpvpn_routes is not None:
|
|
275
|
+
for bgpvpn_id, local_pref in bgpvpn_routes.items():
|
|
276
|
+
route = {
|
|
277
|
+
'type': 'bgpvpn',
|
|
278
|
+
'bgpvpn_id': bgpvpn_id,
|
|
279
|
+
}
|
|
280
|
+
if local_pref:
|
|
281
|
+
route['local_pref'] = int(local_pref)
|
|
282
|
+
attrs.setdefault('routes', []).append(route)
|
|
283
|
+
|
|
284
|
+
return attrs
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
class CreateBgpvpnPortAssoc(command.ShowOne):
|
|
288
|
+
_description = _("Create a BGP VPN port association")
|
|
289
|
+
|
|
290
|
+
def get_parser(self, prog_name):
|
|
291
|
+
parser = super().get_parser(prog_name)
|
|
292
|
+
osc_id.add_project_owner_option_to_parser(parser)
|
|
293
|
+
parser.add_argument(
|
|
294
|
+
'bgpvpn',
|
|
295
|
+
metavar="<bgpvpn>",
|
|
296
|
+
help=_("BGP VPN to apply the port association (name or ID)"),
|
|
297
|
+
)
|
|
298
|
+
parser.add_argument(
|
|
299
|
+
'port',
|
|
300
|
+
metavar="<port>",
|
|
301
|
+
help=_("Port to associate the BGP VPN (name or ID)"),
|
|
302
|
+
)
|
|
303
|
+
_get_common_parser(parser, 'create')
|
|
304
|
+
return parser
|
|
305
|
+
|
|
306
|
+
def take_action(self, parsed_args):
|
|
307
|
+
client = self.app.client_manager.network
|
|
308
|
+
bgpvpn = client.find_bgpvpn(parsed_args.bgpvpn, ignore_missing=False)
|
|
309
|
+
port = client.find_port(parsed_args.port, ignore_missing=False)
|
|
310
|
+
body: dict[str, ty.Any] = {'port_id': port['id']}
|
|
311
|
+
if 'project' in parsed_args and parsed_args.project is not None:
|
|
312
|
+
project_id = osc_id.find_project(
|
|
313
|
+
self.app.client_manager.sdk_connection,
|
|
314
|
+
parsed_args.project,
|
|
315
|
+
parsed_args.project_domain,
|
|
316
|
+
).id
|
|
317
|
+
body['project_id'] = project_id
|
|
318
|
+
|
|
319
|
+
body.update(_args2body(client, 'create', bgpvpn['id'], parsed_args))
|
|
320
|
+
|
|
321
|
+
obj = client.create_bgpvpn_port_association(bgpvpn['id'], **body)
|
|
322
|
+
_transform_resource(obj)
|
|
323
|
+
display_columns, columns = _get_columns(obj)
|
|
324
|
+
data = osc_utils.get_dict_properties(
|
|
325
|
+
obj, columns, formatters=_formatters
|
|
326
|
+
)
|
|
327
|
+
return display_columns, data
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
class SetBgpvpnPortAssoc(command.Command):
|
|
331
|
+
_description = _("Set BGP VPN port association properties")
|
|
332
|
+
_action = 'set'
|
|
333
|
+
|
|
334
|
+
def get_parser(self, prog_name):
|
|
335
|
+
parser = super().get_parser(prog_name)
|
|
336
|
+
parser.add_argument(
|
|
337
|
+
'port_association_id',
|
|
338
|
+
metavar="<port association ID>",
|
|
339
|
+
help=_("Port association ID to update"),
|
|
340
|
+
)
|
|
341
|
+
parser.add_argument(
|
|
342
|
+
'bgpvpn',
|
|
343
|
+
metavar="<bgpvpn>",
|
|
344
|
+
help=_("BGP VPN the port association belongs to (name or ID)"),
|
|
345
|
+
)
|
|
346
|
+
_get_common_parser(parser, self._action)
|
|
347
|
+
return parser
|
|
348
|
+
|
|
349
|
+
def take_action(self, parsed_args):
|
|
350
|
+
client = self.app.client_manager.network
|
|
351
|
+
bgpvpn = client.find_bgpvpn(parsed_args.bgpvpn, ignore_missing=False)
|
|
352
|
+
body = _args2body(client, self._action, bgpvpn['id'], parsed_args)
|
|
353
|
+
client.update_bgpvpn_port_association(
|
|
354
|
+
bgpvpn['id'], parsed_args.port_association_id, **body
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
class UnsetBgpvpnPortAssoc(SetBgpvpnPortAssoc):
|
|
359
|
+
_description = _("Unset BGP VPN port association properties")
|
|
360
|
+
_action = 'unset'
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
class DeleteBgpvpnPortAssoc(command.Command):
|
|
364
|
+
_description = _(
|
|
365
|
+
"Delete a BGP VPN port association(s) for a given BGP VPN"
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
def get_parser(self, prog_name):
|
|
369
|
+
parser = super().get_parser(prog_name)
|
|
370
|
+
parser.add_argument(
|
|
371
|
+
'port_association_ids',
|
|
372
|
+
metavar="<port association ID>",
|
|
373
|
+
nargs="+",
|
|
374
|
+
help=_("Port association ID(s) to remove"),
|
|
375
|
+
)
|
|
376
|
+
parser.add_argument(
|
|
377
|
+
'bgpvpn',
|
|
378
|
+
metavar="<bgpvpn>",
|
|
379
|
+
help=_("BGP VPN the port association belongs to (name or ID)"),
|
|
380
|
+
)
|
|
381
|
+
return parser
|
|
382
|
+
|
|
383
|
+
def take_action(self, parsed_args):
|
|
384
|
+
client = self.app.client_manager.network
|
|
385
|
+
bgpvpn = client.find_bgpvpn(parsed_args.bgpvpn, ignore_missing=False)
|
|
386
|
+
fails = 0
|
|
387
|
+
for id in parsed_args.port_association_ids:
|
|
388
|
+
try:
|
|
389
|
+
client.delete_bgpvpn_port_association(bgpvpn['id'], id)
|
|
390
|
+
LOG.warning(
|
|
391
|
+
"Port association %(id)s deleted",
|
|
392
|
+
{'id': id},
|
|
393
|
+
)
|
|
394
|
+
except Exception as e:
|
|
395
|
+
fails += 1
|
|
396
|
+
LOG.error(
|
|
397
|
+
"Failed to delete port "
|
|
398
|
+
"association with ID '%(id)s': %(e)s",
|
|
399
|
+
{'id': id, 'e': e},
|
|
400
|
+
)
|
|
401
|
+
if fails > 0:
|
|
402
|
+
msg = _(
|
|
403
|
+
"Failed to delete %(fails)s of %(total)s "
|
|
404
|
+
"port BGP VPN association(s)."
|
|
405
|
+
) % {
|
|
406
|
+
'fails': fails,
|
|
407
|
+
'total': len(parsed_args.port_association_ids),
|
|
408
|
+
}
|
|
409
|
+
raise exceptions.CommandError(msg)
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
class ListBgpvpnPortAssoc(command.Lister):
|
|
413
|
+
_description = _("List BGP VPN port associations for a given BGP VPN")
|
|
414
|
+
|
|
415
|
+
def get_parser(self, prog_name):
|
|
416
|
+
parser = super().get_parser(prog_name)
|
|
417
|
+
parser.add_argument(
|
|
418
|
+
'bgpvpn',
|
|
419
|
+
metavar="<bgpvpn>",
|
|
420
|
+
help=_("BGP VPN listed associations belong to (name or ID)"),
|
|
421
|
+
)
|
|
422
|
+
parser.add_argument(
|
|
423
|
+
'--long',
|
|
424
|
+
action='store_true',
|
|
425
|
+
help=_("List additional fields in output"),
|
|
426
|
+
)
|
|
427
|
+
parser.add_argument(
|
|
428
|
+
'--property',
|
|
429
|
+
metavar="<key=value>",
|
|
430
|
+
help=_(
|
|
431
|
+
"Filter property to apply on returned BGP VPNs (repeat to "
|
|
432
|
+
"filter on multiple properties)"
|
|
433
|
+
),
|
|
434
|
+
action=parseractions.KeyValueAction,
|
|
435
|
+
)
|
|
436
|
+
return parser
|
|
437
|
+
|
|
438
|
+
def take_action(self, parsed_args):
|
|
439
|
+
client = self.app.client_manager.network
|
|
440
|
+
bgpvpn = client.find_bgpvpn(parsed_args.bgpvpn, ignore_missing=False)
|
|
441
|
+
params = {}
|
|
442
|
+
if parsed_args.property:
|
|
443
|
+
params.update(parsed_args.property)
|
|
444
|
+
objs = client.bgpvpn_port_associations(
|
|
445
|
+
bgpvpn['id'], retrieve_all=True, **params
|
|
446
|
+
)
|
|
447
|
+
transformed_objs = [_transform_resource(obj) for obj in objs]
|
|
448
|
+
headers, columns = column_util.get_column_definitions(
|
|
449
|
+
list(_attr_map), long_listing=parsed_args.long
|
|
450
|
+
)
|
|
451
|
+
return (
|
|
452
|
+
headers,
|
|
453
|
+
(
|
|
454
|
+
osc_utils.get_dict_properties(
|
|
455
|
+
s, columns, formatters=_formatters
|
|
456
|
+
)
|
|
457
|
+
for s in transformed_objs
|
|
458
|
+
),
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
class ShowBgpvpnPortAssoc(command.ShowOne):
|
|
463
|
+
_description = _("Show information of a given BGP VPN port association")
|
|
464
|
+
|
|
465
|
+
def get_parser(self, prog_name):
|
|
466
|
+
parser = super().get_parser(prog_name)
|
|
467
|
+
parser.add_argument(
|
|
468
|
+
'port_association_id',
|
|
469
|
+
metavar="<port association ID>",
|
|
470
|
+
help=_("Port association ID to look up"),
|
|
471
|
+
)
|
|
472
|
+
parser.add_argument(
|
|
473
|
+
'bgpvpn',
|
|
474
|
+
metavar="<bgpvpn>",
|
|
475
|
+
help=_("BGP VPN the association belongs to (name or ID)"),
|
|
476
|
+
)
|
|
477
|
+
return parser
|
|
478
|
+
|
|
479
|
+
def take_action(self, parsed_args):
|
|
480
|
+
client = self.app.client_manager.network
|
|
481
|
+
bgpvpn = client.find_bgpvpn(parsed_args.bgpvpn, ignore_missing=False)
|
|
482
|
+
obj = client.get_bgpvpn_port_association(
|
|
483
|
+
bgpvpn['id'], parsed_args.port_association_id
|
|
484
|
+
)
|
|
485
|
+
_transform_resource(obj)
|
|
486
|
+
display_columns, columns = _get_columns(obj)
|
|
487
|
+
data = osc_utils.get_dict_properties(
|
|
488
|
+
obj, columns, formatters=_formatters
|
|
489
|
+
)
|
|
490
|
+
return display_columns, data
|