summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Page <james.page@ubuntu.com>2022-04-04 14:41:18 +0100
committergit-ubuntu importer <ubuntu-devel-discuss@lists.ubuntu.com>2022-04-05 08:03:13 +0000
commit4c7c05ece5d38fb781c721d1f21af502060b897a (patch)
tree553d69231b6cb4cf8878ef59df482174b0271b2a
parentf2de72e735dc8ed5afbc2dd79edb612f827300c9 (diff)
Imported using git-ubuntu import.
Notes
Notes: * New upstream release for OpenStack Yoga. * d/control: Bump minimum version of openstacksdk.
-rw-r--r--AUTHORS9
-rw-r--r--ChangeLog43
-rw-r--r--PKG-INFO2
-rw-r--r--debian/changelog7
-rw-r--r--debian/control4
-rw-r--r--doc/source/cli/command-objects/local-ip-association.rst11
-rw-r--r--doc/source/cli/command-objects/local-ip.rst12
-rw-r--r--doc/source/cli/command-objects/server-migration.rst2
-rw-r--r--doc/source/cli/data/nova.csv2
-rw-r--r--doc/source/cli/plugin-commands/aodh.rst4
-rw-r--r--doc/source/cli/plugin-commands/index.rst5
-rw-r--r--lower-constraints.txt2
-rw-r--r--openstackclient/common/quota.py9
-rw-r--r--openstackclient/compute/v2/aggregate.py2
-rw-r--r--openstackclient/compute/v2/flavor.py2
-rw-r--r--openstackclient/compute/v2/server.py531
-rw-r--r--openstackclient/compute/v2/server_image.py18
-rw-r--r--openstackclient/compute/v2/service.py131
-rw-r--r--openstackclient/image/v2/image.py90
-rw-r--r--openstackclient/network/v2/address_group.py13
-rw-r--r--openstackclient/network/v2/address_scope.py11
-rw-r--r--openstackclient/network/v2/floating_ip.py17
-rw-r--r--openstackclient/network/v2/floating_ip_port_forwarding.py11
-rw-r--r--openstackclient/network/v2/ip_availability.py12
-rw-r--r--openstackclient/network/v2/l3_conntrack_helper.py7
-rw-r--r--openstackclient/network/v2/local_ip.py310
-rw-r--r--openstackclient/network/v2/local_ip_association.py197
-rw-r--r--openstackclient/network/v2/network.py15
-rw-r--r--openstackclient/network/v2/network_agent.py7
-rw-r--r--openstackclient/network/v2/network_auto_allocated_topology.py13
-rw-r--r--openstackclient/network/v2/network_flavor.py10
-rw-r--r--openstackclient/network/v2/network_flavor_profile.py10
-rw-r--r--openstackclient/network/v2/network_meter.py10
-rw-r--r--openstackclient/network/v2/network_meter_rule.py13
-rw-r--r--openstackclient/network/v2/network_qos_policy.py10
-rw-r--r--openstackclient/network/v2/network_qos_rule.py11
-rw-r--r--openstackclient/network/v2/network_qos_rule_type.py2
-rw-r--r--openstackclient/network/v2/network_rbac.py10
-rw-r--r--openstackclient/network/v2/network_segment.py8
-rw-r--r--openstackclient/network/v2/network_segment_range.py8
-rw-r--r--openstackclient/network/v2/port.py48
-rw-r--r--openstackclient/network/v2/router.py85
-rw-r--r--openstackclient/network/v2/security_group.py12
-rw-r--r--openstackclient/network/v2/security_group_rule.py13
-rw-r--r--openstackclient/network/v2/subnet.py22
-rw-r--r--openstackclient/network/v2/subnet_pool.py11
-rw-r--r--openstackclient/tests/functional/common/test_quota.py25
-rw-r--r--openstackclient/tests/functional/compute/v2/test_server.py179
-rw-r--r--openstackclient/tests/functional/network/v2/test_local_ip.py161
-rw-r--r--openstackclient/tests/functional/volume/v3/test_volume.py1
-rw-r--r--openstackclient/tests/unit/common/test_project_purge.py2
-rw-r--r--openstackclient/tests/unit/common/test_quota.py43
-rw-r--r--openstackclient/tests/unit/compute/v2/fakes.py96
-rw-r--r--openstackclient/tests/unit/compute/v2/test_aggregate.py4
-rw-r--r--openstackclient/tests/unit/compute/v2/test_server.py1426
-rw-r--r--openstackclient/tests/unit/compute/v2/test_server_backup.py13
-rw-r--r--openstackclient/tests/unit/compute/v2/test_server_image.py31
-rw-r--r--openstackclient/tests/unit/compute/v2/test_service.py248
-rw-r--r--openstackclient/tests/unit/image/v1/fakes.py115
-rw-r--r--openstackclient/tests/unit/image/v1/test_image.py17
-rw-r--r--openstackclient/tests/unit/image/v2/fakes.py311
-rw-r--r--openstackclient/tests/unit/image/v2/test_image.py169
-rw-r--r--openstackclient/tests/unit/network/v2/fakes.py255
-rw-r--r--openstackclient/tests/unit/network/v2/test_address_group.py4
-rw-r--r--openstackclient/tests/unit/network/v2/test_address_scope.py8
-rw-r--r--openstackclient/tests/unit/network/v2/test_floating_ip_network.py14
-rw-r--r--openstackclient/tests/unit/network/v2/test_floating_ip_port_forwarding.py6
-rw-r--r--openstackclient/tests/unit/network/v2/test_ip_availability.py5
-rw-r--r--openstackclient/tests/unit/network/v2/test_local_ip.py480
-rw-r--r--openstackclient/tests/unit/network/v2/test_local_ip_association.py328
-rw-r--r--openstackclient/tests/unit/network/v2/test_network.py12
-rw-r--r--openstackclient/tests/unit/network/v2/test_network_auto_allocated_topology.py6
-rw-r--r--openstackclient/tests/unit/network/v2/test_network_flavor.py2
-rw-r--r--openstackclient/tests/unit/network/v2/test_network_flavor_profile.py6
-rw-r--r--openstackclient/tests/unit/network/v2/test_network_meter.py2
-rw-r--r--openstackclient/tests/unit/network/v2/test_network_qos_policy.py6
-rw-r--r--openstackclient/tests/unit/network/v2/test_network_rbac.py14
-rw-r--r--openstackclient/tests/unit/network/v2/test_port.py48
-rw-r--r--openstackclient/tests/unit/network/v2/test_router.py47
-rw-r--r--openstackclient/tests/unit/network/v2/test_security_group_network.py6
-rw-r--r--openstackclient/tests/unit/network/v2/test_security_group_rule_network.py2
-rw-r--r--openstackclient/tests/unit/network/v2/test_subnet.py56
-rw-r--r--openstackclient/tests/unit/network/v2/test_subnet_pool.py8
-rw-r--r--openstackclient/tests/unit/volume/v1/test_volume.py4
-rw-r--r--openstackclient/tests/unit/volume/v2/fakes.py110
-rw-r--r--openstackclient/tests/unit/volume/v2/test_volume.py4
-rw-r--r--python_openstackclient.egg-info/PKG-INFO2
-rw-r--r--python_openstackclient.egg-info/SOURCES.txt26
-rw-r--r--python_openstackclient.egg-info/entry_points.txt8
-rw-r--r--python_openstackclient.egg-info/pbr.json2
-rw-r--r--python_openstackclient.egg-info/requires.txt2
-rw-r--r--releasenotes/notes/add-network-local-ip-df3a9ce7610d8b90.yaml8
-rw-r--r--releasenotes/notes/add-option-to-unset-port-host-c76de9b1d2addf9a.yaml5
-rw-r--r--releasenotes/notes/add-remote-managed-vnic-type-4fc540b47427c37f.yaml6
-rw-r--r--releasenotes/notes/check-limit-quota-cc7f291dd1b537c1.yaml5
-rw-r--r--releasenotes/notes/fix-flavor-in-server-list-microversion-2.47-af200e9bb4747e2d.yaml8
-rw-r--r--releasenotes/notes/list-subnet-by-pool-id-a642efc13d04fa08.yaml5
-rw-r--r--releasenotes/notes/migrate-add-fixed-ip-to-sdk-3d932d77633bc765.yaml3
-rw-r--r--releasenotes/notes/migrate-create-server-image-to-sdk-e3d8077ffe05bb3d.yaml4
-rw-r--r--releasenotes/notes/migrate-server-add-network-add-port-to-sdk-7d81b25f59cfbec9.yaml4
-rw-r--r--releasenotes/notes/migrate-server-add-volume-to-sdk-685e036a88839651.yaml4
-rw-r--r--releasenotes/notes/migrate-server-pause-unpause-to-sdk-d74ec8536b764af6.yaml5
-rw-r--r--releasenotes/notes/migrate-server-suspend-resume-to-sdk-fd1709336607b496.yaml5
-rw-r--r--releasenotes/notes/migrate-service-list-delete-set-to-sdk-920cbe0d210af565.yaml3
-rw-r--r--releasenotes/notes/options-create-router-97910a882b604652.yaml8
-rw-r--r--releasenotes/notes/pass_ssh_args-cf26a2ce26ccddaf.yaml14
-rw-r--r--releasenotes/notes/port-list-security-group-4af5d2e789174ff9.yaml5
-rw-r--r--releasenotes/notes/switch-server-remove-network-port-to-sdk-829ba711e0e198d5.yaml4
-rw-r--r--releasenotes/notes/switch-server-remove-volume-to-sdk-47e9befd2672dcdf.yaml4
-rw-r--r--releasenotes/source/conf.py8
-rw-r--r--requirements.txt2
-rw-r--r--setup.cfg10
112 files changed, 4548 insertions, 1668 deletions
diff --git a/AUTHORS b/AUTHORS
index 85ad49e..40c44d8 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -89,6 +89,7 @@ Daniel Strong <dstrong@glyx.co.uk>
Dao Cong Tien <tiendc@vn.fujitsu.com>
Davanum Srinivas <davanum@gmail.com>
Dave Chen <wei.d.chen@intel.com>
+David Caro <me@dcaro.es>
David Moreau Simard <dms@redhat.com>
David Moreau Simard <dmsimard@iweb.com>
David Rabel <rabel@b1-systems.de>
@@ -106,6 +107,7 @@ Doug Hellmann <doug.hellmann@dreamhost.com>
Doug Hellmann <doug@doughellmann.com>
Doug Wiegley <dwiegley@salesforce.com>
Dougal Matthews <dougal@redhat.com>
+Dr. Jens Harbott <harbott@osism.tech>
Einst Crazy <yu.changcai@99cloud.net>
Elena Ezhova <eezhova@mirantis.com>
Elod Illes <elod.illes@est.tech>
@@ -118,6 +120,7 @@ Fei Long Wang <flwang@catalyst.net.nz>
Felix Yan <felixonmars@archlinux.org>
Flavio Percoco <flaper87@gmail.com>
Florent Flament <florent.flament-ext@cloudwatt.com>
+Frode Nordahl <frode.nordahl@canonical.com>
Gabriel Ramirez <gabrielramirez1109@gmail.com>
Gage Hugo <gagehugo@gmail.com>
Gary Kotton <gkotton@vmware.com>
@@ -179,6 +182,7 @@ Jeremy Houser <jh629g@att.com>
Jeremy Liu <liujiong@gohighsec.com>
Jeremy Stanley <fungi@yuggoth.org>
Jerry George <jerry@ca.ibm.com>
+JieonLee <dlwldjs7544@naver.com>
Jim Rollenhagen <jim@jimrollenhagen.com>
Jimmy McCrory <jimmy.mccrory@gmail.com>
JingLiu <liu.jing5@zte.com.cn>
@@ -207,6 +211,7 @@ Ken Thomas <krt@yahoo-inc.com>
Kendall Nelson <kennelson11@gmail.com>
Kenneth Chu <chukenne@ca.ibm.com>
Kevin_Zheng <zhengzhenyu@huawei.com>
+Khomesh Thakre <khomeshthakre24@gmail.com>
Kristi Nikolla <knikolla@bu.edu>
Kyrylo Romanenko <kromanenko@mirantis.com>
LEE JAE YONG <jaeljy135@gmail.com>
@@ -269,6 +274,7 @@ Nir Magnezi <nmagnezi@redhat.com>
Noam Angel <noama@mellanox.com>
Nobuto Murata <nobuto.murata@canonical.com>
Noorul Islam K M <noorul@noorul.com>
+Nurmatov Mamatisa <nurmatov.mamatisa@huawei.com>
Oleksii Chuprykov <ochuprykov@mirantis.com>
Ondřej Nový <ondrej.novy@firma.seznam.cz>
OpenStack Release Bot <infra-root@openstack.org>
@@ -293,6 +299,7 @@ Reedip <reedip.banerjee@nectechnologies.in>
Reedip <reedip14@gmail.com>
Richard Theis <rtheis@us.ibm.com>
Rikimaru Honjo <honjo.rikimaru@po.ntts.co.jp>
+Ritvik Vinodkumar <vinodkumar.r@northeastern.edu>
Robert Francis <robefran@ca.ibm.com>
Robin Cernin <rcernin@redhat.com>
Rodolfo Alonso Hernandez <ralonsoh@redhat.com>
@@ -334,6 +341,7 @@ Slawek Kaplonski <skaplons@redhat.com>
SongmingYan <yan.songming@zte.com.cn>
Stephen Finucane <sfinucan@redhat.com>
Stephen Finucane <stephen.finucane@intel.com>
+Stephen Finucane <stephen@that.guru>
Steve Martinelli <s.martinelli@gmail.com>
Steve Martinelli <stevemar@ca.ibm.com>
Steven Hardy <shardy@redhat.com>
@@ -350,6 +358,7 @@ Terry Howe <terrylhowe@gmail.com>
Terry Howe <thowe@hp.com>
TerryHowe <terrylhowe@gmail.com>
Thomas Goirand <zigo@debian.org>
+Thrivikram Mudunuri <mthrivikram+opendev@gmail.com>
Tim Burke <tim.burke@gmail.com>
Tom Cocozzello <tjcocozz@us.ibm.com>
Tom Jose Kalapura <tomjosekal@gmail.com>
diff --git a/ChangeLog b/ChangeLog
index 4a84d9d..33abd4e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,10 +1,51 @@
CHANGES
=======
+5.8.0
+-----
+
+* Add support for setting extra DHCP options on existing ports
+* docs: Document additional 'server migration' commands
+* Add support for 'remote-managed' vnic type
+* Don't fail on extlinks warnings for reno build
+* Support Neutron Local IP CRUD
+* Get rid of tenant\_id in the network commands
+* Switch compute service list, delete and set to sdk
+* Skip original\_name from flavor info
+* Fix volume set functional test
+* Add location to fake network objects
+* Hide location columns for network objects
+* compute: Pass through args to ssh
+* compute: Fix weird option definition for 'server ssh'
+* compute: Return information about fixed IP
+* Switch add fixed IP to SDK
+* Allow setting gateway when creating a router
+* Fix RemoveServerVolume
+* Add network update quota "limit\_check" parameter
+* Add --security-group to port list
+* compute: Show flavor in 'server list' with API >= 2.47
+* compute: Reorder building of columns for 'server list'
+* Switch server suspend and server resume to SDK
+* Switch server pause and server unpause to SDK
+* Switch openstack server remove port/network to using sdk
+* Allow unset port's host\_id
+* Switch command server remove volume to sdk
+* Add functional test for server add/remove volume
+* Temporarily drop aodhclient from doc build
+* Switch command server add volume to sdk
+* Add missing command mapping in nova
+* image: Sanity check the 'SetImage' command
+* tests: Update fake image client in tests
+* image: Remove FakeImage test helper
+* image: Remove dead test helper methods
+* Switch server image create to SDK
+* Switch openstack server add port/network to using sdk
+
5.7.0
-----
* compute: Return details of attached volumes
+* compute: Don't warn if disk overcommit params unset
* Switch server backup to sdk
* Remove remnants of 'six'
* Remove 'get\_osc\_show\_columns\_for\_sdk\_resource' duplicates
@@ -52,6 +93,7 @@ CHANGES
* docs: Update glanceclient comparison doc
* docs: Update novaclient comparison doc
* docs: Update cinderclient comparison doc
+* Include hosts in aggregate list --long
* compute: Fix typo
* setup.cfg: Replace dashes with underscores
* Make functional Neutron tests running fine on ML2/OVN environments
@@ -75,6 +117,7 @@ CHANGES
5.5.0
-----
+* Add --subnet-pool to subnet list
* Update the file paths mentioned in README.rst
* Add pre-commit
* compute: Remove 'file://' prefix from '--block-device'
diff --git a/PKG-INFO b/PKG-INFO
index 16507c6..7868b65 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.2
Name: python-openstackclient
-Version: 5.7.0
+Version: 5.8.0
Summary: OpenStack Command-line Client
Home-page: https://docs.openstack.org/python-openstackclient/latest/
Author: OpenStack
diff --git a/debian/changelog b/debian/changelog
index 7588e0f..21a3e15 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+python-openstackclient (5.8.0-0ubuntu1) jammy; urgency=medium
+
+ * New upstream release for OpenStack Yoga.
+ * d/control: Bump minimum version of openstacksdk.
+
+ -- James Page <james.page@ubuntu.com> Mon, 04 Apr 2022 14:41:18 +0100
+
python-openstackclient (5.7.0-0ubuntu1) jammy; urgency=medium
* New upstream release for OpenStack Yoga.
diff --git a/debian/control b/debian/control
index 1c35f26..81b14b9 100644
--- a/debian/control
+++ b/debian/control
@@ -39,7 +39,7 @@ Build-Depends-Indep:
python3-novaclient (>= 2:17.0.0),
python3-octaviaclient (>= 1.11.0),
python3-openstackdocstheme (>= 2.2.1),
- python3-openstacksdk (>= 0.56.0),
+ python3-openstacksdk (>= 0.61.0),
python3-os-client-config (>= 1.28.0),
python3-osc-lib (>= 2.3.0),
python3-osc-placement (>= 1.7.0),
@@ -99,7 +99,7 @@ Depends:
python3-iso8601 (>= 0.1.11),
python3-keystoneclient (>= 1:3.22.0),
python3-novaclient (>= 2:17.0.0),
- python3-openstacksdk (>= 0.56.0),
+ python3-openstacksdk (>= 0.61.0),
python3-osc-lib (>= 2.3.0),
python3-oslo.i18n (>= 3.15.3),
python3-oslo.serialization (>= 1.2.0),
diff --git a/doc/source/cli/command-objects/local-ip-association.rst b/doc/source/cli/command-objects/local-ip-association.rst
new file mode 100644
index 0000000..824ee4d
--- /dev/null
+++ b/doc/source/cli/command-objects/local-ip-association.rst
@@ -0,0 +1,11 @@
+=============================================
+Local IP Associations (local_ip_associations)
+=============================================
+
+The resource lets users assign Local IPs to user Ports.
+This is a sub-resource of the Local IP resource.
+
+Network v2
+
+.. autoprogram-cliff:: openstack.network.v2
+ :command: local ip association *
diff --git a/doc/source/cli/command-objects/local-ip.rst b/doc/source/cli/command-objects/local-ip.rst
new file mode 100644
index 0000000..c8c5ab4
--- /dev/null
+++ b/doc/source/cli/command-objects/local-ip.rst
@@ -0,0 +1,12 @@
+=====================
+Local IPs (local_ips)
+=====================
+
+Extension that allows users to create a virtual IP that can later be assigned
+to multiple ports/VMs (similar to anycast IP) and is guaranteed to only be
+reachable within the same physical server/node boundaries
+
+Network v2
+
+.. autoprogram-cliff:: openstack.network.v2
+ :command: local ip *
diff --git a/doc/source/cli/command-objects/server-migration.rst b/doc/source/cli/command-objects/server-migration.rst
index 6e2982c..9db58e3 100644
--- a/doc/source/cli/command-objects/server-migration.rst
+++ b/doc/source/cli/command-objects/server-migration.rst
@@ -9,4 +9,4 @@ supported: live migration, cold migration, resize and evacuation.
Compute v2
.. autoprogram-cliff:: openstack.compute.v2
- :command: server migration list
+ :command: server migration *
diff --git a/doc/source/cli/data/nova.csv b/doc/source/cli/data/nova.csv
index dd8992f..0ab2b2f 100644
--- a/doc/source/cli/data/nova.csv
+++ b/doc/source/cli/data/nova.csv
@@ -46,7 +46,7 @@ hypervisor-show,hypervisor show,Display the details of the specified hypervisor.
hypervisor-stats,hypervisor stats show,Get hypervisor statistics over all compute nodes.
hypervisor-uptime,,Display the uptime of the specified hypervisor.
image-create,server image create,Create a new image by taking a snapshot of a running server.
-instance-action,,Show an action.
+instance-action,server event show,Show an action.
instance-action-list,,List actions on a server.
instance-usage-audit-log,,List/Get server usage audits.
interface-attach,server add port / server add floating ip / server add fixed ip,Attach a network interface to a server.
diff --git a/doc/source/cli/plugin-commands/aodh.rst b/doc/source/cli/plugin-commands/aodh.rst
deleted file mode 100644
index 5d8b433..0000000
--- a/doc/source/cli/plugin-commands/aodh.rst
+++ /dev/null
@@ -1,4 +0,0 @@
-aodh
-----
-
-.. autoprogram-cliff:: openstack.alarming.v2
diff --git a/doc/source/cli/plugin-commands/index.rst b/doc/source/cli/plugin-commands/index.rst
index 4e1ce54..638dcbe 100644
--- a/doc/source/cli/plugin-commands/index.rst
+++ b/doc/source/cli/plugin-commands/index.rst
@@ -7,7 +7,6 @@ Plugin Commands
.. toctree::
:maxdepth: 1
- aodh
barbican
designate
gnocchi
@@ -29,6 +28,10 @@ Plugin Commands
.. TODO(efried): Make pages for the following once they're fixed.
+.. aodh
+.. # aodhclient docs build is failing with recent pyparsing
+.. # autoprogram-cliff:: openstack.alarming.v2
+
.. cue
.. # cueclient is not in global-requirements
.. # list-plugins:: openstack.mb.v1
diff --git a/lower-constraints.txt b/lower-constraints.txt
index b98b843..495b102 100644
--- a/lower-constraints.txt
+++ b/lower-constraints.txt
@@ -38,7 +38,7 @@ msgpack-python==0.4.0
munch==2.1.0
netaddr==0.7.18
netifaces==0.10.4
-openstacksdk==0.56.0
+openstacksdk==0.61.0
os-client-config==2.1.0
os-service-types==1.7.0
osc-lib==2.3.0
diff --git a/openstackclient/common/quota.py b/openstackclient/common/quota.py
index 643cb4e..677cba0 100644
--- a/openstackclient/common/quota.py
+++ b/openstackclient/common/quota.py
@@ -535,6 +535,12 @@ class SetQuota(common.NetDetectionMixin, command.Command):
action='store_true',
help=_('Force quota update (only supported by compute)')
)
+ parser.add_argument(
+ '--check-limit',
+ action='store_true',
+ help=_('Check quota limit when updating (only supported by '
+ 'network)')
+ )
return parser
def take_action(self, parsed_args):
@@ -561,6 +567,9 @@ class SetQuota(common.NetDetectionMixin, command.Command):
volume_kwargs[k] = value
network_kwargs = {}
+ if parsed_args.check_limit:
+ network_kwargs['check_limit'] = True
+
if self.app.client_manager.is_network_endpoint_enabled():
for k, v in NETWORK_QUOTAS.items():
value = getattr(parsed_args, k, None)
diff --git a/openstackclient/compute/v2/aggregate.py b/openstackclient/compute/v2/aggregate.py
index e39eb2d..37522a7 100644
--- a/openstackclient/compute/v2/aggregate.py
+++ b/openstackclient/compute/v2/aggregate.py
@@ -193,12 +193,14 @@ class ListAggregate(command.Lister):
"Name",
"Availability Zone",
"Properties",
+ "Hosts",
)
columns = (
"ID",
"Name",
"Availability Zone",
"Metadata",
+ "Hosts",
)
else:
column_headers = columns = (
diff --git a/openstackclient/compute/v2/flavor.py b/openstackclient/compute/v2/flavor.py
index a55aba2..8a9eb07 100644
--- a/openstackclient/compute/v2/flavor.py
+++ b/openstackclient/compute/v2/flavor.py
@@ -48,7 +48,7 @@ def _get_flavor_columns(item):
'is_public': 'os-flavor-access:is_public'
}
- hidden_columns = ['links', 'location']
+ hidden_columns = ['links', 'location', 'original_name']
return utils.get_osc_show_columns_for_sdk_resource(
item, column_map, hidden_columns)
diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py
index 80bdc61..a46fb90 100644
--- a/openstackclient/compute/v2/server.py
+++ b/openstackclient/compute/v2/server.py
@@ -27,6 +27,7 @@ import iso8601
from novaclient import api_versions
from novaclient.v2 import servers
from openstack import exceptions as sdk_exceptions
+from openstack import utils as sdk_utils
from osc_lib.cli import format_columns
from osc_lib.cli import parseractions
from osc_lib.command import command
@@ -203,7 +204,7 @@ def boolenv(*vars, default=False):
return default
-class AddFixedIP(command.Command):
+class AddFixedIP(command.ShowOne):
_description = _("Add fixed IP address to server")
def get_parser(self, prog_name):
@@ -230,36 +231,73 @@ class AddFixedIP(command.Command):
metavar='<tag>',
help=_(
'Tag for the attached interface. '
- '(supported by --os-compute-api-version 2.52 or above)'
+ '(supported by --os-compute-api-version 2.49 or above)'
)
)
return parser
def take_action(self, parsed_args):
- compute_client = self.app.client_manager.compute
-
- server = utils.find_resource(
- compute_client.servers, parsed_args.server)
-
- network = compute_client.api.network_find(parsed_args.network)
-
- kwargs = {
- 'port_id': None,
- 'net_id': network['id'],
- 'fixed_ip': parsed_args.fixed_ip_address,
- }
+ compute_client = self.app.client_manager.sdk_connection.compute
+ server = compute_client.find_server(
+ parsed_args.server,
+ ignore_missing=False
+ )
if parsed_args.tag:
- if compute_client.api_version < api_versions.APIVersion('2.49'):
+ if not sdk_utils.supports_microversion(compute_client, '2.49'):
msg = _(
'--os-compute-api-version 2.49 or greater is required to '
'support the --tag option'
)
raise exceptions.CommandError(msg)
+ if self.app.client_manager.is_network_endpoint_enabled():
+ network_client = self.app.client_manager.network
+ net_id = network_client.find_network(
+ parsed_args.network,
+ ignore_missing=False
+ ).id
+ else:
+ net_id = parsed_args.network
+
+ if not sdk_utils.supports_microversion(compute_client, '2.44'):
+ compute_client.add_fixed_ip_to_server(
+ server.id,
+ net_id
+ )
+ return ((), ())
+
+ kwargs = {
+ 'net_id': net_id,
+ 'fixed_ip': parsed_args.fixed_ip_address,
+ }
+ if parsed_args.tag:
kwargs['tag'] = parsed_args.tag
- server.interface_attach(**kwargs)
+ interface = compute_client.create_server_interface(server.id, **kwargs)
+
+ columns = (
+ 'port_id', 'server_id', 'net_id', 'mac_addr', 'port_state',
+ 'fixed_ips',
+ )
+ column_headers = (
+ 'Port ID', 'Server ID', 'Network ID', 'MAC Address', 'Port State',
+ 'Fixed IPs',
+ )
+ if sdk_utils.supports_microversion(compute_client, '2.49'):
+ columns += ('tag',)
+ column_headers += ('Tag',)
+
+ return (
+ column_headers,
+ utils.get_item_properties(
+ interface,
+ columns,
+ formatters={
+ 'fixed_ips': format_columns.ListDictColumn,
+ },
+ ),
+ )
class AddFloatingIP(network_common.NetworkAndComputeCommand):
@@ -378,10 +416,10 @@ class AddPort(command.Command):
return parser
def take_action(self, parsed_args):
- compute_client = self.app.client_manager.compute
+ compute_client = self.app.client_manager.sdk_connection.compute
- server = utils.find_resource(
- compute_client.servers, parsed_args.server)
+ server = compute_client.find_server(
+ parsed_args.server, ignore_missing=False)
if self.app.client_manager.is_network_endpoint_enabled():
network_client = self.app.client_manager.network
@@ -392,12 +430,11 @@ class AddPort(command.Command):
kwargs = {
'port_id': port_id,
- 'net_id': None,
'fixed_ip': None,
}
if parsed_args.tag:
- if compute_client.api_version < api_versions.APIVersion("2.49"):
+ if not sdk_utils.supports_microversion(compute_client, '2.49'):
msg = _(
'--os-compute-api-version 2.49 or greater is required to '
'support the --tag option'
@@ -405,7 +442,7 @@ class AddPort(command.Command):
raise exceptions.CommandError(msg)
kwargs['tag'] = parsed_args.tag
- server.interface_attach(**kwargs)
+ compute_client.create_server_interface(server, **kwargs)
class AddNetwork(command.Command):
@@ -434,10 +471,10 @@ class AddNetwork(command.Command):
return parser
def take_action(self, parsed_args):
- compute_client = self.app.client_manager.compute
+ compute_client = self.app.client_manager.sdk_connection.compute
- server = utils.find_resource(
- compute_client.servers, parsed_args.server)
+ server = compute_client.find_server(
+ parsed_args.server, ignore_missing=False)
if self.app.client_manager.is_network_endpoint_enabled():
network_client = self.app.client_manager.network
@@ -447,13 +484,12 @@ class AddNetwork(command.Command):
net_id = parsed_args.network
kwargs = {
- 'port_id': None,
'net_id': net_id,
'fixed_ip': None,
}
if parsed_args.tag:
- if compute_client.api_version < api_versions.APIVersion('2.49'):
+ if not sdk_utils.supports_microversion(compute_client, '2.49'):
msg = _(
'--os-compute-api-version 2.49 or greater is required to '
'support the --tag option'
@@ -462,7 +498,7 @@ class AddNetwork(command.Command):
kwargs['tag'] = parsed_args.tag
- server.interface_attach(**kwargs)
+ compute_client.create_server_interface(server, **kwargs)
class AddServerSecurityGroup(command.Command):
@@ -549,24 +585,25 @@ class AddServerVolume(command.ShowOne):
return parser
def take_action(self, parsed_args):
- compute_client = self.app.client_manager.compute
- volume_client = self.app.client_manager.volume
+ compute_client = self.app.client_manager.sdk_connection.compute
+ volume_client = self.app.client_manager.sdk_connection.volume
- server = utils.find_resource(
- compute_client.servers,
+ server = compute_client.find_server(
parsed_args.server,
+ ignore_missing=False,
)
- volume = utils.find_resource(
- volume_client.volumes,
+ volume = volume_client.find_volume(
parsed_args.volume,
+ ignore_missing=False,
)
kwargs = {
+ "volumeId": volume.id,
"device": parsed_args.device
}
if parsed_args.tag:
- if compute_client.api_version < api_versions.APIVersion('2.49'):
+ if not sdk_utils.supports_microversion(compute_client, '2.49'):
msg = _(
'--os-compute-api-version 2.49 or greater is required to '
'support the --tag option'
@@ -576,7 +613,7 @@ class AddServerVolume(command.ShowOne):
kwargs['tag'] = parsed_args.tag
if parsed_args.enable_delete_on_termination:
- if compute_client.api_version < api_versions.APIVersion('2.79'):
+ if not sdk_utils.supports_microversion(compute_client, '2.79'):
msg = _(
'--os-compute-api-version 2.79 or greater is required to '
'support the --enable-delete-on-termination option.'
@@ -586,7 +623,7 @@ class AddServerVolume(command.ShowOne):
kwargs['delete_on_termination'] = True
if parsed_args.disable_delete_on_termination:
- if compute_client.api_version < api_versions.APIVersion('2.79'):
+ if not sdk_utils.supports_microversion(compute_client, '2.79'):
msg = _(
'--os-compute-api-version 2.79 or greater is required to '
'support the --disable-delete-on-termination option.'
@@ -595,28 +632,23 @@ class AddServerVolume(command.ShowOne):
kwargs['delete_on_termination'] = False
- volume_attachment = compute_client.volumes.create_server_volume(
- server.id,
- volume.id,
- **kwargs
+ volume_attachment = compute_client.create_volume_attachment(
+ server,
+ **kwargs,
)
- columns = ('id', 'serverId', 'volumeId', 'device')
+ columns = ('id', 'server id', 'volume id', 'device')
column_headers = ('ID', 'Server ID', 'Volume ID', 'Device')
- if compute_client.api_version >= api_versions.APIVersion('2.49'):
+ if sdk_utils.supports_microversion(compute_client, '2.49'):
columns += ('tag',)
column_headers += ('Tag',)
- if compute_client.api_version >= api_versions.APIVersion('2.79'):
+ if sdk_utils.supports_microversion(compute_client, '2.79'):
columns += ('delete_on_termination',)
column_headers += ('Delete On Termination',)
return (
column_headers,
- utils.get_item_properties(
- volume_attachment,
- columns,
- mixed_case_fields=('serverId', 'volumeId'),
- )
+ utils.get_item_properties(volume_attachment, columns,)
)
@@ -2209,15 +2241,19 @@ class ListServer(command.Lister):
# flavor name is given, map it to ID.
flavor_id = None
if parsed_args.flavor:
- flavor_id = utils.find_resource(compute_client.flavors,
- parsed_args.flavor).id
+ flavor_id = utils.find_resource(
+ compute_client.flavors,
+ parsed_args.flavor,
+ ).id
# Nova only supports list servers searching by image ID. So if a
# image name is given, map it to ID.
image_id = None
if parsed_args.image:
- image_id = image_client.find_image(parsed_args.image,
- ignore_missing=False).id
+ image_id = image_client.find_image(
+ parsed_args.image,
+ ignore_missing=False,
+ ).id
search_opts = {
'reservation_id': parsed_args.reservation_id,
@@ -2325,95 +2361,100 @@ class ListServer(command.Lister):
try:
iso8601.parse_date(search_opts['changes-since'])
except (TypeError, iso8601.ParseError):
+ msg = _('Invalid changes-since value: %s')
raise exceptions.CommandError(
- _('Invalid changes-since value: %s') %
- search_opts['changes-since']
+ msg % search_opts['changes-since']
)
+ columns = (
+ 'id',
+ 'name',
+ 'status',
+ )
+ column_headers = (
+ 'ID',
+ 'Name',
+ 'Status',
+ )
+
if parsed_args.long:
- columns = (
- 'ID',
- 'Name',
- 'Status',
+ columns += (
'OS-EXT-STS:task_state',
'OS-EXT-STS:power_state',
- 'Networks',
- 'Image Name',
- 'Image ID',
- 'Flavor Name',
- 'Flavor ID',
- 'OS-EXT-AZ:availability_zone',
- 'OS-EXT-SRV-ATTR:host',
- 'Metadata',
)
- column_headers = (
- 'ID',
- 'Name',
- 'Status',
+ column_headers += (
'Task State',
'Power State',
- 'Networks',
+ )
+
+ columns += ('networks',)
+ column_headers += ('Networks',)
+
+ if parsed_args.long:
+ columns += (
+ 'image_name',
+ 'image_id',
+ )
+ column_headers += (
'Image Name',
'Image ID',
- 'Flavor Name',
- 'Flavor ID',
- 'Availability Zone',
- 'Host',
- 'Properties',
)
- mixed_case_fields = [
- 'OS-EXT-STS:task_state',
- 'OS-EXT-STS:power_state',
- 'OS-EXT-AZ:availability_zone',
- 'OS-EXT-SRV-ATTR:host',
- ]
else:
if parsed_args.no_name_lookup:
- columns = (
- 'ID',
- 'Name',
- 'Status',
- 'Networks',
- 'Image ID',
- 'Flavor ID',
- )
+ columns += ('image_id',)
else:
- columns = (
- 'ID',
- 'Name',
- 'Status',
- 'Networks',
- 'Image Name',
+ columns += ('image_name',)
+ column_headers += ('Image',)
+
+ # microversion 2.47 puts the embedded flavor into the server response
+ # body but omits the id, so if not present we just expose the original
+ # flavor name in the output
+ if compute_client.api_version >= api_versions.APIVersion('2.47'):
+ columns += ('flavor_name',)
+ column_headers += ('Flavor',)
+ else:
+ if parsed_args.long:
+ columns += (
+ 'flavor_name',
+ 'flavor_id',
+ )
+ column_headers += (
'Flavor Name',
+ 'Flavor ID',
)
- column_headers = (
- 'ID',
- 'Name',
- 'Status',
- 'Networks',
- 'Image',
- 'Flavor',
+ else:
+ if parsed_args.no_name_lookup:
+ columns += ('flavor_id',)
+ else:
+ columns += ('flavor_name',)
+ column_headers += ('Flavor',)
+
+ if parsed_args.long:
+ columns += (
+ 'OS-EXT-AZ:availability_zone',
+ 'OS-EXT-SRV-ATTR:host',
+ 'metadata',
+ )
+ column_headers += (
+ 'Availability Zone',
+ 'Host',
+ 'Properties',
)
- mixed_case_fields = []
marker_id = None
# support for additional columns
if parsed_args.columns:
- # convert tuple to list to edit them
- column_headers = list(column_headers)
- columns = list(columns)
-
for c in parsed_args.columns:
if c in ('Project ID', 'project_id'):
- columns.append('tenant_id')
- column_headers.append('Project ID')
+ columns += ('tenant_id',)
+ column_headers += ('Project ID',)
if c in ('User ID', 'user_id'):
- columns.append('user_id')
- column_headers.append('User ID')
+ columns += ('user_id',)
+ column_headers += ('User ID',)
if c in ('Created At', 'created_at'):
- columns.append('created')
- column_headers.append('Created At')
+ columns += ('created',)
+ column_headers += ('Created At',)
# convert back to tuple
column_headers = tuple(column_headers)
@@ -2427,25 +2468,29 @@ class ListServer(command.Lister):
if parsed_args.deleted:
marker_id = parsed_args.marker
else:
- marker_id = utils.find_resource(compute_client.servers,
- parsed_args.marker).id
+ marker_id = utils.find_resource(
+ compute_client.servers,
+ parsed_args.marker,
+ ).id
- data = compute_client.servers.list(search_opts=search_opts,
- marker=marker_id,
- limit=parsed_args.limit)
+ data = compute_client.servers.list(
+ search_opts=search_opts,
+ marker=marker_id,
+ limit=parsed_args.limit)
images = {}
flavors = {}
if data and not parsed_args.no_name_lookup:
- # Create a dict that maps image_id to image object.
- # Needed so that we can display the "Image Name" column.
- # "Image Name" is not crucial, so we swallow any exceptions.
- # The 'image' attribute can be an empty string if the server was
- # booted from a volume.
+ # create a dict that maps image_id to image object, which is used
+ # to display the "Image Name" column. Note that 'image.id' can be
+ # empty for BFV instances and 'image' can be missing entirely if
+ # there are infra failures
if parsed_args.name_lookup_one_by_one or image_id:
- for i_id in set(filter(lambda x: x is not None,
- (s.image.get('id') for s in data
- if s.image))):
+ for i_id in set(
+ s.image['id'] for s in data
+ if s.image and s.image.get('id')
+ ):
+ # "Image Name" is not crucial, so we swallow any exceptions
try:
images[i_id] = image_client.get_image(i_id)
except Exception:
@@ -2458,12 +2503,17 @@ class ListServer(command.Lister):
except Exception:
pass
- # Create a dict that maps flavor_id to flavor object.
- # Needed so that we can display the "Flavor Name" column.
- # "Flavor Name" is not crucial, so we swallow any exceptions.
+ # create a dict that maps flavor_id to flavor object, which is used
+ # to display the "Flavor Name" column. Note that 'flavor.id' is not
+ # present on microversion 2.47 or later and 'flavor' won't be
+ # present if there are infra failures
if parsed_args.name_lookup_one_by_one or flavor_id:
- for f_id in set(filter(lambda x: x is not None,
- (s.flavor.get('id') for s in data))):
+ for f_id in set(
+ s.flavor['id'] for s in data
+ if s.flavor and s.flavor.get('id')
+ ):
+ # "Flavor Name" is not crucial, so we swallow any
+ # exceptions
try:
flavors[f_id] = compute_client.flavors.get(f_id)
except Exception:
@@ -2487,6 +2537,7 @@ class ListServer(command.Lister):
# processing of the image and flavor informations.
if not hasattr(s, 'image') or not hasattr(s, 'flavor'):
continue
+
if 'id' in s.image:
image = images.get(s.image['id'])
if image:
@@ -2499,29 +2550,30 @@ class ListServer(command.Lister):
# able to grep for boot-from-volume servers when using the CLI.
s.image_name = IMAGE_STRING_FOR_BFV
s.image_id = IMAGE_STRING_FOR_BFV
- if 'id' in s.flavor:
+
+ if compute_client.api_version < api_versions.APIVersion('2.47'):
flavor = flavors.get(s.flavor['id'])
if flavor:
s.flavor_name = flavor.name
s.flavor_id = s.flavor['id']
else:
- # TODO(mriedem): Fix this for microversion >= 2.47 where the
- # flavor is embedded in the server response without the id.
- # We likely need to drop the Flavor ID column in that case if
- # --long is specified.
- s.flavor_name = ''
- s.flavor_id = ''
+ s.flavor_name = s.flavor['original_name']
table = (
column_headers,
(
utils.get_item_properties(
s, columns,
- mixed_case_fields=mixed_case_fields,
+ mixed_case_fields=(
+ 'OS-EXT-STS:task_state',
+ 'OS-EXT-STS:power_state',
+ 'OS-EXT-AZ:availability_zone',
+ 'OS-EXT-SRV-ATTR:host',
+ ),
formatters={
'OS-EXT-STS:power_state': PowerStateColumn,
- 'Networks': format_columns.DictListColumn,
- 'Metadata': format_columns.DictColumn,
+ 'networks': format_columns.DictListColumn,
+ 'metadata': format_columns.DictColumn,
},
) for s in data
),
@@ -2639,7 +2691,7 @@ revert to release the new server and restart the old one.""")
disk_group.add_argument(
'--disk-overcommit',
action='store_true',
- default=False,
+ default=None,
help=_(
'Allow disk over-commit on the destination host'
'(supported with --os-compute-api-version 2.24 or below)'
@@ -2649,7 +2701,6 @@ revert to release the new server and restart the old one.""")
'--no-disk-overcommit',
dest='disk_overcommit',
action='store_false',
- default=False,
help=_(
'Do not over-commit disk on the destination host (default)'
'(supported with --os-compute-api-version 2.24 or below)'
@@ -2711,6 +2762,11 @@ revert to release the new server and restart the old one.""")
if compute_client.api_version < api_versions.APIVersion('2.25'):
kwargs['disk_over_commit'] = parsed_args.disk_overcommit
+ # We can't use an argparse default value because then we can't
+ # distinguish between explicit 'False' and unset for the below
+ # case (microversion >= 2.25)
+ if kwargs['disk_over_commit'] is None:
+ kwargs['disk_over_commit'] = False
elif parsed_args.disk_overcommit is not None:
# TODO(stephenfin): Raise an error here in OSC 7.0
msg = _(
@@ -3135,12 +3191,13 @@ class PauseServer(command.Command):
return parser
def take_action(self, parsed_args):
- compute_client = self.app.client_manager.compute
+ compute_client = self.app.client_manager.sdk_connection.compute
for server in parsed_args.server:
- utils.find_resource(
- compute_client.servers,
- server
- ).pause()
+ server_id = compute_client.find_server(
+ server,
+ ignore_missing=False,
+ ).id
+ compute_client.pause_server(server_id)
class RebootServer(command.Command):
@@ -3695,10 +3752,10 @@ class RemovePort(command.Command):
return parser
def take_action(self, parsed_args):
- compute_client = self.app.client_manager.compute
+ compute_client = self.app.client_manager.sdk_connection.compute
- server = utils.find_resource(
- compute_client.servers, parsed_args.server)
+ server = compute_client.find_server(
+ parsed_args.server, ignore_missing=False)
if self.app.client_manager.is_network_endpoint_enabled():
network_client = self.app.client_manager.network
@@ -3707,7 +3764,11 @@ class RemovePort(command.Command):
else:
port_id = parsed_args.port
- server.interface_detach(port_id)
+ compute_client.delete_server_interface(
+ port_id,
+ server=server,
+ ignore_missing=False,
+ )
class RemoveNetwork(command.Command):
@@ -3728,10 +3789,10 @@ class RemoveNetwork(command.Command):
return parser
def take_action(self, parsed_args):
- compute_client = self.app.client_manager.compute
+ compute_client = self.app.client_manager.sdk_connection.compute
- server = utils.find_resource(
- compute_client.servers, parsed_args.server)
+ server = compute_client.find_server(
+ parsed_args.server, ignore_missing=False)
if self.app.client_manager.is_network_endpoint_enabled():
network_client = self.app.client_manager.network
@@ -3740,9 +3801,12 @@ class RemoveNetwork(command.Command):
else:
net_id = parsed_args.network
- for inf in server.interface_list():
+ for inf in compute_client.server_interfaces(server):
if inf.net_id == net_id:
- server.interface_detach(inf.port_id)
+ compute_client.delete_server_interface(
+ inf.port_id,
+ server=server,
+ )
class RemoveServerSecurityGroup(command.Command):
@@ -3798,21 +3862,22 @@ class RemoveServerVolume(command.Command):
return parser
def take_action(self, parsed_args):
- compute_client = self.app.client_manager.compute
- volume_client = self.app.client_manager.volume
+ compute_client = self.app.client_manager.sdk_connection.compute
+ volume_client = self.app.client_manager.sdk_connection.volume
- server = utils.find_resource(
- compute_client.servers,
+ server = compute_client.find_server(
parsed_args.server,
+ ignore_missing=False,
)
- volume = utils.find_resource(
- volume_client.volumes,
+ volume = volume_client.find_volume(
parsed_args.volume,
+ ignore_missing=False,
)
- compute_client.volumes.delete_server_volume(
- server.id,
- volume.id,
+ compute_client.delete_volume_attachment(
+ volume,
+ server,
+ ignore_missing=False,
)
@@ -4078,13 +4143,13 @@ class ResumeServer(command.Command):
return parser
def take_action(self, parsed_args):
-
- compute_client = self.app.client_manager.compute
+ compute_client = self.app.client_manager.sdk_connection.compute
for server in parsed_args.server:
- utils.find_resource(
- compute_client.servers,
+ server_id = compute_client.find_server(
server,
- ).resume()
+ ignore_missing=False,
+ ).id
+ compute_client.resume_server(server_id)
class SetServer(command.Command):
@@ -4437,50 +4502,29 @@ class SshServer(command.Command):
metavar='<server>',
help=_('Server (name or ID)'),
)
+ # Deprecated during the Yoga cycle
parser.add_argument(
- '--login',
- metavar='<login-name>',
- help=_('Login name (ssh -l option)'),
- )
- parser.add_argument(
- '-l',
- dest='login',
+ '--login', '-l',
metavar='<login-name>',
help=argparse.SUPPRESS,
)
+ # Deprecated during the Yoga cycle
parser.add_argument(
- '--port',
- metavar='<port>',
- type=int,
- help=_('Destination port (ssh -p option)'),
- )
- parser.add_argument(
- '-p',
+ '--port', '-p',
metavar='<port>',
- dest='port',
type=int,
help=argparse.SUPPRESS,
)
+ # Deprecated during the Yoga cycle
parser.add_argument(
- '--identity',
+ '--identity', '-i',
metavar='<keyfile>',
- help=_('Private key file (ssh -i option)'),
- )
- parser.add_argument(
- '-i',
- metavar='<filename>',
- dest='identity',
help=argparse.SUPPRESS,
)
+ # Deprecated during the Yoga cycle
parser.add_argument(
- '--option',
+ '--option', '-o',
metavar='<config-options>',
- help=_('Options in ssh_config(5) format (ssh -o option)'),
- )
- parser.add_argument(
- '-o',
- metavar='<option>',
- dest='option',
help=argparse.SUPPRESS,
)
ip_group = parser.add_mutually_exclusive_group()
@@ -4522,6 +4566,7 @@ class SshServer(command.Command):
default='public',
help=_('Use other IP address (public, private, etc)'),
)
+ # Deprecated during the Yoga cycle
parser.add_argument(
'-v',
dest='verbose',
@@ -4529,46 +4574,77 @@ class SshServer(command.Command):
default=False,
help=argparse.SUPPRESS,
)
+ parser.add_argument(
+ 'ssh_args',
+ nargs='*',
+ metavar='-- <standard ssh args>',
+ help=(
+ 'Any argument or option that ssh allows. '
+ 'Use -- once between openstackclient args and SSH args.'
+ ),
+ )
return parser
def take_action(self, parsed_args):
compute_client = self.app.client_manager.compute
+
server = utils.find_resource(
compute_client.servers,
parsed_args.server,
)
- # Build the command
- cmd = "ssh"
+ # first, handle the deprecated options
+ if any((
+ parsed_args.port,
+ parsed_args.identity,
+ parsed_args.option,
+ parsed_args.login,
+ parsed_args.verbose,
+ )):
+ msg = _(
+ 'The ssh options have been deprecated. The ssh equivalent '
+ 'options can be used instead as arguments after "--" on '
+ 'the command line.'
+ )
+ self.log.warning(msg)
ip_address_family = [4, 6]
if parsed_args.ipv4:
ip_address_family = [4]
- cmd += " -4"
if parsed_args.ipv6:
ip_address_family = [6]
- cmd += " -6"
+
+ args = parsed_args.ssh_args[:]
if parsed_args.port:
- cmd += " -p %d" % parsed_args.port
+ args.extend(['-p', str(parsed_args.port)])
+
if parsed_args.identity:
- cmd += " -i %s" % parsed_args.identity
+ args.extend(['-i', parsed_args.identity])
+
if parsed_args.option:
- cmd += " -o %s" % parsed_args.option
+ args.extend(['-o', parsed_args.option])
+
if parsed_args.login:
login = parsed_args.login
- else:
+ args.extend(['-l', login])
+ elif '-l' not in args:
login = self.app.client_manager.auth_ref.username
+ args.extend(['-l', login])
+
if parsed_args.verbose:
- cmd += " -v"
+ args.append('-v')
- cmd += " %s@%s"
- ip_address = _get_ip_address(server.addresses,
- parsed_args.address_type,
- ip_address_family)
- LOG.debug("ssh command: %s", (cmd % (login, ip_address)))
- os.system(cmd % (login, ip_address))
+ ip_address = _get_ip_address(
+ server.addresses,
+ parsed_args.address_type,
+ ip_address_family,
+ )
+
+ cmd = ' '.join(['ssh', ip_address] + args)
+ LOG.debug("ssh command: {cmd}".format(cmd=cmd))
+ os.system(cmd)
class StartServer(command.Command):
@@ -4649,13 +4725,13 @@ class SuspendServer(command.Command):
return parser
def take_action(self, parsed_args):
-
- compute_client = self.app.client_manager.compute
+ compute_client = self.app.client_manager.sdk_connection.compute
for server in parsed_args.server:
- utils.find_resource(
- compute_client.servers,
+ server_id = compute_client.find_server(
server,
- ).suspend()
+ ignore_missing=False,
+ ).id
+ compute_client.suspend_server(server_id)
class UnlockServer(command.Command):
@@ -4672,7 +4748,6 @@ class UnlockServer(command.Command):
return parser
def take_action(self, parsed_args):
-
compute_client = self.app.client_manager.compute
for server in parsed_args.server:
utils.find_resource(
@@ -4695,13 +4770,13 @@ class UnpauseServer(command.Command):
return parser
def take_action(self, parsed_args):
-
- compute_client = self.app.client_manager.compute
+ compute_client = self.app.client_manager.sdk_connection.compute
for server in parsed_args.server:
- utils.find_resource(
- compute_client.servers,
+ server_id = compute_client.find_server(
server,
- ).unpause()
+ ignore_missing=False,
+ ).id
+ compute_client.unpause_server(server_id)
class UnrescueServer(command.Command):
diff --git a/openstackclient/compute/v2/server_image.py b/openstackclient/compute/v2/server_image.py
index 6c0e3b2..2021fae 100644
--- a/openstackclient/compute/v2/server_image.py
+++ b/openstackclient/compute/v2/server_image.py
@@ -73,25 +73,23 @@ class CreateServerImage(command.ShowOne):
self.app.stdout.write('\rProgress: %s' % progress)
self.app.stdout.flush()
- compute_client = self.app.client_manager.compute
+ compute_client = self.app.client_manager.sdk_connection.compute
+ image_client = self.app.client_manager.image
- server = utils.find_resource(
- compute_client.servers,
- parsed_args.server,
+ server = compute_client.find_server(
+ parsed_args.server, ignore_missing=False,
)
+
if parsed_args.name:
image_name = parsed_args.name
else:
image_name = server.name
- image_id = compute_client.servers.create_image(
+ image_id = compute_client.create_server_image(
server.id,
image_name,
parsed_args.properties,
- )
-
- image_client = self.app.client_manager.image
- image = image_client.find_image(image_id)
+ ).id
if parsed_args.wait:
if utils.wait_for_status(
@@ -105,6 +103,8 @@ class CreateServerImage(command.ShowOne):
_('Error creating server image: %s'), parsed_args.server)
raise exceptions.CommandError
+ image = image_client.find_image(image_id, ignore_missing=False)
+
if self.app.client_manager._api_version['image'] == '1':
info = {}
info.update(image._info)
diff --git a/openstackclient/compute/v2/service.py b/openstackclient/compute/v2/service.py
index 6427e54..8605156 100644
--- a/openstackclient/compute/v2/service.py
+++ b/openstackclient/compute/v2/service.py
@@ -17,7 +17,7 @@
import logging
-from novaclient import api_versions
+from openstack import utils as sdk_utils
from osc_lib.command import command
from osc_lib import exceptions
from osc_lib import utils
@@ -40,16 +40,24 @@ class DeleteService(command.Command):
help=_("Compute service(s) to delete (ID only). If using "
"``--os-compute-api-version`` 2.53 or greater, the ID is "
"a UUID which can be retrieved by listing compute services "
- "using the same 2.53+ microversion.")
+ "using the same 2.53+ microversion. "
+ "If deleting a compute service, be sure to stop the actual "
+ "compute process on the physical host before deleting the "
+ "service with this command. Failing to do so can lead to "
+ "the running service re-creating orphaned compute_nodes "
+ "table records in the database.")
)
return parser
def take_action(self, parsed_args):
- compute_client = self.app.client_manager.compute
+ compute_client = self.app.client_manager.sdk_connection.compute
result = 0
for s in parsed_args.service:
try:
- compute_client.services.delete(s)
+ compute_client.delete_service(
+ s,
+ ignore_missing=False
+ )
except Exception as e:
result += 1
LOG.error(_("Failed to delete compute service with "
@@ -91,38 +99,40 @@ class ListService(command.Lister):
return parser
def take_action(self, parsed_args):
- compute_client = self.app.client_manager.compute
+ compute_client = self.app.client_manager.sdk_connection.compute
+ columns = (
+ "id",
+ "binary",
+ "host",
+ "availability_zone",
+ "status",
+ "state",
+ "updated_at",
+ )
+ column_headers = (
+ "ID",
+ "Binary",
+ "Host",
+ "Zone",
+ "Status",
+ "State",
+ "Updated At",
+ )
if parsed_args.long:
- columns = (
- "ID",
- "Binary",
- "Host",
- "Zone",
- "Status",
- "State",
- "Updated At",
- "Disabled Reason"
- )
- has_forced_down = (
- compute_client.api_version >= api_versions.APIVersion('2.11'))
- if has_forced_down:
- columns += ("Forced Down",)
- else:
- columns = (
- "ID",
- "Binary",
- "Host",
- "Zone",
- "Status",
- "State",
- "Updated At"
- )
- data = compute_client.services.list(parsed_args.host,
- parsed_args.service)
- return (columns,
- (utils.get_item_properties(
- s, columns,
- ) for s in data))
+ columns += ("disabled_reason",)
+ column_headers += ("Disabled Reason",)
+ if sdk_utils.supports_microversion(compute_client, '2.11'):
+ columns += ("is_forced_down",)
+ column_headers += ("Forced Down",)
+
+ data = compute_client.services(
+ host=parsed_args.host,
+ binary=parsed_args.service
+ )
+ return (
+ column_headers,
+ (utils.get_item_properties(s, columns) for s in data)
+ )
class SetService(command.Command):
@@ -175,7 +185,7 @@ class SetService(command.Command):
return parser
@staticmethod
- def _find_service_by_host_and_binary(cs, host, binary):
+ def _find_service_by_host_and_binary(compute_client, host, binary):
"""Utility method to find a compute service by host and binary
:param host: the name of the compute service host
@@ -183,7 +193,7 @@ class SetService(command.Command):
:returns: novaclient.v2.services.Service dict-like object
:raises: CommandError if no or multiple results were found
"""
- services = cs.list(host=host, binary=binary)
+ services = list(compute_client.services(host=host, binary=binary))
# Did we find anything?
if not len(services):
msg = _('Compute service for host "%(host)s" and binary '
@@ -202,8 +212,7 @@ class SetService(command.Command):
return services[0]
def take_action(self, parsed_args):
- compute_client = self.app.client_manager.compute
- cs = compute_client.services
+ compute_client = self.app.client_manager.sdk_connection.compute
if (parsed_args.enable or not parsed_args.disable) and \
parsed_args.disable_reason:
@@ -216,14 +225,17 @@ class SetService(command.Command):
# services. If 2.53+ is used we need to find the nova-compute
# service using the --host and --service (binary) values.
requires_service_id = (
- compute_client.api_version >= api_versions.APIVersion('2.53'))
+ sdk_utils.supports_microversion(compute_client, '2.53'))
service_id = None
if requires_service_id:
# TODO(mriedem): Add an --id option so users can pass the service
# id (as a uuid) directly rather than make us look it up using
# host/binary.
service_id = SetService._find_service_by_host_and_binary(
- cs, parsed_args.host, parsed_args.service).id
+ compute_client,
+ parsed_args.host,
+ parsed_args.service
+ ).id
result = 0
enabled = None
@@ -235,21 +247,18 @@ class SetService(command.Command):
if enabled is not None:
if enabled:
- args = (service_id,) if requires_service_id else (
- parsed_args.host, parsed_args.service)
- cs.enable(*args)
+ compute_client.enable_service(
+ service_id,
+ parsed_args.host,
+ parsed_args.service
+ )
else:
- if parsed_args.disable_reason:
- args = (service_id, parsed_args.disable_reason) if \
- requires_service_id else (
- parsed_args.host,
- parsed_args.service,
- parsed_args.disable_reason)
- cs.disable_log_reason(*args)
- else:
- args = (service_id,) if requires_service_id else (
- parsed_args.host, parsed_args.service)
- cs.disable(*args)
+ compute_client.disable_service(
+ service_id,
+ parsed_args.host,
+ parsed_args.service,
+ parsed_args.disable_reason
+ )
except Exception:
status = "enabled" if enabled else "disabled"
LOG.error("Failed to set service status to %s", status)
@@ -261,15 +270,17 @@ class SetService(command.Command):
if parsed_args.up:
force_down = False
if force_down is not None:
- if compute_client.api_version < api_versions.APIVersion(
- '2.11'):
+ if not sdk_utils.supports_microversion(compute_client, '2.11'):
msg = _('--os-compute-api-version 2.11 or later is '
'required')
raise exceptions.CommandError(msg)
try:
- args = (service_id, force_down) if requires_service_id else (
- parsed_args.host, parsed_args.service, force_down)
- cs.force_down(*args)
+ compute_client.update_service_forced_down(
+ service_id,
+ parsed_args.host,
+ parsed_args.service,
+ force_down
+ )
except Exception:
state = "down" if force_down else "up"
LOG.error("Failed to set service state to %s", state)
diff --git a/openstackclient/image/v2/image.py b/openstackclient/image/v2/image.py
index becb54f..407c129 100644
--- a/openstackclient/image/v2/image.py
+++ b/openstackclient/image/v2/image.py
@@ -1012,17 +1012,26 @@ class SetImage(command.Command):
membership_group = parser.add_mutually_exclusive_group()
membership_group.add_argument(
"--accept",
- action="store_true",
+ action="store_const",
+ const="accepted",
+ dest="membership",
+ default=None,
help=_("Accept the image membership"),
)
membership_group.add_argument(
"--reject",
- action="store_true",
+ action="store_const",
+ const="rejected",
+ dest="membership",
+ default=None,
help=_("Reject the image membership"),
)
membership_group.add_argument(
"--pending",
- action="store_true",
+ action="store_const",
+ const="pending",
+ dest="membership",
+ default=None,
help=_("Reset the image membership to 'pending'"),
)
@@ -1053,6 +1062,43 @@ class SetImage(command.Command):
_("ERROR: --%s was given, which is an Image v1 option"
" that is no longer supported in Image v2") % deadopt)
+ image = image_client.find_image(
+ parsed_args.image, ignore_missing=False,
+ )
+ project_id = None
+ if parsed_args.project:
+ project_id = common.find_project(
+ identity_client,
+ parsed_args.project,
+ parsed_args.project_domain,
+ ).id
+
+ # handle activation status changes
+
+ activation_status = None
+ if parsed_args.deactivate or parsed_args.activate:
+ if parsed_args.deactivate:
+ image_client.deactivate_image(image.id)
+ activation_status = "deactivated"
+ if parsed_args.activate:
+ image_client.reactivate_image(image.id)
+ activation_status = "activated"
+
+ # handle membership changes
+
+ if parsed_args.membership:
+ # If a specific project is not passed, assume we want to update
+ # our own membership
+ if not project_id:
+ project_id = self.app.client_manager.auth_ref.project_id
+ image_client.update_member(
+ image=image.id,
+ member=project_id,
+ status=parsed_args.membership,
+ )
+
+ # handle everything else
+
kwargs = {}
copy_attrs = ('architecture', 'container_format', 'disk_format',
'file', 'instance_id', 'kernel_id', 'locations',
@@ -1089,48 +1135,12 @@ class SetImage(command.Command):
kwargs['visibility'] = 'community'
if parsed_args.shared:
kwargs['visibility'] = 'shared'
- project_id = None
if parsed_args.project:
- project_id = common.find_project(
- identity_client,
- parsed_args.project,
- parsed_args.project_domain,
- ).id
+ # We already did the project lookup above
kwargs['owner_id'] = project_id
-
- image = image_client.find_image(parsed_args.image,
- ignore_missing=False)
-
- # image = utils.find_resource(
- # image_client.images, parsed_args.image)
-
- activation_status = None
- if parsed_args.deactivate:
- image_client.deactivate_image(image.id)
- activation_status = "deactivated"
- if parsed_args.activate:
- image_client.reactivate_image(image.id)
- activation_status = "activated"
-
- membership_group_args = ('accept', 'reject', 'pending')
- membership_status = [status for status in membership_group_args
- if getattr(parsed_args, status)]
- if membership_status:
- # If a specific project is not passed, assume we want to update
- # our own membership
- if not project_id:
- project_id = self.app.client_manager.auth_ref.project_id
- # The mutually exclusive group of the arg parser ensure we have at
- # most one item in the membership_status list.
- if membership_status[0] != 'pending':
- membership_status[0] += 'ed' # Glance expects the past form
- image_client.update_member(
- image=image.id, member=project_id, status=membership_status[0])
-
if parsed_args.tags:
# Tags should be extended, but duplicates removed
kwargs['tags'] = list(set(image.tags).union(set(parsed_args.tags)))
-
if parsed_args.hidden is not None:
kwargs['is_hidden'] = parsed_args.hidden
diff --git a/openstackclient/network/v2/address_group.py b/openstackclient/network/v2/address_group.py
index 9017047..b08fa87 100644
--- a/openstackclient/network/v2/address_group.py
+++ b/openstackclient/network/v2/address_group.py
@@ -28,10 +28,13 @@ LOG = logging.getLogger(__name__)
def _get_columns(item):
- column_map = {
- 'tenant_id': 'project_id',
- }
- return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ column_map = {}
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
def _format_addresses(addresses):
@@ -51,7 +54,7 @@ def _get_attrs(client_manager, parsed_args):
parsed_args.project,
parsed_args.project_domain,
).id
- attrs['tenant_id'] = project_id
+ attrs['project_id'] = project_id
return attrs
diff --git a/openstackclient/network/v2/address_scope.py b/openstackclient/network/v2/address_scope.py
index 5748793..488e160 100644
--- a/openstackclient/network/v2/address_scope.py
+++ b/openstackclient/network/v2/address_scope.py
@@ -29,9 +29,13 @@ LOG = logging.getLogger(__name__)
def _get_columns(item):
column_map = {
'is_shared': 'shared',
- 'tenant_id': 'project_id',
}
- return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
def _get_attrs(client_manager, parsed_args):
@@ -49,7 +53,7 @@ def _get_attrs(client_manager, parsed_args):
parsed_args.project,
parsed_args.project_domain,
).id
- attrs['tenant_id'] = project_id
+ attrs['project_id'] = project_id
return attrs
@@ -215,7 +219,6 @@ class ListAddressScope(command.Lister):
parsed_args.project,
parsed_args.project_domain,
).id
- attrs['tenant_id'] = project_id
attrs['project_id'] = project_id
data = client.address_scopes(**attrs)
diff --git a/openstackclient/network/v2/floating_ip.py b/openstackclient/network/v2/floating_ip.py
index 0951565..4c03074 100644
--- a/openstackclient/network/v2/floating_ip.py
+++ b/openstackclient/network/v2/floating_ip.py
@@ -27,17 +27,17 @@ _formatters = {
def _get_network_columns(item):
- column_map = {
- 'tenant_id': 'project_id',
- }
- return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ column_map = {}
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
def _get_columns(item):
columns = list(item.keys())
- if 'tenant_id' in columns:
- columns.remove('tenant_id')
- columns.append('project_id')
return tuple(sorted(columns))
@@ -81,7 +81,7 @@ def _get_attrs(client_manager, parsed_args):
parsed_args.project,
parsed_args.project_domain,
).id
- attrs['tenant_id'] = project_id
+ attrs['project_id'] = project_id
if parsed_args.dns_domain:
attrs['dns_domain'] = parsed_args.dns_domain
@@ -349,7 +349,6 @@ class ListFloatingIP(common.NetworkAndComputeLister):
parsed_args.project,
parsed_args.project_domain,
)
- query['tenant_id'] = project.id
query['project_id'] = project.id
if parsed_args.router is not None:
router = network_client.find_router(parsed_args.router,
diff --git a/openstackclient/network/v2/floating_ip_port_forwarding.py b/openstackclient/network/v2/floating_ip_port_forwarding.py
index f137174..b33633d 100644
--- a/openstackclient/network/v2/floating_ip_port_forwarding.py
+++ b/openstackclient/network/v2/floating_ip_port_forwarding.py
@@ -26,10 +26,13 @@ LOG = logging.getLogger(__name__)
def _get_columns(item):
- column_map = {
- 'tenant_id': 'project_id',
- }
- return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ column_map = {}
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
class CreateFloatingIPPortForwarding(command.ShowOne,
diff --git a/openstackclient/network/v2/ip_availability.py b/openstackclient/network/v2/ip_availability.py
index 6a3c67e..9e56c5b 100644
--- a/openstackclient/network/v2/ip_availability.py
+++ b/openstackclient/network/v2/ip_availability.py
@@ -26,10 +26,13 @@ _formatters = {
def _get_columns(item):
- column_map = {
- 'tenant_id': 'project_id',
- }
- return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ column_map = {}
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
# TODO(ankur-gupta-f): Use the SDK resource mapped attribute names once
@@ -84,7 +87,6 @@ class ListIPAvailability(command.Lister):
parsed_args.project,
parsed_args.project_domain,
).id
- filters['tenant_id'] = project_id
filters['project_id'] = project_id
data = client.network_ip_availabilities(**filters)
return (column_headers,
diff --git a/openstackclient/network/v2/l3_conntrack_helper.py b/openstackclient/network/v2/l3_conntrack_helper.py
index 9fc33d8..1de5b78 100644
--- a/openstackclient/network/v2/l3_conntrack_helper.py
+++ b/openstackclient/network/v2/l3_conntrack_helper.py
@@ -26,7 +26,12 @@ LOG = logging.getLogger(__name__)
def _get_columns(item):
column_map = {}
- return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
def _get_attrs(client, parsed_args):
diff --git a/openstackclient/network/v2/local_ip.py b/openstackclient/network/v2/local_ip.py
new file mode 100644
index 0000000..109f64c
--- /dev/null
+++ b/openstackclient/network/v2/local_ip.py
@@ -0,0 +1,310 @@
+# Copyright 2021 Huawei, Inc. 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.
+#
+
+"""Node Local IP action implementations"""
+
+import logging
+
+from osc_lib.command import command
+from osc_lib import exceptions
+from osc_lib import utils
+
+from openstackclient.i18n import _
+from openstackclient.identity import common as identity_common
+
+LOG = logging.getLogger(__name__)
+
+
+def _get_columns(item):
+ column_map = {}
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item, column_map, hidden_columns)
+
+
+def _get_attrs(client_manager, parsed_args):
+ attrs = {}
+ network_client = client_manager.network
+
+ if parsed_args.name:
+ attrs['name'] = parsed_args.name
+ if parsed_args.description:
+ attrs['description'] = parsed_args.description
+ if 'project' in parsed_args and parsed_args.project is not None:
+ identity_client = client_manager.identity
+ project_id = identity_common.find_project(
+ identity_client,
+ parsed_args.project,
+ parsed_args.project_domain,
+ ).id
+ attrs['project_id'] = project_id
+ if parsed_args.network:
+ network = network_client.find_network(parsed_args.network,
+ ignore_missing=False)
+ attrs['network_id'] = network.id
+ if parsed_args.local_ip_address:
+ attrs['local_ip_address'] = parsed_args.local_ip_address
+ if parsed_args.local_port:
+ port = network_client.find_port(parsed_args.local_port,
+ ignore_missing=False)
+ attrs['local_port_id'] = port.id
+ if parsed_args.ip_mode:
+ attrs['ip_mode'] = parsed_args.ip_mode
+ return attrs
+
+
+class CreateLocalIP(command.ShowOne):
+ _description = _("Create Local IP")
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ parser.add_argument(
+ '--name',
+ metavar="<name>",
+ help=_("New local IP name")
+ )
+ parser.add_argument(
+ '--description',
+ metavar="<description>",
+ help=_("New local IP description")
+ )
+ parser.add_argument(
+ '--network',
+ metavar='<network>',
+ help=_("Network to allocate Local IP (name or ID)")
+ )
+ parser.add_argument(
+ '--local-port',
+ metavar='<local_port>',
+ help=_("Port to allocate Local IP (name or ID)")
+ )
+ parser.add_argument(
+ "--local-ip-address",
+ metavar="<local_ip_address>",
+ help=_("IP address or CIDR "),
+ )
+ parser.add_argument(
+ '--ip-mode',
+ metavar='<ip_mode>',
+ help=_("local IP ip mode")
+ )
+
+ identity_common.add_project_domain_option_to_parser(parser)
+
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+ attrs = _get_attrs(self.app.client_manager, parsed_args)
+
+ obj = client.create_local_ip(**attrs)
+ display_columns, columns = _get_columns(obj)
+ data = utils.get_item_properties(obj, columns, formatters={})
+
+ return (display_columns, data)
+
+
+class DeleteLocalIP(command.Command):
+ _description = _("Delete local IP(s)")
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ parser.add_argument(
+ 'local_ip',
+ metavar="<local-ip>",
+ nargs='+',
+ help=_("Local IP(s) to delete (name or ID)")
+ )
+
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+ result = 0
+
+ for lip in parsed_args.local_ip:
+ try:
+ obj = client.find_local_ip(lip, ignore_missing=False)
+ client.delete_local_ip(obj)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete Local IP with "
+ "name or ID '%(lip)s': %(e)s"),
+ {'lip': lip, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.local_ip)
+ msg = (_("%(result)s of %(total)s local IPs failed "
+ "to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
+
+
+class SetLocalIP(command.Command):
+ _description = _("Set local ip properties")
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ parser.add_argument(
+ 'local_ip',
+ metavar="<local-ip>",
+ help=_("Local IP to modify (name or ID)")
+ )
+ parser.add_argument(
+ '--name',
+ metavar="<name>",
+ help=_('Set local IP name')
+ )
+ parser.add_argument(
+ '--description',
+ metavar="<description>",
+ help=_('Set local IP description')
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+ obj = client.find_local_ip(
+ parsed_args.local_ip,
+ ignore_missing=False)
+ attrs = {}
+ if parsed_args.name is not None:
+ attrs['name'] = parsed_args.name
+ if parsed_args.description is not None:
+ attrs['description'] = parsed_args.description
+ if attrs:
+ client.update_local_ip(obj, **attrs)
+
+
+class ListLocalIP(command.Lister):
+ _description = _("List local IPs")
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+
+ parser.add_argument(
+ '--name',
+ metavar='<name>',
+ help=_("List only local IPs of given name in output")
+ )
+ parser.add_argument(
+ '--project',
+ metavar="<project>",
+ help=_("List Local IPs according to their project "
+ "(name or ID)")
+ )
+ parser.add_argument(
+ '--network',
+ metavar='<network>',
+ help=_("List Local IP(s) according to "
+ "given network (name or ID)")
+ )
+ parser.add_argument(
+ '--local-port',
+ metavar='<local_port>',
+ help=_("List Local IP(s) according to "
+ "given port (name or ID)")
+ )
+ parser.add_argument(
+ '--local-ip-address',
+ metavar='<local_ip_address>',
+ help=_("List Local IP(s) according to "
+ "given Local IP Address")
+ )
+ parser.add_argument(
+ '--ip-mode',
+ metavar='<ip_mode>',
+ help=_("List Local IP(s) according to "
+ "given IP mode")
+ )
+
+ identity_common.add_project_domain_option_to_parser(parser)
+
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+ columns = (
+ 'id',
+ 'name',
+ 'description',
+ 'project_id',
+ 'local_port_id',
+ 'network_id',
+ 'local_ip_address',
+ 'ip_mode',
+ )
+ column_headers = (
+ 'ID',
+ 'Name',
+ 'Description',
+ 'Project',
+ 'Local Port ID',
+ 'Network',
+ 'Local IP address',
+ 'IP mode',
+ )
+ attrs = {}
+ if parsed_args.name:
+ attrs['name'] = parsed_args.name
+ if 'project' in parsed_args and parsed_args.project is not None:
+ identity_client = self.app.client_manager.identity
+ project_id = identity_common.find_project(
+ identity_client,
+ parsed_args.project,
+ parsed_args.project_domain,
+ ).id
+ attrs['project_id'] = project_id
+ if parsed_args.network is not None:
+ network = client.find_network(parsed_args.network,
+ ignore_missing=False)
+ attrs['network_id'] = network.id
+ if parsed_args.local_port:
+ port = client.find_port(parsed_args.local_port,
+ ignore_missing=False)
+ attrs['local_port_id'] = port.id
+ if parsed_args.local_ip_address:
+ attrs['local_ip_address'] = parsed_args.local_ip_address
+ if parsed_args.ip_mode:
+ attrs['ip_mode'] = parsed_args.ip_mode
+ data = client.local_ips(**attrs)
+
+ return (column_headers,
+ (utils.get_item_properties(s,
+ columns,
+ formatters={},) for s in data))
+
+
+class ShowLocalIP(command.ShowOne):
+ _description = _("Display local IP details")
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ parser.add_argument(
+ 'local_ip',
+ metavar="<local-ip>",
+ help=_("Local IP to display (name or ID)")
+ )
+
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+ obj = client.find_local_ip(
+ parsed_args.local_ip,
+ ignore_missing=False)
+ display_columns, columns = _get_columns(obj)
+ data = utils.get_item_properties(obj, columns, formatters={})
+
+ return (display_columns, data)
diff --git a/openstackclient/network/v2/local_ip_association.py b/openstackclient/network/v2/local_ip_association.py
new file mode 100644
index 0000000..aa0747c
--- /dev/null
+++ b/openstackclient/network/v2/local_ip_association.py
@@ -0,0 +1,197 @@
+# Copyright 2021 Huawei, Inc. 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.
+#
+
+"""Node Local IP action implementations"""
+
+import logging
+
+from osc_lib.command import command
+from osc_lib import exceptions
+from osc_lib import utils
+
+from openstackclient.i18n import _
+from openstackclient.identity import common as identity_common
+
+LOG = logging.getLogger(__name__)
+
+
+def _get_columns(item):
+ column_map = {}
+ hidden_columns = ['location', 'name', 'id']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item, column_map, hidden_columns)
+
+
+class CreateLocalIPAssociation(command.ShowOne):
+ _description = _("Create Local IP Association")
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ parser.add_argument(
+ 'local_ip',
+ metavar='<local-ip>',
+ help=_("Local IP that the port association belongs to "
+ "(IP address or ID)")
+ )
+ parser.add_argument(
+ 'fixed_port',
+ metavar='<fixed_port>',
+ help=_("The ID or Name of Port to allocate Local IP Association")
+ )
+ parser.add_argument(
+ '--fixed-ip',
+ metavar='<fixed_ip>',
+ help=_("Fixed IP for Local IP Association")
+ )
+
+ identity_common.add_project_domain_option_to_parser(parser)
+
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+
+ attrs = {}
+ port = client.find_port(parsed_args.fixed_port,
+ ignore_missing=False)
+ attrs['fixed_port_id'] = port.id
+ if parsed_args.fixed_ip:
+ attrs['fixed_ip'] = parsed_args.fixed_ip
+ local_ip = client.find_local_ip(
+ parsed_args.local_ip,
+ ignore_missing=False,
+ )
+ obj = client.create_local_ip_association(local_ip.id, **attrs)
+ display_columns, columns = _get_columns(obj)
+ data = utils.get_item_properties(obj, columns, formatters={})
+
+ return (display_columns, data)
+
+
+class DeleteLocalIPAssociation(command.Command):
+ _description = _("Delete Local IP association(s)")
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ parser.add_argument(
+ 'local_ip',
+ metavar="<local_ip>",
+ help=_("Local IP that the port association belongs to "
+ "(IP address or ID)")
+ )
+ parser.add_argument(
+ 'fixed_port_id',
+ nargs="+",
+ metavar="<fixed_port_id>",
+ help=_("The fixed port ID of Local IP Association")
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+ local_ip = client.find_local_ip(
+ parsed_args.local_ip,
+ ignore_missing=False,
+ )
+ result = 0
+
+ for fixed_port_id in parsed_args.fixed_port_id:
+ try:
+ client.delete_local_ip_association(
+ local_ip.id,
+ fixed_port_id,
+ ignore_missing=False,
+ )
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete Local IP Association with "
+ "fixed port "
+ "name or ID '%(fixed_port_id)s': %(e)s"),
+ {'fixed port ID': fixed_port_id, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.fixed_port_id)
+ msg = (_("%(result)s of %(total)s Local IP Associations failed "
+ "to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
+
+
+class ListLocalIPAssociation(command.Lister):
+ _description = _("List Local IP Associations")
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+
+ parser.add_argument(
+ 'local_ip',
+ metavar='<local_ip>',
+ help=_("Local IP that port associations belongs to")
+ )
+ parser.add_argument(
+ '--fixed-port',
+ metavar='<fixed_port>',
+ help=_("Filter the list result by the ID or name of "
+ "the fixed port")
+ )
+ parser.add_argument(
+ '--fixed-ip',
+ metavar='<fixed_ip>',
+ help=_("Filter the list result by fixed ip")
+ )
+ parser.add_argument(
+ '--host',
+ metavar='<host>',
+ help=_("Filter the list result by given host")
+ )
+ identity_common.add_project_domain_option_to_parser(parser)
+
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+ columns = (
+ 'local_ip_id',
+ 'local_ip_address',
+ 'fixed_port_id',
+ 'fixed_ip',
+ 'host',
+ )
+ column_headers = (
+ 'Local IP ID',
+ 'Local IP Address',
+ 'Fixed port ID',
+ 'Fixed IP',
+ 'Host'
+ )
+ attrs = {}
+ obj = client.find_local_ip(
+ parsed_args.local_ip,
+ ignore_missing=False,
+ )
+ if parsed_args.fixed_port:
+ port = client.find_port(parsed_args.fixed_port,
+ ignore_missing=False)
+ attrs['fixed_port_id'] = port.id
+ if parsed_args.fixed_ip:
+ attrs['fixed_ip'] = parsed_args.fixed_ip
+ if parsed_args.host:
+ attrs['host'] = parsed_args.host
+
+ data = client.local_ip_associations(obj, **attrs)
+
+ return (column_headers,
+ (utils.get_item_properties(s,
+ columns,
+ formatters={}) for s in data))
diff --git a/openstackclient/network/v2/network.py b/openstackclient/network/v2/network.py
index 191e4aa..a239e0f 100644
--- a/openstackclient/network/v2/network.py
+++ b/openstackclient/network/v2/network.py
@@ -58,16 +58,18 @@ def _get_columns_network(item):
'is_shared': 'shared',
'ipv4_address_scope_id': 'ipv4_address_scope',
'ipv6_address_scope_id': 'ipv6_address_scope',
- 'tenant_id': 'project_id',
'tags': 'tags',
}
- return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
def _get_columns_compute(item):
- column_map = {
- 'tenant_id': 'project_id',
- }
+ column_map = {}
return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
@@ -96,8 +98,6 @@ def _get_attrs_network(client_manager, parsed_args):
parsed_args.project,
parsed_args.project_domain,
).id
- # TODO(dtroyer): Remove tenant_id when we clean up the SDK refactor
- attrs['tenant_id'] = project_id
attrs['project_id'] = project_id
# "network set" command doesn't support setting availability zone hints.
@@ -568,7 +568,6 @@ class ListNetwork(common.NetworkAndComputeLister):
parsed_args.project,
parsed_args.project_domain,
)
- args['tenant_id'] = project.id
args['project_id'] = project.id
if parsed_args.share:
diff --git a/openstackclient/network/v2/network_agent.py b/openstackclient/network/v2/network_agent.py
index c995e36..3024d02 100644
--- a/openstackclient/network/v2/network_agent.py
+++ b/openstackclient/network/v2/network_agent.py
@@ -50,7 +50,12 @@ def _get_network_columns(item):
'is_admin_state_up': 'admin_state_up',
'is_alive': 'alive',
}
- return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
class AddNetworkToAgent(command.Command):
diff --git a/openstackclient/network/v2/network_auto_allocated_topology.py b/openstackclient/network/v2/network_auto_allocated_topology.py
index 7b7df4d..496606b 100644
--- a/openstackclient/network/v2/network_auto_allocated_topology.py
+++ b/openstackclient/network/v2/network_auto_allocated_topology.py
@@ -25,10 +25,13 @@ LOG = logging.getLogger(__name__)
def _get_columns(item):
- column_map = {
- 'tenant_id': 'project_id',
- }
- return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ column_map = {}
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
def _format_check_resource_columns():
@@ -51,7 +54,7 @@ def _get_attrs(client_manager, parsed_args):
parsed_args.project,
parsed_args.project_domain,
).id
- attrs['tenant_id'] = project_id
+ attrs['project_id'] = project_id
if parsed_args.check_resources:
attrs['check_resources'] = True
diff --git a/openstackclient/network/v2/network_flavor.py b/openstackclient/network/v2/network_flavor.py
index 6e3a5a0..862155c 100644
--- a/openstackclient/network/v2/network_flavor.py
+++ b/openstackclient/network/v2/network_flavor.py
@@ -29,10 +29,14 @@ LOG = logging.getLogger(__name__)
def _get_columns(item):
column_map = {
'is_enabled': 'enabled',
- 'tenant_id': 'project_id',
}
- return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
def _get_attrs(client_manager, parsed_args):
@@ -52,7 +56,7 @@ def _get_attrs(client_manager, parsed_args):
parsed_args.project,
parsed_args.project_domain,
).id
- attrs['tenant_id'] = project_id
+ attrs['project_id'] = project_id
return attrs
diff --git a/openstackclient/network/v2/network_flavor_profile.py b/openstackclient/network/v2/network_flavor_profile.py
index df7cfb7..719f955 100644
--- a/openstackclient/network/v2/network_flavor_profile.py
+++ b/openstackclient/network/v2/network_flavor_profile.py
@@ -27,10 +27,14 @@ LOG = logging.getLogger(__name__)
def _get_columns(item):
column_map = {
'is_enabled': 'enabled',
- 'tenant_id': 'project_id',
}
- return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
def _get_attrs(client_manager, parsed_args):
@@ -52,7 +56,7 @@ def _get_attrs(client_manager, parsed_args):
parsed_args.project,
parsed_args.project_domain,
).id
- attrs['tenant_id'] = project_id
+ attrs['project_id'] = project_id
return attrs
diff --git a/openstackclient/network/v2/network_meter.py b/openstackclient/network/v2/network_meter.py
index 8b63de2..b7b77fb 100644
--- a/openstackclient/network/v2/network_meter.py
+++ b/openstackclient/network/v2/network_meter.py
@@ -29,9 +29,13 @@ LOG = logging.getLogger(__name__)
def _get_columns(item):
column_map = {
'is_shared': 'shared',
- 'tenant_id': 'project_id',
}
- return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
def _get_attrs(client_manager, parsed_args):
@@ -46,7 +50,7 @@ def _get_attrs(client_manager, parsed_args):
parsed_args.project,
parsed_args.project_domain,
).id
- attrs['tenant_id'] = project_id
+ attrs['project_id'] = project_id
if parsed_args.share:
attrs['shared'] = True
if parsed_args.no_share:
diff --git a/openstackclient/network/v2/network_meter_rule.py b/openstackclient/network/v2/network_meter_rule.py
index 4117d04..0f42727 100644
--- a/openstackclient/network/v2/network_meter_rule.py
+++ b/openstackclient/network/v2/network_meter_rule.py
@@ -27,10 +27,13 @@ LOG = logging.getLogger(__name__)
def _get_columns(item):
- column_map = {
- 'tenant_id': 'project_id',
- }
- return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ column_map = {}
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
def _get_attrs(client_manager, parsed_args):
@@ -59,7 +62,7 @@ def _get_attrs(client_manager, parsed_args):
parsed_args.project,
parsed_args.project_domain,
).id
- attrs['tenant_id'] = project_id
+ attrs['project_id'] = project_id
return attrs
diff --git a/openstackclient/network/v2/network_qos_policy.py b/openstackclient/network/v2/network_qos_policy.py
index 8d43124..bc25790 100644
--- a/openstackclient/network/v2/network_qos_policy.py
+++ b/openstackclient/network/v2/network_qos_policy.py
@@ -29,9 +29,13 @@ LOG = logging.getLogger(__name__)
def _get_columns(item):
column_map = {
'is_shared': 'shared',
- 'tenant_id': 'project_id',
}
- return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
def _get_attrs(client_manager, parsed_args):
@@ -59,7 +63,7 @@ def _get_attrs(client_manager, parsed_args):
parsed_args.project,
parsed_args.project_domain,
).id
- attrs['tenant_id'] = project_id
+ attrs['project_id'] = project_id
return attrs
diff --git a/openstackclient/network/v2/network_qos_rule.py b/openstackclient/network/v2/network_qos_rule.py
index 4bf72d2..a4129b8 100644
--- a/openstackclient/network/v2/network_qos_rule.py
+++ b/openstackclient/network/v2/network_qos_rule.py
@@ -46,10 +46,13 @@ ACTION_SHOW = 'get'
def _get_columns(item):
- column_map = {
- 'tenant_id': 'project_id',
- }
- return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ column_map = {}
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
def _check_type_parameters(attrs, type, is_create):
diff --git a/openstackclient/network/v2/network_qos_rule_type.py b/openstackclient/network/v2/network_qos_rule_type.py
index 036b682..1bcfda8 100644
--- a/openstackclient/network/v2/network_qos_rule_type.py
+++ b/openstackclient/network/v2/network_qos_rule_type.py
@@ -24,7 +24,7 @@ def _get_columns(item):
"type": "rule_type_name",
"drivers": "drivers",
}
- invisible_columns = ["id", "name"]
+ invisible_columns = ["id", "location", "name"]
return utils.get_osc_show_columns_for_sdk_resource(
item, column_map, invisible_columns)
diff --git a/openstackclient/network/v2/network_rbac.py b/openstackclient/network/v2/network_rbac.py
index edca872..0066739 100644
--- a/openstackclient/network/v2/network_rbac.py
+++ b/openstackclient/network/v2/network_rbac.py
@@ -29,9 +29,13 @@ LOG = logging.getLogger(__name__)
def _get_columns(item):
column_map = {
'target_tenant': 'target_project_id',
- 'tenant_id': 'project_id',
}
- return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
def _get_attrs(client_manager, parsed_args):
@@ -82,7 +86,7 @@ def _get_attrs(client_manager, parsed_args):
parsed_args.project,
parsed_args.project_domain,
).id
- attrs['tenant_id'] = project_id
+ attrs['project_id'] = project_id
return attrs
diff --git a/openstackclient/network/v2/network_segment.py b/openstackclient/network/v2/network_segment.py
index e18ac47..0f64bd8 100644
--- a/openstackclient/network/v2/network_segment.py
+++ b/openstackclient/network/v2/network_segment.py
@@ -26,7 +26,13 @@ LOG = logging.getLogger(__name__)
def _get_columns(item):
- return utils.get_osc_show_columns_for_sdk_resource(item, {})
+ column_map = {}
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
class CreateNetworkSegment(command.ShowOne,
diff --git a/openstackclient/network/v2/network_segment_range.py b/openstackclient/network/v2/network_segment_range.py
index e105111..a95adb0 100644
--- a/openstackclient/network/v2/network_segment_range.py
+++ b/openstackclient/network/v2/network_segment_range.py
@@ -32,7 +32,13 @@ LOG = logging.getLogger(__name__)
def _get_columns(item):
- return utils.get_osc_show_columns_for_sdk_resource(item, {})
+ column_map = {}
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
def _get_ranges(item):
diff --git a/openstackclient/network/v2/port.py b/openstackclient/network/v2/port.py
index 132c384..16072bc 100644
--- a/openstackclient/network/v2/port.py
+++ b/openstackclient/network/v2/port.py
@@ -63,9 +63,13 @@ def _get_columns(item):
'binding:vnic_type': 'binding_vnic_type',
'is_admin_state_up': 'admin_state_up',
'is_port_security_enabled': 'port_security_enabled',
- 'tenant_id': 'project_id',
}
- return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
class JSONKeyValueAction(argparse.Action):
@@ -134,7 +138,7 @@ def _get_attrs(client_manager, parsed_args):
parsed_args.project,
parsed_args.project_domain,
).id
- attrs['tenant_id'] = project_id
+ attrs['project_id'] = project_id
if parsed_args.disable_port_security:
attrs['port_security_enabled'] = False
@@ -255,11 +259,12 @@ def _add_updatable_args(parser):
metavar='<vnic-type>',
choices=(
'direct', 'direct-physical', 'macvtap',
- 'normal', 'baremetal', 'virtio-forwarder', 'vdpa'
+ 'normal', 'baremetal', 'virtio-forwarder', 'vdpa', 'remote-managed'
),
help=_(
"VNIC type for this port (direct | direct-physical | "
- "macvtap | normal | baremetal | virtio-forwarder | vdpa, "
+ "macvtap | normal | baremetal | virtio-forwarder | vdpa | "
+ "remote-managed, "
"default: normal)"
),
)
@@ -610,6 +615,13 @@ class ListPort(command.Lister):
metavar='<name>',
help=_("List ports according to their name")
)
+ parser.add_argument(
+ '--security-group',
+ action='append',
+ dest='security_groups',
+ metavar='<security-group>',
+ help=_("List only ports associated with this security group")
+ )
identity_common.add_project_domain_option_to_parser(parser)
parser.add_argument(
'--fixed-ip',
@@ -675,13 +687,14 @@ class ListPort(command.Lister):
parsed_args.project,
parsed_args.project_domain,
).id
- filters['tenant_id'] = project_id
filters['project_id'] = project_id
if parsed_args.name:
filters['name'] = parsed_args.name
if parsed_args.fixed_ip:
filters['fixed_ips'] = _prepare_filter_fixed_ips(
self.app.client_manager, parsed_args)
+ if parsed_args.security_groups:
+ filters['security_groups'] = parsed_args.security_groups
_tag.get_tag_filtering_args(parsed_args, filters)
@@ -808,6 +821,17 @@ class SetPort(common.NeutronCommandWithExtraArgs):
"to overwrite the current allowed-address pairs)")
)
parser.add_argument(
+ '--extra-dhcp-option',
+ metavar='name=<name>[,value=<value>,ip-version={4,6}]',
+ default=[],
+ action=parseractions.MultiKeyValueCommaAction,
+ dest='extra_dhcp_options',
+ required_keys=['name'],
+ optional_keys=['value', "ip-version"],
+ help=_('Extra DHCP options to be assigned to this port: '
+ 'name=<name>[,value=<value>,ip-version={4,6}] '
+ '(repeat option to set multiple extra DHCP options)'))
+ parser.add_argument(
'--data-plane-status',
metavar='<status>',
choices=['ACTIVE', 'DOWN'],
@@ -869,6 +893,10 @@ class SetPort(common.NeutronCommandWithExtraArgs):
attrs['allowed_address_pairs'].extend(
_convert_address_pairs(parsed_args)
)
+
+ if parsed_args.extra_dhcp_options:
+ attrs["extra_dhcp_opts"] = _convert_extra_dhcp_options(parsed_args)
+
if parsed_args.data_plane_status:
attrs['data_plane_status'] = parsed_args.data_plane_status
@@ -969,6 +997,12 @@ class UnsetPort(common.NeutronUnsetCommandWithExtraArgs):
action='store_true',
help=_("Clear existing NUMA affinity policy")
)
+ parser.add_argument(
+ '--host',
+ action='store_true',
+ default=False,
+ help=_("Clear host binding for the port.")
+ )
_tag.add_tag_option_to_parser_for_unset(parser, _('port'))
@@ -1026,6 +1060,8 @@ class UnsetPort(common.NeutronUnsetCommandWithExtraArgs):
attrs['data_plane_status'] = None
if parsed_args.numa_policy:
attrs['numa_affinity_policy'] = None
+ if parsed_args.host:
+ attrs['binding:host_id'] = None
attrs.update(
self._parse_extra_properties(parsed_args.extra_properties))
diff --git a/openstackclient/network/v2/router.py b/openstackclient/network/v2/router.py
index dde4eda..f1fce29 100644
--- a/openstackclient/network/v2/router.py
+++ b/openstackclient/network/v2/router.py
@@ -67,14 +67,13 @@ _formatters = {
def _get_columns(item):
column_map = {
- 'tenant_id': 'project_id',
'is_ha': 'ha',
'is_distributed': 'distributed',
'is_admin_state_up': 'admin_state_up',
}
if hasattr(item, 'interfaces_info'):
column_map['interfaces_info'] = 'interfaces_info'
- invisible_columns = []
+ invisible_columns = ['location']
if item.is_ha is None:
invisible_columns.append('is_ha')
column_map.pop('is_ha')
@@ -110,7 +109,31 @@ def _get_attrs(client_manager, parsed_args):
parsed_args.project,
parsed_args.project_domain,
).id
- attrs['tenant_id'] = project_id
+ attrs['project_id'] = project_id
+ if parsed_args.external_gateway:
+ gateway_info = {}
+ n_client = client_manager.network
+ network = n_client.find_network(
+ parsed_args.external_gateway, ignore_missing=False)
+ gateway_info['network_id'] = network.id
+ if parsed_args.disable_snat:
+ gateway_info['enable_snat'] = False
+ if parsed_args.enable_snat:
+ gateway_info['enable_snat'] = True
+ if parsed_args.fixed_ip:
+ ips = []
+ for ip_spec in parsed_args.fixed_ip:
+ if ip_spec.get('subnet', False):
+ subnet_name_id = ip_spec.pop('subnet')
+ if subnet_name_id:
+ subnet = n_client.find_subnet(subnet_name_id,
+ ignore_missing=False)
+ ip_spec['subnet_id'] = subnet.id
+ if ip_spec.get('ip-address', False):
+ ip_spec['ip_address'] = ip_spec.pop('ip-address')
+ ips.append(ip_spec)
+ gateway_info['external_fixed_ips'] = ips
+ attrs['external_gateway_info'] = gateway_info
return attrs
@@ -320,6 +343,32 @@ class CreateRouter(command.ShowOne, common.NeutronCommandWithExtraArgs):
"repeat option to set multiple availability zones)")
)
_tag.add_tag_option_to_parser_for_create(parser, _('router'))
+ parser.add_argument(
+ '--external-gateway',
+ metavar="<network>",
+ help=_("External Network used as router's gateway (name or ID)")
+ )
+ parser.add_argument(
+ '--fixed-ip',
+ metavar='subnet=<subnet>,ip-address=<ip-address>',
+ action=parseractions.MultiKeyValueAction,
+ optional_keys=['subnet', 'ip-address'],
+ help=_("Desired IP and/or subnet (name or ID) "
+ "on external gateway: "
+ "subnet=<subnet>,ip-address=<ip-address> "
+ "(repeat option to set multiple fixed IP addresses)")
+ )
+ snat_group = parser.add_mutually_exclusive_group()
+ snat_group.add_argument(
+ '--enable-snat',
+ action='store_true',
+ help=_("Enable Source NAT on external gateway")
+ )
+ snat_group.add_argument(
+ '--disable-snat',
+ action='store_true',
+ help=_("Disable Source NAT on external gateway")
+ )
return parser
@@ -338,6 +387,12 @@ class CreateRouter(command.ShowOne, common.NeutronCommandWithExtraArgs):
# tags cannot be set when created, so tags need to be set later.
_tag.update_tags_for_set(client, obj, parsed_args)
+ if (parsed_args.disable_snat or parsed_args.enable_snat or
+ parsed_args.fixed_ip) and not parsed_args.external_gateway:
+ msg = (_("You must specify '--external-gateway' in order "
+ "to specify SNAT or fixed-ip values"))
+ raise exceptions.CommandError(msg)
+
display_columns, columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns, formatters=_formatters)
@@ -459,7 +514,6 @@ class ListRouter(command.Lister):
parsed_args.project,
parsed_args.project_domain,
).id
- args['tenant_id'] = project_id
args['project_id'] = project_id
_tag.get_tag_filtering_args(parsed_args, args)
@@ -725,29 +779,6 @@ class SetRouter(common.NeutronCommandWithExtraArgs):
msg = (_("You must specify '--external-gateway' in order "
"to update the SNAT or fixed-ip values"))
raise exceptions.CommandError(msg)
- if parsed_args.external_gateway:
- gateway_info = {}
- network = client.find_network(
- parsed_args.external_gateway, ignore_missing=False)
- gateway_info['network_id'] = network.id
- if parsed_args.disable_snat:
- gateway_info['enable_snat'] = False
- if parsed_args.enable_snat:
- gateway_info['enable_snat'] = True
- if parsed_args.fixed_ip:
- ips = []
- for ip_spec in parsed_args.fixed_ip:
- if ip_spec.get('subnet', False):
- subnet_name_id = ip_spec.pop('subnet')
- if subnet_name_id:
- subnet = client.find_subnet(subnet_name_id,
- ignore_missing=False)
- ip_spec['subnet_id'] = subnet.id
- if ip_spec.get('ip-address', False):
- ip_spec['ip_address'] = ip_spec.pop('ip-address')
- ips.append(ip_spec)
- gateway_info['external_fixed_ips'] = ips
- attrs['external_gateway_info'] = gateway_info
if ((parsed_args.qos_policy or parsed_args.no_qos_policy) and
not parsed_args.external_gateway):
diff --git a/openstackclient/network/v2/security_group.py b/openstackclient/network/v2/security_group.py
index 37d2dc5..d8c38f4 100644
--- a/openstackclient/network/v2/security_group.py
+++ b/openstackclient/network/v2/security_group.py
@@ -35,7 +35,6 @@ def _format_network_security_group_rules(sg_rules):
for key in empty_keys:
sg_rule.pop(key)
sg_rule.pop('security_group_id', None)
- sg_rule.pop('tenant_id', None)
sg_rule.pop('project_id', None)
return utils.format_list_of_dicts(sg_rules)
@@ -85,11 +84,17 @@ _formatters_compute = {
def _get_columns(item):
+ # We still support Nova managed security groups, where we have tenant_id.
column_map = {
'security_group_rules': 'rules',
'tenant_id': 'project_id',
}
- return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
# TODO(abhiraut): Use the SDK resource mapped attribute names once the
@@ -159,7 +164,7 @@ class CreateSecurityGroup(common.NetworkAndComputeShowOne,
parsed_args.project,
parsed_args.project_domain,
).id
- attrs['tenant_id'] = project_id
+ attrs['project_id'] = project_id
attrs.update(
self._parse_extra_properties(parsed_args.extra_properties))
@@ -264,7 +269,6 @@ class ListSecurityGroup(common.NetworkAndComputeLister):
parsed_args.project,
parsed_args.project_domain,
).id
- filters['tenant_id'] = project_id
filters['project_id'] = project_id
_tag.get_tag_filtering_args(parsed_args, filters)
diff --git a/openstackclient/network/v2/security_group_rule.py b/openstackclient/network/v2/security_group_rule.py
index 252dcb0..a112261 100644
--- a/openstackclient/network/v2/security_group_rule.py
+++ b/openstackclient/network/v2/security_group_rule.py
@@ -71,10 +71,13 @@ def _format_remote_ip_prefix(rule):
def _get_columns(item):
- column_map = {
- 'tenant_id': 'project_id',
- }
- return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ column_map = {}
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
def _convert_to_lowercase(string):
@@ -352,7 +355,7 @@ class CreateSecurityGroupRule(common.NetworkAndComputeShowOne,
parsed_args.project,
parsed_args.project_domain,
).id
- attrs['tenant_id'] = project_id
+ attrs['project_id'] = project_id
attrs.update(
self._parse_extra_properties(parsed_args.extra_properties))
diff --git a/openstackclient/network/v2/subnet.py b/openstackclient/network/v2/subnet.py
index c07fab4..bf6a46d 100644
--- a/openstackclient/network/v2/subnet.py
+++ b/openstackclient/network/v2/subnet.py
@@ -137,14 +137,17 @@ def _get_columns(item):
column_map = {
'is_dhcp_enabled': 'enable_dhcp',
'subnet_pool_id': 'subnetpool_id',
- 'tenant_id': 'project_id',
}
# Do not show this column when displaying a subnet
- invisible_columns = ['use_default_subnet_pool', 'prefix_length']
+ invisible_columns = [
+ 'location',
+ 'use_default_subnet_pool',
+ 'prefix_length'
+ ]
return utils.get_osc_show_columns_for_sdk_resource(
item,
column_map,
- invisible_columns=invisible_columns
+ invisible_columns
)
@@ -184,7 +187,7 @@ def _get_attrs(client_manager, parsed_args, is_create=True):
parsed_args.project,
parsed_args.project_domain,
).id
- attrs['tenant_id'] = project_id
+ attrs['project_id'] = project_id
attrs['network_id'] = client.find_network(parsed_args.network,
ignore_missing=False).id
if parsed_args.subnet_pool is not None:
@@ -489,6 +492,12 @@ class ListSubnet(command.Lister):
"(in CIDR notation) in output "
"e.g.: --subnet-range 10.10.0.0/16")
)
+ parser.add_argument(
+ '--subnet-pool',
+ metavar='<subnet-pool>',
+ help=_("List only subnets which belong to a given subnet pool "
+ "in output (Name or ID)")
+ )
_tag.add_tag_filtering_option_to_parser(parser, _('subnets'))
return parser
@@ -512,7 +521,6 @@ class ListSubnet(command.Lister):
parsed_args.project,
parsed_args.project_domain,
).id
- filters['tenant_id'] = project_id
filters['project_id'] = project_id
if parsed_args.network:
network_id = network_client.find_network(parsed_args.network,
@@ -524,6 +532,10 @@ class ListSubnet(command.Lister):
filters['name'] = parsed_args.name
if parsed_args.subnet_range:
filters['cidr'] = parsed_args.subnet_range
+ if parsed_args.subnet_pool:
+ subnetpool_id = network_client.find_subnet_pool(
+ parsed_args.subnet_pool, ignore_missing=False).id
+ filters['subnetpool_id'] = subnetpool_id
_tag.get_tag_filtering_args(parsed_args, filters)
data = network_client.subnets(**filters)
diff --git a/openstackclient/network/v2/subnet_pool.py b/openstackclient/network/v2/subnet_pool.py
index 6b88888..b4142f3 100644
--- a/openstackclient/network/v2/subnet_pool.py
+++ b/openstackclient/network/v2/subnet_pool.py
@@ -36,9 +36,13 @@ def _get_columns(item):
'is_shared': 'shared',
'maximum_prefix_length': 'max_prefixlen',
'minimum_prefix_length': 'min_prefixlen',
- 'tenant_id': 'project_id',
}
- return utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ hidden_columns = ['location']
+ return utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ hidden_columns
+ )
_formatters = {
@@ -86,7 +90,7 @@ def _get_attrs(client_manager, parsed_args):
parsed_args.project,
parsed_args.project_domain,
).id
- attrs['tenant_id'] = project_id
+ attrs['project_id'] = project_id
if parsed_args.description is not None:
attrs['description'] = parsed_args.description
@@ -324,7 +328,6 @@ class ListSubnetPool(command.Lister):
parsed_args.project,
parsed_args.project_domain,
).id
- filters['tenant_id'] = project_id
filters['project_id'] = project_id
if parsed_args.name is not None:
filters['name'] = parsed_args.name
diff --git a/openstackclient/tests/functional/common/test_quota.py b/openstackclient/tests/functional/common/test_quota.py
index 9c05746..bf67101 100644
--- a/openstackclient/tests/functional/common/test_quota.py
+++ b/openstackclient/tests/functional/common/test_quota.py
@@ -11,6 +11,9 @@
# under the License.
import json
+import uuid
+
+from tempest.lib import exceptions
from openstackclient.tests.functional import base
@@ -165,3 +168,25 @@ class QuotaTests(base.TestCase):
# returned attributes
self.assertTrue(cmd_output["key-pairs"] >= 0)
self.assertTrue(cmd_output["snapshots"] >= 0)
+
+ def test_quota_network_set_with_check_limit(self):
+ if not self.haz_network:
+ self.skipTest('No Network service present')
+ if not self.is_extension_enabled('quota-check-limit'):
+ self.skipTest('No "quota-check-limit" extension present')
+
+ self.openstack('quota set --networks 40 ' + self.PROJECT_NAME)
+ cmd_output = json.loads(self.openstack(
+ 'quota list -f json --network'
+ ))
+ self.assertIsNotNone(cmd_output)
+ self.assertEqual(40, cmd_output[0]['Networks'])
+
+ # That will ensure we have at least two networks in the system.
+ for _ in range(2):
+ self.openstack('network create --project %s %s' %
+ (self.PROJECT_NAME, uuid.uuid4().hex))
+
+ self.assertRaises(exceptions.CommandFailed, self.openstack,
+ 'quota set --networks 1 --check-limit ' +
+ self.PROJECT_NAME)
diff --git a/openstackclient/tests/functional/compute/v2/test_server.py b/openstackclient/tests/functional/compute/v2/test_server.py
index 9cf2fc7..cf4bcbc 100644
--- a/openstackclient/tests/functional/compute/v2/test_server.py
+++ b/openstackclient/tests/functional/compute/v2/test_server.py
@@ -1071,3 +1071,182 @@ class ServerTests(common.ComputeTestCase):
# networks and the test didn't specify a specific network.
self.assertNotIn('nics are required after microversion 2.36',
e.stderr)
+
+ def test_server_add_remove_network(self):
+ name = uuid.uuid4().hex
+ cmd_output = json.loads(self.openstack(
+ 'server create -f json ' +
+ '--network private ' +
+ '--flavor ' + self.flavor_name + ' ' +
+ '--image ' + self.image_name + ' ' +
+ '--wait ' +
+ name
+ ))
+
+ self.assertIsNotNone(cmd_output['id'])
+ self.assertEqual(name, cmd_output['name'])
+ self.addCleanup(self.openstack, 'server delete --wait ' + name)
+
+ # add network and check 'public' is in server show
+ self.openstack(
+ 'server add network ' + name + ' public')
+
+ wait_time = 0
+ while wait_time < 60:
+ cmd_output = json.loads(self.openstack(
+ 'server show -f json ' + name
+ ))
+ if 'public' not in cmd_output['addresses']:
+ # Hang out for a bit and try again
+ print('retrying add network check')
+ wait_time += 10
+ time.sleep(10)
+ else:
+ break
+ addresses = cmd_output['addresses']
+ self.assertIn('public', addresses)
+
+ # remove network and check 'public' is not in server show
+ self.openstack('server remove network ' + name + ' public')
+
+ wait_time = 0
+ while wait_time < 60:
+ cmd_output = json.loads(self.openstack(
+ 'server show -f json ' + name
+ ))
+ if 'public' in cmd_output['addresses']:
+ # Hang out for a bit and try again
+ print('retrying remove network check')
+ wait_time += 10
+ time.sleep(10)
+ else:
+ break
+
+ addresses = cmd_output['addresses']
+ self.assertNotIn('public', addresses)
+
+ def test_server_add_remove_port(self):
+ name = uuid.uuid4().hex
+ cmd_output = json.loads(self.openstack(
+ 'server create -f json ' +
+ '--network private ' +
+ '--flavor ' + self.flavor_name + ' ' +
+ '--image ' + self.image_name + ' ' +
+ '--wait ' +
+ name
+ ))
+
+ self.assertIsNotNone(cmd_output['id'])
+ self.assertEqual(name, cmd_output['name'])
+ self.addCleanup(self.openstack, 'server delete --wait ' + name)
+
+ # create port, record one of its ip address
+ port_name = uuid.uuid4().hex
+
+ cmd_output = json.loads(self.openstack(
+ 'port list -f json'
+ ))
+ self.assertNotIn(port_name, cmd_output)
+
+ cmd_output = json.loads(self.openstack(
+ 'port create -f json ' +
+ '--network private ' + port_name
+ ))
+ self.assertIsNotNone(cmd_output['id'])
+ ip_address = cmd_output['fixed_ips'][0]['ip_address']
+ self.addCleanup(self.openstack, 'port delete ' + port_name)
+
+ # add port to server, assert the ip address of the port appears
+ self.openstack('server add port ' + name + ' ' + port_name)
+
+ wait_time = 0
+ while wait_time < 60:
+ cmd_output = json.loads(self.openstack(
+ 'server show -f json ' + name
+ ))
+ if ip_address not in cmd_output['addresses']['private']:
+ # Hang out for a bit and try again
+ print('retrying add port check')
+ wait_time += 10
+ time.sleep(10)
+ else:
+ break
+ addresses = cmd_output['addresses']['private']
+ self.assertIn(ip_address, addresses)
+
+ # remove port, assert the ip address of the port doesn't appear
+ self.openstack('server remove port ' + name + ' ' + port_name)
+
+ wait_time = 0
+ while wait_time < 60:
+ cmd_output = json.loads(self.openstack(
+ 'server show -f json ' + name
+ ))
+ if ip_address in cmd_output['addresses']['private']:
+ # Hang out for a bit and try again
+ print('retrying add port check')
+ wait_time += 10
+ time.sleep(10)
+ else:
+ break
+ addresses = cmd_output['addresses']['private']
+ self.assertNotIn(ip_address, addresses)
+
+ def test_server_add_remove_volume(self):
+ volume_wait_for = volume_common.BaseVolumeTests.wait_for_status
+
+ name = uuid.uuid4().hex
+ cmd_output = json.loads(self.openstack(
+ 'server create -f json ' +
+ '--network private ' +
+ '--flavor ' + self.flavor_name + ' ' +
+ '--image ' + self.image_name + ' ' +
+ '--wait ' +
+ name
+ ))
+
+ self.assertIsNotNone(cmd_output['id'])
+ self.assertEqual(name, cmd_output['name'])
+ self.addCleanup(self.openstack, 'server delete --wait ' + name)
+ server_id = cmd_output['id']
+
+ volume_name = uuid.uuid4().hex
+ cmd_output = json.loads(self.openstack(
+ 'volume create -f json ' +
+ '--size 1 ' +
+ volume_name
+ ))
+
+ self.assertIsNotNone(cmd_output['id'])
+ self.assertEqual(volume_name, cmd_output['name'])
+ volume_wait_for('volume', volume_name, 'available')
+ self.addCleanup(self.openstack, 'volume delete ' + volume_name)
+ volume_id = cmd_output['id']
+
+ cmd_output = json.loads(self.openstack(
+ 'server add volume -f json ' +
+ name + ' ' +
+ volume_name + ' ' +
+ '--tag bar'
+ ))
+
+ self.assertIsNotNone(cmd_output['ID'])
+ self.assertEqual(server_id, cmd_output['Server ID'])
+ self.assertEqual(volume_id, cmd_output['Volume ID'])
+ volume_attachment_id = cmd_output['ID']
+
+ cmd_output = json.loads(self.openstack(
+ 'server volume list -f json ' +
+ name
+ ))
+
+ self.assertEqual(volume_attachment_id, cmd_output[0]['ID'])
+ self.assertEqual(server_id, cmd_output[0]['Server ID'])
+ self.assertEqual(volume_id, cmd_output[0]['Volume ID'])
+
+ volume_wait_for('volume', volume_name, 'in-use')
+ self.openstack('server remove volume ' + name + ' ' + volume_name)
+ volume_wait_for('volume', volume_name, 'available')
+
+ raw_output = self.openstack('server volume list ' + name)
+ self.assertEqual('\n', raw_output)
diff --git a/openstackclient/tests/functional/network/v2/test_local_ip.py b/openstackclient/tests/functional/network/v2/test_local_ip.py
new file mode 100644
index 0000000..dd278e3
--- /dev/null
+++ b/openstackclient/tests/functional/network/v2/test_local_ip.py
@@ -0,0 +1,161 @@
+# Copyright 2021 Huawei, Inc. 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 json
+import uuid
+
+from openstackclient.tests.functional.network.v2 import common
+
+
+class LocalIPTests(common.NetworkTests):
+ """Functional tests for local IP"""
+
+ def setUp(self):
+ super(LocalIPTests, self).setUp()
+ # Nothing in this class works with Nova Network
+ if not self.haz_network:
+ self.skipTest("No Network service present")
+ if not self.is_extension_enabled('local-ip'):
+ self.skipTest("No local-ip extension present")
+
+ def test_local_ip_create_and_delete(self):
+ """Test create, delete multiple"""
+ name1 = uuid.uuid4().hex
+ cmd_output = json.loads(self.openstack(
+ 'local ip create -f json ' +
+ name1
+ ))
+ self.assertEqual(
+ name1,
+ cmd_output['name'],
+ )
+
+ name2 = uuid.uuid4().hex
+ cmd_output = json.loads(self.openstack(
+ 'local ip create -f json ' +
+ name2
+ ))
+ self.assertEqual(
+ name2,
+ cmd_output['name'],
+ )
+
+ raw_output = self.openstack(
+ 'local ip delete ' + name1 + ' ' + name2,
+ )
+ self.assertOutput('', raw_output)
+
+ def test_local_ip_list(self):
+ """Test create, list filters, delete"""
+ # Get project IDs
+ cmd_output = json.loads(self.openstack('token issue -f json '))
+ auth_project_id = cmd_output['project_id']
+
+ cmd_output = json.loads(self.openstack('project list -f json '))
+ admin_project_id = None
+ demo_project_id = None
+ for p in cmd_output:
+ if p['Name'] == 'admin':
+ admin_project_id = p['ID']
+ if p['Name'] == 'demo':
+ demo_project_id = p['ID']
+
+ # Verify assumptions:
+ # * admin and demo projects are present
+ # * demo and admin are distinct projects
+ # * tests run as admin
+ self.assertIsNotNone(admin_project_id)
+ self.assertIsNotNone(demo_project_id)
+ self.assertNotEqual(admin_project_id, demo_project_id)
+ self.assertEqual(admin_project_id, auth_project_id)
+
+ name1 = uuid.uuid4().hex
+ cmd_output = json.loads(self.openstack(
+ 'local ip create -f json ' +
+ name1
+ ))
+ self.addCleanup(self.openstack, 'local ip delete ' + name1)
+ self.assertEqual(
+ admin_project_id,
+ cmd_output["project_id"],
+ )
+
+ name2 = uuid.uuid4().hex
+ cmd_output = json.loads(self.openstack(
+ 'local ip create -f json ' +
+ '--project ' + demo_project_id +
+ ' ' + name2
+ ))
+ self.addCleanup(self.openstack, 'local ip delete ' + name2)
+ self.assertEqual(
+ demo_project_id,
+ cmd_output["project_id"],
+ )
+
+ # Test list
+ cmd_output = json.loads(self.openstack(
+ 'local ip list -f json ',
+ ))
+ names = [x["Name"] for x in cmd_output]
+ self.assertIn(name1, names)
+ self.assertIn(name2, names)
+
+ # Test list --project
+ cmd_output = json.loads(self.openstack(
+ 'local ip list -f json ' +
+ '--project ' + demo_project_id
+ ))
+ names = [x["Name"] for x in cmd_output]
+ self.assertNotIn(name1, names)
+ self.assertIn(name2, names)
+
+ # Test list --name
+ cmd_output = json.loads(self.openstack(
+ 'local ip list -f json ' +
+ '--name ' + name1
+ ))
+ names = [x["Name"] for x in cmd_output]
+ self.assertIn(name1, names)
+ self.assertNotIn(name2, names)
+
+ def test_local_ip_set_unset_and_show(self):
+ """Tests create options, set, and show"""
+ name = uuid.uuid4().hex
+ newname = name + "_"
+ cmd_output = json.loads(self.openstack(
+ 'local ip create -f json ' +
+ '--description aaaa ' +
+ name
+ ))
+ self.addCleanup(self.openstack, 'local ip delete ' + newname)
+ self.assertEqual(name, cmd_output['name'])
+ self.assertEqual('aaaa', cmd_output['description'])
+
+ # Test set name and description
+ raw_output = self.openstack(
+ 'local ip set ' +
+ '--name ' + newname + ' ' +
+ '--description bbbb ' +
+ name,
+ )
+ self.assertOutput('', raw_output)
+
+ # Show the updated local ip
+ cmd_output = json.loads(self.openstack(
+ 'local ip show -f json ' +
+ newname,
+ ))
+ self.assertEqual(newname, cmd_output['name'])
+ self.assertEqual('bbbb', cmd_output['description'])
diff --git a/openstackclient/tests/functional/volume/v3/test_volume.py b/openstackclient/tests/functional/volume/v3/test_volume.py
index 6635167..c1b45e2 100644
--- a/openstackclient/tests/functional/volume/v3/test_volume.py
+++ b/openstackclient/tests/functional/volume/v3/test_volume.py
@@ -152,6 +152,7 @@ class VolumeTests(common.BaseVolumeTests):
name,
)
self.assertOutput('', raw_output)
+ self.wait_for_status("volume", new_name, "available")
cmd_output = json.loads(self.openstack(
'volume show -f json ' +
diff --git a/openstackclient/tests/unit/common/test_project_purge.py b/openstackclient/tests/unit/common/test_project_purge.py
index adc48ce..5199093 100644
--- a/openstackclient/tests/unit/common/test_project_purge.py
+++ b/openstackclient/tests/unit/common/test_project_purge.py
@@ -70,7 +70,7 @@ class TestProjectPurge(TestProjectPurgeInit):
project = identity_fakes.FakeProject.create_one_project()
server = compute_fakes.FakeServer.create_one_server()
- image = image_fakes.FakeImage.create_one_image()
+ image = image_fakes.create_one_image()
volume = volume_fakes.FakeVolume.create_one_volume()
backup = volume_fakes.FakeBackup.create_one_backup()
snapshot = volume_fakes.FakeSnapshot.create_one_snapshot()
diff --git a/openstackclient/tests/unit/common/test_quota.py b/openstackclient/tests/unit/common/test_quota.py
index 8771359..896a63a 100644
--- a/openstackclient/tests/unit/common/test_quota.py
+++ b/openstackclient/tests/unit/common/test_quota.py
@@ -950,6 +950,49 @@ class TestQuotaSet(TestQuota):
)
self.assertIsNone(result)
+ def test_quota_set_with_check_limit(self):
+ arglist = [
+ '--subnets', str(network_fakes.QUOTA['subnet']),
+ '--volumes', str(volume_fakes.QUOTA['volumes']),
+ '--cores', str(compute_fakes.core_num),
+ '--check-limit',
+ self.projects[0].name,
+ ]
+ verifylist = [
+ ('subnet', network_fakes.QUOTA['subnet']),
+ ('volumes', volume_fakes.QUOTA['volumes']),
+ ('cores', compute_fakes.core_num),
+ ('check_limit', True),
+ ('project', self.projects[0].name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs_compute = {
+ 'cores': compute_fakes.core_num,
+ }
+ kwargs_volume = {
+ 'volumes': volume_fakes.QUOTA['volumes'],
+ }
+ kwargs_network = {
+ 'subnet': network_fakes.QUOTA['subnet'],
+ 'check_limit': True,
+ }
+ self.compute_quotas_mock.update.assert_called_once_with(
+ self.projects[0].id,
+ **kwargs_compute
+ )
+ self.volume_quotas_mock.update.assert_called_once_with(
+ self.projects[0].id,
+ **kwargs_volume
+ )
+ self.network_mock.update_quota.assert_called_once_with(
+ self.projects[0].id,
+ **kwargs_network
+ )
+ self.assertIsNone(result)
+
class TestQuotaShow(TestQuota):
diff --git a/openstackclient/tests/unit/compute/v2/fakes.py b/openstackclient/tests/unit/compute/v2/fakes.py
index 23468eb..55572cd 100644
--- a/openstackclient/tests/unit/compute/v2/fakes.py
+++ b/openstackclient/tests/unit/compute/v2/fakes.py
@@ -21,6 +21,9 @@ import uuid
from novaclient import api_versions
from openstack.compute.v2 import flavor as _flavor
from openstack.compute.v2 import server
+from openstack.compute.v2 import server_interface as _server_interface
+from openstack.compute.v2 import service
+from openstack.compute.v2 import volume_attachment
from openstackclient.api import compute_v2
from openstackclient.tests.unit import fakes
@@ -762,7 +765,7 @@ class FakeService(object):
:param dict attrs:
A dictionary with all attributes
:return:
- A FakeResource object, with id, host, binary, and so on
+ A fake Service object, with id, host, binary, and so on
"""
attrs = attrs or {}
@@ -772,21 +775,18 @@ class FakeService(object):
'host': 'host-' + uuid.uuid4().hex,
'binary': 'binary-' + uuid.uuid4().hex,
'status': 'enabled',
- 'zone': 'zone-' + uuid.uuid4().hex,
+ 'availability_zone': 'zone-' + uuid.uuid4().hex,
'state': 'state-' + uuid.uuid4().hex,
'updated_at': 'time-' + uuid.uuid4().hex,
'disabled_reason': 'earthquake',
# Introduced in API microversion 2.11
- 'forced_down': False,
+ 'is_forced_down': False,
}
# Overwrite default attributes.
service_info.update(attrs)
- service = fakes.FakeResource(info=copy.deepcopy(service_info),
- loaded=True)
-
- return service
+ return service.Service(**service_info)
@staticmethod
def create_services(attrs=None, count=2):
@@ -1803,3 +1803,85 @@ class FakeVolumeAttachment(object):
attrs, methods))
return volume_attachments
+
+ @staticmethod
+ def create_one_sdk_volume_attachment(attrs=None, methods=None):
+ """Create a fake sdk VolumeAttachment.
+
+ :param dict attrs:
+ A dictionary with all attributes
+ :param dict methods:
+ A dictionary with all methods
+ :return:
+ A fake VolumeAttachment object, with id, device, and so on
+ """
+ attrs = attrs or {}
+ methods = methods or {}
+
+ # Set default attributes.
+ volume_attachment_info = {
+ "id": uuid.uuid4().hex,
+ "device": "/dev/sdb",
+ "server_id": uuid.uuid4().hex,
+ "volume_id": uuid.uuid4().hex,
+ # introduced in API microversion 2.70
+ "tag": "foo",
+ # introduced in API microversion 2.79
+ "delete_on_termination": True,
+ # introduced in API microversion 2.89
+ "attachment_id": uuid.uuid4().hex,
+ "bdm_uuid": uuid.uuid4().hex
+ }
+
+ # Overwrite default attributes.
+ volume_attachment_info.update(attrs)
+
+ return volume_attachment.VolumeAttachment(**volume_attachment_info)
+
+ @staticmethod
+ def create_sdk_volume_attachments(attrs=None, methods=None, count=2):
+ """Create multiple fake VolumeAttachment objects (BDMs).
+
+ :param dict attrs:
+ A dictionary with all attributes
+ :param dict methods:
+ A dictionary with all methods
+ :param int count:
+ The number of volume attachments to fake
+ :return:
+ A list of VolumeAttachment objects faking the volume attachments.
+ """
+ volume_attachments = []
+ for i in range(0, count):
+ volume_attachments.append(
+ FakeVolumeAttachment.create_one_sdk_volume_attachment(
+ attrs, methods))
+
+ return volume_attachments
+
+
+def create_one_server_interface(attrs=None):
+ """Create a fake SDK ServerInterface.
+
+ :param dict attrs: A dictionary with all attributes
+ :param dict methods: A dictionary with all methods
+ :return: A fake ServerInterface object with various attributes set
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ server_interface_info = {
+ "fixed_ips": uuid.uuid4().hex,
+ "mac_addr": "aa:aa:aa:aa:aa:aa",
+ "net_id": uuid.uuid4().hex,
+ "port_id": uuid.uuid4().hex,
+ "port_state": "ACTIVE",
+ "server_id": uuid.uuid4().hex,
+ # introduced in API microversion 2.70
+ "tag": "foo",
+ }
+
+ # Overwrite default attributes.
+ server_interface_info.update(attrs)
+
+ return _server_interface.ServerInterface(**server_interface_info)
diff --git a/openstackclient/tests/unit/compute/v2/test_aggregate.py b/openstackclient/tests/unit/compute/v2/test_aggregate.py
index 7c4fe5c..3a7a81c 100644
--- a/openstackclient/tests/unit/compute/v2/test_aggregate.py
+++ b/openstackclient/tests/unit/compute/v2/test_aggregate.py
@@ -234,6 +234,7 @@ class TestAggregateList(TestAggregate):
"Name",
"Availability Zone",
"Properties",
+ "Hosts",
)
list_data = ((
@@ -251,6 +252,7 @@ class TestAggregateList(TestAggregate):
for key, value in TestAggregate.fake_ag.metadata.items()
if key != 'availability_zone'
}),
+ format_columns.ListColumn(TestAggregate.fake_ag.hosts),
), )
def setUp(self):
@@ -552,7 +554,7 @@ class TestAggregateUnset(TestAggregate):
class TestAggregateCacheImage(TestAggregate):
- images = image_fakes.FakeImage.create_images(count=2)
+ images = image_fakes.create_images(count=2)
def setUp(self):
super(TestAggregateCacheImage, self).setUp()
diff --git a/openstackclient/tests/unit/compute/v2/test_server.py b/openstackclient/tests/unit/compute/v2/test_server.py
index 585f49d..480dcfe 100644
--- a/openstackclient/tests/unit/compute/v2/test_server.py
+++ b/openstackclient/tests/unit/compute/v2/test_server.py
@@ -24,6 +24,7 @@ from unittest.mock import call
import iso8601
from novaclient import api_versions
from openstack import exceptions as sdk_exceptions
+from openstack import utils as sdk_utils
from osc_lib.cli import format_columns
from osc_lib import exceptions
from osc_lib import utils as common_utils
@@ -69,6 +70,10 @@ class TestServer(compute_fakes.TestComputev2):
self.servers_mock = self.app.client_manager.compute.servers
self.servers_mock.reset_mock()
+ self.app.client_manager.sdk_connection = mock.Mock()
+ self.app.client_manager.sdk_connection.compute = mock.Mock()
+ self.sdk_client = self.app.client_manager.sdk_connection.compute
+
# Get a shortcut to the compute client ServerMigrationsManager Mock
self.server_migrations_mock = \
self.app.client_manager.compute.server_migrations
@@ -100,6 +105,9 @@ class TestServer(compute_fakes.TestComputev2):
self.volumes_mock = self.app.client_manager.volume.volumes
self.volumes_mock.reset_mock()
+ self.app.client_manager.sdk_connection.volume = mock.Mock()
+ self.sdk_volume_client = self.app.client_manager.sdk_connection.volume
+
# Get a shortcut to the volume client VolumeManager Mock
self.snapshots_mock = self.app.client_manager.volume.volume_snapshots
self.snapshots_mock.reset_mock()
@@ -133,6 +141,26 @@ class TestServer(compute_fakes.TestComputev2):
0)
return servers
+ def setup_sdk_servers_mock(self, count):
+ servers = compute_fakes.FakeServer.create_sdk_servers(
+ attrs=self.attrs,
+ methods=self.methods,
+ count=count,
+ )
+
+ # This is the return value for compute_client.find_server()
+ self.sdk_client.find_server.side_effect = servers
+
+ return servers
+
+ def setup_sdk_volumes_mock(self, count):
+ volumes = volume_fakes.FakeVolume.create_sdk_volumes(count=count)
+
+ # This is the return value for volume_client.find_volume()
+ self.sdk_volume_client.find_volume.side_effect = volumes
+
+ return volumes
+
def run_method_with_servers(self, method_name, server_count):
servers = self.setup_servers_mock(server_count)
@@ -164,113 +192,160 @@ class TestServer(compute_fakes.TestComputev2):
method.assert_called_with()
self.assertIsNone(result)
+ def run_method_with_sdk_servers(self, method_name, server_count):
+ servers = self.setup_sdk_servers_mock(count=server_count)
+
+ arglist = [s.id for s in servers]
+ verifylist = [
+ ('server', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = [call(s.id) for s in servers]
+ method = getattr(self.sdk_client, method_name)
+ method.assert_has_calls(calls)
+ self.assertIsNone(result)
+
class TestServerAddFixedIP(TestServer):
def setUp(self):
- super(TestServerAddFixedIP, self).setUp()
+ super().setUp()
# Get the command object to test
self.cmd = server.AddFixedIP(self.app, None)
- # Set add_fixed_ip method to be tested.
- self.methods = {
- 'interface_attach': None,
- }
+ # Mock network methods
+ self.find_network = mock.Mock()
+ self.app.client_manager.network.find_network = self.find_network
- def _test_server_add_fixed_ip(self, extralist, fixed_ip_address):
- servers = self.setup_servers_mock(count=1)
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_server_add_fixed_ip_pre_v244(self, sm_mock):
+ sm_mock.return_value = False
+
+ servers = self.setup_sdk_servers_mock(count=1)
network = compute_fakes.FakeNetwork.create_one_network()
- with mock.patch(
- 'openstackclient.api.compute_v2.APIv2.network_find'
- ) as net_mock:
- net_mock.return_value = network
+ with mock.patch.object(
+ self.app.client_manager,
+ 'is_network_endpoint_enabled',
+ return_value=False
+ ):
arglist = [
servers[0].id,
network['id'],
- ] + extralist
+ ]
verifylist = [
('server', servers[0].id),
('network', network['id']),
- ('fixed_ip_address', fixed_ip_address),
+ ('fixed_ip_address', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
- servers[0].interface_attach.assert_called_once_with(
- port_id=None,
- net_id=network['id'],
- fixed_ip=fixed_ip_address,
+ self.sdk_client.add_fixed_ip_to_server.assert_called_once_with(
+ servers[0].id,
+ network['id']
)
- self.assertIsNone(result)
+ # the legacy API operates asynchronously
+ self.assertEqual(((), ()), result)
- def test_server_add_fixed_ip(self):
- self._test_server_add_fixed_ip([], None)
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_server_add_fixed_ip_pre_v244_with_fixed_ip(self, sm_mock):
+ sm_mock.return_value = False
- def test_server_add_specific_fixed_ip(self):
- extralist = ['--fixed-ip-address', '5.6.7.8']
- self._test_server_add_fixed_ip(extralist, '5.6.7.8')
+ servers = self.setup_sdk_servers_mock(count=1)
+ network = compute_fakes.FakeNetwork.create_one_network()
- def test_server_add_fixed_ip_with_tag(self):
- self.app.client_manager.compute.api_version = api_versions.APIVersion(
- '2.49')
+ with mock.patch.object(
+ self.app.client_manager,
+ 'is_network_endpoint_enabled',
+ return_value=False
+ ):
+ arglist = [
+ servers[0].id,
+ network['id'],
+ '--fixed-ip-address', '5.6.7.8'
+ ]
+ verifylist = [
+ ('server', servers[0].id),
+ ('network', network['id']),
+ ('fixed_ip_address', '5.6.7.8'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- servers = self.setup_servers_mock(count=1)
+ result = self.cmd.take_action(parsed_args)
+
+ self.sdk_client.add_fixed_ip_to_server.assert_called_once_with(
+ servers[0].id,
+ network['id']
+ )
+ # the legacy API operates asynchronously
+ self.assertEqual(((), ()), result)
+
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_server_add_fixed_ip_pre_v244_with_tag(self, sm_mock):
+ sm_mock.return_value = False
+
+ servers = self.setup_sdk_servers_mock(count=1)
network = compute_fakes.FakeNetwork.create_one_network()
- with mock.patch(
- 'openstackclient.api.compute_v2.APIv2.network_find'
- ) as net_mock:
- net_mock.return_value = network
+ with mock.patch.object(
+ self.app.client_manager,
+ 'is_network_endpoint_enabled',
+ return_value=False
+ ):
arglist = [
servers[0].id,
network['id'],
'--fixed-ip-address', '5.6.7.8',
- '--tag', 'tag1',
+ '--tag', 'tag1'
]
verifylist = [
('server', servers[0].id),
('network', network['id']),
('fixed_ip_address', '5.6.7.8'),
- ('tag', 'tag1'),
+ ('tag', 'tag1')
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- result = self.cmd.take_action(parsed_args)
- servers[0].interface_attach.assert_called_once_with(
- port_id=None,
- net_id=network['id'],
- fixed_ip='5.6.7.8',
- tag='tag1'
- )
- self.assertIsNone(result)
+ ex = self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+ self.assertIn(
+ '--os-compute-api-version 2.49 or greater is required',
+ str(ex))
- def test_server_add_fixed_ip_with_tag_pre_v249(self):
- self.app.client_manager.compute.api_version = api_versions.APIVersion(
- '2.48')
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_server_add_fixed_ip_pre_v249_with_tag(self, sm_mock):
+ sm_mock.side_effect = [False, True]
- servers = self.setup_servers_mock(count=1)
+ servers = self.setup_sdk_servers_mock(count=1)
network = compute_fakes.FakeNetwork.create_one_network()
- with mock.patch(
- 'openstackclient.api.compute_v2.APIv2.network_find'
- ) as net_mock:
- net_mock.return_value = network
+ with mock.patch.object(
+ self.app.client_manager,
+ 'is_network_endpoint_enabled',
+ return_value=False
+ ):
arglist = [
servers[0].id,
network['id'],
'--fixed-ip-address', '5.6.7.8',
- '--tag', 'tag1',
+ '--tag', 'tag1'
]
verifylist = [
('server', servers[0].id),
('network', network['id']),
('fixed_ip_address', '5.6.7.8'),
- ('tag', 'tag1'),
+ ('tag', 'tag1')
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
ex = self.assertRaises(
exceptions.CommandError,
self.cmd.take_action,
@@ -279,6 +354,170 @@ class TestServerAddFixedIP(TestServer):
'--os-compute-api-version 2.49 or greater is required',
str(ex))
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_server_add_fixed_ip(self, sm_mock):
+ sm_mock.side_effect = [True, False]
+
+ servers = self.setup_sdk_servers_mock(count=1)
+ network = compute_fakes.FakeNetwork.create_one_network()
+ interface = compute_fakes.create_one_server_interface()
+ self.sdk_client.create_server_interface.return_value = interface
+
+ with mock.patch.object(
+ self.app.client_manager,
+ 'is_network_endpoint_enabled',
+ return_value=False
+ ):
+ arglist = [
+ servers[0].id,
+ network['id']
+ ]
+ verifylist = [
+ ('server', servers[0].id),
+ ('network', network['id'])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ expected_columns = (
+ 'Port ID',
+ 'Server ID',
+ 'Network ID',
+ 'MAC Address',
+ 'Port State',
+ 'Fixed IPs',
+ )
+ expected_data = (
+ interface.port_id,
+ interface.server_id,
+ interface.net_id,
+ interface.mac_addr,
+ interface.port_state,
+ format_columns.ListDictColumn(interface.fixed_ips),
+ )
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(expected_columns, columns)
+ self.assertEqual(expected_data, tuple(data))
+ self.sdk_client.create_server_interface.assert_called_once_with(
+ servers[0].id,
+ net_id=network['id'],
+ fixed_ip=None
+ )
+
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_server_add_fixed_ip_with_fixed_ip(self, sm_mock):
+ sm_mock.side_effect = [True, True]
+
+ servers = self.setup_sdk_servers_mock(count=1)
+ network = compute_fakes.FakeNetwork.create_one_network()
+ interface = compute_fakes.create_one_server_interface()
+ self.sdk_client.create_server_interface.return_value = interface
+
+ with mock.patch.object(
+ self.app.client_manager,
+ 'is_network_endpoint_enabled',
+ return_value=False
+ ):
+ arglist = [
+ servers[0].id,
+ network['id'],
+ '--fixed-ip-address', '5.6.7.8'
+ ]
+ verifylist = [
+ ('server', servers[0].id),
+ ('network', network['id']),
+ ('fixed_ip_address', '5.6.7.8')
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ expected_columns = (
+ 'Port ID',
+ 'Server ID',
+ 'Network ID',
+ 'MAC Address',
+ 'Port State',
+ 'Fixed IPs',
+ 'Tag',
+ )
+ expected_data = (
+ interface.port_id,
+ interface.server_id,
+ interface.net_id,
+ interface.mac_addr,
+ interface.port_state,
+ format_columns.ListDictColumn(interface.fixed_ips),
+ interface.tag,
+ )
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(expected_columns, columns)
+ self.assertEqual(expected_data, tuple(data))
+ self.sdk_client.create_server_interface.assert_called_once_with(
+ servers[0].id,
+ net_id=network['id'],
+ fixed_ip='5.6.7.8'
+ )
+
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_server_add_fixed_ip_with_tag(self, sm_mock):
+ sm_mock.side_effect = [True, True, True]
+
+ servers = self.setup_sdk_servers_mock(count=1)
+ network = compute_fakes.FakeNetwork.create_one_network()
+ interface = compute_fakes.create_one_server_interface()
+ self.sdk_client.create_server_interface.return_value = interface
+
+ with mock.patch.object(
+ self.app.client_manager,
+ 'is_network_endpoint_enabled',
+ return_value=False
+ ):
+ arglist = [
+ servers[0].id,
+ network['id'],
+ '--fixed-ip-address', '5.6.7.8',
+ '--tag', 'tag1'
+ ]
+ verifylist = [
+ ('server', servers[0].id),
+ ('network', network['id']),
+ ('fixed_ip_address', '5.6.7.8'),
+ ('tag', 'tag1')
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ expected_columns = (
+ 'Port ID',
+ 'Server ID',
+ 'Network ID',
+ 'MAC Address',
+ 'Port State',
+ 'Fixed IPs',
+ 'Tag',
+ )
+ expected_data = (
+ interface.port_id,
+ interface.server_id,
+ interface.net_id,
+ interface.mac_addr,
+ interface.port_state,
+ format_columns.ListDictColumn(interface.fixed_ips),
+ interface.tag,
+ )
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(expected_columns, columns)
+ self.assertEqual(expected_data, tuple(data))
+ self.sdk_client.create_server_interface.assert_called_once_with(
+ servers[0].id,
+ net_id=network['id'],
+ fixed_ip='5.6.7.8',
+ tag='tag1',
+ )
+
@mock.patch(
'openstackclient.api.compute_v2.APIv2.floating_ip_add'
@@ -570,7 +809,7 @@ class TestServerAddPort(TestServer):
self.app.client_manager.network.find_port = self.find_port
def _test_server_add_port(self, port_id):
- servers = self.setup_servers_mock(count=1)
+ servers = self.setup_sdk_servers_mock(count=1)
port = 'fake-port'
arglist = [
@@ -585,8 +824,8 @@ class TestServerAddPort(TestServer):
result = self.cmd.take_action(parsed_args)
- servers[0].interface_attach.assert_called_once_with(
- port_id=port_id, net_id=None, fixed_ip=None)
+ self.sdk_client.create_server_interface.assert_called_once_with(
+ servers[0], port_id=port_id, fixed_ip=None)
self.assertIsNone(result)
def test_server_add_port(self):
@@ -599,11 +838,12 @@ class TestServerAddPort(TestServer):
self._test_server_add_port('fake-port')
self.find_port.assert_not_called()
- def test_server_add_port_with_tag(self):
+ @mock.patch.object(sdk_utils, 'supports_microversion', return_value=True)
+ def test_server_add_port_with_tag(self, sm_mock):
self.app.client_manager.compute.api_version = api_versions.APIVersion(
'2.49')
- servers = self.setup_servers_mock(count=1)
+ servers = self.setup_sdk_servers_mock(count=1)
self.find_port.return_value.id = 'fake-port'
arglist = [
servers[0].id,
@@ -620,13 +860,14 @@ class TestServerAddPort(TestServer):
result = self.cmd.take_action(parsed_args)
self.assertIsNone(result)
- servers[0].interface_attach.assert_called_once_with(
+ self.sdk_client.create_server_interface.assert_called_once_with(
+ servers[0],
port_id='fake-port',
- net_id=None,
fixed_ip=None,
tag='tag1')
- def test_server_add_port_with_tag_pre_v249(self):
+ @mock.patch.object(sdk_utils, 'supports_microversion', return_value=False)
+ def test_server_add_port_with_tag_pre_v249(self, sm_mock):
self.app.client_manager.compute.api_version = api_versions.APIVersion(
'2.48')
@@ -658,31 +899,44 @@ class TestServerVolume(TestServer):
def setUp(self):
super(TestServerVolume, self).setUp()
- self.volume = volume_fakes.FakeVolume.create_one_volume()
- self.volumes_mock.get.return_value = self.volume
-
self.methods = {
- 'create_server_volume': None,
+ 'create_volume_attachment': None,
+ }
+
+ self.servers = self.setup_sdk_servers_mock(count=1)
+ self.volumes = self.setup_sdk_volumes_mock(count=1)
+
+ attrs = {
+ 'server_id': self.servers[0].id,
+ 'volume_id': self.volumes[0].id,
}
+ self.volume_attachment = \
+ compute_fakes.FakeVolumeAttachment.\
+ create_one_sdk_volume_attachment(attrs=attrs)
+
+ self.sdk_client.create_volume_attachment.return_value = \
+ self.volume_attachment
+
+
+class TestServerAddVolume(TestServerVolume):
+
+ def setUp(self):
+ super(TestServerAddVolume, self).setUp()
# Get the command object to test
self.cmd = server.AddServerVolume(self.app, None)
- def test_server_add_volume(self):
- servers = self.setup_servers_mock(count=1)
- volume_attachment = \
- compute_fakes.FakeVolumeAttachment.create_one_volume_attachment()
- self.servers_volumes_mock.create_server_volume.return_value = \
- volume_attachment
+ @mock.patch.object(sdk_utils, 'supports_microversion', return_value=False)
+ def test_server_add_volume(self, sm_mock):
arglist = [
'--device', '/dev/sdb',
- servers[0].id,
- self.volume.id,
+ self.servers[0].id,
+ self.volumes[0].id,
]
verifylist = [
- ('server', servers[0].id),
- ('volume', self.volume.id),
+ ('server', self.servers[0].id),
+ ('volume', self.volumes[0].id),
('device', '/dev/sdb'),
]
@@ -690,39 +944,36 @@ class TestServerVolume(TestServer):
expected_columns = ('ID', 'Server ID', 'Volume ID', 'Device')
expected_data = (
- volume_attachment.id,
- volume_attachment.serverId,
- volume_attachment.volumeId,
- volume_attachment.device,
+ self.volume_attachment.id,
+ self.volume_attachment.server_id,
+ self.volume_attachment.volume_id,
+ '/dev/sdb',
)
columns, data = self.cmd.take_action(parsed_args)
- self.servers_volumes_mock.create_server_volume.assert_called_once_with(
- servers[0].id, self.volume.id, device='/dev/sdb')
self.assertEqual(expected_columns, columns)
self.assertEqual(expected_data, data)
+ self.sdk_client.create_volume_attachment.assert_called_once_with(
+ self.servers[0], volumeId=self.volumes[0].id, device='/dev/sdb')
- def test_server_add_volume_with_tag(self):
- # requires API 2.49 or later
- self.app.client_manager.compute.api_version = api_versions.APIVersion(
- '2.49')
-
- servers = self.setup_servers_mock(count=1)
- volume_attachment = \
- compute_fakes.FakeVolumeAttachment.create_one_volume_attachment()
- self.servers_volumes_mock.create_server_volume.return_value = \
- volume_attachment
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_server_add_volume_with_tag(self, sm_mock):
+ def side_effect(compute_client, version):
+ if version == '2.49':
+ return True
+ return False
+ sm_mock.side_effect = side_effect
arglist = [
'--device', '/dev/sdb',
'--tag', 'foo',
- servers[0].id,
- self.volume.id,
+ self.servers[0].id,
+ self.volumes[0].id,
]
verifylist = [
- ('server', servers[0].id),
- ('volume', self.volume.id),
+ ('server', self.servers[0].id),
+ ('volume', self.volumes[0].id),
('device', '/dev/sdb'),
('tag', 'foo'),
]
@@ -731,33 +982,33 @@ class TestServerVolume(TestServer):
expected_columns = ('ID', 'Server ID', 'Volume ID', 'Device', 'Tag')
expected_data = (
- volume_attachment.id,
- volume_attachment.serverId,
- volume_attachment.volumeId,
- volume_attachment.device,
- volume_attachment.tag,
+ self.volume_attachment.id,
+ self.volume_attachment.server_id,
+ self.volume_attachment.volume_id,
+ self.volume_attachment.device,
+ self.volume_attachment.tag,
)
columns, data = self.cmd.take_action(parsed_args)
- self.servers_volumes_mock.create_server_volume.assert_called_once_with(
- servers[0].id, self.volume.id, device='/dev/sdb', tag='foo')
self.assertEqual(expected_columns, columns)
self.assertEqual(expected_data, data)
+ self.sdk_client.create_volume_attachment.assert_called_once_with(
+ self.servers[0],
+ volumeId=self.volumes[0].id,
+ device='/dev/sdb',
+ tag='foo')
- def test_server_add_volume_with_tag_pre_v249(self):
- self.app.client_manager.compute.api_version = api_versions.APIVersion(
- '2.48')
-
- servers = self.setup_servers_mock(count=1)
+ @mock.patch.object(sdk_utils, 'supports_microversion', return_value=False)
+ def test_server_add_volume_with_tag_pre_v249(self, sm_mock):
arglist = [
- servers[0].id,
- self.volume.id,
+ self.servers[0].id,
+ self.volumes[0].id,
'--tag', 'foo',
]
verifylist = [
- ('server', servers[0].id),
- ('volume', self.volume.id),
+ ('server', self.servers[0].id),
+ ('volume', self.volumes[0].id),
('tag', 'foo'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -770,26 +1021,22 @@ class TestServerVolume(TestServer):
'--os-compute-api-version 2.49 or greater is required',
str(ex))
- def test_server_add_volume_with_enable_delete_on_termination(self):
- self.app.client_manager.compute.api_version = api_versions.APIVersion(
- '2.79')
-
- servers = self.setup_servers_mock(count=1)
- volume_attachment = \
- compute_fakes.FakeVolumeAttachment.create_one_volume_attachment()
- self.servers_volumes_mock.create_server_volume.return_value = \
- volume_attachment
-
+ @mock.patch.object(sdk_utils, 'supports_microversion', return_value=True)
+ def test_server_add_volume_with_enable_delete_on_termination(
+ self,
+ sm_mock,
+ ):
+ self.volume_attachment.delete_on_termination = True
arglist = [
'--enable-delete-on-termination',
'--device', '/dev/sdb',
- servers[0].id,
- self.volume.id,
+ self.servers[0].id,
+ self.volumes[0].id,
]
verifylist = [
- ('server', servers[0].id),
- ('volume', self.volume.id),
+ ('server', self.servers[0].id),
+ ('volume', self.volumes[0].id),
('device', '/dev/sdb'),
('enable_delete_on_termination', True),
]
@@ -804,42 +1051,40 @@ class TestServerVolume(TestServer):
'Delete On Termination',
)
expected_data = (
- volume_attachment.id,
- volume_attachment.serverId,
- volume_attachment.volumeId,
- volume_attachment.device,
- volume_attachment.tag,
- volume_attachment.delete_on_termination,
+ self.volume_attachment.id,
+ self.volume_attachment.server_id,
+ self.volume_attachment.volume_id,
+ self.volume_attachment.device,
+ self.volume_attachment.tag,
+ self.volume_attachment.delete_on_termination,
)
columns, data = self.cmd.take_action(parsed_args)
-
- self.servers_volumes_mock.create_server_volume.assert_called_once_with(
- servers[0].id, self.volume.id,
- device='/dev/sdb', delete_on_termination=True)
self.assertEqual(expected_columns, columns)
self.assertEqual(expected_data, data)
-
- def test_server_add_volume_with_disable_delete_on_termination(self):
- self.app.client_manager.compute.api_version = api_versions.APIVersion(
- '2.79')
-
- servers = self.setup_servers_mock(count=1)
- volume_attachment = \
- compute_fakes.FakeVolumeAttachment.create_one_volume_attachment()
- self.servers_volumes_mock.create_server_volume.return_value = \
- volume_attachment
+ self.sdk_client.create_volume_attachment.assert_called_once_with(
+ self.servers[0],
+ volumeId=self.volumes[0].id,
+ device='/dev/sdb',
+ delete_on_termination=True)
+
+ @mock.patch.object(sdk_utils, 'supports_microversion', return_value=True)
+ def test_server_add_volume_with_disable_delete_on_termination(
+ self,
+ sm_mock,
+ ):
+ self.volume_attachment.delete_on_termination = False
arglist = [
'--disable-delete-on-termination',
'--device', '/dev/sdb',
- servers[0].id,
- self.volume.id,
+ self.servers[0].id,
+ self.volumes[0].id,
]
verifylist = [
- ('server', servers[0].id),
- ('volume', self.volume.id),
+ ('server', self.servers[0].id),
+ ('volume', self.volumes[0].id),
('device', '/dev/sdb'),
('disable_delete_on_termination', True),
]
@@ -854,37 +1099,43 @@ class TestServerVolume(TestServer):
'Delete On Termination',
)
expected_data = (
- volume_attachment.id,
- volume_attachment.serverId,
- volume_attachment.volumeId,
- volume_attachment.device,
- volume_attachment.tag,
- volume_attachment.delete_on_termination,
+ self.volume_attachment.id,
+ self.volume_attachment.server_id,
+ self.volume_attachment.volume_id,
+ self.volume_attachment.device,
+ self.volume_attachment.tag,
+ self.volume_attachment.delete_on_termination,
)
columns, data = self.cmd.take_action(parsed_args)
- self.servers_volumes_mock.create_server_volume.assert_called_once_with(
- servers[0].id, self.volume.id,
- device='/dev/sdb', delete_on_termination=False)
self.assertEqual(expected_columns, columns)
self.assertEqual(expected_data, data)
+ self.sdk_client.create_volume_attachment.assert_called_once_with(
+ self.servers[0],
+ volumeId=self.volumes[0].id,
+ device='/dev/sdb',
+ delete_on_termination=False)
+ @mock.patch.object(sdk_utils, 'supports_microversion')
def test_server_add_volume_with_enable_delete_on_termination_pre_v279(
self,
+ sm_mock,
):
- self.app.client_manager.compute.api_version = api_versions.APIVersion(
- '2.78')
+ def side_effect(compute_client, version):
+ if version == '2.79':
+ return False
+ return True
+ sm_mock.side_effect = side_effect
- servers = self.setup_servers_mock(count=1)
arglist = [
- servers[0].id,
- self.volume.id,
+ self.servers[0].id,
+ self.volumes[0].id,
'--enable-delete-on-termination',
]
verifylist = [
- ('server', servers[0].id),
- ('volume', self.volume.id),
+ ('server', self.servers[0].id),
+ ('volume', self.volumes[0].id),
('enable_delete_on_termination', True),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -895,21 +1146,25 @@ class TestServerVolume(TestServer):
self.assertIn('--os-compute-api-version 2.79 or greater is required',
str(ex))
+ @mock.patch.object(sdk_utils, 'supports_microversion')
def test_server_add_volume_with_disable_delete_on_termination_pre_v279(
self,
+ sm_mock,
):
- self.app.client_manager.compute.api_version = api_versions.APIVersion(
- '2.78')
+ def side_effect(compute_client, version):
+ if version == '2.79':
+ return False
+ return True
+ sm_mock.side_effect = side_effect
- servers = self.setup_servers_mock(count=1)
arglist = [
- servers[0].id,
- self.volume.id,
+ self.servers[0].id,
+ self.volumes[0].id,
'--disable-delete-on-termination',
]
verifylist = [
- ('server', servers[0].id),
- ('volume', self.volume.id),
+ ('server', self.servers[0].id),
+ ('volume', self.volumes[0].id),
('disable_delete_on_termination', True),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -920,24 +1175,22 @@ class TestServerVolume(TestServer):
self.assertIn('--os-compute-api-version 2.79 or greater is required',
str(ex))
+ @mock.patch.object(sdk_utils, 'supports_microversion', return_value=True)
def test_server_add_volume_with_disable_and_enable_delete_on_termination(
self,
+ sm_mock,
):
- self.app.client_manager.compute.api_version = api_versions.APIVersion(
- '2.79')
-
- servers = self.setup_servers_mock(count=1)
arglist = [
'--enable-delete-on-termination',
'--disable-delete-on-termination',
'--device', '/dev/sdb',
- servers[0].id,
- self.volume.id,
+ self.servers[0].id,
+ self.volumes[0].id,
]
verifylist = [
- ('server', servers[0].id),
- ('volume', self.volume.id),
+ ('server', self.servers[0].id),
+ ('volume', self.volumes[0].id),
('device', '/dev/sdb'),
('enable_delete_on_termination', True),
('disable_delete_on_termination', True),
@@ -949,6 +1202,37 @@ class TestServerVolume(TestServer):
'with argument --enable-delete-on-termination', str(ex))
+class TestServerRemoveVolume(TestServerVolume):
+
+ def setUp(self):
+ super(TestServerRemoveVolume, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server.RemoveServerVolume(self.app, None)
+
+ def test_server_remove_volume(self):
+ arglist = [
+ self.servers[0].id,
+ self.volumes[0].id,
+ ]
+
+ verifylist = [
+ ('server', self.servers[0].id),
+ ('volume', self.volumes[0].id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.assertIsNone(result)
+ self.sdk_client.delete_volume_attachment.assert_called_once_with(
+ self.volumes[0],
+ self.servers[0],
+ ignore_missing=False,
+ )
+
+
class TestServerAddNetwork(TestServer):
def setUp(self):
@@ -966,7 +1250,7 @@ class TestServerAddNetwork(TestServer):
self.app.client_manager.network.find_network = self.find_network
def _test_server_add_network(self, net_id):
- servers = self.setup_servers_mock(count=1)
+ servers = self.setup_sdk_servers_mock(count=1)
network = 'fake-network'
arglist = [
@@ -981,8 +1265,8 @@ class TestServerAddNetwork(TestServer):
result = self.cmd.take_action(parsed_args)
- servers[0].interface_attach.assert_called_once_with(
- port_id=None, net_id=net_id, fixed_ip=None)
+ self.sdk_client.create_server_interface.assert_called_once_with(
+ servers[0], net_id=net_id, fixed_ip=None)
self.assertIsNone(result)
def test_server_add_network(self):
@@ -995,11 +1279,12 @@ class TestServerAddNetwork(TestServer):
self._test_server_add_network('fake-network')
self.find_network.assert_not_called()
- def test_server_add_network_with_tag(self):
+ @mock.patch.object(sdk_utils, 'supports_microversion', return_value=True)
+ def test_server_add_network_with_tag(self, sm_mock):
self.app.client_manager.compute.api_version = api_versions.APIVersion(
'2.49')
- servers = self.setup_servers_mock(count=1)
+ servers = self.setup_sdk_servers_mock(count=1)
self.find_network.return_value.id = 'fake-network'
arglist = [
@@ -1017,18 +1302,19 @@ class TestServerAddNetwork(TestServer):
result = self.cmd.take_action(parsed_args)
self.assertIsNone(result)
- servers[0].interface_attach.assert_called_once_with(
- port_id=None,
+ self.sdk_client.create_server_interface.assert_called_once_with(
+ servers[0],
net_id='fake-network',
fixed_ip=None,
tag='tag1'
)
- def test_server_add_network_with_tag_pre_v249(self):
+ @mock.patch.object(sdk_utils, 'supports_microversion', return_value=False)
+ def test_server_add_network_with_tag_pre_v249(self, sm_mock):
self.app.client_manager.compute.api_version = api_versions.APIVersion(
'2.48')
- servers = self.setup_servers_mock(count=1)
+ servers = self.setup_sdk_servers_mock(count=1)
self.find_network.return_value.id = 'fake-network'
arglist = [
@@ -1144,7 +1430,7 @@ class TestServerCreate(TestServer):
self.servers_mock.create.return_value = self.new_server
- self.image = image_fakes.FakeImage.create_one_image()
+ self.image = image_fakes.create_one_image()
self.find_image_mock.return_value = self.image
self.get_image_mock.return_value = self.image
@@ -2894,7 +3180,7 @@ class TestServerCreate(TestServer):
'hypervisor_type': 'qemu',
}
- _image = image_fakes.FakeImage.create_one_image(image_info)
+ _image = image_fakes.create_one_image(image_info)
self.images_mock.return_value = [_image]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -2950,7 +3236,7 @@ class TestServerCreate(TestServer):
'hypervisor_type': 'qemu',
'hw_disk_bus': 'ide',
}
- _image = image_fakes.FakeImage.create_one_image(image_info)
+ _image = image_fakes.create_one_image(image_info)
self.images_mock.return_value = [_image]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -3007,7 +3293,7 @@ class TestServerCreate(TestServer):
'hw_disk_bus': 'ide',
}
- _image = image_fakes.FakeImage.create_one_image(image_info)
+ _image = image_fakes.create_one_image(image_info)
self.images_mock.return_value = [_image]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -3039,8 +3325,8 @@ class TestServerCreate(TestServer):
}
}
- target_image = image_fakes.FakeImage.create_one_image(image_info)
- another_image = image_fakes.FakeImage.create_one_image({})
+ target_image = image_fakes.create_one_image(image_info)
+ another_image = image_fakes.create_one_image({})
self.images_mock.return_value = [target_image, another_image]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -4004,7 +4290,7 @@ class TestServerDumpCreate(TestServer):
self.run_method_with_servers('trigger_crash_dump', 3)
-class TestServerList(TestServer):
+class _TestServerList(TestServer):
# Columns to be listed up.
columns = (
@@ -4032,7 +4318,7 @@ class TestServerList(TestServer):
)
def setUp(self):
- super(TestServerList, self).setUp()
+ super(_TestServerList, self).setUp()
self.search_opts = {
'reservation_id': None,
@@ -4071,14 +4357,14 @@ class TestServerList(TestServer):
},
'OS-EXT-AZ:availability_zone': 'availability-zone-xxx',
'OS-EXT-SRV-ATTR:host': 'host-name-xxx',
- 'Metadata': '',
+ 'Metadata': format_columns.DictColumn({}),
}
# The servers to be listed.
self.servers = self.setup_servers_mock(3)
self.servers_mock.list.return_value = self.servers
- self.image = image_fakes.FakeImage.create_one_image()
+ self.image = image_fakes.create_one_image()
# self.images_mock.return_value = [self.image]
self.find_image_mock.return_value = self.image
@@ -4090,10 +4376,11 @@ class TestServerList(TestServer):
# Get the command object to test
self.cmd = server.ListServer(self.app, None)
- # Prepare data returned by fake Nova API.
- self.data = []
- self.data_long = []
- self.data_no_name_lookup = []
+
+class TestServerList(_TestServerList):
+
+ def setUp(self):
+ super(TestServerList, self).setUp()
Image = collections.namedtuple('Image', 'id name')
self.images_mock.return_value = [
@@ -4108,8 +4395,8 @@ class TestServerList(TestServer):
for s in self.servers
]
- for s in self.servers:
- self.data.append((
+ self.data = tuple(
+ (
s.id,
s.name,
s.status,
@@ -4117,34 +4404,8 @@ class TestServerList(TestServer):
# Image will be an empty string if boot-from-volume
self.image.name if s.image else server.IMAGE_STRING_FOR_BFV,
self.flavor.name,
- ))
- self.data_long.append((
- s.id,
- s.name,
- s.status,
- getattr(s, 'OS-EXT-STS:task_state'),
- server.PowerStateColumn(
- getattr(s, 'OS-EXT-STS:power_state')
- ),
- format_columns.DictListColumn(s.networks),
- # Image will be an empty string if boot-from-volume
- self.image.name if s.image else server.IMAGE_STRING_FOR_BFV,
- s.image['id'] if s.image else server.IMAGE_STRING_FOR_BFV,
- self.flavor.name,
- s.flavor['id'],
- getattr(s, 'OS-EXT-AZ:availability_zone'),
- getattr(s, 'OS-EXT-SRV-ATTR:host'),
- format_columns.DictColumn({}),
- ))
- self.data_no_name_lookup.append((
- s.id,
- s.name,
- s.status,
- format_columns.DictListColumn(s.networks),
- # Image will be an empty string if boot-from-volume
- s.image['id'] if s.image else server.IMAGE_STRING_FOR_BFV,
- s.flavor['id']
- ))
+ ) for s in self.servers
+ )
def test_server_list_no_option(self):
arglist = []
@@ -4165,7 +4426,7 @@ class TestServerList(TestServer):
self.assertFalse(self.flavors_mock.get.call_count)
self.assertFalse(self.get_image_mock.call_count)
self.assertEqual(self.columns, columns)
- self.assertEqual(tuple(self.data), tuple(data))
+ self.assertEqual(self.data, tuple(data))
def test_server_list_no_servers(self):
arglist = []
@@ -4184,9 +4445,28 @@ class TestServerList(TestServer):
self.assertEqual(0, self.images_mock.list.call_count)
self.assertEqual(0, self.flavors_mock.list.call_count)
self.assertEqual(self.columns, columns)
- self.assertEqual(tuple(self.data), tuple(data))
+ self.assertEqual(self.data, tuple(data))
def test_server_list_long_option(self):
+ self.data = tuple(
+ (
+ s.id,
+ s.name,
+ s.status,
+ getattr(s, 'OS-EXT-STS:task_state'),
+ server.PowerStateColumn(
+ getattr(s, 'OS-EXT-STS:power_state')
+ ),
+ format_columns.DictListColumn(s.networks),
+ # Image will be an empty string if boot-from-volume
+ self.image.name if s.image else server.IMAGE_STRING_FOR_BFV,
+ s.image['id'] if s.image else server.IMAGE_STRING_FOR_BFV,
+ self.flavor.name,
+ s.flavor['id'],
+ getattr(s, 'OS-EXT-AZ:availability_zone'),
+ getattr(s, 'OS-EXT-SRV-ATTR:host'),
+ s.Metadata,
+ ) for s in self.servers)
arglist = [
'--long',
]
@@ -4197,10 +4477,9 @@ class TestServerList(TestServer):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
-
self.servers_mock.list.assert_called_with(**self.kwargs)
self.assertEqual(self.columns_long, columns)
- self.assertCountEqual(tuple(self.data_long), tuple(data))
+ self.assertEqual(self.data, tuple(data))
def test_server_list_column_option(self):
arglist = [
@@ -4222,6 +4501,18 @@ class TestServerList(TestServer):
self.assertIn('Created At', columns)
def test_server_list_no_name_lookup_option(self):
+ self.data = tuple(
+ (
+ s.id,
+ s.name,
+ s.status,
+ format_columns.DictListColumn(s.networks),
+ # Image will be an empty string if boot-from-volume
+ s.image['id'] if s.image else server.IMAGE_STRING_FOR_BFV,
+ s.flavor['id']
+ ) for s in self.servers
+ )
+
arglist = [
'--no-name-lookup',
]
@@ -4235,9 +4526,21 @@ class TestServerList(TestServer):
self.servers_mock.list.assert_called_with(**self.kwargs)
self.assertEqual(self.columns, columns)
- self.assertEqual(tuple(self.data_no_name_lookup), tuple(data))
+ self.assertEqual(self.data, tuple(data))
def test_server_list_n_option(self):
+ self.data = tuple(
+ (
+ s.id,
+ s.name,
+ s.status,
+ format_columns.DictListColumn(s.networks),
+ # Image will be an empty string if boot-from-volume
+ s.image['id'] if s.image else server.IMAGE_STRING_FOR_BFV,
+ s.flavor['id']
+ ) for s in self.servers
+ )
+
arglist = [
'-n',
]
@@ -4251,7 +4554,7 @@ class TestServerList(TestServer):
self.servers_mock.list.assert_called_with(**self.kwargs)
self.assertEqual(self.columns, columns)
- self.assertEqual(tuple(self.data_no_name_lookup), tuple(data))
+ self.assertEqual(self.data, tuple(data))
def test_server_list_name_lookup_one_by_one(self):
arglist = [
@@ -4273,7 +4576,7 @@ class TestServerList(TestServer):
self.flavors_mock.get.assert_called()
self.assertEqual(self.columns, columns)
- self.assertEqual(tuple(self.data), tuple(data))
+ self.assertEqual(self.data, tuple(data))
def test_server_list_with_image(self):
@@ -4294,81 +4597,7 @@ class TestServerList(TestServer):
self.servers_mock.list.assert_called_with(**self.kwargs)
self.assertEqual(self.columns, columns)
- self.assertEqual(tuple(self.data), tuple(data))
-
- def test_server_list_with_locked_pre_v273(self):
-
- arglist = [
- '--locked'
- ]
- verifylist = [
- ('locked', True)
- ]
-
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- ex = self.assertRaises(exceptions.CommandError,
- self.cmd.take_action,
- parsed_args)
- self.assertIn(
- '--os-compute-api-version 2.73 or greater is required', str(ex))
-
- def test_server_list_with_locked_v273(self):
-
- self.app.client_manager.compute.api_version = \
- api_versions.APIVersion('2.73')
- arglist = [
- '--locked'
- ]
- verifylist = [
- ('locked', True)
- ]
-
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- columns, data = self.cmd.take_action(parsed_args)
-
- self.search_opts['locked'] = True
- self.servers_mock.list.assert_called_with(**self.kwargs)
-
- self.assertEqual(self.columns, columns)
- self.assertEqual(tuple(self.data), tuple(data))
-
- def test_server_list_with_unlocked_v273(self):
-
- self.app.client_manager.compute.api_version = \
- api_versions.APIVersion('2.73')
- arglist = [
- '--unlocked'
- ]
- verifylist = [
- ('unlocked', True)
- ]
-
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- columns, data = self.cmd.take_action(parsed_args)
-
- self.search_opts['locked'] = False
- self.servers_mock.list.assert_called_with(**self.kwargs)
-
- self.assertEqual(self.columns, columns)
- self.assertEqual(tuple(self.data), tuple(data))
-
- def test_server_list_with_locked_and_unlocked_v273(self):
-
- self.app.client_manager.compute.api_version = \
- api_versions.APIVersion('2.73')
- arglist = [
- '--locked',
- '--unlocked'
- ]
- verifylist = [
- ('locked', True),
- ('unlocked', True)
- ]
-
- ex = self.assertRaises(
- utils.ParserException,
- self.check_parser, self.cmd, arglist, verifylist)
- self.assertIn('Argument parse failed', str(ex))
+ self.assertEqual(self.data, tuple(data))
def test_server_list_with_flavor(self):
@@ -4388,7 +4617,7 @@ class TestServerList(TestServer):
self.servers_mock.list.assert_called_with(**self.kwargs)
self.assertEqual(self.columns, columns)
- self.assertEqual(tuple(self.data), tuple(data))
+ self.assertEqual(self.data, tuple(data))
def test_server_list_with_changes_since(self):
@@ -4409,7 +4638,7 @@ class TestServerList(TestServer):
self.servers_mock.list.assert_called_with(**self.kwargs)
self.assertEqual(self.columns, columns)
- self.assertEqual(tuple(self.data), tuple(data))
+ self.assertEqual(self.data, tuple(data))
@mock.patch.object(iso8601, 'parse_date', side_effect=iso8601.ParseError)
def test_server_list_with_invalid_changes_since(self, mock_parse_isotime):
@@ -4432,123 +4661,6 @@ class TestServerList(TestServer):
'Invalid time value'
)
- def test_server_list_v266_with_changes_before(self):
- self.app.client_manager.compute.api_version = (
- api_versions.APIVersion('2.66'))
- arglist = [
- '--changes-before', '2016-03-05T06:27:59Z',
- '--deleted'
- ]
- verifylist = [
- ('changes_before', '2016-03-05T06:27:59Z'),
- ('deleted', True),
- ]
-
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- columns, data = self.cmd.take_action(parsed_args)
-
- self.search_opts['changes-before'] = '2016-03-05T06:27:59Z'
- self.search_opts['deleted'] = True
-
- self.servers_mock.list.assert_called_with(**self.kwargs)
-
- self.assertEqual(self.columns, columns)
- self.assertEqual(tuple(self.data), tuple(data))
-
- @mock.patch.object(iso8601, 'parse_date', side_effect=iso8601.ParseError)
- def test_server_list_v266_with_invalid_changes_before(
- self, mock_parse_isotime):
- self.app.client_manager.compute.api_version = (
- api_versions.APIVersion('2.66'))
-
- arglist = [
- '--changes-before', 'Invalid time value',
- ]
- verifylist = [
- ('changes_before', 'Invalid time value'),
- ]
-
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- try:
- self.cmd.take_action(parsed_args)
- self.fail('CommandError should be raised.')
- except exceptions.CommandError as e:
- self.assertEqual('Invalid changes-before value: Invalid time '
- 'value', str(e))
- mock_parse_isotime.assert_called_once_with(
- 'Invalid time value'
- )
-
- def test_server_with_changes_before_pre_v266(self):
- self.app.client_manager.compute.api_version = (
- api_versions.APIVersion('2.65'))
-
- arglist = [
- '--changes-before', '2016-03-05T06:27:59Z',
- '--deleted'
- ]
- verifylist = [
- ('changes_before', '2016-03-05T06:27:59Z'),
- ('deleted', True),
- ]
-
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
-
- self.assertRaises(exceptions.CommandError,
- self.cmd.take_action,
- parsed_args)
-
- def test_server_list_v269_with_partial_constructs(self):
- self.app.client_manager.compute.api_version = \
- api_versions.APIVersion('2.69')
-
- arglist = []
- verifylist = []
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
-
- # include "partial results" from non-responsive part of
- # infrastructure.
- server_dict = {
- "id": "server-id-95a56bfc4xxxxxx28d7e418bfd97813a",
- "status": "UNKNOWN",
- "tenant_id": "6f70656e737461636b20342065766572",
- "created": "2018-12-03T21:06:18Z",
- "links": [
- {
- "href": "http://fake/v2.1/",
- "rel": "self"
- },
- {
- "href": "http://fake",
- "rel": "bookmark"
- }
- ],
- # We need to pass networks as {} because its defined as a property
- # of the novaclient Server class which gives {} by default. If not
- # it will fail at formatting the networks info later on.
- "networks": {}
- }
- _server = compute_fakes.fakes.FakeResource(
- info=server_dict,
- )
- self.servers.append(_server)
- columns, data = self.cmd.take_action(parsed_args)
- # get the first three servers out since our interest is in the partial
- # server.
- next(data)
- next(data)
- next(data)
- partial_server = next(data)
- expected_row = (
- 'server-id-95a56bfc4xxxxxx28d7e418bfd97813a',
- '',
- 'UNKNOWN',
- format_columns.DictListColumn({}),
- '',
- '',
- )
- self.assertEqual(expected_row, partial_server)
-
def test_server_list_with_tag(self):
self.app.client_manager.compute.api_version = api_versions.APIVersion(
'2.26')
@@ -4569,7 +4681,7 @@ class TestServerList(TestServer):
self.servers_mock.list.assert_called_with(**self.kwargs)
self.assertEqual(self.columns, columns)
- self.assertEqual(tuple(self.data), tuple(data))
+ self.assertEqual(self.data, tuple(data))
def test_server_list_with_tag_pre_v225(self):
self.app.client_manager.compute.api_version = api_versions.APIVersion(
@@ -4612,7 +4724,7 @@ class TestServerList(TestServer):
self.servers_mock.list.assert_called_with(**self.kwargs)
self.assertEqual(self.columns, columns)
- self.assertEqual(tuple(self.data), tuple(data))
+ self.assertEqual(self.data, tuple(data))
def test_server_list_with_not_tag_pre_v226(self):
self.app.client_manager.compute.api_version = api_versions.APIVersion(
@@ -4773,6 +4885,258 @@ class TestServerList(TestServer):
self.assertEqual(tuple(self.data), tuple(data))
+class TestServerListV273(_TestServerList):
+
+ # Columns to be listed up.
+ columns = (
+ 'ID',
+ 'Name',
+ 'Status',
+ 'Networks',
+ 'Image',
+ 'Flavor',
+ )
+ columns_long = (
+ 'ID',
+ 'Name',
+ 'Status',
+ 'Task State',
+ 'Power State',
+ 'Networks',
+ 'Image Name',
+ 'Image ID',
+ 'Flavor',
+ 'Availability Zone',
+ 'Host',
+ 'Properties',
+ )
+
+ def setUp(self):
+ super(TestServerListV273, self).setUp()
+
+ # The fake servers' attributes. Use the original attributes names in
+ # nova, not the ones printed by "server list" command.
+ self.attrs['flavor'] = {
+ 'vcpus': self.flavor.vcpus,
+ 'ram': self.flavor.ram,
+ 'disk': self.flavor.disk,
+ 'ephemeral': self.flavor.ephemeral,
+ 'swap': self.flavor.swap,
+ 'original_name': self.flavor.name,
+ 'extra_specs': self.flavor.extra_specs,
+ }
+
+ # The servers to be listed.
+ self.servers = self.setup_servers_mock(3)
+ self.servers_mock.list.return_value = self.servers
+
+ Image = collections.namedtuple('Image', 'id name')
+ self.images_mock.return_value = [
+ Image(id=s.image['id'], name=self.image.name)
+ # Image will be an empty string if boot-from-volume
+ for s in self.servers if s.image
+ ]
+
+ # The flavor information is embedded, so now reason for this to be
+ # called
+ self.flavors_mock.list = mock.NonCallableMock()
+
+ self.data = tuple(
+ (
+ s.id,
+ s.name,
+ s.status,
+ format_columns.DictListColumn(s.networks),
+ # Image will be an empty string if boot-from-volume
+ self.image.name if s.image else server.IMAGE_STRING_FOR_BFV,
+ self.flavor.name,
+ ) for s in self.servers)
+
+ def test_server_list_with_locked_pre_v273(self):
+
+ arglist = [
+ '--locked'
+ ]
+ verifylist = [
+ ('locked', True)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ ex = self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+ self.assertIn(
+ '--os-compute-api-version 2.73 or greater is required', str(ex))
+
+ def test_server_list_with_locked(self):
+
+ self.app.client_manager.compute.api_version = \
+ api_versions.APIVersion('2.73')
+ arglist = [
+ '--locked'
+ ]
+ verifylist = [
+ ('locked', True)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.search_opts['locked'] = True
+ self.servers_mock.list.assert_called_with(**self.kwargs)
+
+ self.assertItemsEqual(self.columns, columns)
+ self.assertItemsEqual(self.data, tuple(data))
+
+ def test_server_list_with_unlocked_v273(self):
+
+ self.app.client_manager.compute.api_version = \
+ api_versions.APIVersion('2.73')
+ arglist = [
+ '--unlocked'
+ ]
+ verifylist = [
+ ('unlocked', True)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.search_opts['locked'] = False
+ self.servers_mock.list.assert_called_with(**self.kwargs)
+
+ self.assertItemsEqual(self.columns, columns)
+ self.assertItemsEqual(self.data, tuple(data))
+
+ def test_server_list_with_locked_and_unlocked(self):
+
+ self.app.client_manager.compute.api_version = \
+ api_versions.APIVersion('2.73')
+ arglist = [
+ '--locked',
+ '--unlocked'
+ ]
+ verifylist = [
+ ('locked', True),
+ ('unlocked', True)
+ ]
+
+ ex = self.assertRaises(
+ utils.ParserException,
+ self.check_parser, self.cmd, arglist, verifylist)
+ self.assertIn('Argument parse failed', str(ex))
+
+ def test_server_list_with_changes_before(self):
+ self.app.client_manager.compute.api_version = (
+ api_versions.APIVersion('2.66'))
+ arglist = [
+ '--changes-before', '2016-03-05T06:27:59Z',
+ '--deleted'
+ ]
+ verifylist = [
+ ('changes_before', '2016-03-05T06:27:59Z'),
+ ('deleted', True),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.search_opts['changes-before'] = '2016-03-05T06:27:59Z'
+ self.search_opts['deleted'] = True
+
+ self.servers_mock.list.assert_called_with(**self.kwargs)
+
+ self.assertItemsEqual(self.columns, columns)
+ self.assertItemsEqual(self.data, tuple(data))
+
+ @mock.patch.object(iso8601, 'parse_date', side_effect=iso8601.ParseError)
+ def test_server_list_with_invalid_changes_before(
+ self, mock_parse_isotime):
+ self.app.client_manager.compute.api_version = (
+ api_versions.APIVersion('2.66'))
+
+ arglist = [
+ '--changes-before', 'Invalid time value',
+ ]
+ verifylist = [
+ ('changes_before', 'Invalid time value'),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('Invalid changes-before value: Invalid time '
+ 'value', str(e))
+ mock_parse_isotime.assert_called_once_with(
+ 'Invalid time value'
+ )
+
+ def test_server_with_changes_before_pre_v266(self):
+ self.app.client_manager.compute.api_version = (
+ api_versions.APIVersion('2.65'))
+
+ arglist = [
+ '--changes-before', '2016-03-05T06:27:59Z',
+ '--deleted'
+ ]
+ verifylist = [
+ ('changes_before', '2016-03-05T06:27:59Z'),
+ ('deleted', True),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+
+ def test_server_list_v269_with_partial_constructs(self):
+ self.app.client_manager.compute.api_version = \
+ api_versions.APIVersion('2.69')
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ # include "partial results" from non-responsive part of
+ # infrastructure.
+ server_dict = {
+ "id": "server-id-95a56bfc4xxxxxx28d7e418bfd97813a",
+ "status": "UNKNOWN",
+ "tenant_id": "6f70656e737461636b20342065766572",
+ "created": "2018-12-03T21:06:18Z",
+ "links": [
+ {
+ "href": "http://fake/v2.1/",
+ "rel": "self"
+ },
+ {
+ "href": "http://fake",
+ "rel": "bookmark"
+ }
+ ],
+ # We need to pass networks as {} because its defined as a property
+ # of the novaclient Server class which gives {} by default. If not
+ # it will fail at formatting the networks info later on.
+ "networks": {}
+ }
+ server = compute_fakes.fakes.FakeResource(
+ info=server_dict,
+ )
+ self.servers.append(server)
+ columns, data = self.cmd.take_action(parsed_args)
+ # get the first three servers out since our interest is in the partial
+ # server.
+ next(data)
+ next(data)
+ next(data)
+ partial_server = next(data)
+ expected_row = (
+ 'server-id-95a56bfc4xxxxxx28d7e418bfd97813a', '',
+ 'UNKNOWN', format_columns.DictListColumn({}), '', '')
+ self.assertEqual(expected_row, partial_server)
+
+
class TestServerLock(TestServer):
def setUp(self):
@@ -4887,7 +5251,7 @@ class TestServerMigrate(TestServer):
verifylist = [
('live_migration', False),
('block_migration', None),
- ('disk_overcommit', False),
+ ('disk_overcommit', None),
('wait', False),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -4909,7 +5273,7 @@ class TestServerMigrate(TestServer):
('live_migration', False),
('host', 'fakehost'),
('block_migration', None),
- ('disk_overcommit', False),
+ ('disk_overcommit', None),
('wait', False),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -4931,7 +5295,7 @@ class TestServerMigrate(TestServer):
verifylist = [
('live_migration', False),
('block_migration', True),
- ('disk_overcommit', False),
+ ('disk_overcommit', None),
('wait', False),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -4962,7 +5326,7 @@ class TestServerMigrate(TestServer):
self.assertNotCalled(self.servers_mock.live_migrate)
self.assertNotCalled(self.servers_mock.migrate)
- def test_server_migrate_with_host_pre_2_56(self):
+ def test_server_migrate_with_host_pre_v256(self):
# Tests that --host is not allowed for a cold migration
# before microversion 2.56 (the test defaults to 2.1).
arglist = [
@@ -4972,7 +5336,7 @@ class TestServerMigrate(TestServer):
('live_migration', False),
('host', 'fakehost'),
('block_migration', None),
- ('disk_overcommit', False),
+ ('disk_overcommit', None),
('wait', False),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -4998,7 +5362,7 @@ class TestServerMigrate(TestServer):
('live_migration', True),
('host', None),
('block_migration', None),
- ('disk_overcommit', False),
+ ('disk_overcommit', None),
('wait', False),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -5022,7 +5386,7 @@ class TestServerMigrate(TestServer):
('live_migration', True),
('host', 'fakehost'),
('block_migration', None),
- ('disk_overcommit', False),
+ ('disk_overcommit', None),
('wait', False),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -5050,7 +5414,7 @@ class TestServerMigrate(TestServer):
('live_migration', True),
('host', 'fakehost'),
('block_migration', None),
- ('disk_overcommit', False),
+ ('disk_overcommit', None),
('wait', False),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -5077,7 +5441,7 @@ class TestServerMigrate(TestServer):
verifylist = [
('live_migration', True),
('block_migration', True),
- ('disk_overcommit', False),
+ ('disk_overcommit', None),
('wait', False),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -5163,7 +5527,7 @@ class TestServerMigrate(TestServer):
verifylist = [
('live_migration', False),
('block_migration', None),
- ('disk_overcommit', False),
+ ('disk_overcommit', None),
('wait', True),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -5183,7 +5547,7 @@ class TestServerMigrate(TestServer):
verifylist = [
('live_migration', False),
('block_migration', None),
- ('disk_overcommit', False),
+ ('disk_overcommit', None),
('wait', True),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -5985,10 +6349,10 @@ class TestServerPause(TestServer):
}
def test_server_pause_one_server(self):
- self.run_method_with_servers('pause', 1)
+ self.run_method_with_sdk_servers('pause_server', 1)
def test_server_pause_multi_servers(self):
- self.run_method_with_servers('pause', 3)
+ self.run_method_with_sdk_servers('pause_server', 3)
class TestServerRebuild(TestServer):
@@ -5997,7 +6361,7 @@ class TestServerRebuild(TestServer):
super(TestServerRebuild, self).setUp()
# Return value for utils.find_resource for image
- self.image = image_fakes.FakeImage.create_one_image()
+ self.image = image_fakes.create_one_image()
self.get_image_mock.return_value = self.image
# Fake the rebuilt new server.
@@ -6027,7 +6391,7 @@ class TestServerRebuild(TestServer):
def test_rebuild_with_image_name(self):
image_name = 'my-custom-image'
- user_image = image_fakes.FakeImage.create_one_image(
+ user_image = image_fakes.create_one_image(
attrs={'name': image_name})
self.find_image_mock.return_value = user_image
@@ -6379,7 +6743,7 @@ class TestServerRebuild(TestServer):
self.image, None,
userdata=mock_file,)
- def test_rebuild_with_user_data_pre_257(self):
+ def test_rebuild_with_user_data_pre_v257(self):
self.app.client_manager.compute.api_version = \
api_versions.APIVersion('2.56')
@@ -6419,7 +6783,7 @@ class TestServerRebuild(TestServer):
self.server.rebuild.assert_called_with(
self.image, None, userdata=None)
- def test_rebuild_with_no_user_data_pre_254(self):
+ def test_rebuild_with_no_user_data_pre_v254(self):
self.app.client_manager.compute.api_version = \
api_versions.APIVersion('2.53')
@@ -6511,7 +6875,7 @@ class TestServerRebuild(TestServer):
self.server.rebuild.assert_called_with(
self.image, None, trusted_image_certificates=None)
- def test_rebuild_with_no_trusted_image_cert_pre_257(self):
+ def test_rebuild_with_no_trusted_image_cert_pre_v263(self):
self.app.client_manager.compute.api_version = \
api_versions.APIVersion('2.62')
@@ -6576,7 +6940,7 @@ class TestEvacuateServer(TestServer):
def setUp(self):
super(TestEvacuateServer, self).setUp()
# Return value for utils.find_resource for image
- self.image = image_fakes.FakeImage.create_one_image()
+ self.image = image_fakes.create_one_image()
self.images_mock.get.return_value = self.image
# Fake the rebuilt new server.
@@ -6770,7 +7134,7 @@ class TestServerRescue(TestServer):
super(TestServerRescue, self).setUp()
# Return value for utils.find_resource for image
- self.image = image_fakes.FakeImage.create_one_image()
+ self.image = image_fakes.create_one_image()
self.get_image_mock.return_value = self.image
new_server = compute_fakes.FakeServer.create_one_server()
@@ -6811,7 +7175,7 @@ class TestServerRescue(TestServer):
self.server.rescue.assert_called_with(image=None, password=None)
def test_rescue_with_new_image(self):
- new_image = image_fakes.FakeImage.create_one_image()
+ new_image = image_fakes.create_one_image()
self.find_image_mock.return_value = new_image
arglist = [
'--image', new_image.id,
@@ -6935,14 +7299,14 @@ class TestServerRemovePort(TestServer):
# Set method to be tested.
self.methods = {
- 'interface_detach': None,
+ 'delete_server_interface': None,
}
self.find_port = mock.Mock()
self.app.client_manager.network.find_port = self.find_port
def _test_server_remove_port(self, port_id):
- servers = self.setup_servers_mock(count=1)
+ servers = self.setup_sdk_servers_mock(count=1)
port = 'fake-port'
arglist = [
@@ -6957,7 +7321,8 @@ class TestServerRemovePort(TestServer):
result = self.cmd.take_action(parsed_args)
- servers[0].interface_detach.assert_called_once_with(port_id)
+ self.sdk_client.delete_server_interface.assert_called_with(
+ port_id, server=servers[0], ignore_missing=False)
self.assertIsNone(result)
def test_server_remove_port(self):
@@ -6982,17 +7347,18 @@ class TestServerRemoveNetwork(TestServer):
# Set method to be tested.
self.fake_inf = mock.Mock()
self.methods = {
- 'interface_list': [self.fake_inf],
- 'interface_detach': None,
+ 'server_interfaces': [self.fake_inf],
+ 'delete_server_interface': None,
}
self.find_network = mock.Mock()
self.app.client_manager.network.find_network = self.find_network
+ self.sdk_client.server_interfaces.return_value = [self.fake_inf]
def _test_server_remove_network(self, network_id):
self.fake_inf.net_id = network_id
self.fake_inf.port_id = 'fake-port'
- servers = self.setup_servers_mock(count=1)
+ servers = self.setup_sdk_servers_mock(count=1)
network = 'fake-network'
arglist = [
@@ -7007,8 +7373,9 @@ class TestServerRemoveNetwork(TestServer):
result = self.cmd.take_action(parsed_args)
- servers[0].interface_list.assert_called_once_with()
- servers[0].interface_detach.assert_called_once_with('fake-port')
+ self.sdk_client.server_interfaces.assert_called_once_with(servers[0])
+ self.sdk_client.delete_server_interface.assert_called_once_with(
+ 'fake-port', server=servers[0])
self.assertIsNone(result)
def test_server_remove_network(self):
@@ -7524,10 +7891,10 @@ class TestServerResume(TestServer):
}
def test_server_resume_one_server(self):
- self.run_method_with_servers('resume', 1)
+ self.run_method_with_sdk_servers('resume_server', 1)
def test_server_resume_multi_servers(self):
- self.run_method_with_servers('resume', 3)
+ self.run_method_with_sdk_servers('resume_server', 3)
class TestServerSet(TestServer):
@@ -7926,7 +8293,7 @@ class TestServerShow(TestServer):
def setUp(self):
super(TestServerShow, self).setUp()
- self.image = image_fakes.FakeImage.create_one_image()
+ self.image = image_fakes.create_one_image()
self.flavor = compute_fakes.FakeFlavor.create_one_flavor()
self.topology = {
'nodes': [{'vcpu_set': [0, 1]}, {'vcpu_set': [2, 3]}],
@@ -8093,6 +8460,123 @@ class TestServerShow(TestServer):
exceptions.CommandError, self.cmd.take_action, parsed_args)
+@mock.patch('openstackclient.compute.v2.server.os.system')
+class TestServerSsh(TestServer):
+
+ def setUp(self):
+ super().setUp()
+
+ self.cmd = server.SshServer(self.app, None)
+
+ self.app.client_manager.auth_ref = mock.Mock()
+ self.app.client_manager.auth_ref.username = 'cloud'
+
+ self.attrs = {
+ 'addresses': {
+ 'public': [
+ {
+ 'addr': '192.168.1.30',
+ 'OS-EXT-IPS-MAC:mac_addr': '00:0c:29:0d:11:74',
+ 'OS-EXT-IPS:type': 'fixed',
+ 'version': 4,
+ },
+ ],
+ },
+ }
+ self.server = compute_fakes.FakeServer.create_one_server(
+ attrs=self.attrs, methods=self.methods,
+ )
+ self.servers_mock.get.return_value = self.server
+
+ def test_server_ssh_no_opts(self, mock_exec):
+ arglist = [
+ self.server.name,
+ ]
+ verifylist = [
+ ('server', self.server.name),
+ ('login', None),
+ ('port', None),
+ ('identity', None),
+ ('option', None),
+ ('ipv4', False),
+ ('ipv6', False),
+ ('address_type', 'public'),
+ ('verbose', False),
+ ('ssh_args', []),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ with mock.patch.object(self.cmd.log, 'warning') as mock_warning:
+ result = self.cmd.take_action(parsed_args)
+
+ self.assertIsNone(result)
+ mock_exec.assert_called_once_with('ssh 192.168.1.30 -l cloud')
+ mock_warning.assert_not_called()
+
+ def test_server_ssh_passthrough_opts(self, mock_exec):
+ arglist = [
+ self.server.name,
+ '--',
+ '-l', 'username',
+ '-p', '2222',
+ ]
+ verifylist = [
+ ('server', self.server.name),
+ ('login', None),
+ ('port', None),
+ ('identity', None),
+ ('option', None),
+ ('ipv4', False),
+ ('ipv6', False),
+ ('address_type', 'public'),
+ ('verbose', False),
+ ('ssh_args', ['-l', 'username', '-p', '2222']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ with mock.patch.object(self.cmd.log, 'warning') as mock_warning:
+ result = self.cmd.take_action(parsed_args)
+
+ self.assertIsNone(result)
+ mock_exec.assert_called_once_with(
+ 'ssh 192.168.1.30 -l username -p 2222'
+ )
+ mock_warning.assert_not_called()
+
+ def test_server_ssh_deprecated_opts(self, mock_exec):
+ arglist = [
+ self.server.name,
+ '-l', 'username',
+ '-p', '2222',
+ ]
+ verifylist = [
+ ('server', self.server.name),
+ ('login', 'username'),
+ ('port', 2222),
+ ('identity', None),
+ ('option', None),
+ ('ipv4', False),
+ ('ipv6', False),
+ ('address_type', 'public'),
+ ('verbose', False),
+ ('ssh_args', []),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ with mock.patch.object(self.cmd.log, 'warning') as mock_warning:
+ result = self.cmd.take_action(parsed_args)
+
+ self.assertIsNone(result)
+ mock_exec.assert_called_once_with(
+ 'ssh 192.168.1.30 -p 2222 -l username'
+ )
+ mock_warning.assert_called_once()
+ self.assertIn(
+ 'The ssh options have been deprecated.',
+ mock_warning.call_args[0][0],
+ )
+
+
class TestServerStart(TestServer):
def setUp(self):
@@ -8191,10 +8675,10 @@ class TestServerSuspend(TestServer):
}
def test_server_suspend_one_server(self):
- self.run_method_with_servers('suspend', 1)
+ self.run_method_with_sdk_servers('suspend_server', 1)
def test_server_suspend_multi_servers(self):
- self.run_method_with_servers('suspend', 3)
+ self.run_method_with_sdk_servers('suspend_server', 3)
class TestServerUnlock(TestServer):
@@ -8231,10 +8715,10 @@ class TestServerUnpause(TestServer):
}
def test_server_unpause_one_server(self):
- self.run_method_with_servers('unpause', 1)
+ self.run_method_with_sdk_servers('unpause_server', 1)
def test_server_unpause_multi_servers(self):
- self.run_method_with_servers('unpause', 3)
+ self.run_method_with_sdk_servers('unpause_server', 3)
class TestServerUnset(TestServer):
@@ -8516,7 +9000,7 @@ class TestServerGeneral(TestServer):
# - The first time, return server info.
# - The second time, return image info.
# - The third time, return flavor info.
- _image = image_fakes.FakeImage.create_one_image()
+ _image = image_fakes.create_one_image()
_flavor = compute_fakes.FakeFlavor.create_one_flavor()
server_info = {
'image': {u'id': _image.id},
diff --git a/openstackclient/tests/unit/compute/v2/test_server_backup.py b/openstackclient/tests/unit/compute/v2/test_server_backup.py
index 1644baa..1a5e0a1 100644
--- a/openstackclient/tests/unit/compute/v2/test_server_backup.py
+++ b/openstackclient/tests/unit/compute/v2/test_server_backup.py
@@ -91,7 +91,7 @@ class TestServerBackupCreate(TestServerBackup):
def setup_images_mock(self, count, servers=None):
if servers:
- images = image_fakes.FakeImage.create_images(
+ images = image_fakes.create_images(
attrs={
'name': servers[0].name,
'status': 'active',
@@ -99,7 +99,7 @@ class TestServerBackupCreate(TestServerBackup):
count=count,
)
else:
- images = image_fakes.FakeImage.create_images(
+ images = image_fakes.create_images(
attrs={
'status': 'active',
},
@@ -178,15 +178,6 @@ class TestServerBackupCreate(TestServerBackup):
def test_server_backup_wait_fail(self, mock_wait_for_status):
servers = self.setup_servers_mock(count=1)
images = self.setup_images_mock(count=1, servers=servers)
-# images = image_fakes.FakeImage.create_images(
-# attrs={
-# 'name': servers[0].name,
-# 'status': 'active',
-# },
-# count=1,
-# )
-#
-# self.images_mock.find_image.return_value = images[0]
self.images_mock.get_image = mock.Mock(
side_effect=images[0],
)
diff --git a/openstackclient/tests/unit/compute/v2/test_server_image.py b/openstackclient/tests/unit/compute/v2/test_server_image.py
index 9b14428..db0e1d9 100644
--- a/openstackclient/tests/unit/compute/v2/test_server_image.py
+++ b/openstackclient/tests/unit/compute/v2/test_server_image.py
@@ -27,8 +27,9 @@ class TestServerImage(compute_fakes.TestComputev2):
super(TestServerImage, self).setUp()
# Get a shortcut to the compute client ServerManager Mock
- self.servers_mock = self.app.client_manager.compute.servers
- self.servers_mock.reset_mock()
+ self.app.client_manager.sdk_connection = mock.Mock()
+ self.app.client_manager.sdk_connection.compute = mock.Mock()
+ self.sdk_client = self.app.client_manager.sdk_connection.compute
# Get a shortcut to the image client ImageManager Mock
self.images_mock = self.app.client_manager.image
@@ -41,14 +42,14 @@ class TestServerImage(compute_fakes.TestComputev2):
self.methods = {}
def setup_servers_mock(self, count):
- servers = compute_fakes.FakeServer.create_servers(
+ servers = compute_fakes.FakeServer.create_sdk_servers(
attrs=self.attrs,
methods=self.methods,
count=count,
)
- # This is the return value for utils.find_resource()
- self.servers_mock.get = compute_fakes.FakeServer.get_servers(
+ # This is the return value for compute_client.find_server()
+ self.sdk_client.find_server = compute_fakes.FakeServer.get_servers(
servers,
0,
)
@@ -88,7 +89,7 @@ class TestServerImageCreate(TestServerImage):
def setup_images_mock(self, count, servers=None):
if servers:
- images = image_fakes.FakeImage.create_images(
+ images = image_fakes.create_images(
attrs={
'name': servers[0].name,
'status': 'active',
@@ -96,7 +97,7 @@ class TestServerImageCreate(TestServerImage):
count=count,
)
else:
- images = image_fakes.FakeImage.create_images(
+ images = image_fakes.create_images(
attrs={
'status': 'active',
},
@@ -104,8 +105,8 @@ class TestServerImageCreate(TestServerImage):
)
self.images_mock.find_image = mock.Mock(side_effect=images)
- self.servers_mock.create_image = mock.Mock(
- return_value=images[0].id,
+ self.sdk_client.create_server_image = mock.Mock(
+ return_value=images[0],
)
return images
@@ -126,8 +127,7 @@ class TestServerImageCreate(TestServerImage):
# data to be shown.
columns, data = self.cmd.take_action(parsed_args)
- # ServerManager.create_image(server, image_name, metadata=)
- self.servers_mock.create_image.assert_called_with(
+ self.sdk_client.create_server_image.assert_called_with(
servers[0].id,
servers[0].name,
None,
@@ -157,8 +157,7 @@ class TestServerImageCreate(TestServerImage):
# data to be shown.
columns, data = self.cmd.take_action(parsed_args)
- # ServerManager.create_image(server, image_name, metadata=)
- self.servers_mock.create_image.assert_called_with(
+ self.sdk_client.create_server_image.assert_called_with(
servers[0].id,
'img-nam',
{'key': 'value'},
@@ -188,8 +187,7 @@ class TestServerImageCreate(TestServerImage):
parsed_args,
)
- # ServerManager.create_image(server, image_name, metadata=)
- self.servers_mock.create_image.assert_called_with(
+ self.sdk_client.create_server_image.assert_called_with(
servers[0].id,
servers[0].name,
None,
@@ -221,8 +219,7 @@ class TestServerImageCreate(TestServerImage):
# data to be shown.
columns, data = self.cmd.take_action(parsed_args)
- # ServerManager.create_image(server, image_name, metadata=)
- self.servers_mock.create_image.assert_called_with(
+ self.sdk_client.create_server_image.assert_called_with(
servers[0].id,
servers[0].name,
None,
diff --git a/openstackclient/tests/unit/compute/v2/test_service.py b/openstackclient/tests/unit/compute/v2/test_service.py
index c547c3a..5b58431 100644
--- a/openstackclient/tests/unit/compute/v2/test_service.py
+++ b/openstackclient/tests/unit/compute/v2/test_service.py
@@ -17,6 +17,7 @@ from unittest import mock
from unittest.mock import call
from novaclient import api_versions
+from openstack import utils as sdk_utils
from osc_lib import exceptions
from openstackclient.compute.v2 import service
@@ -28,9 +29,9 @@ class TestService(compute_fakes.TestComputev2):
def setUp(self):
super(TestService, self).setUp()
- # Get a shortcut to the ServiceManager Mock
- self.service_mock = self.app.client_manager.compute.services
- self.service_mock.reset_mock()
+ self.app.client_manager.sdk_connection = mock.Mock()
+ self.app.client_manager.sdk_connection.compute = mock.Mock()
+ self.sdk_client = self.app.client_manager.sdk_connection.compute
class TestServiceDelete(TestService):
@@ -40,7 +41,7 @@ class TestServiceDelete(TestService):
def setUp(self):
super(TestServiceDelete, self).setUp()
- self.service_mock.delete.return_value = None
+ self.sdk_client.delete_service.return_value = None
# Get the command object to test
self.cmd = service.DeleteService(self.app, None)
@@ -56,8 +57,9 @@ class TestServiceDelete(TestService):
result = self.cmd.take_action(parsed_args)
- self.service_mock.delete.assert_called_with(
+ self.sdk_client.delete_service.assert_called_with(
self.services[0].binary,
+ ignore_missing=False
)
self.assertIsNone(result)
@@ -74,8 +76,8 @@ class TestServiceDelete(TestService):
calls = []
for s in self.services:
- calls.append(call(s.binary))
- self.service_mock.delete.assert_has_calls(calls)
+ calls.append(call(s.binary, ignore_missing=False))
+ self.sdk_client.delete_service.assert_has_calls(calls)
self.assertIsNone(result)
def test_multi_services_delete_with_exception(self):
@@ -89,7 +91,7 @@ class TestServiceDelete(TestService):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
delete_mock_result = [None, exceptions.CommandError]
- self.service_mock.delete = (
+ self.sdk_client.delete_service = (
mock.Mock(side_effect=delete_mock_result)
)
@@ -100,8 +102,14 @@ class TestServiceDelete(TestService):
self.assertEqual(
'1 of 2 compute services failed to delete.', str(e))
- self.service_mock.delete.assert_any_call(self.services[0].binary)
- self.service_mock.delete.assert_any_call('unexist_service')
+ self.sdk_client.delete_service.assert_any_call(
+ self.services[0].binary,
+ ignore_missing=False
+ )
+ self.sdk_client.delete_service.assert_any_call(
+ 'unexist_service',
+ ignore_missing=False
+ )
class TestServiceList(TestService):
@@ -125,7 +133,7 @@ class TestServiceList(TestService):
service.id,
service.binary,
service.host,
- service.zone,
+ service.availability_zone,
service.status,
service.state,
service.updated_at,
@@ -135,7 +143,7 @@ class TestServiceList(TestService):
def setUp(self):
super(TestServiceList, self).setUp()
- self.service_mock.list.return_value = [self.service]
+ self.sdk_client.services.return_value = [self.service]
# Get the command object to test
self.cmd = service.ListService(self.app, None)
@@ -156,15 +164,18 @@ class TestServiceList(TestService):
# containing the data to be listed.
columns, data = self.cmd.take_action(parsed_args)
- self.service_mock.list.assert_called_with(
- self.service.host,
- self.service.binary,
+ self.sdk_client.services.assert_called_with(
+ host=self.service.host,
+ binary=self.service.binary,
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, list(data))
- def test_service_list_with_long_option(self):
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_service_list_with_long_option(self, sm_mock):
+ sm_mock.return_value = False
+
arglist = [
'--host', self.service.host,
'--service', self.service.binary,
@@ -182,15 +193,18 @@ class TestServiceList(TestService):
# containing the data to be listed.
columns, data = self.cmd.take_action(parsed_args)
- self.service_mock.list.assert_called_with(
- self.service.host,
- self.service.binary,
+ self.sdk_client.services.assert_called_with(
+ host=self.service.host,
+ binary=self.service.binary,
)
self.assertEqual(self.columns_long, columns)
self.assertEqual(self.data_long, list(data))
- def test_service_list_with_long_option_2_11(self):
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_service_list_with_long_option_2_11(self, sm_mock):
+ sm_mock.return_value = True
+
arglist = [
'--host', self.service.host,
'--service', self.service.binary,
@@ -210,14 +224,14 @@ class TestServiceList(TestService):
# containing the data to be listed.
columns, data = self.cmd.take_action(parsed_args)
- self.service_mock.list.assert_called_with(
- self.service.host,
- self.service.binary,
+ self.sdk_client.services.assert_called_with(
+ host=self.service.host,
+ binary=self.service.binary,
)
# In 2.11 there is also a forced_down column.
columns_long = self.columns_long + ('Forced Down',)
- data_long = [self.data_long[0] + (self.service.forced_down,)]
+ data_long = [self.data_long[0] + (self.service.is_forced_down,)]
self.assertEqual(columns_long, columns)
self.assertEqual(data_long, list(data))
@@ -230,12 +244,14 @@ class TestServiceSet(TestService):
self.service = compute_fakes.FakeService.create_one_service()
- self.service_mock.enable.return_value = self.service
- self.service_mock.disable.return_value = self.service
+ self.sdk_client.enable_service.return_value = self.service
+ self.sdk_client.disable_service.return_value = self.service
self.cmd = service.SetService(self.app, None)
- def test_set_nothing(self):
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_set_nothing(self, sm_mock):
+ sm_mock.return_value = False
arglist = [
self.service.host,
self.service.binary,
@@ -247,12 +263,13 @@ class TestServiceSet(TestService):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
- self.service_mock.enable.assert_not_called()
- self.service_mock.disable.assert_not_called()
- self.service_mock.disable_log_reason.assert_not_called()
+ self.sdk_client.enable_service.assert_not_called()
+ self.sdk_client.disable_service.assert_not_called()
self.assertIsNone(result)
- def test_service_set_enable(self):
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_service_set_enable(self, sm_mock):
+ sm_mock.return_value = False
arglist = [
'--enable',
self.service.host,
@@ -267,13 +284,16 @@ class TestServiceSet(TestService):
result = self.cmd.take_action(parsed_args)
- self.service_mock.enable.assert_called_with(
+ self.sdk_client.enable_service.assert_called_with(
+ None,
self.service.host,
self.service.binary
)
self.assertIsNone(result)
- def test_service_set_disable(self):
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_service_set_disable(self, sm_mock):
+ sm_mock.return_value = False
arglist = [
'--disable',
self.service.host,
@@ -288,13 +308,17 @@ class TestServiceSet(TestService):
result = self.cmd.take_action(parsed_args)
- self.service_mock.disable.assert_called_with(
+ self.sdk_client.disable_service.assert_called_with(
+ None,
self.service.host,
- self.service.binary
+ self.service.binary,
+ None
)
self.assertIsNone(result)
- def test_service_set_disable_with_reason(self):
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_service_set_disable_with_reason(self, sm_mock):
+ sm_mock.return_value = False
reason = 'earthquake'
arglist = [
'--disable',
@@ -312,14 +336,17 @@ class TestServiceSet(TestService):
result = self.cmd.take_action(parsed_args)
- self.service_mock.disable_log_reason.assert_called_with(
+ self.sdk_client.disable_service.assert_called_with(
+ None,
self.service.host,
self.service.binary,
reason
)
self.assertIsNone(result)
- def test_service_set_only_with_disable_reason(self):
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_service_set_only_with_disable_reason(self, sm_mock):
+ sm_mock.return_value = False
reason = 'earthquake'
arglist = [
'--disable-reason', reason,
@@ -339,7 +366,9 @@ class TestServiceSet(TestService):
self.assertEqual("Cannot specify option --disable-reason without "
"--disable specified.", str(e))
- def test_service_set_enable_with_disable_reason(self):
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_service_set_enable_with_disable_reason(self, sm_mock):
+ sm_mock.return_value = False
reason = 'earthquake'
arglist = [
'--enable',
@@ -361,7 +390,9 @@ class TestServiceSet(TestService):
self.assertEqual("Cannot specify option --disable-reason without "
"--disable specified.", str(e))
- def test_service_set_state_up(self):
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_service_set_state_up(self, sm_mock):
+ sm_mock.side_effect = [False, True]
arglist = [
'--up',
self.service.host,
@@ -373,16 +404,20 @@ class TestServiceSet(TestService):
('service', self.service.binary),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.app.client_manager.compute.api_version = api_versions.APIVersion(
- '2.11')
result = self.cmd.take_action(parsed_args)
- self.service_mock.force_down.assert_called_once_with(
- self.service.host, self.service.binary, False)
- self.assertNotCalled(self.service_mock.enable)
- self.assertNotCalled(self.service_mock.disable)
+ self.sdk_client.update_service_forced_down.assert_called_once_with(
+ None,
+ self.service.host,
+ self.service.binary,
+ False
+ )
+ self.assertNotCalled(self.sdk_client.enable_service)
+ self.assertNotCalled(self.sdk_client.disable_service)
self.assertIsNone(result)
- def test_service_set_state_down(self):
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_service_set_state_down(self, sm_mock):
+ sm_mock.side_effect = [False, True]
arglist = [
'--down',
self.service.host,
@@ -394,16 +429,20 @@ class TestServiceSet(TestService):
('service', self.service.binary),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.app.client_manager.compute.api_version = api_versions.APIVersion(
- '2.11')
result = self.cmd.take_action(parsed_args)
- self.service_mock.force_down.assert_called_once_with(
- self.service.host, self.service.binary, True)
- self.assertNotCalled(self.service_mock.enable)
- self.assertNotCalled(self.service_mock.disable)
+ self.sdk_client.update_service_forced_down.assert_called_once_with(
+ None,
+ self.service.host,
+ self.service.binary,
+ True
+ )
+ self.assertNotCalled(self.sdk_client.enable_service)
+ self.assertNotCalled(self.sdk_client.disable_service)
self.assertIsNone(result)
- def test_service_set_enable_and_state_down(self):
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_service_set_enable_and_state_down(self, sm_mock):
+ sm_mock.side_effect = [False, True]
arglist = [
'--enable',
'--down',
@@ -417,16 +456,23 @@ class TestServiceSet(TestService):
('service', self.service.binary),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.app.client_manager.compute.api_version = api_versions.APIVersion(
- '2.11')
result = self.cmd.take_action(parsed_args)
- self.service_mock.enable.assert_called_once_with(
- self.service.host, self.service.binary)
- self.service_mock.force_down.assert_called_once_with(
- self.service.host, self.service.binary, True)
+ self.sdk_client.enable_service.assert_called_once_with(
+ None,
+ self.service.host,
+ self.service.binary
+ )
+ self.sdk_client.update_service_forced_down.assert_called_once_with(
+ None,
+ self.service.host,
+ self.service.binary,
+ True
+ )
self.assertIsNone(result)
- def test_service_set_enable_and_state_down_with_exception(self):
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_service_set_enable_and_state_down_with_exception(self, sm_mock):
+ sm_mock.side_effect = [False, True]
arglist = [
'--enable',
'--down',
@@ -441,18 +487,22 @@ class TestServiceSet(TestService):
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.app.client_manager.compute.api_version = api_versions.APIVersion(
- '2.11')
- with mock.patch.object(self.service_mock, 'enable',
+ with mock.patch.object(self.sdk_client, 'enable_service',
side_effect=Exception()):
self.assertRaises(exceptions.CommandError,
self.cmd.take_action, parsed_args)
- self.service_mock.force_down.assert_called_once_with(
- self.service.host, self.service.binary, True)
-
- def test_service_set_2_53_disable_down(self):
+ self.sdk_client.update_service_forced_down.assert_called_once_with(
+ None,
+ self.service.host,
+ self.service.binary,
+ True
+ )
+
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_service_set_2_53_disable_down(self, sm_mock):
# Tests disabling and forcing down a compute service with microversion
# 2.53 which requires looking up the service by host and binary.
+ sm_mock.return_value = True
arglist = [
'--disable',
'--down',
@@ -466,18 +516,27 @@ class TestServiceSet(TestService):
('service', self.service.binary),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.app.client_manager.compute.api_version = api_versions.APIVersion(
- '2.53')
service_id = '339478d0-0b95-4a94-be63-d5be05dfeb1c'
- self.service_mock.list.return_value = [mock.Mock(id=service_id)]
+ self.sdk_client.services.return_value = [mock.Mock(id=service_id)]
result = self.cmd.take_action(parsed_args)
- self.service_mock.disable.assert_called_once_with(service_id)
- self.service_mock.force_down.assert_called_once_with(service_id, True)
+ self.sdk_client.disable_service.assert_called_once_with(
+ service_id,
+ self.service.host,
+ self.service.binary,
+ None
+ )
+ self.sdk_client.update_service_forced_down.assert_called_once_with(
+ service_id,
+ self.service.host,
+ self.service.binary,
+ True)
self.assertIsNone(result)
- def test_service_set_2_53_disable_reason(self):
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_service_set_2_53_disable_reason(self, sm_mock):
# Tests disabling with reason a compute service with microversion
# 2.53 which requires looking up the service by host and binary.
+ sm_mock.return_value = True
reason = 'earthquake'
arglist = [
'--disable',
@@ -492,18 +551,22 @@ class TestServiceSet(TestService):
('service', self.service.binary),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.app.client_manager.compute.api_version = api_versions.APIVersion(
- '2.53')
service_id = '339478d0-0b95-4a94-be63-d5be05dfeb1c'
- self.service_mock.list.return_value = [mock.Mock(id=service_id)]
+ self.sdk_client.services.return_value = [mock.Mock(id=service_id)]
result = self.cmd.take_action(parsed_args)
- self.service_mock.disable_log_reason.assert_called_once_with(
- service_id, reason)
+ self.sdk_client.disable_service.assert_called_once_with(
+ service_id,
+ self.service.host,
+ self.service.binary,
+ reason
+ )
self.assertIsNone(result)
- def test_service_set_2_53_enable_up(self):
+ @mock.patch.object(sdk_utils, 'supports_microversion')
+ def test_service_set_2_53_enable_up(self, sm_mock):
# Tests enabling and bringing up a compute service with microversion
# 2.53 which requires looking up the service by host and binary.
+ sm_mock.return_value = True
arglist = [
'--enable',
'--up',
@@ -517,30 +580,37 @@ class TestServiceSet(TestService):
('service', self.service.binary),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.app.client_manager.compute.api_version = api_versions.APIVersion(
- '2.53')
service_id = '339478d0-0b95-4a94-be63-d5be05dfeb1c'
- self.service_mock.list.return_value = [mock.Mock(id=service_id)]
+ self.sdk_client.services.return_value = [mock.Mock(id=service_id)]
result = self.cmd.take_action(parsed_args)
- self.service_mock.enable.assert_called_once_with(service_id)
- self.service_mock.force_down.assert_called_once_with(service_id, False)
+ self.sdk_client.enable_service.assert_called_once_with(
+ service_id,
+ self.service.host,
+ self.service.binary
+ )
+ self.sdk_client.update_service_forced_down.assert_called_once_with(
+ service_id,
+ self.service.host,
+ self.service.binary,
+ False
+ )
self.assertIsNone(result)
def test_service_set_find_service_by_host_and_binary_no_results(self):
# Tests that no compute services are found by host and binary.
- self.service_mock.list.return_value = []
+ self.sdk_client.services.return_value = []
ex = self.assertRaises(exceptions.CommandError,
self.cmd._find_service_by_host_and_binary,
- self.service_mock, 'fake-host', 'nova-compute')
+ self.sdk_client, 'fake-host', 'nova-compute')
self.assertIn('Compute service for host "fake-host" and binary '
'"nova-compute" not found.', str(ex))
def test_service_set_find_service_by_host_and_binary_many_results(self):
# Tests that more than one compute service is found by host and binary.
- self.service_mock.list.return_value = [mock.Mock(), mock.Mock()]
+ self.sdk_client.services.return_value = [mock.Mock(), mock.Mock()]
ex = self.assertRaises(exceptions.CommandError,
self.cmd._find_service_by_host_and_binary,
- self.service_mock, 'fake-host', 'nova-compute')
+ self.sdk_client, 'fake-host', 'nova-compute')
self.assertIn('Multiple compute services found for host "fake-host" '
'and binary "nova-compute". Unable to proceed.',
str(ex))
diff --git a/openstackclient/tests/unit/image/v1/fakes.py b/openstackclient/tests/unit/image/v1/fakes.py
index add3978..164050c 100644
--- a/openstackclient/tests/unit/image/v1/fakes.py
+++ b/openstackclient/tests/unit/image/v1/fakes.py
@@ -11,7 +11,6 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-#
from unittest import mock
import uuid
@@ -23,45 +22,11 @@ from openstackclient.tests.unit import utils
from openstackclient.tests.unit.volume.v1 import fakes as volume_fakes
-image_id = 'im1'
-image_name = 'graven'
-image_owner = 'baal'
-image_protected = False
-image_public = True
-image_properties = {
- 'Alpha': 'a',
- 'Beta': 'b',
- 'Gamma': 'g',
-}
-image_properties_str = "Alpha='a', Beta='b', Gamma='g'"
-image_data = 'line 1\nline 2\n'
-image_size = 0
-
-IMAGE = {
- 'id': image_id,
- 'name': image_name,
- 'container_format': '',
- 'disk_format': '',
- 'owner': image_owner,
- 'min_disk': 0,
- 'min_ram': 0,
- 'is_public': image_public,
- 'protected': image_protected,
- 'properties': image_properties,
- 'size': image_size,
-}
-
-IMAGE_columns = tuple(sorted(IMAGE))
-IMAGE_output = dict(IMAGE)
-IMAGE_output['properties'] = image_properties_str
-IMAGE_data = tuple((IMAGE_output[x] for x in sorted(IMAGE_output)))
-
-
-class FakeImagev1Client(object):
+class FakeImagev1Client:
def __init__(self, **kwargs):
self.images = mock.Mock()
- self.images.resource_class = fakes.FakeResource(None, {})
+
self.auth_token = kwargs['token']
self.management_url = kwargs['endpoint']
self.version = 1.0
@@ -70,7 +35,7 @@ class FakeImagev1Client(object):
class TestImagev1(utils.TestCommand):
def setUp(self):
- super(TestImagev1, self).setUp()
+ super().setUp()
self.app.client_manager.image = FakeImagev1Client(
endpoint=fakes.AUTH_URL,
@@ -81,41 +46,39 @@ class TestImagev1(utils.TestCommand):
token=fakes.AUTH_TOKEN,
)
-
-class FakeImage(object):
- """Fake one or more images."""
-
- @staticmethod
- def create_one_image(attrs=None):
- """Create a fake image.
-
- :param Dictionary attrs:
- A dictionary with all attrbutes of image
- :return:
- A FakeResource object with id, name, owner, protected,
- visibility and tags attrs
- """
- attrs = attrs or {}
-
- # Set default attribute
- image_info = {
- 'id': str(uuid.uuid4()),
- 'name': 'image-name' + uuid.uuid4().hex,
- 'owner': 'image-owner' + uuid.uuid4().hex,
- 'container_format': '',
- 'disk_format': '',
- 'min_disk': 0,
- 'min_ram': 0,
- 'is_public': True,
- 'protected': False,
- 'properties': {
- 'Alpha': 'a',
- 'Beta': 'b',
- 'Gamma': 'g'},
- 'status': 'status' + uuid.uuid4().hex
- }
-
- # Overwrite default attributes if there are some attributes set
- image_info.update(attrs)
-
- return image.Image(**image_info)
+ self.client = self.app.client_manager.image
+
+
+def create_one_image(attrs=None):
+ """Create a fake image.
+
+ :param Dictionary attrs:
+ A dictionary with all attrbutes of image
+ :return:
+ A FakeResource object with id, name, owner, protected,
+ visibility and tags attrs
+ """
+ attrs = attrs or {}
+
+ # Set default attribute
+ image_info = {
+ 'id': str(uuid.uuid4()),
+ 'name': 'image-name' + uuid.uuid4().hex,
+ 'owner': 'image-owner' + uuid.uuid4().hex,
+ 'container_format': '',
+ 'disk_format': '',
+ 'min_disk': 0,
+ 'min_ram': 0,
+ 'is_public': True,
+ 'protected': False,
+ 'properties': {
+ 'Alpha': 'a',
+ 'Beta': 'b',
+ 'Gamma': 'g'},
+ 'status': 'status' + uuid.uuid4().hex
+ }
+
+ # Overwrite default attributes if there are some attributes set
+ image_info.update(attrs)
+
+ return image.Image(**image_info)
diff --git a/openstackclient/tests/unit/image/v1/test_image.py b/openstackclient/tests/unit/image/v1/test_image.py
index 5c69bf0..6c65f9a 100644
--- a/openstackclient/tests/unit/image/v1/test_image.py
+++ b/openstackclient/tests/unit/image/v1/test_image.py
@@ -25,16 +25,12 @@ from openstackclient.tests.unit.image.v1 import fakes as image_fakes
class TestImage(image_fakes.TestImagev1):
- def setUp(self):
- super(TestImage, self).setUp()
-
- self.app.client_manager.image = mock.Mock()
- self.client = self.app.client_manager.image
+ pass
class TestImageCreate(TestImage):
- new_image = image_fakes.FakeImage.create_one_image()
+ new_image = image_fakes.create_one_image()
columns = (
'container_format',
'disk_format',
@@ -210,7 +206,7 @@ class TestImageCreate(TestImage):
class TestImageDelete(TestImage):
- _image = image_fakes.FakeImage.create_one_image()
+ _image = image_fakes.create_one_image()
def setUp(self):
super(TestImageDelete, self).setUp()
@@ -239,7 +235,7 @@ class TestImageDelete(TestImage):
class TestImageList(TestImage):
- _image = image_fakes.FakeImage.create_one_image()
+ _image = image_fakes.create_one_image()
columns = (
'ID',
@@ -443,7 +439,7 @@ class TestImageList(TestImage):
class TestImageSet(TestImage):
- _image = image_fakes.FakeImage.create_one_image()
+ _image = image_fakes.create_one_image()
def setUp(self):
super(TestImageSet, self).setUp()
@@ -682,8 +678,7 @@ class TestImageSet(TestImage):
class TestImageShow(TestImage):
- _image = image_fakes.FakeImage.create_one_image(
- attrs={'size': 2000})
+ _image = image_fakes.create_one_image(attrs={'size': 2000})
columns = (
'container_format',
'disk_format',
diff --git a/openstackclient/tests/unit/image/v2/fakes.py b/openstackclient/tests/unit/image/v2/fakes.py
index 0d83f98..a0eda6d 100644
--- a/openstackclient/tests/unit/image/v2/fakes.py
+++ b/openstackclient/tests/unit/image/v2/fakes.py
@@ -11,155 +11,39 @@
# 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 copy
import random
from unittest import mock
import uuid
from openstack.image.v2 import image
from openstack.image.v2 import member
-from osc_lib.cli import format_columns
from openstackclient.tests.unit import fakes
from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
from openstackclient.tests.unit import utils
-image_id = '0f41529e-7c12-4de8-be2d-181abb825b3c'
-image_name = 'graven'
-image_owner = 'baal'
-image_protected = False
-image_visibility = 'public'
-image_tags = []
-image_size = 0
-
-IMAGE = {
- 'id': image_id,
- 'name': image_name,
- 'owner': image_owner,
- 'protected': image_protected,
- 'visibility': image_visibility,
- 'tags': image_tags,
- 'size': image_size
-}
-
-IMAGE_columns = tuple(sorted(IMAGE))
-IMAGE_data = tuple((IMAGE[x] for x in sorted(IMAGE)))
-
-IMAGE_SHOW = copy.copy(IMAGE)
-IMAGE_SHOW['tags'] = format_columns.ListColumn(IMAGE_SHOW['tags'])
-IMAGE_SHOW_data = tuple((IMAGE_SHOW[x] for x in sorted(IMAGE_SHOW)))
-
-# Just enough v2 schema to do some testing
-IMAGE_schema = {
- "additionalProperties": {
- "type": "string"
- },
- "name": "image",
- "links": [
- {
- "href": "{self}",
- "rel": "self"
- },
- {
- "href": "{file}",
- "rel": "enclosure"
- },
- {
- "href": "{schema}",
- "rel": "describedby"
- }
- ],
- "properties": {
- "id": {
- "pattern": "^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$", # noqa
- "type": "string",
- "description": "An identifier for the image"
- },
- "name": {
- "type": [
- "null",
- "string"
- ],
- "description": "Descriptive name for the image",
- "maxLength": 255
- },
- "owner": {
- "type": [
- "null",
- "string"
- ],
- "description": "Owner of the image",
- "maxLength": 255
- },
- "protected": {
- "type": "boolean",
- "description": "If true, image will not be deletable."
- },
- "self": {
- "type": "string",
- "description": "(READ-ONLY)"
- },
- "schema": {
- "type": "string",
- "description": "(READ-ONLY)"
- },
- "size": {
- "type": [
- "null",
- "integer",
- "string"
- ],
- "description": "Size of image file in bytes (READ-ONLY)"
- },
- "status": {
- "enum": [
- "queued",
- "saving",
- "active",
- "killed",
- "deleted",
- "pending_delete"
- ],
- "type": "string",
- "description": "Status of the image (READ-ONLY)"
- },
- "tags": {
- "items": {
- "type": "string",
- "maxLength": 255
- },
- "type": "array",
- "description": "List of strings related to the image"
- },
- "visibility": {
- "enum": [
- "public",
- "private"
- ],
- "type": "string",
- "description": "Scope of image accessibility"
- },
- }
-}
-
-class FakeImagev2Client(object):
+class FakeImagev2Client:
def __init__(self, **kwargs):
self.images = mock.Mock()
- self.images.resource_class = fakes.FakeResource(None, {})
- self.image_members = mock.Mock()
- self.image_members.resource_class = fakes.FakeResource(None, {})
- self.image_tags = mock.Mock()
- self.image_tags.resource_class = fakes.FakeResource(None, {})
-
+ self.create_image = mock.Mock()
+ self.delete_image = mock.Mock()
+ self.update_image = mock.Mock()
self.find_image = mock.Mock()
- self.find_image.resource_class = fakes.FakeResource(None, {})
-
self.get_image = mock.Mock()
- self.get_image.resource_class = fakes.FakeResource(None, {})
+ self.download_image = mock.Mock()
+ self.reactivate_image = mock.Mock()
+ self.deactivate_image = mock.Mock()
+
+ self.members = mock.Mock()
+ self.add_member = mock.Mock()
+ self.remove_member = mock.Mock()
+ self.update_member = mock.Mock()
+
+ self.remove_tag = mock.Mock()
+
self.auth_token = kwargs['token']
self.management_url = kwargs['endpoint']
self.version = 2.0
@@ -168,7 +52,7 @@ class FakeImagev2Client(object):
class TestImagev2(utils.TestCommand):
def setUp(self):
- super(TestImagev2, self).setUp()
+ super().setUp()
self.app.client_manager.image = FakeImagev2Client(
endpoint=fakes.AUTH_URL,
@@ -181,130 +65,67 @@ class TestImagev2(utils.TestCommand):
)
-class FakeImage(object):
- """Fake one or more images.
+def create_one_image(attrs=None):
+ """Create a fake image.
- TODO(xiexs): Currently, only image API v2 is supported by this class.
+ :param attrs: A dictionary with all attributes of image
+ :type attrs: dict
+ :return: A fake Image object.
+ :rtype: `openstack.image.v2.image.Image`
"""
+ attrs = attrs or {}
+
+ # Set default attribute
+ image_info = {
+ 'id': str(uuid.uuid4()),
+ 'name': 'image-name' + uuid.uuid4().hex,
+ 'owner_id': 'image-owner' + uuid.uuid4().hex,
+ 'is_protected': bool(random.choice([0, 1])),
+ 'visibility': random.choice(['public', 'private']),
+ 'tags': [uuid.uuid4().hex for r in range(2)],
+ }
- @staticmethod
- def create_one_image(attrs=None):
- """Create a fake image.
-
- :param Dictionary attrs:
- A dictionary with all attrbutes of image
- :return:
- A FakeResource object with id, name, owner, protected,
- visibility, tags and size attrs
- """
- attrs = attrs or {}
-
- # Set default attribute
- image_info = {
- 'id': str(uuid.uuid4()),
- 'name': 'image-name' + uuid.uuid4().hex,
- 'owner_id': 'image-owner' + uuid.uuid4().hex,
- 'is_protected': bool(random.choice([0, 1])),
- 'visibility': random.choice(['public', 'private']),
- 'tags': [uuid.uuid4().hex for r in range(2)],
- }
-
- # Overwrite default attributes if there are some attributes set
- image_info.update(attrs)
-
- return image.Image(**image_info)
-
- @staticmethod
- def create_images(attrs=None, count=2):
- """Create multiple fake images.
-
- :param Dictionary attrs:
- A dictionary with all attributes of image
- :param Integer count:
- The number of images to be faked
- :return:
- A list of FakeResource objects
- """
- images = []
- for n in range(0, count):
- images.append(FakeImage.create_one_image(attrs))
-
- return images
-
- @staticmethod
- def get_images(images=None, count=2):
- """Get an iterable MagicMock object with a list of faked images.
-
- If images list is provided, then initialize the Mock object with the
- list. Otherwise create one.
+ # Overwrite default attributes if there are some attributes set
+ image_info.update(attrs)
- :param List images:
- A list of FakeResource objects faking images
- :param Integer count:
- The number of images to be faked
- :return:
- An iterable Mock object with side_effect set to a list of faked
- images
- """
- if images is None:
- images = FakeImage.create_images(count)
+ return image.Image(**image_info)
- return mock.Mock(side_effect=images)
- @staticmethod
- def get_image_columns(image=None):
- """Get the image columns from a faked image object.
+def create_images(attrs=None, count=2):
+ """Create multiple fake images.
- :param image:
- A FakeResource objects faking image
- :return:
- A tuple which may include the following keys:
- ('id', 'name', 'owner', 'protected', 'visibility', 'tags')
- """
- if image is not None:
- return tuple(sorted(image))
- return IMAGE_columns
+ :param attrs: A dictionary with all attributes of image
+ :type attrs: dict
+ :param count: The number of images to be faked
+ :type count: int
+ :return: A list of fake Image objects
+ :rtype: list
+ """
+ images = []
+ for n in range(0, count):
+ images.append(create_one_image(attrs))
- @staticmethod
- def get_image_data(image=None):
- """Get the image data from a faked image object.
+ return images
- :param image:
- A FakeResource objects faking image
- :return:
- A tuple which may include the following values:
- ('image-123', 'image-foo', 'admin', False, 'public', 'bar, baz')
- """
- data_list = []
- if image is not None:
- for x in sorted(image.keys()):
- if x == 'tags':
- # The 'tags' should be format_list
- data_list.append(
- format_columns.ListColumn(getattr(image, x)))
- else:
- data_list.append(getattr(image, x))
- return tuple(data_list)
- @staticmethod
- def create_one_image_member(attrs=None):
- """Create a fake image member.
+def create_one_image_member(attrs=None):
+ """Create a fake image member.
- :param Dictionary attrs:
- A dictionary with all attributes of image member
- :return:
- A FakeResource object with member_id, image_id and so on
- """
- attrs = attrs or {}
+ :param attrs: A dictionary with all attributes of image member
+ :type attrs: dict
+ :return: A fake Member object.
+ :rtype: `openstack.image.v2.member.Member`
+ """
+ attrs = attrs or {}
- # Set default attribute
- image_member_info = {
- 'member_id': 'member-id-' + uuid.uuid4().hex,
- 'image_id': 'image-id-' + uuid.uuid4().hex,
- 'status': 'pending',
- }
+ # Set default attribute
+ image_member_info = {
+ 'member_id': 'member-id-' + uuid.uuid4().hex,
+ 'image_id': 'image-id-' + uuid.uuid4().hex,
+ 'status': 'pending',
+ }
- # Overwrite default attributes if there are some attributes set
- image_member_info.update(attrs)
+ # Overwrite default attributes if there are some attributes set
+ image_member_info.update(attrs)
- return member.Member(**image_member_info)
+ return member.Member(**image_member_info)
diff --git a/openstackclient/tests/unit/image/v2/test_image.py b/openstackclient/tests/unit/image/v2/test_image.py
index 35af679..7ccc9f0 100644
--- a/openstackclient/tests/unit/image/v2/test_image.py
+++ b/openstackclient/tests/unit/image/v2/test_image.py
@@ -11,7 +11,6 @@
# 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 copy
import io
@@ -33,18 +32,9 @@ class TestImage(image_fakes.TestImagev2):
def setUp(self):
super(TestImage, self).setUp()
- # Get shortcuts to the Mocks in image client
- # SDK proxy mock
- self.app.client_manager.image = mock.Mock()
+ # Get shortcuts to mocked image client
self.client = self.app.client_manager.image
- self.client.remove_member = mock.Mock()
-
- self.client.create_image = mock.Mock()
- self.client.update_image = mock.Mock()
- self.image_members_mock = self.app.client_manager.image.image_members
- self.image_tags_mock = self.app.client_manager.image.image_tags
-
# Get shortcut to the Mocks in identity client
self.project_mock = self.app.client_manager.identity.projects
self.project_mock.reset_mock()
@@ -52,7 +42,7 @@ class TestImage(image_fakes.TestImagev2):
self.domain_mock.reset_mock()
def setup_images_mock(self, count):
- images = image_fakes.FakeImage.create_images(count=count)
+ images = image_fakes.create_images(count=count)
return images
@@ -65,7 +55,7 @@ class TestImageCreate(TestImage):
def setUp(self):
super(TestImageCreate, self).setUp()
- self.new_image = image_fakes.FakeImage.create_one_image()
+ self.new_image = image_fakes.create_one_image()
self.client.create_image.return_value = self.new_image
self.project_mock.get.return_value = self.project
@@ -182,7 +172,7 @@ class TestImageCreate(TestImage):
'--protected',
'--private',
'--project', 'unexist_owner',
- image_fakes.image_name,
+ 'graven',
]
verifylist = [
('container_format', 'ovf'),
@@ -194,7 +184,7 @@ class TestImageCreate(TestImage):
('public', False),
('private', True),
('project', 'unexist_owner'),
- ('name', image_fakes.image_name),
+ ('name', 'graven'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -302,8 +292,8 @@ class TestAddProjectToImage(TestImage):
project = identity_fakes.FakeProject.create_one_project()
domain = identity_fakes.FakeDomain.create_one_domain()
- _image = image_fakes.FakeImage.create_one_image()
- new_member = image_fakes.FakeImage.create_one_image_member(
+ _image = image_fakes.create_one_image()
+ new_member = image_fakes.create_one_image_member(
attrs={'image_id': _image.id,
'member_id': project.id}
)
@@ -435,7 +425,7 @@ class TestImageDelete(TestImage):
def test_image_delete_multi_images_exception(self):
- images = image_fakes.FakeImage.create_images(count=2)
+ images = image_fakes.create_images(count=2)
arglist = [
images[0].id,
images[1].id,
@@ -467,7 +457,7 @@ class TestImageDelete(TestImage):
class TestImageList(TestImage):
- _image = image_fakes.FakeImage.create_one_image()
+ _image = image_fakes.create_one_image()
columns = (
'ID',
@@ -484,11 +474,7 @@ class TestImageList(TestImage):
def setUp(self):
super(TestImageList, self).setUp()
- self.api_mock = mock.Mock()
- self.api_mock.side_effect = [
- [self._image], [],
- ]
- self.client.images = self.api_mock
+ self.client.images.side_effect = [[self._image], []]
# Get the command object to test
self.cmd = image.ListImage(self.app, None)
@@ -786,18 +772,13 @@ class TestImageList(TestImage):
@mock.patch('osc_lib.utils.find_resource')
def test_image_list_marker_option(self, fr_mock):
- # tangchen: Since image_fakes.IMAGE is a dict, it cannot offer a .id
- # operation. Will fix this by using FakeImage class instead
- # of IMAGE dict.
self.client.find_image = mock.Mock(return_value=self._image)
-# fr_mock.return_value = mock.Mock()
-# fr_mock.return_value.id = image_fakes.image_id
arglist = [
- '--marker', image_fakes.image_name,
+ '--marker', 'graven',
]
verifylist = [
- ('marker', image_fakes.image_name),
+ ('marker', 'graven'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -806,7 +787,7 @@ class TestImageList(TestImage):
marker=self._image.id,
)
- self.client.find_image.assert_called_with(image_fakes.image_name)
+ self.client.find_image.assert_called_with('graven')
def test_image_list_name_option(self):
arglist = [
@@ -869,8 +850,8 @@ class TestImageList(TestImage):
class TestListImageProjects(TestImage):
project = identity_fakes.FakeProject.create_one_project()
- _image = image_fakes.FakeImage.create_one_image()
- member = image_fakes.FakeImage.create_one_image_member(
+ _image = image_fakes.create_one_image()
+ member = image_fakes.create_one_image_member(
attrs={'image_id': _image.id,
'member_id': project.id}
)
@@ -920,7 +901,7 @@ class TestRemoveProjectImage(TestImage):
def setUp(self):
super(TestRemoveProjectImage, self).setUp()
- self._image = image_fakes.FakeImage.create_one_image()
+ self._image = image_fakes.create_one_image()
# This is the return value for utils.find_resource()
self.client.find_image.return_value = self._image
@@ -979,7 +960,7 @@ class TestImageSet(TestImage):
project = identity_fakes.FakeProject.create_one_project()
domain = identity_fakes.FakeDomain.create_one_domain()
- _image = image_fakes.FakeImage.create_one_image({'tags': []})
+ _image = image_fakes.create_one_image({'tags': []})
def setUp(self):
super(TestImageSet, self).setUp()
@@ -999,22 +980,24 @@ class TestImageSet(TestImage):
def test_image_set_no_options(self):
arglist = [
- image_fakes.image_id,
+ '0f41529e-7c12-4de8-be2d-181abb825b3c',
]
verifylist = [
- ('image', image_fakes.image_id)
+ ('image', '0f41529e-7c12-4de8-be2d-181abb825b3c')
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.assertIsNone(result)
-
- self.image_members_mock.update.assert_not_called()
+ # we'll have called this but not set anything
+ self.app.client_manager.image.update_image.called_once_with(
+ self._image.id,
+ )
def test_image_set_membership_option_accept(self):
- membership = image_fakes.FakeImage.create_one_image_member(
- attrs={'image_id': image_fakes.image_id,
+ membership = image_fakes.create_one_image_member(
+ attrs={'image_id': '0f41529e-7c12-4de8-be2d-181abb825b3c',
'member_id': self.project.id}
)
self.client.update_member.return_value = membership
@@ -1024,9 +1007,7 @@ class TestImageSet(TestImage):
self._image.id,
]
verifylist = [
- ('accept', True),
- ('reject', False),
- ('pending', False),
+ ('membership', 'accepted'),
('image', self._image.id)
]
@@ -1044,21 +1025,19 @@ class TestImageSet(TestImage):
self.client.update_image.assert_called_with(self._image.id)
def test_image_set_membership_option_reject(self):
- membership = image_fakes.FakeImage.create_one_image_member(
- attrs={'image_id': image_fakes.image_id,
+ membership = image_fakes.create_one_image_member(
+ attrs={'image_id': '0f41529e-7c12-4de8-be2d-181abb825b3c',
'member_id': self.project.id}
)
self.client.update_member.return_value = membership
arglist = [
'--reject',
- image_fakes.image_id,
+ '0f41529e-7c12-4de8-be2d-181abb825b3c',
]
verifylist = [
- ('accept', False),
- ('reject', True),
- ('pending', False),
- ('image', image_fakes.image_id)
+ ('membership', 'rejected'),
+ ('image', '0f41529e-7c12-4de8-be2d-181abb825b3c')
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1075,21 +1054,19 @@ class TestImageSet(TestImage):
self.client.update_image.assert_called_with(self._image.id)
def test_image_set_membership_option_pending(self):
- membership = image_fakes.FakeImage.create_one_image_member(
- attrs={'image_id': image_fakes.image_id,
+ membership = image_fakes.create_one_image_member(
+ attrs={'image_id': '0f41529e-7c12-4de8-be2d-181abb825b3c',
'member_id': self.project.id}
)
self.client.update_member.return_value = membership
arglist = [
'--pending',
- image_fakes.image_id,
+ '0f41529e-7c12-4de8-be2d-181abb825b3c',
]
verifylist = [
- ('accept', False),
- ('reject', False),
- ('pending', True),
- ('image', image_fakes.image_id)
+ ('membership', 'pending'),
+ ('image', '0f41529e-7c12-4de8-be2d-181abb825b3c')
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1149,11 +1126,11 @@ class TestImageSet(TestImage):
arglist = [
'--project', 'unexist_owner',
- image_fakes.image_id,
+ '0f41529e-7c12-4de8-be2d-181abb825b3c',
]
verifylist = [
('project', 'unexist_owner'),
- ('image', image_fakes.image_id),
+ ('image', '0f41529e-7c12-4de8-be2d-181abb825b3c'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1165,14 +1142,14 @@ class TestImageSet(TestImage):
arglist = [
'--protected',
'--private',
- image_fakes.image_name,
+ 'graven',
]
verifylist = [
('protected', True),
('unprotected', False),
('public', False),
('private', True),
- ('image', image_fakes.image_name),
+ ('image', 'graven'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1193,14 +1170,14 @@ class TestImageSet(TestImage):
arglist = [
'--unprotected',
'--public',
- image_fakes.image_name,
+ 'graven',
]
verifylist = [
('protected', False),
('unprotected', True),
('public', True),
('private', False),
- ('image', image_fakes.image_name),
+ ('image', 'graven'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1221,11 +1198,11 @@ class TestImageSet(TestImage):
arglist = [
'--property', 'Alpha=1',
'--property', 'Beta=2',
- image_fakes.image_name,
+ 'graven',
]
verifylist = [
('properties', {'Alpha': '1', 'Beta': '2'}),
- ('image', image_fakes.image_name),
+ ('image', 'graven'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1250,7 +1227,7 @@ class TestImageSet(TestImage):
'--os-distro', 'cpm',
'--os-version', '2.2H',
'--ramdisk-id', 'xyzpdq',
- image_fakes.image_name,
+ 'graven',
]
verifylist = [
('architecture', 'z80'),
@@ -1259,7 +1236,7 @@ class TestImageSet(TestImage):
('os_distro', 'cpm'),
('os_version', '2.2H'),
('ramdisk_id', 'xyzpdq'),
- ('image', image_fakes.image_name),
+ ('image', 'graven'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1283,11 +1260,11 @@ class TestImageSet(TestImage):
def test_image_set_tag(self):
arglist = [
'--tag', 'test-tag',
- image_fakes.image_name,
+ 'graven',
]
verifylist = [
('tags', ['test-tag']),
- ('image', image_fakes.image_name),
+ ('image', 'graven'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1307,11 +1284,11 @@ class TestImageSet(TestImage):
arglist = [
'--tag', 'test-tag',
'--activate',
- image_fakes.image_name,
+ 'graven',
]
verifylist = [
('tags', ['test-tag']),
- ('image', image_fakes.image_name),
+ ('image', 'graven'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1335,11 +1312,11 @@ class TestImageSet(TestImage):
arglist = [
'--tag', 'test-tag',
'--deactivate',
- image_fakes.image_name,
+ 'graven',
]
verifylist = [
('tags', ['test-tag']),
- ('image', image_fakes.image_name),
+ ('image', 'graven'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1365,11 +1342,11 @@ class TestImageSet(TestImage):
self.client.find_image.return_value = old_image
arglist = [
'--tag', 'test-tag',
- image_fakes.image_name,
+ 'graven',
]
verifylist = [
('tags', ['test-tag']),
- ('image', image_fakes.image_name),
+ ('image', 'graven'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1391,11 +1368,11 @@ class TestImageSet(TestImage):
self.client.find_image.return_value = old_image
arglist = [
'--tag', 'old1',
- image_fakes.image_name,
+ 'graven',
]
verifylist = [
('tags', ['old1']),
- ('image', image_fakes.image_name),
+ ('image', 'graven'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1415,11 +1392,11 @@ class TestImageSet(TestImage):
arglist = [
'--visibility', '1-mile',
- image_fakes.image_name,
+ 'graven',
]
verifylist = [
('visibility', '1-mile'),
- ('image', image_fakes.image_name),
+ ('image', 'graven'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1431,12 +1408,12 @@ class TestImageSet(TestImage):
arglist = [
'--min-disk', '0',
'--min-ram', '0',
- image_fakes.image_name,
+ 'graven',
]
verifylist = [
('min_disk', 0),
('min_ram', 0),
- ('image', image_fakes.image_name),
+ ('image', 'graven'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1457,13 +1434,13 @@ class TestImageSet(TestImage):
arglist = [
'--hidden',
'--public',
- image_fakes.image_name,
+ 'graven',
]
verifylist = [
('hidden', True),
('public', True),
('private', False),
- ('image', image_fakes.image_name),
+ ('image', 'graven'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1484,13 +1461,13 @@ class TestImageSet(TestImage):
arglist = [
'--unhidden',
'--public',
- image_fakes.image_name,
+ 'graven',
]
verifylist = [
('hidden', False),
('public', True),
('private', False),
- ('image', image_fakes.image_name),
+ ('image', 'graven'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1510,10 +1487,10 @@ class TestImageSet(TestImage):
class TestImageShow(TestImage):
- new_image = image_fakes.FakeImage.create_one_image(
+ new_image = image_fakes.create_one_image(
attrs={'size': 1000})
- _data = image_fakes.FakeImage.create_one_image()
+ _data = image_fakes.create_one_image()
columns = (
'id', 'name', 'owner', 'protected', 'tags', 'visibility'
@@ -1538,10 +1515,10 @@ class TestImageShow(TestImage):
def test_image_show(self):
arglist = [
- image_fakes.image_id,
+ '0f41529e-7c12-4de8-be2d-181abb825b3c',
]
verifylist = [
- ('image', image_fakes.image_id),
+ ('image', '0f41529e-7c12-4de8-be2d-181abb825b3c'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1550,7 +1527,7 @@ class TestImageShow(TestImage):
# data to be shown.
columns, data = self.cmd.take_action(parsed_args)
self.client.find_image.assert_called_with(
- image_fakes.image_id,
+ '0f41529e-7c12-4de8-be2d-181abb825b3c',
ignore_missing=False
)
@@ -1592,7 +1569,7 @@ class TestImageUnset(TestImage):
attrs['hw_rng_model'] = 'virtio'
attrs['prop'] = 'test'
attrs['prop2'] = 'fake'
- self.image = image_fakes.FakeImage.create_one_image(attrs)
+ self.image = image_fakes.create_one_image(attrs)
self.client.find_image.return_value = self.image
self.client.remove_tag.return_value = self.image
@@ -1603,10 +1580,10 @@ class TestImageUnset(TestImage):
def test_image_unset_no_options(self):
arglist = [
- image_fakes.image_id,
+ '0f41529e-7c12-4de8-be2d-181abb825b3c',
]
verifylist = [
- ('image', image_fakes.image_id)
+ ('image', '0f41529e-7c12-4de8-be2d-181abb825b3c')
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1681,7 +1658,7 @@ class TestImageUnset(TestImage):
class TestImageSave(TestImage):
- image = image_fakes.FakeImage.create_one_image({})
+ image = image_fakes.create_one_image({})
def setUp(self):
super(TestImageSave, self).setUp()
diff --git a/openstackclient/tests/unit/network/v2/fakes.py b/openstackclient/tests/unit/network/v2/fakes.py
index ab77d71..2f839d1 100644
--- a/openstackclient/tests/unit/network/v2/fakes.py
+++ b/openstackclient/tests/unit/network/v2/fakes.py
@@ -18,6 +18,9 @@ from random import randint
from unittest import mock
import uuid
+from openstack.network.v2 import local_ip as _local_ip
+from openstack.network.v2 import local_ip_association as _local_ip_association
+
from openstackclient.tests.unit import fakes
from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes_v3
from openstackclient.tests.unit import utils
@@ -102,8 +105,9 @@ class FakeAddressGroup(object):
'name': 'address-group-name-' + uuid.uuid4().hex,
'description': 'address-group-description-' + uuid.uuid4().hex,
'id': 'address-group-id-' + uuid.uuid4().hex,
- 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
'addresses': ['10.0.0.1/32'],
+ 'location': 'MUNCHMUNCHMUNCH',
}
# Overwrite default attributes.
@@ -113,9 +117,6 @@ class FakeAddressGroup(object):
info=copy.deepcopy(address_group_attrs),
loaded=True)
- # Set attributes with special mapping in OpenStack SDK.
- address_group.project_id = address_group_attrs['tenant_id']
-
return address_group
@staticmethod
@@ -174,9 +175,10 @@ class FakeAddressScope(object):
address_scope_attrs = {
'name': 'address-scope-name-' + uuid.uuid4().hex,
'id': 'address-scope-id-' + uuid.uuid4().hex,
- 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
'shared': False,
'ip_version': 4,
+ 'location': 'MUNCHMUNCHMUNCH',
}
# Overwrite default attributes.
@@ -188,7 +190,6 @@ class FakeAddressScope(object):
# Set attributes with special mapping in OpenStack SDK.
address_scope.is_shared = address_scope_attrs['shared']
- address_scope.project_id = address_scope_attrs['tenant_id']
return address_scope
@@ -239,7 +240,7 @@ class FakeAutoAllocatedTopology(object):
auto_allocated_topology_attrs = {
'id': 'network-id-' + uuid.uuid4().hex,
- 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
}
auto_allocated_topology_attrs.update(attrs)
@@ -248,10 +249,6 @@ class FakeAutoAllocatedTopology(object):
info=copy.deepcopy(auto_allocated_topology_attrs),
loaded=True)
- auto_allocated_topology.project_id = auto_allocated_topology_attrs[
- 'tenant_id'
- ]
-
return auto_allocated_topology
@@ -322,17 +319,17 @@ class FakeIPAvailability(object):
network_ip_attrs = {
'network_id': 'network-id-' + uuid.uuid4().hex,
'network_name': 'network-name-' + uuid.uuid4().hex,
- 'tenant_id': '',
+ 'project_id': '',
'subnet_ip_availability': [],
'total_ips': 254,
'used_ips': 6,
+ 'location': 'MUNCHMUNCHMUNCH',
}
network_ip_attrs.update(attrs)
network_ip_availability = fakes.FakeResource(
info=copy.deepcopy(network_ip_attrs),
loaded=True)
- network_ip_availability.project_id = network_ip_attrs['tenant_id']
return network_ip_availability
@@ -409,7 +406,7 @@ class FakeNetwork(object):
'description': 'network-description-' + uuid.uuid4().hex,
'dns_domain': 'example.org.',
'mtu': '1350',
- 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
'admin_state_up': True,
'shared': False,
'subnets': ['a', 'b'],
@@ -425,6 +422,7 @@ class FakeNetwork(object):
'ipv4_address_scope': 'ipv4' + uuid.uuid4().hex,
'ipv6_address_scope': 'ipv6' + uuid.uuid4().hex,
'tags': [],
+ 'location': 'MUNCHMUNCHMUNCH',
}
# Overwrite default attributes.
@@ -434,7 +432,6 @@ class FakeNetwork(object):
loaded=True)
# Set attributes with special mapping in OpenStack SDK.
- network.project_id = network_attrs['tenant_id']
network.is_router_external = network_attrs['router:external']
network.is_admin_state_up = network_attrs['admin_state_up']
network.is_port_security_enabled = \
@@ -513,7 +510,8 @@ class FakeNetworkFlavor(object):
'id': 'network-flavor-id-' + fake_uuid,
'name': 'network-flavor-name-' + fake_uuid,
'service_type': 'vpn',
- 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
+ 'location': 'MUNCHMUNCHMUNCH',
}
# Overwrite default attributes.
@@ -524,7 +522,6 @@ class FakeNetworkFlavor(object):
loaded=True
)
- network_flavor.project_id = network_flavor_attrs['tenant_id']
network_flavor.is_enabled = network_flavor_attrs['enabled']
return network_flavor
@@ -579,6 +576,7 @@ class FakeNetworkSegment(object):
'network_type': 'vlan',
'physical_network': 'physical-network-name-' + fake_uuid,
'segmentation_id': 1024,
+ 'location': 'MUNCHMUNCHMUNCH',
}
# Overwrite default attributes.
@@ -639,6 +637,7 @@ class FakeNetworkSegmentRange(object):
'used': {104: '3312e4ba67864b2eb53f3f41432f8efc',
106: '3312e4ba67864b2eb53f3f41432f8efc'},
'available': [100, 101, 102, 103, 105],
+ 'location': 'MUNCHMUNCHMUNCH',
}
# Overwrite default attributes.
@@ -712,11 +711,12 @@ class FakePort(object):
'port_security_enabled': True,
'security_group_ids': [],
'status': 'ACTIVE',
- 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
'qos_network_policy_id': 'qos-policy-id-' + uuid.uuid4().hex,
'qos_policy_id': 'qos-policy-id-' + uuid.uuid4().hex,
'tags': [],
'propagate_uplink_status': False,
+ 'location': 'MUNCHMUNCHMUNCH',
}
# Overwrite default attributes.
@@ -733,11 +733,6 @@ class FakePort(object):
port.binding_vnic_type = port_attrs['binding:vnic_type']
port.is_admin_state_up = port_attrs['admin_state_up']
port.is_port_security_enabled = port_attrs['port_security_enabled']
- port.project_id = port_attrs['tenant_id']
- port.security_group_ids = port_attrs['security_group_ids']
- port.qos_policy_id = port_attrs['qos_policy_id']
- port.propagate_uplink_status = port_attrs[
- 'propagate_uplink_status']
return port
@@ -802,6 +797,7 @@ class FakeNetworkAgent(object):
'admin_state_up': True,
'binary': 'binary-' + uuid.uuid4().hex,
'configurations': {'subnet': 2, 'networks': 1},
+ 'location': 'MUNCHMUNCHMUNCH',
}
agent_attrs.update(attrs)
agent = fakes.FakeResource(info=copy.deepcopy(agent_attrs),
@@ -858,7 +854,7 @@ class FakeNetworkRBAC(object):
A dictionary with all attributes
:return:
A FakeResource object, with id, action, target_tenant,
- tenant_id, type
+ project_id, type
"""
attrs = attrs or {}
@@ -869,13 +865,13 @@ class FakeNetworkRBAC(object):
'object_id': 'object-id-' + uuid.uuid4().hex,
'action': 'access_as_shared',
'target_tenant': 'target-tenant-' + uuid.uuid4().hex,
- 'tenant_id': 'tenant-id-' + uuid.uuid4().hex,
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
+ 'location': 'MUNCHMUNCHMUNCH',
}
rbac_attrs.update(attrs)
rbac = fakes.FakeResource(info=copy.deepcopy(rbac_attrs),
loaded=True)
# Set attributes with special mapping in OpenStack SDK.
- rbac.project_id = rbac_attrs['tenant_id']
rbac.target_project_id = rbac_attrs['target_tenant']
return rbac
@@ -928,10 +924,11 @@ class FakeNetworkFlavorProfile(object):
flavor_profile_attrs = {
'id': 'flavor-profile-id' + uuid.uuid4().hex,
'description': 'flavor-profile-description-' + uuid.uuid4().hex,
- 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
'driver': 'driver-' + uuid.uuid4().hex,
'metainfo': 'metainfo-' + uuid.uuid4().hex,
- 'enabled': True
+ 'enabled': True,
+ 'location': 'MUNCHMUNCHMUNCH',
}
flavor_profile_attrs.update(attrs)
@@ -940,7 +937,6 @@ class FakeNetworkFlavorProfile(object):
info=copy.deepcopy(flavor_profile_attrs),
loaded=True)
- flavor_profile.project_id = flavor_profile_attrs['tenant_id']
flavor_profile.is_enabled = flavor_profile_attrs['enabled']
return flavor_profile
@@ -986,10 +982,11 @@ class FakeNetworkQosPolicy(object):
'name': 'qos-policy-name-' + uuid.uuid4().hex,
'id': qos_id,
'is_default': False,
- 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
'shared': False,
'description': 'qos-policy-description-' + uuid.uuid4().hex,
'rules': rules,
+ 'location': 'MUNCHMUNCHMUNCH',
}
# Overwrite default attributes.
@@ -1001,7 +998,6 @@ class FakeNetworkQosPolicy(object):
# Set attributes with special mapping in OpenStack SDK.
qos_policy.is_shared = qos_policy_attrs['shared']
- qos_policy.project_id = qos_policy_attrs['tenant_id']
return qos_policy
@@ -1062,17 +1058,15 @@ class FakeNetworkSecGroup(object):
security_group_attrs = {
'name': 'security-group-name-' + uuid.uuid4().hex,
'id': sg_id,
- 'tenant_id': 'project-id-' + uuid.uuid4().hex,
- 'description': 'security-group-description-' + uuid.uuid4().hex
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
+ 'description': 'security-group-description-' + uuid.uuid4().hex,
+ 'location': 'MUNCHMUNCHMUNCH',
}
security_group = fakes.FakeResource(
info=copy.deepcopy(security_group_attrs),
loaded=True)
- # Set attributes with special mapping in OpenStack SDK.
- security_group.project_id = security_group_attrs['tenant_id']
-
return security_group
@@ -1095,8 +1089,9 @@ class FakeNetworkQosRule(object):
qos_rule_attrs = {
'id': 'qos-rule-id-' + uuid.uuid4().hex,
'qos_policy_id': 'qos-policy-id-' + uuid.uuid4().hex,
- 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
'type': type,
+ 'location': 'MUNCHMUNCHMUNCH',
}
if type == RULE_TYPE_BANDWIDTH_LIMIT:
qos_rule_attrs['max_kbps'] = randint(1, 10000)
@@ -1114,9 +1109,6 @@ class FakeNetworkQosRule(object):
qos_rule = fakes.FakeResource(info=copy.deepcopy(qos_rule_attrs),
loaded=True)
- # Set attributes with special mapping in OpenStack SDK.
- qos_rule.project_id = qos_rule['tenant_id']
-
return qos_rule
@staticmethod
@@ -1172,6 +1164,7 @@ class FakeNetworkQosRuleType(object):
# Set default attributes.
qos_rule_type_attrs = {
'type': 'rule-type-' + uuid.uuid4().hex,
+ 'location': 'MUNCHMUNCHMUNCH',
}
# Overwrite default attributes.
@@ -1211,7 +1204,7 @@ class FakeRouter(object):
A dictionary with all attributes
:return:
A FakeResource object, with id, name, admin_state_up,
- status, tenant_id
+ status, project_id
"""
attrs = attrs or {}
@@ -1224,12 +1217,13 @@ class FakeRouter(object):
'description': 'router-description-' + uuid.uuid4().hex,
'distributed': False,
'ha': False,
- 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
'routes': [],
'external_gateway_info': {},
'availability_zone_hints': [],
'availability_zones': [],
'tags': [],
+ 'location': 'MUNCHMUNCHMUNCH',
}
# Overwrite default attributes.
@@ -1239,7 +1233,6 @@ class FakeRouter(object):
loaded=True)
# Set attributes with special mapping in OpenStack SDK.
- router.project_id = router_attrs['tenant_id']
router.is_admin_state_up = router_attrs['admin_state_up']
router.is_distributed = router_attrs['distributed']
router.is_ha = router_attrs['ha']
@@ -1305,7 +1298,8 @@ class FakeSecurityGroup(object):
'stateful': True,
'project_id': 'project-id-' + uuid.uuid4().hex,
'security_group_rules': [],
- 'tags': []
+ 'tags': [],
+ 'location': 'MUNCHMUNCHMUNCH',
}
# Overwrite default attributes.
@@ -1315,9 +1309,6 @@ class FakeSecurityGroup(object):
info=copy.deepcopy(security_group_attrs),
loaded=True)
- # Set attributes with special mapping in OpenStack SDK.
- security_group.project_id = security_group_attrs['project_id']
-
return security_group
@staticmethod
@@ -1386,7 +1377,8 @@ class FakeSecurityGroupRule(object):
'remote_address_group_id': None,
'remote_ip_prefix': '0.0.0.0/0',
'security_group_id': 'security-group-id-' + uuid.uuid4().hex,
- 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
+ 'location': 'MUNCHMUNCHMUNCH',
}
# Overwrite default attributes.
@@ -1396,9 +1388,6 @@ class FakeSecurityGroupRule(object):
info=copy.deepcopy(security_group_rule_attrs),
loaded=True)
- # Set attributes with special mapping in OpenStack SDK.
- security_group_rule.project_id = security_group_rule_attrs['tenant_id']
-
return security_group_rule
@staticmethod
@@ -1461,7 +1450,7 @@ class FakeSubnet(object):
'name': 'subnet-name-' + uuid.uuid4().hex,
'network_id': 'network-id-' + uuid.uuid4().hex,
'cidr': '10.10.10.0/24',
- 'tenant_id': project_id,
+ 'project_id': project_id,
'enable_dhcp': True,
'dns_nameservers': [],
'allocation_pools': [],
@@ -1475,6 +1464,7 @@ class FakeSubnet(object):
'subnetpool_id': None,
'description': 'subnet-description-' + uuid.uuid4().hex,
'tags': [],
+ 'location': 'MUNCHMUNCHMUNCH',
}
# Overwrite default attributes.
@@ -1486,7 +1476,6 @@ class FakeSubnet(object):
# Set attributes with special mappings in OpenStack SDK.
subnet.is_dhcp_enabled = subnet_attrs['enable_dhcp']
subnet.subnet_pool_id = subnet_attrs['subnetpool_id']
- subnet.project_id = subnet_attrs['tenant_id']
return subnet
@@ -1552,10 +1541,11 @@ class FakeFloatingIP(object):
'floating_network_id': 'network-id-' + uuid.uuid4().hex,
'router_id': 'router-id-' + uuid.uuid4().hex,
'port_id': 'port-id-' + uuid.uuid4().hex,
- 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
'description': 'floating-ip-description-' + uuid.uuid4().hex,
'qos_policy_id': 'qos-policy-id-' + uuid.uuid4().hex,
'tags': [],
+ 'location': 'MUNCHMUNCHMUNCH',
}
# Overwrite default attributes.
@@ -1566,9 +1556,6 @@ class FakeFloatingIP(object):
loaded=True
)
- # Set attributes with special mappings in OpenStack SDK.
- floating_ip.project_id = floating_ip_attrs['tenant_id']
-
return floating_ip
@staticmethod
@@ -1619,8 +1606,9 @@ class FakeNetworkMeter(object):
'id': 'meter-id-' + uuid.uuid4().hex,
'name': 'meter-name-' + uuid.uuid4().hex,
'description': 'meter-description-' + uuid.uuid4().hex,
- 'tenant_id': 'project-id-' + uuid.uuid4().hex,
- 'shared': False
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
+ 'shared': False,
+ 'location': 'MUNCHMUNCHMUNCH',
}
meter_attrs.update(attrs)
@@ -1629,8 +1617,6 @@ class FakeNetworkMeter(object):
info=copy.deepcopy(meter_attrs),
loaded=True)
- meter.project_id = meter_attrs['tenant_id']
-
return meter
@staticmethod
@@ -1668,7 +1654,8 @@ class FakeNetworkMeterRule(object):
'remote_ip_prefix': '10.0.0.0/24',
'source_ip_prefix': '8.8.8.8/32',
'destination_ip_prefix': '10.0.0.0/24',
- 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
+ 'location': 'MUNCHMUNCHMUNCH',
}
meter_rule_attrs.update(attrs)
@@ -1677,8 +1664,6 @@ class FakeNetworkMeterRule(object):
info=copy.deepcopy(meter_rule_attrs),
loaded=True)
- meter_rule.project_id = meter_rule_attrs['tenant_id']
-
return meter_rule
@staticmethod
@@ -1721,7 +1706,7 @@ class FakeSubnetPool(object):
'prefixes': ['10.0.0.0/24', '10.1.0.0/24'],
'default_prefixlen': '8',
'address_scope_id': 'address-scope-id-' + uuid.uuid4().hex,
- 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
'is_default': False,
'shared': False,
'max_prefixlen': '32',
@@ -1730,6 +1715,7 @@ class FakeSubnetPool(object):
'ip_version': '4',
'description': 'subnet-pool-description-' + uuid.uuid4().hex,
'tags': [],
+ 'location': 'MUNCHMUNCHMUNCH',
}
# Overwrite default attributes.
@@ -1746,7 +1732,6 @@ class FakeSubnetPool(object):
subnet_pool.is_shared = subnet_pool_attrs['shared']
subnet_pool.maximum_prefix_length = subnet_pool_attrs['max_prefixlen']
subnet_pool.minimum_prefix_length = subnet_pool_attrs['min_prefixlen']
- subnet_pool.project_id = subnet_pool_attrs['tenant_id']
return subnet_pool
@@ -1801,6 +1786,7 @@ class FakeNetworkServiceProvider(object):
'name': 'provider-name-' + uuid.uuid4().hex,
'service_type': 'service-type-' + uuid.uuid4().hex,
'default': False,
+ 'location': 'MUNCHMUNCHMUNCH',
}
service_provider.update(attrs)
@@ -1923,6 +1909,7 @@ class FakeFloatingIPPortForwarding(object):
'external_port': randint(1, 65535),
'protocol': 'tcp',
'description': 'some description',
+ 'location': 'MUNCHMUNCHMUNCH',
}
# Overwrite default attributes.
@@ -1998,6 +1985,7 @@ class FakeL3ConntrackHelper(object):
'helper': 'tftp',
'protocol': 'tcp',
'port': randint(1, 65535),
+ 'location': 'MUNCHMUNCHMUNCH',
}
# Overwrite default attributes.
@@ -2048,3 +2036,138 @@ class FakeL3ConntrackHelper(object):
)
return mock.Mock(side_effect=ct_helpers)
+
+
+def create_one_local_ip(attrs=None):
+ """Create a fake local ip.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object with name, id, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ local_ip_attrs = {
+ 'created_at': '2021-11-29T10:10:23.000000',
+ 'name': 'local-ip-name-' + uuid.uuid4().hex,
+ 'description': 'local-ip-description-' + uuid.uuid4().hex,
+ 'id': 'local-ip-id-' + uuid.uuid4().hex,
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
+ 'local_port_id': 'local_port_id-' + uuid.uuid4().hex,
+ 'network_id': 'network_id-' + uuid.uuid4().hex,
+ 'local_ip_address': '10.0.0.1',
+ 'ip_mode': 'translate',
+ 'revision_number': 'local-ip-revision-number-' + uuid.uuid4().hex,
+ 'updated_at': '2021-11-29T10:10:25.000000',
+ }
+
+ # Overwrite default attributes.
+ local_ip_attrs.update(attrs)
+
+ local_ip = _local_ip.LocalIP(**local_ip_attrs)
+
+ return local_ip
+
+
+def create_local_ips(attrs=None, count=2):
+ """Create multiple fake local ips.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of local ips to fake
+ :return:
+ A list of FakeResource objects faking the local ips
+ """
+ local_ips = []
+ for i in range(0, count):
+ local_ips.append(create_one_local_ip(attrs))
+
+ return local_ips
+
+
+def get_local_ips(local_ips=None, count=2):
+ """Get an iterable Mock object with a list of faked local ips.
+
+ If local ip list is provided, then initialize the Mock object
+ with the list. Otherwise create one.
+
+ :param List local_ips:
+ A list of FakeResource objects faking local ips
+ :param int count:
+ The number of local ips to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ local ips
+ """
+ if local_ips is None:
+ local_ips = create_local_ips(count)
+ return mock.Mock(side_effect=local_ips)
+
+
+def create_one_local_ip_association(attrs=None):
+ """Create a fake local ip association.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object with local_ip_id, local_ip_address, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ local_ip_association_attrs = {
+ 'local_ip_id': 'local-ip-id-' + uuid.uuid4().hex,
+ 'local_ip_address': '172.24.4.228',
+ 'fixed_port_id': 'fixed-port-id-' + uuid.uuid4().hex,
+ 'fixed_ip': '10.0.0.5',
+ 'host': 'host-' + uuid.uuid4().hex,
+ }
+
+ # Overwrite default attributes.
+ local_ip_association_attrs.update(attrs)
+
+ local_ip_association = (
+ _local_ip_association.LocalIPAssociation(
+ **local_ip_association_attrs))
+
+ return local_ip_association
+
+
+def create_local_ip_associations(attrs=None, count=2):
+ """Create multiple fake local ip associations.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of address groups to fake
+ :return:
+ A list of FakeResource objects faking the local ip associations
+ """
+ local_ip_associations = []
+ for i in range(0, count):
+ local_ip_associations.append(create_one_local_ip_association(attrs))
+
+ return local_ip_associations
+
+
+def get_local_ip_associations(local_ip_associations=None, count=2):
+ """Get a list of faked local ip associations
+
+ If local ip association list is provided, then initialize
+ the Mock object with the list. Otherwise create one.
+
+ :param List local_ip_associations:
+ A list of FakeResource objects faking local ip associations
+ :param int count:
+ The number of local ip associations to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ local ip associations
+ """
+ if local_ip_associations is None:
+ local_ip_associations = create_local_ip_associations(count)
+
+ return mock.Mock(side_effect=local_ip_associations)
diff --git a/openstackclient/tests/unit/network/v2/test_address_group.py b/openstackclient/tests/unit/network/v2/test_address_group.py
index a5ee83c..703ab74 100644
--- a/openstackclient/tests/unit/network/v2/test_address_group.py
+++ b/openstackclient/tests/unit/network/v2/test_address_group.py
@@ -43,7 +43,7 @@ class TestCreateAddressGroup(TestAddressGroup):
new_address_group = (
network_fakes.FakeAddressGroup.create_one_address_group(
attrs={
- 'tenant_id': project.id,
+ 'project_id': project.id,
}
))
columns = (
@@ -122,7 +122,7 @@ class TestCreateAddressGroup(TestAddressGroup):
self.network.create_address_group.assert_called_once_with(**{
'addresses': ['10.0.0.1/32'],
- 'tenant_id': self.project.id,
+ 'project_id': self.project.id,
'name': self.new_address_group.name,
'description': self.new_address_group.description,
})
diff --git a/openstackclient/tests/unit/network/v2/test_address_scope.py b/openstackclient/tests/unit/network/v2/test_address_scope.py
index 17f13e8..7e7c421 100644
--- a/openstackclient/tests/unit/network/v2/test_address_scope.py
+++ b/openstackclient/tests/unit/network/v2/test_address_scope.py
@@ -43,7 +43,7 @@ class TestCreateAddressScope(TestAddressScope):
new_address_scope = (
network_fakes.FakeAddressScope.create_one_address_scope(
attrs={
- 'tenant_id': project.id,
+ 'project_id': project.id,
}
))
columns = (
@@ -122,7 +122,7 @@ class TestCreateAddressScope(TestAddressScope):
self.network.create_address_scope.assert_called_once_with(**{
'ip_version': self.new_address_scope.ip_version,
'shared': True,
- 'tenant_id': self.project.id,
+ 'project_id': self.project.id,
'name': self.new_address_scope.name,
})
self.assertEqual(self.columns, columns)
@@ -318,7 +318,7 @@ class TestListAddressScope(TestAddressScope):
columns, data = self.cmd.take_action(parsed_args)
self.network.address_scopes.assert_called_once_with(
- **{'tenant_id': project.id, 'project_id': project.id})
+ **{'project_id': project.id})
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, list(data))
@@ -335,7 +335,7 @@ class TestListAddressScope(TestAddressScope):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
- filters = {'tenant_id': project.id, 'project_id': project.id}
+ filters = {'project_id': project.id}
self.network.address_scopes.assert_called_once_with(**filters)
self.assertEqual(self.columns, columns)
diff --git a/openstackclient/tests/unit/network/v2/test_floating_ip_network.py b/openstackclient/tests/unit/network/v2/test_floating_ip_network.py
index dbcd5c9..5b5c83a 100644
--- a/openstackclient/tests/unit/network/v2/test_floating_ip_network.py
+++ b/openstackclient/tests/unit/network/v2/test_floating_ip_network.py
@@ -179,7 +179,7 @@ class TestCreateFloatingIPNetwork(TestFloatingIPNetwork):
self.network.create_ip.assert_called_once_with(**{
'floating_network_id': self.floating_ip.floating_network_id,
- 'tenant_id': project.id,
+ 'project_id': project.id,
})
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
@@ -205,7 +205,7 @@ class TestCreateFloatingIPNetwork(TestFloatingIPNetwork):
self.network.create_ip.assert_called_once_with(**{
'floating_network_id': self.floating_ip.floating_network_id,
- 'tenant_id': project.id,
+ 'project_id': project.id,
})
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
@@ -414,7 +414,7 @@ class TestListFloatingIPNetwork(TestFloatingIPNetwork):
ip.fixed_ip_address,
ip.port_id,
ip.floating_network_id,
- ip.tenant_id,
+ ip.project_id,
))
data_long.append((
ip.id,
@@ -422,7 +422,7 @@ class TestListFloatingIPNetwork(TestFloatingIPNetwork):
ip.fixed_ip_address,
ip.port_id,
ip.floating_network_id,
- ip.tenant_id,
+ ip.project_id,
ip.router_id,
ip.status,
ip.description,
@@ -563,8 +563,7 @@ class TestListFloatingIPNetwork(TestFloatingIPNetwork):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
- filters = {'tenant_id': project.id,
- 'project_id': project.id, }
+ filters = {'project_id': project.id}
self.network.ips.assert_called_once_with(**filters)
@@ -584,8 +583,7 @@ class TestListFloatingIPNetwork(TestFloatingIPNetwork):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
- filters = {'tenant_id': project.id,
- 'project_id': project.id, }
+ filters = {'project_id': project.id}
self.network.ips.assert_called_once_with(**filters)
self.assertEqual(self.columns, columns)
diff --git a/openstackclient/tests/unit/network/v2/test_floating_ip_port_forwarding.py b/openstackclient/tests/unit/network/v2/test_floating_ip_port_forwarding.py
index 1028c18..7b9e3aa 100644
--- a/openstackclient/tests/unit/network/v2/test_floating_ip_port_forwarding.py
+++ b/openstackclient/tests/unit/network/v2/test_floating_ip_port_forwarding.py
@@ -39,7 +39,6 @@ class TestFloatingIPPortForwarding(network_fakes.TestNetworkV2):
class TestCreateFloatingIPPortForwarding(TestFloatingIPPortForwarding):
def setUp(self):
- project_id = ''
super(TestCreateFloatingIPPortForwarding, self).setUp()
self.new_port_forwarding = (
network_fakes.FakeFloatingIPPortForwarding.
@@ -69,7 +68,6 @@ class TestCreateFloatingIPPortForwarding(TestFloatingIPPortForwarding):
'internal_ip_address',
'internal_port',
'internal_port_id',
- 'project_id',
'protocol'
)
@@ -81,7 +79,6 @@ class TestCreateFloatingIPPortForwarding(TestFloatingIPPortForwarding):
self.new_port_forwarding.internal_ip_address,
self.new_port_forwarding.internal_port,
self.new_port_forwarding.internal_port_id,
- project_id,
self.new_port_forwarding.protocol,
)
@@ -446,12 +443,10 @@ class TestShowFloatingIPPortForwarding(TestFloatingIPPortForwarding):
'internal_ip_address',
'internal_port',
'internal_port_id',
- 'project_id',
'protocol',
)
def setUp(self):
- project_id = ''
super(TestShowFloatingIPPortForwarding, self).setUp()
self._port_forwarding = (
network_fakes.FakeFloatingIPPortForwarding.
@@ -469,7 +464,6 @@ class TestShowFloatingIPPortForwarding(TestFloatingIPPortForwarding):
self._port_forwarding.internal_ip_address,
self._port_forwarding.internal_port,
self._port_forwarding.internal_port_id,
- project_id,
self._port_forwarding.protocol,
)
self.network.find_floating_ip_port_forwarding = mock.Mock(
diff --git a/openstackclient/tests/unit/network/v2/test_ip_availability.py b/openstackclient/tests/unit/network/v2/test_ip_availability.py
index a722a02..880cf58 100644
--- a/openstackclient/tests/unit/network/v2/test_ip_availability.py
+++ b/openstackclient/tests/unit/network/v2/test_ip_availability.py
@@ -106,8 +106,7 @@ class TestListIPAvailability(TestIPAvailability):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
- filters = {'tenant_id': self.project.id,
- 'project_id': self.project.id,
+ filters = {'project_id': self.project.id,
'ip_version': 4}
self.network.network_ip_availabilities.assert_called_once_with(
@@ -134,7 +133,7 @@ class TestShowIPAvailability(TestIPAvailability):
data = (
_ip_availability.network_id,
_ip_availability.network_name,
- _ip_availability.tenant_id,
+ _ip_availability.project_id,
format_columns.ListDictColumn(
_ip_availability.subnet_ip_availability),
_ip_availability.total_ips,
diff --git a/openstackclient/tests/unit/network/v2/test_local_ip.py b/openstackclient/tests/unit/network/v2/test_local_ip.py
new file mode 100644
index 0000000..17e8dcd
--- /dev/null
+++ b/openstackclient/tests/unit/network/v2/test_local_ip.py
@@ -0,0 +1,480 @@
+# Copyright 2021 Huawei, Inc. 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.
+#
+
+from unittest import mock
+from unittest.mock import call
+
+from osc_lib import exceptions
+
+from openstackclient.network.v2 import local_ip
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes_v3
+from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+from openstackclient.tests.unit import utils as tests_utils
+
+
+class TestLocalIP(network_fakes.TestNetworkV2):
+
+ def setUp(self):
+ super().setUp()
+
+ # Get a shortcut to the network client
+ self.network = self.app.client_manager.network
+ # Get a shortcut to the ProjectManager Mock
+ self.projects_mock = self.app.client_manager.identity.projects
+ # Get a shortcut to the DomainManager Mock
+ self.domains_mock = self.app.client_manager.identity.domains
+
+
+class TestCreateLocalIP(TestLocalIP):
+ project = identity_fakes_v3.FakeProject.create_one_project()
+ domain = identity_fakes_v3.FakeDomain.create_one_domain()
+ local_ip_network = network_fakes.FakeNetwork.create_one_network()
+ port = network_fakes.FakePort.create_one_port()
+ # The new local ip created.
+ new_local_ip = network_fakes.create_one_local_ip(
+ attrs={'project_id': project.id,
+ 'network_id': local_ip_network.id,
+ 'local_port_id': port.id})
+
+ columns = (
+ 'created_at',
+ 'description',
+ 'id',
+ 'name',
+ 'project_id',
+ 'local_port_id',
+ 'network_id',
+ 'local_ip_address',
+ 'ip_mode',
+ 'revision_number',
+ 'updated_at',
+ )
+ data = (
+ new_local_ip.created_at,
+ new_local_ip.description,
+ new_local_ip.id,
+ new_local_ip.name,
+ new_local_ip.project_id,
+ new_local_ip.local_port_id,
+ new_local_ip.network_id,
+ new_local_ip.local_ip_address,
+ new_local_ip.ip_mode,
+ new_local_ip.revision_number,
+ new_local_ip.updated_at,
+ )
+
+ def setUp(self):
+ super().setUp()
+ self.network.create_local_ip = mock.Mock(
+ return_value=self.new_local_ip)
+ self.network.find_network = mock.Mock(
+ return_value=self.local_ip_network)
+ self.network.find_port = mock.Mock(
+ return_value=self.port)
+
+ # Get the command object to test
+ self.cmd = local_ip.CreateLocalIP(self.app, self.namespace)
+
+ self.projects_mock.get.return_value = self.project
+ self.domains_mock.get.return_value = self.domain
+
+ def test_create_no_options(self):
+ parsed_args = self.check_parser(self.cmd, [], [])
+ columns, data = (self.cmd.take_action(parsed_args))
+
+ self.network.create_local_ip.assert_called_once_with(**{})
+ self.assertEqual(set(self.columns), set(columns))
+ self.assertItemsEqual(self.data, data)
+
+ def test_create_all_options(self):
+ arglist = [
+ '--project-domain', self.domain.name,
+ '--description', self.new_local_ip.description,
+ '--name', self.new_local_ip.name,
+ '--network', self.new_local_ip.network_id,
+ '--local-port', self.new_local_ip.local_port_id,
+ '--local-ip-address', '10.0.0.1',
+ '--ip-mode', self.new_local_ip.ip_mode,
+ ]
+ verifylist = [
+ ('project_domain', self.domain.name),
+ ('description', self.new_local_ip.description),
+ ('name', self.new_local_ip.name),
+ ('network', self.new_local_ip.network_id),
+ ('local_port', self.new_local_ip.local_port_id),
+ ('local_ip_address', '10.0.0.1'),
+ ('ip_mode', self.new_local_ip.ip_mode),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = (self.cmd.take_action(parsed_args))
+
+ self.network.create_local_ip.assert_called_once_with(**{
+ 'name': self.new_local_ip.name,
+ 'description': self.new_local_ip.description,
+ 'network_id': self.new_local_ip.network_id,
+ 'local_port_id': self.new_local_ip.local_port_id,
+ 'local_ip_address': '10.0.0.1',
+ 'ip_mode': self.new_local_ip.ip_mode,
+ })
+ self.assertEqual(set(self.columns), set(columns))
+ self.assertItemsEqual(self.data, data)
+
+
+class TestDeleteLocalIP(TestLocalIP):
+ # The local ip to delete.
+ _local_ips = network_fakes.create_local_ips(count=2)
+
+ def setUp(self):
+ super().setUp()
+ self.network.delete_local_ip = mock.Mock(return_value=None)
+ self.network.find_local_ip = network_fakes.get_local_ips(
+ local_ips=self._local_ips)
+
+ # Get the command object to test
+ self.cmd = local_ip.DeleteLocalIP(self.app, self.namespace)
+
+ def test_local_ip_delete(self):
+ arglist = [
+ self._local_ips[0].name,
+ ]
+ verifylist = [
+ ('local_ip', [self._local_ips[0].name]),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.network.find_local_ip.assert_called_once_with(
+ self._local_ips[0].name, ignore_missing=False)
+ self.network.delete_local_ip.assert_called_once_with(
+ self._local_ips[0])
+ self.assertIsNone(result)
+
+ def test_multi_local_ips_delete(self):
+ arglist = []
+
+ for a in self._local_ips:
+ arglist.append(a.name)
+ verifylist = [
+ ('local_ip', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for a in self._local_ips:
+ calls.append(call(a))
+ self.network.delete_local_ip.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_multi_local_ips_delete_with_exception(self):
+ arglist = [
+ self._local_ips[0].name,
+ 'unexist_local_ip',
+ ]
+ verifylist = [
+ ('local_ip',
+ [self._local_ips[0].name, 'unexist_local_ip']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self._local_ips[0], exceptions.CommandError]
+ self.network.find_local_ip = (
+ mock.Mock(side_effect=find_mock_result)
+ )
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 local IPs failed to delete.', str(e))
+
+ self.network.find_local_ip.assert_any_call(
+ self._local_ips[0].name, ignore_missing=False)
+ self.network.find_local_ip.assert_any_call(
+ 'unexist_local_ip', ignore_missing=False)
+ self.network.delete_local_ip.assert_called_once_with(
+ self._local_ips[0]
+ )
+
+
+class TestListLocalIP(TestLocalIP):
+ # The local ip to list up.
+ local_ips = (
+ network_fakes.create_local_ips(count=3))
+ fake_network = network_fakes.FakeNetwork.create_one_network(
+ {'id': 'fake_network_id'}
+ )
+
+ columns = (
+ 'ID',
+ 'Name',
+ 'Description',
+ 'Project',
+ 'Local Port ID',
+ 'Network',
+ 'Local IP address',
+ 'IP mode',
+ )
+ data = []
+ for lip in local_ips:
+ data.append((
+ lip.id,
+ lip.name,
+ lip.description,
+ lip.project_id,
+ lip.local_port_id,
+ lip.network_id,
+ lip.local_ip_address,
+ lip.ip_mode,
+ ))
+
+ def setUp(self):
+ super().setUp()
+ self.network.local_ips = mock.Mock(
+ return_value=self.local_ips)
+ self.network.find_network = mock.Mock(
+ return_value=self.fake_network
+ )
+
+ # Get the command object to test
+ self.cmd = local_ip.ListLocalIP(self.app, self.namespace)
+
+ def test_local_ip_list(self):
+ arglist = []
+ verifylist = []
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.local_ips.assert_called_once_with(**{})
+ self.assertEqual(self.columns, columns)
+ self.assertItemsEqual(self.data, list(data))
+
+ def test_local_ip_list_name(self):
+ arglist = [
+ '--name', self.local_ips[0].name,
+ ]
+ verifylist = [
+ ('name', self.local_ips[0].name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.local_ips.assert_called_once_with(
+ **{'name': self.local_ips[0].name})
+ self.assertEqual(self.columns, columns)
+ self.assertItemsEqual(self.data, list(data))
+
+ def test_local_ip_list_project(self):
+ project = identity_fakes_v3.FakeProject.create_one_project()
+ self.projects_mock.get.return_value = project
+ arglist = [
+ '--project', project.id,
+ ]
+ verifylist = [
+ ('project', project.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.local_ips.assert_called_once_with(
+ **{'project_id': project.id})
+ self.assertEqual(self.columns, columns)
+ self.assertItemsEqual(self.data, list(data))
+
+ def test_local_ip_project_domain(self):
+ project = identity_fakes_v3.FakeProject.create_one_project()
+ self.projects_mock.get.return_value = project
+ arglist = [
+ '--project', project.id,
+ '--project-domain', project.domain_id,
+ ]
+ verifylist = [
+ ('project', project.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'project_id': project.id}
+
+ self.network.local_ips.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertItemsEqual(self.data, list(data))
+
+ def test_local_ip_list_network(self):
+ arglist = [
+ '--network', 'fake_network_id',
+ ]
+ verifylist = [
+ ('network', 'fake_network_id'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.local_ips.assert_called_once_with(**{
+ 'network_id': 'fake_network_id',
+ })
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_local_ip_list_local_ip_address(self):
+ arglist = [
+ '--local-ip-address', self.local_ips[0].local_ip_address,
+ ]
+ verifylist = [
+ ('local_ip_address', self.local_ips[0].local_ip_address),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.local_ips.assert_called_once_with(**{
+ 'local_ip_address': self.local_ips[0].local_ip_address,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_local_ip_list_ip_mode(self):
+ arglist = [
+ '--ip-mode', self.local_ips[0].ip_mode,
+ ]
+ verifylist = [
+ ('ip_mode', self.local_ips[0].ip_mode),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.local_ips.assert_called_once_with(**{
+ 'ip_mode': self.local_ips[0].ip_mode,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+
+class TestSetLocalIP(TestLocalIP):
+ # The local ip to set.
+ _local_ip = network_fakes.create_one_local_ip()
+
+ def setUp(self):
+ super().setUp()
+ self.network.update_local_ip = mock.Mock(return_value=None)
+ self.network.find_local_ip = mock.Mock(
+ return_value=self._local_ip)
+
+ # Get the command object to test
+ self.cmd = local_ip.SetLocalIP(self.app, self.namespace)
+
+ def test_set_nothing(self):
+ arglist = [self._local_ip.name, ]
+ verifylist = [
+ ('local_ip', self._local_ip.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.network.update_local_ip.assert_not_called()
+ self.assertIsNone(result)
+
+ def test_set_name_and_description(self):
+ arglist = [
+ '--name', 'new_local_ip_name',
+ '--description', 'new_local_ip_description',
+ self._local_ip.name,
+ ]
+ verifylist = [
+ ('name', 'new_local_ip_name'),
+ ('description', 'new_local_ip_description'),
+ ('local_ip', self._local_ip.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ attrs = {
+ 'name': "new_local_ip_name",
+ 'description': 'new_local_ip_description',
+ }
+ self.network.update_local_ip.assert_called_with(
+ self._local_ip, **attrs)
+ self.assertIsNone(result)
+
+
+class TestShowLocalIP(TestLocalIP):
+ # The local ip to show.
+ _local_ip = network_fakes.create_one_local_ip()
+ columns = (
+ 'created_at',
+ 'description',
+ 'id',
+ 'name',
+ 'project_id',
+ 'local_port_id',
+ 'network_id',
+ 'local_ip_address',
+ 'ip_mode',
+ 'revision_number',
+ 'updated_at',
+ )
+ data = (
+ _local_ip.created_at,
+ _local_ip.description,
+ _local_ip.id,
+ _local_ip.name,
+ _local_ip.project_id,
+ _local_ip.local_port_id,
+ _local_ip.network_id,
+ _local_ip.local_ip_address,
+ _local_ip.ip_mode,
+ _local_ip.revision_number,
+ _local_ip.updated_at,
+ )
+
+ def setUp(self):
+ super().setUp()
+ self.network.find_local_ip = mock.Mock(
+ return_value=self._local_ip)
+
+ # Get the command object to test
+ self.cmd = local_ip.ShowLocalIP(self.app, self.namespace)
+
+ def test_show_no_options(self):
+ arglist = []
+ verifylist = []
+
+ # Missing required args should bail here
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_show_all_options(self):
+ arglist = [
+ self._local_ip.name,
+ ]
+ verifylist = [
+ ('local_ip', self._local_ip.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.find_local_ip.assert_called_once_with(
+ self._local_ip.name, ignore_missing=False)
+ self.assertEqual(set(self.columns), set(columns))
+ self.assertItemsEqual(self.data, list(data))
diff --git a/openstackclient/tests/unit/network/v2/test_local_ip_association.py b/openstackclient/tests/unit/network/v2/test_local_ip_association.py
new file mode 100644
index 0000000..9775930
--- /dev/null
+++ b/openstackclient/tests/unit/network/v2/test_local_ip_association.py
@@ -0,0 +1,328 @@
+# Copyright 2021 Huawei, Inc. 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.
+#
+
+from unittest import mock
+from unittest.mock import call
+
+from osc_lib import exceptions
+
+from openstackclient.network.v2 import local_ip_association
+from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes_v2
+from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+
+
+class TestLocalIPAssociation(network_fakes.TestNetworkV2):
+
+ def setUp(self):
+ super().setUp()
+ self.network = self.app.client_manager.network
+ self.local_ip = network_fakes.create_one_local_ip()
+ self.fixed_port = network_fakes.FakePort.create_one_port()
+ self.project = identity_fakes_v2.FakeProject.create_one_project()
+ self.network.find_port = mock.Mock(return_value=self.fixed_port)
+
+
+class TestCreateLocalIPAssociation(TestLocalIPAssociation):
+
+ def setUp(self):
+ super().setUp()
+ self.new_local_ip_association = (
+ network_fakes.create_one_local_ip_association(
+ attrs={
+ 'fixed_port_id': self.fixed_port.id,
+ 'local_ip_id': self.local_ip.id,
+ }
+ )
+ )
+ self.network.create_local_ip_association = mock.Mock(
+ return_value=self.new_local_ip_association)
+
+ self.network.find_local_ip = mock.Mock(
+ return_value=self.local_ip
+ )
+
+ # Get the command object to test
+ self.cmd = local_ip_association.CreateLocalIPAssociation(
+ self.app, self.namespace)
+
+ self.columns = (
+ 'local_ip_address',
+ 'fixed_port_id',
+ 'fixed_ip',
+ 'host',
+ )
+
+ self.data = (
+ self.new_local_ip_association.local_ip_address,
+ self.new_local_ip_association.fixed_port_id,
+ self.new_local_ip_association.fixed_ip,
+ self.new_local_ip_association.host,
+ )
+
+ def test_create_no_options(self):
+ arglist = [
+ self.new_local_ip_association.local_ip_id,
+ self.new_local_ip_association.fixed_port_id,
+ ]
+ verifylist = [
+ ('local_ip', self.new_local_ip_association.local_ip_id),
+ ('fixed_port', self.new_local_ip_association.fixed_port_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_local_ip_association.\
+ assert_called_once_with(
+ self.new_local_ip_association.local_ip_id,
+ **{
+ 'fixed_port_id':
+ self.new_local_ip_association.fixed_port_id,
+ })
+ self.assertEqual(set(self.columns), set(columns))
+ self.assertEqual(set(self.data), set(data))
+
+ def test_create_all_options(self):
+ arglist = [
+ self.new_local_ip_association.local_ip_id,
+ self.new_local_ip_association.fixed_port_id,
+ '--fixed-ip', self.new_local_ip_association.fixed_ip,
+ ]
+ verifylist = [
+ ('local_ip', self.new_local_ip_association.local_ip_id),
+ ('fixed_port', self.new_local_ip_association.fixed_port_id),
+ ('fixed_ip', self.new_local_ip_association.fixed_ip),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_local_ip_association.\
+ assert_called_once_with(
+ self.new_local_ip_association.local_ip_id,
+ **{
+ 'fixed_port_id':
+ self.new_local_ip_association.fixed_port_id,
+ 'fixed_ip':
+ self.new_local_ip_association.fixed_ip,
+ })
+ self.assertEqual(set(self.columns), set(columns))
+ self.assertEqual(set(self.data), set(data))
+
+
+class TestDeleteLocalIPAssociation(TestLocalIPAssociation):
+
+ def setUp(self):
+ super().setUp()
+ self._local_ip_association = (
+ network_fakes.create_local_ip_associations(
+ count=2, attrs={
+ 'local_ip_id': self.local_ip.id,
+ }
+ )
+ )
+ self.network.delete_local_ip_association = mock.Mock(
+ return_value=None
+ )
+
+ self.network.find_local_ip = mock.Mock(
+ return_value=self.local_ip
+ )
+ # Get the command object to test
+ self.cmd = local_ip_association.DeleteLocalIPAssociation(
+ self.app, self.namespace)
+
+ def test_local_ip_association_delete(self):
+ arglist = [
+ self.local_ip.id,
+ self._local_ip_association[0].fixed_port_id,
+ ]
+ verifylist = [
+ ('local_ip', self.local_ip.id),
+ ('fixed_port_id', [self._local_ip_association[0].fixed_port_id]),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.network.delete_local_ip_association.\
+ assert_called_once_with(
+ self.local_ip.id,
+ self._local_ip_association[0].fixed_port_id,
+ ignore_missing=False
+ )
+
+ self.assertIsNone(result)
+
+ def test_multi_local_ip_associations_delete(self):
+ arglist = []
+ fixed_port_id = []
+
+ arglist.append(str(self.local_ip))
+
+ for a in self._local_ip_association:
+ arglist.append(a.fixed_port_id)
+ fixed_port_id.append(a.fixed_port_id)
+
+ verifylist = [
+ ('local_ip', str(self.local_ip)),
+ ('fixed_port_id', fixed_port_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for a in self._local_ip_association:
+ calls.append(call(a.local_ip_id, a.fixed_port_id,
+ ignore_missing=False))
+
+ self.network.delete_local_ip_association.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_multi_local_ip_association_delete_with_exception(self):
+ arglist = [
+ self.local_ip.id,
+ self._local_ip_association[0].fixed_port_id,
+ 'unexist_fixed_port_id',
+ ]
+ verifylist = [
+ ('local_ip', self.local_ip.id),
+ ('fixed_port_id',
+ [self._local_ip_association[0].fixed_port_id,
+ 'unexist_fixed_port_id']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ delete_mock_result = [None, exceptions.CommandError]
+
+ self.network.delete_local_ip_association = (
+ mock.MagicMock(side_effect=delete_mock_result)
+ )
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual(
+ '1 of 2 Local IP Associations failed to delete.',
+ str(e)
+ )
+
+ self.network.delete_local_ip_association.\
+ assert_any_call(
+ self.local_ip.id,
+ 'unexist_fixed_port_id',
+ ignore_missing=False
+ )
+ self.network.delete_local_ip_association.\
+ assert_any_call(
+ self.local_ip.id,
+ self._local_ip_association[0].fixed_port_id,
+ ignore_missing=False
+ )
+
+
+class TestListLocalIPAssociation(TestLocalIPAssociation):
+
+ columns = (
+ 'Local IP ID',
+ 'Local IP Address',
+ 'Fixed port ID',
+ 'Fixed IP',
+ 'Host'
+ )
+
+ def setUp(self):
+ super().setUp()
+ self.local_ip_associations = (
+ network_fakes.create_local_ip_associations(
+ count=3, attrs={
+ 'local_ip_id': self.local_ip.id,
+ 'fixed_port_id': self.fixed_port.id,
+ }
+ )
+ )
+ self.data = []
+ for lip_assoc in self.local_ip_associations:
+ self.data.append((
+ lip_assoc.local_ip_id,
+ lip_assoc.local_ip_address,
+ lip_assoc.fixed_port_id,
+ lip_assoc.fixed_ip,
+ lip_assoc.host,
+ ))
+ self.network.local_ip_associations = mock.Mock(
+ return_value=self.local_ip_associations
+ )
+ self.network.find_local_ip = mock.Mock(
+ return_value=self.local_ip
+ )
+ self.network.find_port = mock.Mock(
+ return_value=self.fixed_port
+ )
+ # Get the command object to test
+ self.cmd = local_ip_association.ListLocalIPAssociation(
+ self.app,
+ self.namespace
+ )
+
+ def test_local_ip_association_list(self):
+ arglist = [
+ self.local_ip.id
+ ]
+ verifylist = [
+ ('local_ip', self.local_ip.id)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.local_ip_associations.assert_called_once_with(
+ self.local_ip,
+ **{}
+ )
+ self.assertEqual(set(self.columns), set(columns))
+ self.assertEqual(set(self.data), set(list(data)))
+
+ def test_local_ip_association_list_all_options(self):
+ arglist = [
+ '--fixed-port', self.local_ip_associations[0].fixed_port_id,
+ '--fixed-ip', self.local_ip_associations[0].fixed_ip,
+ '--host', self.local_ip_associations[0].host,
+ self.local_ip_associations[0].local_ip_id
+ ]
+
+ verifylist = [
+ ('fixed_port', self.local_ip_associations[0].fixed_port_id),
+ ('fixed_ip', self.local_ip_associations[0].fixed_ip),
+ ('host', self.local_ip_associations[0].host),
+ ('local_ip', self.local_ip_associations[0].local_ip_id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'fixed_port_id': self.local_ip_associations[0].fixed_port_id,
+ 'fixed_ip': self.local_ip_associations[0].fixed_ip,
+ 'host': self.local_ip_associations[0].host,
+ }
+
+ self.network.local_ip_associations.assert_called_once_with(
+ self.local_ip,
+ **attrs
+ )
+ self.assertEqual(set(self.columns), set(columns))
+ self.assertEqual(set(self.data), set(list(data)))
diff --git a/openstackclient/tests/unit/network/v2/test_network.py b/openstackclient/tests/unit/network/v2/test_network.py
index 127d82b..2b04edf 100644
--- a/openstackclient/tests/unit/network/v2/test_network.py
+++ b/openstackclient/tests/unit/network/v2/test_network.py
@@ -48,7 +48,7 @@ class TestCreateNetworkIdentityV3(TestNetwork):
# The new network created.
_network = network_fakes.FakeNetwork.create_one_network(
attrs={
- 'tenant_id': project.id,
+ 'project_id': project.id,
'availability_zone_hints': ["nova"],
}
)
@@ -197,8 +197,6 @@ class TestCreateNetworkIdentityV3(TestNetwork):
'shared': True,
'description': self._network.description,
'mtu': self._network.mtu,
- # TODO(dtroyer): Remove tenant_id when we clean up the SDK refactor
- 'tenant_id': self.project.id,
'project_id': self.project.id,
'is_default': True,
'router:external': True,
@@ -284,7 +282,7 @@ class TestCreateNetworkIdentityV2(TestNetwork):
project = identity_fakes_v2.FakeProject.create_one_project()
# The new network created.
_network = network_fakes.FakeNetwork.create_one_network(
- attrs={'tenant_id': project.id}
+ attrs={'project_id': project.id}
)
columns = (
@@ -379,8 +377,6 @@ class TestCreateNetworkIdentityV2(TestNetwork):
self.network.create_network.assert_called_once_with(**{
'admin_state_up': True,
'name': self._network.name,
- # TODO(dtroyer): Remove tenant_id when we clean up the SDK refactor
- 'tenant_id': self.project.id,
'project_id': self.project.id,
})
self.assertFalse(self.network.set_tags.called)
@@ -704,7 +700,7 @@ class TestListNetwork(TestNetwork):
columns, data = self.cmd.take_action(parsed_args)
self.network.networks.assert_called_once_with(
- **{'tenant_id': project.id, 'project_id': project.id}
+ **{'project_id': project.id}
)
self.assertEqual(self.columns, columns)
@@ -723,7 +719,7 @@ class TestListNetwork(TestNetwork):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
- filters = {'tenant_id': project.id, 'project_id': project.id}
+ filters = {'project_id': project.id}
self.network.networks.assert_called_once_with(**filters)
self.assertEqual(self.columns, columns)
diff --git a/openstackclient/tests/unit/network/v2/test_network_auto_allocated_topology.py b/openstackclient/tests/unit/network/v2/test_network_auto_allocated_topology.py
index e9687a7..d77d689 100644
--- a/openstackclient/tests/unit/network/v2/test_network_auto_allocated_topology.py
+++ b/openstackclient/tests/unit/network/v2/test_network_auto_allocated_topology.py
@@ -33,7 +33,7 @@ class TestCreateAutoAllocatedTopology(TestAutoAllocatedTopology):
topology = network_fakes.FakeAutoAllocatedTopology.create_one_topology(
attrs={'id': network_object.id,
- 'tenant_id': project.id}
+ 'project_id': project.id}
)
columns = (
@@ -131,7 +131,7 @@ class TestValidateAutoAllocatedTopology(TestAutoAllocatedTopology):
topology = network_fakes.FakeAutoAllocatedTopology.create_one_topology(
attrs={'id': network_object.id,
- 'tenant_id': project.id}
+ 'project_id': project.id}
)
columns = (
@@ -208,7 +208,7 @@ class TestDeleteAutoAllocatedTopology(TestAutoAllocatedTopology):
topology = network_fakes.FakeAutoAllocatedTopology.create_one_topology(
attrs={'id': network_object.id,
- 'tenant_id': project.id}
+ 'project_id': project.id}
)
def setUp(self):
diff --git a/openstackclient/tests/unit/network/v2/test_network_flavor.py b/openstackclient/tests/unit/network/v2/test_network_flavor.py
index 010f53d..20c5b9d 100644
--- a/openstackclient/tests/unit/network/v2/test_network_flavor.py
+++ b/openstackclient/tests/unit/network/v2/test_network_flavor.py
@@ -166,7 +166,7 @@ class TestCreateNetworkFlavor(TestNetworkFlavor):
self.network.create_flavor.assert_called_once_with(**{
'description': self.new_network_flavor.description,
'enabled': True,
- 'tenant_id': self.project.id,
+ 'project_id': self.project.id,
'service_type': self.new_network_flavor.service_type,
'name': self.new_network_flavor.name,
})
diff --git a/openstackclient/tests/unit/network/v2/test_network_flavor_profile.py b/openstackclient/tests/unit/network/v2/test_network_flavor_profile.py
index fcf24da..1cbe30b 100644
--- a/openstackclient/tests/unit/network/v2/test_network_flavor_profile.py
+++ b/openstackclient/tests/unit/network/v2/test_network_flavor_profile.py
@@ -89,7 +89,7 @@ class TestCreateFlavorProfile(TestFlavorProfile):
self.network.create_service_profile.assert_called_once_with(
**{'description': self.new_flavor_profile.description,
- 'tenant_id': self.project.id,
+ 'project_id': self.project.id,
'enabled': self.new_flavor_profile.enabled,
'driver': self.new_flavor_profile.driver,
'metainfo': self.new_flavor_profile.metainfo}
@@ -119,7 +119,7 @@ class TestCreateFlavorProfile(TestFlavorProfile):
self.network.create_service_profile.assert_called_once_with(
**{'description': self.new_flavor_profile.description,
- 'tenant_id': self.project.id,
+ 'project_id': self.project.id,
'enabled': self.new_flavor_profile.enabled,
'metainfo': self.new_flavor_profile.metainfo}
)
@@ -148,7 +148,7 @@ class TestCreateFlavorProfile(TestFlavorProfile):
self.network.create_service_profile.assert_called_once_with(
**{'description': self.new_flavor_profile.description,
- 'tenant_id': self.project.id,
+ 'project_id': self.project.id,
'enabled': self.new_flavor_profile.enabled,
'driver': self.new_flavor_profile.driver,
}
diff --git a/openstackclient/tests/unit/network/v2/test_network_meter.py b/openstackclient/tests/unit/network/v2/test_network_meter.py
index 4fadcfe..5cedf0f 100644
--- a/openstackclient/tests/unit/network/v2/test_network_meter.py
+++ b/openstackclient/tests/unit/network/v2/test_network_meter.py
@@ -112,7 +112,7 @@ class TestCreateMeter(TestMeter):
self.network.create_metering_label.assert_called_once_with(
**{'description': self.new_meter.description,
'name': self.new_meter.name,
- 'tenant_id': self.project.id,
+ 'project_id': self.project.id,
'shared': True, }
)
self.assertEqual(self.columns, columns)
diff --git a/openstackclient/tests/unit/network/v2/test_network_qos_policy.py b/openstackclient/tests/unit/network/v2/test_network_qos_policy.py
index d6a7841..af4cb3f 100644
--- a/openstackclient/tests/unit/network/v2/test_network_qos_policy.py
+++ b/openstackclient/tests/unit/network/v2/test_network_qos_policy.py
@@ -42,7 +42,7 @@ class TestCreateNetworkQosPolicy(TestQosPolicy):
new_qos_policy = (
network_fakes.FakeNetworkQosPolicy.create_one_qos_policy(
attrs={
- 'tenant_id': project.id,
+ 'project_id': project.id,
}
))
columns = (
@@ -123,7 +123,7 @@ class TestCreateNetworkQosPolicy(TestQosPolicy):
self.network.create_qos_policy.assert_called_once_with(**{
'shared': True,
- 'tenant_id': self.project.id,
+ 'project_id': self.project.id,
'name': self.new_qos_policy.name,
'description': 'QoS policy description',
'is_default': True,
@@ -325,7 +325,7 @@ class TestListNetworkQosPolicy(TestQosPolicy):
columns, data = self.cmd.take_action(parsed_args)
self.network.qos_policies.assert_called_once_with(
- **{'tenant_id': project.id}
+ **{'project_id': project.id}
)
self.assertEqual(self.columns, columns)
diff --git a/openstackclient/tests/unit/network/v2/test_network_rbac.py b/openstackclient/tests/unit/network/v2/test_network_rbac.py
index 08be64c..e20efc8 100644
--- a/openstackclient/tests/unit/network/v2/test_network_rbac.py
+++ b/openstackclient/tests/unit/network/v2/test_network_rbac.py
@@ -45,7 +45,7 @@ class TestCreateNetworkRBAC(TestNetworkRBAC):
ag_object = network_fakes.FakeAddressGroup.create_one_address_group()
project = identity_fakes_v3.FakeProject.create_one_project()
rbac_policy = network_fakes.FakeNetworkRBAC.create_one_network_rbac(
- attrs={'tenant_id': project.id,
+ attrs={'project_id': project.id,
'target_tenant': project.id,
'object_id': network_object.id}
)
@@ -64,7 +64,7 @@ class TestCreateNetworkRBAC(TestNetworkRBAC):
rbac_policy.id,
rbac_policy.object_id,
rbac_policy.object_type,
- rbac_policy.tenant_id,
+ rbac_policy.project_id,
rbac_policy.target_tenant,
]
@@ -206,7 +206,7 @@ class TestCreateNetworkRBAC(TestNetworkRBAC):
'--type', self.rbac_policy.object_type,
'--action', self.rbac_policy.action,
'--target-project', self.rbac_policy.target_tenant,
- '--project', self.rbac_policy.tenant_id,
+ '--project', self.rbac_policy.project_id,
'--project-domain', self.project.domain_id,
'--target-project-domain', self.project.domain_id,
self.rbac_policy.object_id,
@@ -215,7 +215,7 @@ class TestCreateNetworkRBAC(TestNetworkRBAC):
('type', self.rbac_policy.object_type),
('action', self.rbac_policy.action),
('target_project', self.rbac_policy.target_tenant),
- ('project', self.rbac_policy.tenant_id),
+ ('project', self.rbac_policy.project_id),
('project_domain', self.project.domain_id),
('target_project_domain', self.project.domain_id),
('rbac_object', self.rbac_policy.object_id),
@@ -230,7 +230,7 @@ class TestCreateNetworkRBAC(TestNetworkRBAC):
'object_type': self.rbac_policy.object_type,
'action': self.rbac_policy.action,
'target_tenant': self.rbac_policy.target_tenant,
- 'tenant_id': self.rbac_policy.tenant_id,
+ 'project_id': self.rbac_policy.project_id,
})
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, list(data))
@@ -276,7 +276,7 @@ class TestCreateNetworkRBAC(TestNetworkRBAC):
self.rbac_policy.id,
obj_fake.id,
obj_type,
- self.rbac_policy.tenant_id,
+ self.rbac_policy.project_id,
self.rbac_policy.target_tenant,
]
self.assertEqual(self.columns, columns)
@@ -541,7 +541,7 @@ class TestShowNetworkRBAC(TestNetworkRBAC):
rbac_policy.id,
rbac_policy.object_id,
rbac_policy.object_type,
- rbac_policy.tenant_id,
+ rbac_policy.project_id,
rbac_policy.target_tenant,
]
diff --git a/openstackclient/tests/unit/network/v2/test_port.py b/openstackclient/tests/unit/network/v2/test_port.py
index 5f2a128..6f830aa 100644
--- a/openstackclient/tests/unit/network/v2/test_port.py
+++ b/openstackclient/tests/unit/network/v2/test_port.py
@@ -1217,7 +1217,6 @@ class TestListPort(TestPort):
columns, data = self.cmd.take_action(parsed_args)
filters = {
- 'tenant_id': project.id,
'project_id': project.id,
'fields': LIST_FIELDS_TO_RETRIEVE,
}
@@ -1241,7 +1240,6 @@ class TestListPort(TestPort):
columns, data = self.cmd.take_action(parsed_args)
filters = {
- 'tenant_id': project.id,
'project_id': project.id,
'fields': LIST_FIELDS_TO_RETRIEVE,
}
@@ -1296,6 +1294,26 @@ class TestListPort(TestPort):
self.assertEqual(self.columns, columns)
self.assertCountEqual(self.data, list(data))
+ def test_port_list_security_group(self):
+ arglist = [
+ '--security-group', 'sg-id1',
+ '--security-group', 'sg-id2',
+ ]
+ verifylist = [
+ ('security_groups', ['sg-id1', 'sg-id2']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {
+ 'security_groups': ['sg-id1', 'sg-id2'],
+ 'fields': LIST_FIELDS_TO_RETRIEVE,
+ }
+
+ self.network.ports.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertCountEqual(self.data, list(data))
+
class TestSetPort(TestPort):
@@ -1709,6 +1727,27 @@ class TestSetPort(TestPort):
self.network.update_port.assert_called_once_with(self._port, **attrs)
self.assertIsNone(result)
+ def test_set_port_extra_dhcp_option(self):
+ arglist = [
+ '--extra-dhcp-option', 'name=foo,value=bar',
+ self._port.name,
+ ]
+ verifylist = [
+ ('extra_dhcp_options', [{'name': 'foo',
+ 'value': 'bar'}]),
+ ('port', self._port.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'extra_dhcp_opts': [{'opt_name': 'foo',
+ 'opt_value': 'bar'}],
+ }
+ self.network.update_port.assert_called_once_with(self._port, **attrs)
+ self.assertIsNone(result)
+
def test_set_port_security_enabled(self):
arglist = [
'--enable-port-security',
@@ -1923,6 +1962,7 @@ class TestUnsetPort(TestPort):
'subnet=042eb10a-3a18-4658-ab-cf47c8d03152,ip-address=1.0.0.0',
'--binding-profile', 'Superman',
'--qos-policy',
+ '--host',
self._testport.name,
]
verifylist = [
@@ -1931,6 +1971,7 @@ class TestUnsetPort(TestPort):
'ip-address': '1.0.0.0'}]),
('binding_profile', ['Superman']),
('qos_policy', True),
+ ('host', True)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1941,7 +1982,8 @@ class TestUnsetPort(TestPort):
'subnet_id': '042eb10a-3a18-4658-ab-cf47c8d03152',
'ip_address': '0.0.0.1'}],
'binding:profile': {'batman': 'Joker'},
- 'qos_policy_id': None
+ 'qos_policy_id': None,
+ 'binding:host_id': None
}
self.network.update_port.assert_called_once_with(
self._testport, **attrs)
diff --git a/openstackclient/tests/unit/network/v2/test_router.py b/openstackclient/tests/unit/network/v2/test_router.py
index 0324674..4d03507 100644
--- a/openstackclient/tests/unit/network/v2/test_router.py
+++ b/openstackclient/tests/unit/network/v2/test_router.py
@@ -141,7 +141,7 @@ class TestCreateRouter(TestRouter):
new_router.ha,
new_router.id,
new_router.name,
- new_router.tenant_id,
+ new_router.project_id,
router.RoutesColumn(new_router.routes),
new_router.status,
format_columns.ListColumn(new_router.tags),
@@ -186,6 +186,43 @@ class TestCreateRouter(TestRouter):
self.assertEqual(self.columns, columns)
self.assertCountEqual(self.data, data)
+ def test_create_with_gateway(self):
+ _network = network_fakes.FakeNetwork.create_one_network()
+ _subnet = network_fakes.FakeSubnet.create_one_subnet()
+ self.network.find_network = mock.Mock(return_value=_network)
+ self.network.find_subnet = mock.Mock(return_value=_subnet)
+ arglist = [
+ self.new_router.name,
+ '--external-gateway', _network.name,
+ '--enable-snat',
+ '--fixed-ip', 'ip-address=2001:db8::1'
+ ]
+ verifylist = [
+ ('name', self.new_router.name),
+ ('enable', True),
+ ('distributed', False),
+ ('ha', False),
+ ('external_gateway', _network.name),
+ ('enable_snat', True),
+ ('fixed_ip', [{'ip-address': '2001:db8::1'}]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = (self.cmd.take_action(parsed_args))
+
+ self.network.create_router.assert_called_once_with(**{
+ 'admin_state_up': True,
+ 'name': self.new_router.name,
+ 'external_gateway_info': {
+ 'network_id': _network.id,
+ 'enable_snat': True,
+ 'external_fixed_ips': [{'ip_address': '2001:db8::1'}],
+ },
+ })
+ self.assertFalse(self.network.set_tags.called)
+ self.assertEqual(self.columns, columns)
+ self.assertCountEqual(self.data, data)
+
def _test_create_with_ha_options(self, option, ha):
arglist = [
option,
@@ -423,7 +460,7 @@ class TestListRouter(TestRouter):
r.name,
r.status,
router.AdminStateColumn(r.admin_state_up),
- r.tenant_id,
+ r.project_id,
r.distributed,
r.ha,
))
@@ -619,7 +656,7 @@ class TestListRouter(TestRouter):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
- filters = {'tenant_id': project.id, 'project_id': project.id}
+ filters = {'project_id': project.id}
self.network.routers.assert_called_once_with(**filters)
self.assertEqual(self.columns, columns)
@@ -639,7 +676,7 @@ class TestListRouter(TestRouter):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
- filters = {'tenant_id': project.id, 'project_id': project.id}
+ filters = {'project_id': project.id}
self.network.routers.assert_called_once_with(**filters)
self.assertEqual(self.columns, columns)
@@ -1364,7 +1401,7 @@ class TestShowRouter(TestRouter):
_router.id,
router.RouterInfoColumn(_router.interfaces_info),
_router.name,
- _router.tenant_id,
+ _router.project_id,
router.RoutesColumn(_router.routes),
_router.status,
format_columns.ListColumn(_router.tags),
diff --git a/openstackclient/tests/unit/network/v2/test_security_group_network.py b/openstackclient/tests/unit/network/v2/test_security_group_network.py
index 569c0cd..95262bf 100644
--- a/openstackclient/tests/unit/network/v2/test_security_group_network.py
+++ b/openstackclient/tests/unit/network/v2/test_security_group_network.py
@@ -121,7 +121,7 @@ class TestCreateSecurityGroupNetwork(TestSecurityGroupNetwork):
'description': self._security_group.description,
'stateful': self._security_group.stateful,
'name': self._security_group.name,
- 'tenant_id': self.project.id,
+ 'project_id': self.project.id,
})
self.assertEqual(self.columns, columns)
self.assertCountEqual(self.data, data)
@@ -324,7 +324,7 @@ class TestListSecurityGroupNetwork(TestSecurityGroupNetwork):
columns, data = self.cmd.take_action(parsed_args)
filters = {
- 'tenant_id': project.id, 'project_id': project.id,
+ 'project_id': project.id,
'fields': security_group.ListSecurityGroup.FIELDS_TO_RETRIEVE}
self.network.security_groups.assert_called_once_with(**filters)
@@ -346,7 +346,7 @@ class TestListSecurityGroupNetwork(TestSecurityGroupNetwork):
columns, data = self.cmd.take_action(parsed_args)
filters = {
- 'tenant_id': project.id, 'project_id': project.id,
+ 'project_id': project.id,
'fields': security_group.ListSecurityGroup.FIELDS_TO_RETRIEVE}
self.network.security_groups.assert_called_once_with(**filters)
diff --git a/openstackclient/tests/unit/network/v2/test_security_group_rule_network.py b/openstackclient/tests/unit/network/v2/test_security_group_rule_network.py
index bcdb0c2..4e765f3 100644
--- a/openstackclient/tests/unit/network/v2/test_security_group_rule_network.py
+++ b/openstackclient/tests/unit/network/v2/test_security_group_rule_network.py
@@ -458,7 +458,7 @@ class TestCreateSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
'protocol': self._security_group_rule.protocol,
'remote_ip_prefix': self._security_group_rule.remote_ip_prefix,
'security_group_id': self._security_group.id,
- 'tenant_id': self.project.id,
+ 'project_id': self.project.id,
})
self.assertEqual(self.expected_columns, columns)
self.assertEqual(self.expected_data, data)
diff --git a/openstackclient/tests/unit/network/v2/test_subnet.py b/openstackclient/tests/unit/network/v2/test_subnet.py
index 5147b64..dcac2ef 100644
--- a/openstackclient/tests/unit/network/v2/test_subnet.py
+++ b/openstackclient/tests/unit/network/v2/test_subnet.py
@@ -44,7 +44,7 @@ class TestCreateSubnet(TestSubnet):
# An IPv4 subnet to be created with mostly default values
self._subnet = network_fakes.FakeSubnet.create_one_subnet(
attrs={
- 'tenant_id': self.project.id,
+ 'project_id': self.project.id,
}
)
@@ -55,7 +55,7 @@ class TestCreateSubnet(TestSubnet):
# An IPv4 subnet to be created using a specific subnet pool
self._subnet_from_pool = network_fakes.FakeSubnet.create_one_subnet(
attrs={
- 'tenant_id': self.project.id,
+ 'project_id': self.project.id,
'subnetpool_id': self._subnet_pool.id,
'dns_nameservers': ['8.8.8.8',
'8.8.4.4'],
@@ -71,7 +71,7 @@ class TestCreateSubnet(TestSubnet):
# An IPv6 subnet to be created with most options specified
self._subnet_ipv6 = network_fakes.FakeSubnet.create_one_subnet(
attrs={
- 'tenant_id': self.project.id,
+ 'project_id': self.project.id,
'cidr': 'fe80:0:0:a00a::/64',
'enable_dhcp': True,
'dns_nameservers': ['fe80:27ff:a00a:f00f::ffff',
@@ -661,7 +661,7 @@ class TestListSubnet(TestSubnet):
subnet.name,
subnet.network_id,
subnet.cidr,
- subnet.tenant_id,
+ subnet.project_id,
subnet.enable_dhcp,
format_columns.ListColumn(subnet.dns_nameservers),
subnet_v2.AllocationPoolsColumn(subnet.allocation_pools),
@@ -783,7 +783,7 @@ class TestListSubnet(TestSubnet):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
- filters = {'tenant_id': project.id, 'project_id': project.id}
+ filters = {'project_id': project.id}
self.network.subnets.assert_called_once_with(**filters)
self.assertEqual(self.columns, columns)
@@ -821,7 +821,7 @@ class TestListSubnet(TestSubnet):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
- filters = {'tenant_id': project.id, 'project_id': project.id}
+ filters = {'project_id': project.id}
self.network.subnets.assert_called_once_with(**filters)
self.assertEqual(self.columns, columns)
@@ -899,6 +899,48 @@ class TestListSubnet(TestSubnet):
self.assertEqual(self.columns, columns)
self.assertCountEqual(self.data, list(data))
+ def test_subnet_list_subnetpool_by_name(self):
+ subnet_pool = network_fakes.FakeSubnetPool.create_one_subnet_pool()
+ subnet = network_fakes.FakeSubnet.create_one_subnet(
+ {'subnetpool_id': subnet_pool.id})
+ self.network.find_network = mock.Mock(return_value=subnet)
+ self.network.find_subnet_pool = mock.Mock(return_value=subnet_pool)
+ arglist = [
+ '--subnet-pool', subnet_pool.name,
+ ]
+ verifylist = [
+ ('subnet_pool', subnet_pool.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'subnetpool_id': subnet_pool.id}
+
+ self.network.subnets.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertItemsEqual(self.data, list(data))
+
+ def test_subnet_list_subnetpool_by_id(self):
+ subnet_pool = network_fakes.FakeSubnetPool.create_one_subnet_pool()
+ subnet = network_fakes.FakeSubnet.create_one_subnet(
+ {'subnetpool_id': subnet_pool.id})
+ self.network.find_network = mock.Mock(return_value=subnet)
+ self.network.find_subnet_pool = mock.Mock(return_value=subnet_pool)
+ arglist = [
+ '--subnet-pool', subnet_pool.id,
+ ]
+ verifylist = [
+ ('subnet_pool', subnet_pool.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'subnetpool_id': subnet_pool.id}
+
+ self.network.subnets.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertItemsEqual(self.data, list(data))
+
def test_list_with_tag_options(self):
arglist = [
'--tags', 'red,blue',
@@ -1205,7 +1247,7 @@ class TestShowSubnet(TestSubnet):
_subnet.ipv6_ra_mode,
_subnet.name,
_subnet.network_id,
- _subnet.tenant_id,
+ _subnet.project_id,
_subnet.segment_id,
format_columns.ListColumn(_subnet.service_types),
_subnet.subnetpool_id,
diff --git a/openstackclient/tests/unit/network/v2/test_subnet_pool.py b/openstackclient/tests/unit/network/v2/test_subnet_pool.py
index 4d18dc9..55d2cc2 100644
--- a/openstackclient/tests/unit/network/v2/test_subnet_pool.py
+++ b/openstackclient/tests/unit/network/v2/test_subnet_pool.py
@@ -197,7 +197,7 @@ class TestCreateSubnetPool(TestSubnetPool):
self.network.create_subnet_pool.assert_called_once_with(**{
'prefixes': ['10.0.10.0/24'],
- 'tenant_id': self.project.id,
+ 'project_id': self.project.id,
'name': self._subnet_pool.name,
})
self.assertEqual(self.columns, columns)
@@ -569,7 +569,7 @@ class TestListSubnetPool(TestSubnetPool):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
- filters = {'tenant_id': project.id, 'project_id': project.id}
+ filters = {'project_id': project.id}
self.network.subnet_pools.assert_called_once_with(**filters)
self.assertEqual(self.columns, columns)
@@ -589,7 +589,7 @@ class TestListSubnetPool(TestSubnetPool):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
- filters = {'tenant_id': project.id, 'project_id': project.id}
+ filters = {'project_id': project.id}
self.network.subnet_pools.assert_called_once_with(**filters)
self.assertEqual(self.columns, columns)
@@ -970,7 +970,7 @@ class TestShowSubnetPool(TestSubnetPool):
_subnet_pool.min_prefixlen,
_subnet_pool.name,
format_columns.ListColumn(_subnet_pool.prefixes),
- _subnet_pool.tenant_id,
+ _subnet_pool.project_id,
_subnet_pool.shared,
format_columns.ListColumn(_subnet_pool.tags),
)
diff --git a/openstackclient/tests/unit/volume/v1/test_volume.py b/openstackclient/tests/unit/volume/v1/test_volume.py
index 702f79e..584eca2 100644
--- a/openstackclient/tests/unit/volume/v1/test_volume.py
+++ b/openstackclient/tests/unit/volume/v1/test_volume.py
@@ -317,7 +317,7 @@ class TestVolumeCreate(TestVolume):
self.assertCountEqual(self.datalist, data)
def test_volume_create_image_id(self):
- image = image_fakes.FakeImage.create_one_image()
+ image = image_fakes.create_one_image()
self.images_mock.get.return_value = image
arglist = [
@@ -360,7 +360,7 @@ class TestVolumeCreate(TestVolume):
self.assertCountEqual(self.datalist, data)
def test_volume_create_image_name(self):
- image = image_fakes.FakeImage.create_one_image()
+ image = image_fakes.create_one_image()
self.images_mock.get.return_value = image
arglist = [
diff --git a/openstackclient/tests/unit/volume/v2/fakes.py b/openstackclient/tests/unit/volume/v2/fakes.py
index b5f66d4..96e381d 100644
--- a/openstackclient/tests/unit/volume/v2/fakes.py
+++ b/openstackclient/tests/unit/volume/v2/fakes.py
@@ -18,6 +18,7 @@ from unittest import mock
import uuid
from cinderclient import api_versions
+from openstack.block_storage.v3 import volume
from osc_lib.cli import format_columns
from openstackclient.tests.unit import fakes
@@ -46,7 +47,7 @@ class FakeTransfer(object):
def create_one_transfer(attrs=None):
"""Create a fake transfer.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes of Transfer Request
:return:
A FakeResource object with volume_id, name, id.
@@ -75,7 +76,7 @@ class FakeTransfer(object):
def create_transfers(attrs=None, count=2):
"""Create multiple fake transfers.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes of transfer
:param Integer count:
The number of transfers to be faked
@@ -116,7 +117,7 @@ class FakeTypeAccess(object):
def create_one_type_access(attrs=None):
"""Create a fake volume type access for project.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes
:return:
A FakeResource object, with Volume_type_ID and Project_ID.
@@ -148,7 +149,7 @@ class FakeService(object):
def create_one_service(attrs=None):
"""Create a fake service.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes of service
:return:
A FakeResource object with host, status, etc.
@@ -180,7 +181,7 @@ class FakeService(object):
def create_services(attrs=None, count=2):
"""Create multiple fake services.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes of service
:param Integer count:
The number of services to be faked
@@ -201,7 +202,7 @@ class FakeCapability(object):
def create_one_capability(attrs=None):
"""Create a fake volume backend capability.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes of the Capabilities.
:return:
A FakeResource object with capability name and attrs.
@@ -260,7 +261,7 @@ class FakePool(object):
def create_one_pool(attrs=None):
"""Create a fake pool.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes of the pool
:return:
A FakeResource object with pool name and attrs.
@@ -362,7 +363,7 @@ class FakeVolume(object):
def create_one_volume(attrs=None):
"""Create a fake volume.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes of volume
:return:
A FakeResource object with id, name, status, etc.
@@ -405,7 +406,7 @@ class FakeVolume(object):
def create_volumes(attrs=None, count=2):
"""Create multiple fake volumes.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes of volume
:param Integer count:
The number of volumes to be faked
@@ -419,6 +420,61 @@ class FakeVolume(object):
return volumes
@staticmethod
+ def create_one_sdk_volume(attrs=None):
+ """Create a fake volume.
+
+ :param dict attrs:
+ A dictionary with all attributes of volume
+ :return:
+ A FakeResource object with id, name, status, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attribute
+ volume_info = {
+ 'id': 'volume-id' + uuid.uuid4().hex,
+ 'name': 'volume-name' + uuid.uuid4().hex,
+ 'description': 'description' + uuid.uuid4().hex,
+ 'status': random.choice(['available', 'in_use']),
+ 'size': random.randint(1, 20),
+ 'volume_type':
+ random.choice(['fake_lvmdriver-1', 'fake_lvmdriver-2']),
+ 'bootable':
+ random.choice(['true', 'false']),
+ 'metadata': {
+ 'key' + uuid.uuid4().hex: 'val' + uuid.uuid4().hex,
+ 'key' + uuid.uuid4().hex: 'val' + uuid.uuid4().hex,
+ 'key' + uuid.uuid4().hex: 'val' + uuid.uuid4().hex},
+ 'snapshot_id': random.randint(1, 5),
+ 'availability_zone': 'zone' + uuid.uuid4().hex,
+ 'attachments': [{
+ 'device': '/dev/' + uuid.uuid4().hex,
+ 'server_id': uuid.uuid4().hex,
+ }, ],
+ }
+
+ # Overwrite default attributes if there are some attributes set
+ volume_info.update(attrs)
+ return volume.Volume(**volume_info)
+
+ @staticmethod
+ def create_sdk_volumes(attrs=None, count=2):
+ """Create multiple fake volumes.
+
+ :param dict attrs:
+ A dictionary with all attributes of volume
+ :param Integer count:
+ The number of volumes to be faked
+ :return:
+ A list of FakeResource objects
+ """
+ volumes = []
+ for n in range(0, count):
+ volumes.append(FakeVolume.create_one_sdk_volume(attrs))
+
+ return volumes
+
+ @staticmethod
def get_volumes(volumes=None, count=2):
"""Get an iterable MagicMock object with a list of faked volumes.
@@ -484,7 +540,7 @@ class FakeAvailabilityZone(object):
def create_one_availability_zone(attrs=None):
"""Create a fake AZ.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes
:return:
A FakeResource object with zoneName, zoneState, etc.
@@ -509,7 +565,7 @@ class FakeAvailabilityZone(object):
def create_availability_zones(attrs=None, count=2):
"""Create multiple fake AZs.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes
:param int count:
The number of AZs to fake
@@ -532,7 +588,7 @@ class FakeBackup(object):
def create_one_backup(attrs=None):
"""Create a fake backup.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes
:return:
A FakeResource object with id, name, volume_id, etc.
@@ -565,7 +621,7 @@ class FakeBackup(object):
def create_backups(attrs=None, count=2):
"""Create multiple fake backups.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes
:param int count:
The number of backups to fake
@@ -636,7 +692,7 @@ class FakeConsistencyGroup(object):
def create_one_consistency_group(attrs=None):
"""Create a fake consistency group.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes
:return:
A FakeResource object with id, name, description, etc.
@@ -666,7 +722,7 @@ class FakeConsistencyGroup(object):
def create_consistency_groups(attrs=None, count=2):
"""Create multiple fake consistency groups.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes
:param int count:
The number of consistency groups to fake
@@ -713,7 +769,7 @@ class FakeConsistencyGroupSnapshot(object):
def create_one_consistency_group_snapshot(attrs=None):
"""Create a fake consistency group snapshot.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes
:return:
A FakeResource object with id, name, description, etc.
@@ -742,7 +798,7 @@ class FakeConsistencyGroupSnapshot(object):
def create_consistency_group_snapshots(attrs=None, count=2):
"""Create multiple fake consistency group snapshots.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes
:param int count:
The number of consistency group snapshots to fake
@@ -789,7 +845,7 @@ class FakeExtension(object):
def create_one_extension(attrs=None):
"""Create a fake extension.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes
:return:
A FakeResource object with name, namespace, etc.
@@ -825,7 +881,7 @@ class FakeQos(object):
def create_one_qos(attrs=None):
"""Create a fake Qos specification.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes
:return:
A FakeResource object with id, name, consumer, etc.
@@ -852,7 +908,7 @@ class FakeQos(object):
def create_one_qos_association(attrs=None):
"""Create a fake Qos specification association.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes
:return:
A FakeResource object with id, name, association_type, etc.
@@ -878,7 +934,7 @@ class FakeQos(object):
def create_qoses(attrs=None, count=2):
"""Create multiple fake Qos specifications.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes
:param int count:
The number of Qos specifications to fake
@@ -920,7 +976,7 @@ class FakeSnapshot(object):
def create_one_snapshot(attrs=None):
"""Create a fake snapshot.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes
:return:
A FakeResource object with id, name, description, etc.
@@ -951,7 +1007,7 @@ class FakeSnapshot(object):
def create_snapshots(attrs=None, count=2):
"""Create multiple fake snapshots.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes
:param int count:
The number of snapshots to fake
@@ -993,9 +1049,9 @@ class FakeVolumeType(object):
def create_one_volume_type(attrs=None, methods=None):
"""Create a fake volume type.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes
- :param Dictionary methods:
+ :param dict methods:
A dictionary with all methods
:return:
A FakeResource object with id, name, description, etc.
@@ -1025,7 +1081,7 @@ class FakeVolumeType(object):
def create_volume_types(attrs=None, count=2):
"""Create multiple fake volume_types.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes
:param int count:
The number of types to fake
@@ -1063,7 +1119,7 @@ class FakeVolumeType(object):
def create_one_encryption_volume_type(attrs=None):
"""Create a fake encryption volume type.
- :param Dictionary attrs:
+ :param dict attrs:
A dictionary with all attributes
:return:
A FakeResource object with volume_type_id etc.
diff --git a/openstackclient/tests/unit/volume/v2/test_volume.py b/openstackclient/tests/unit/volume/v2/test_volume.py
index 4aa6f90..ec82e67 100644
--- a/openstackclient/tests/unit/volume/v2/test_volume.py
+++ b/openstackclient/tests/unit/volume/v2/test_volume.py
@@ -221,7 +221,7 @@ class TestVolumeCreate(TestVolume):
self.assertCountEqual(self.datalist, data)
def test_volume_create_image_id(self):
- image = image_fakes.FakeImage.create_one_image()
+ image = image_fakes.create_one_image()
self.find_image_mock.return_value = image
arglist = [
@@ -259,7 +259,7 @@ class TestVolumeCreate(TestVolume):
self.assertCountEqual(self.datalist, data)
def test_volume_create_image_name(self):
- image = image_fakes.FakeImage.create_one_image()
+ image = image_fakes.create_one_image()
self.find_image_mock.return_value = image
arglist = [
diff --git a/python_openstackclient.egg-info/PKG-INFO b/python_openstackclient.egg-info/PKG-INFO
index 16507c6..7868b65 100644
--- a/python_openstackclient.egg-info/PKG-INFO
+++ b/python_openstackclient.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.2
Name: python-openstackclient
-Version: 5.7.0
+Version: 5.8.0
Summary: OpenStack Command-line Client
Home-page: https://docs.openstack.org/python-openstackclient/latest/
Author: OpenStack
diff --git a/python_openstackclient.egg-info/SOURCES.txt b/python_openstackclient.egg-info/SOURCES.txt
index 0776d2e..43ad681 100644
--- a/python_openstackclient.egg-info/SOURCES.txt
+++ b/python_openstackclient.egg-info/SOURCES.txt
@@ -82,6 +82,8 @@ doc/source/cli/command-objects/ip-availability.rst
doc/source/cli/command-objects/keypair.rst
doc/source/cli/command-objects/limit.rst
doc/source/cli/command-objects/limits.rst
+doc/source/cli/command-objects/local-ip-association.rst
+doc/source/cli/command-objects/local-ip.rst
doc/source/cli/command-objects/mapping.rst
doc/source/cli/command-objects/module.rst
doc/source/cli/command-objects/network-agent.rst
@@ -156,7 +158,6 @@ doc/source/cli/data/neutron.csv
doc/source/cli/data/nova.csv
doc/source/cli/data/swift.csv
doc/source/cli/man/openstack.rst
-doc/source/cli/plugin-commands/aodh.rst
doc/source/cli/plugin-commands/barbican.rst
doc/source/cli/plugin-commands/designate.rst
doc/source/cli/plugin-commands/gnocchi.rst
@@ -295,6 +296,8 @@ openstackclient/network/v2/floating_ip_pool.py
openstackclient/network/v2/floating_ip_port_forwarding.py
openstackclient/network/v2/ip_availability.py
openstackclient/network/v2/l3_conntrack_helper.py
+openstackclient/network/v2/local_ip.py
+openstackclient/network/v2/local_ip_association.py
openstackclient/network/v2/network.py
openstackclient/network/v2/network_agent.py
openstackclient/network/v2/network_auto_allocated_topology.py
@@ -384,6 +387,7 @@ openstackclient/tests/functional/network/v2/test_address_scope.py
openstackclient/tests/functional/network/v2/test_floating_ip.py
openstackclient/tests/functional/network/v2/test_ip_availability.py
openstackclient/tests/functional/network/v2/test_l3_conntrack_helper.py
+openstackclient/tests/functional/network/v2/test_local_ip.py
openstackclient/tests/functional/network/v2/test_network.py
openstackclient/tests/functional/network/v2/test_network_agent.py
openstackclient/tests/functional/network/v2/test_network_flavor.py
@@ -543,6 +547,8 @@ openstackclient/tests/unit/network/v2/test_floating_ip_pool_network.py
openstackclient/tests/unit/network/v2/test_floating_ip_port_forwarding.py
openstackclient/tests/unit/network/v2/test_ip_availability.py
openstackclient/tests/unit/network/v2/test_l3_conntrack_helper.py
+openstackclient/tests/unit/network/v2/test_local_ip.py
+openstackclient/tests/unit/network/v2/test_local_ip_association.py
openstackclient/tests/unit/network/v2/test_network.py
openstackclient/tests/unit/network/v2/test_network_agent.py
openstackclient/tests/unit/network/v2/test_network_auto_allocated_topology.py
@@ -678,12 +684,14 @@ releasenotes/notes/add-missing-volume-backup-opts-b9246aded87427ce.yaml
releasenotes/notes/add-network-auto-allocated-topology-481580f48840bfc4.yaml
releasenotes/notes/add-network-flavor-profile-e7cc5b353c3ed9d9.yaml
releasenotes/notes/add-network-list-option-to-ports-9d101344ddeb3e64.yaml
+releasenotes/notes/add-network-local-ip-df3a9ce7610d8b90.yaml
releasenotes/notes/add-network-qos-policy-b8ad1e408d73c279.yaml
releasenotes/notes/add-network-qos-rule-22cc1ddd509941db.yaml
releasenotes/notes/add-network-qos-rule-type-show-57a714a1d428726e.yaml
releasenotes/notes/add-network-qos-rule-types-337e464c6e81f29c.yaml
releasenotes/notes/add-network-service-provider-c161a4a328a8a408.yaml
releasenotes/notes/add-no-property-f97e4b2f390cec06.yaml
+releasenotes/notes/add-option-to-unset-port-host-c76de9b1d2addf9a.yaml
releasenotes/notes/add-osprofiler-support-adf5286daf220914.yaml
releasenotes/notes/add-overwrite-option-to-router-7c50c8031dab6bae.yaml
releasenotes/notes/add-parent-list-option-to-projects-10382a7176993366.yaml
@@ -697,6 +705,7 @@ releasenotes/notes/add-project-cleanup-beb08c9df3c95b24.yaml
releasenotes/notes/add-qos-policy-list-options-9ba1ae731a88e7ac.yaml
releasenotes/notes/add-quota-list-command-0d865fac61db2430.yaml
releasenotes/notes/add-quota-set-for-network-11fcd7b9e08624b5.yaml
+releasenotes/notes/add-remote-managed-vnic-type-4fc540b47427c37f.yaml
releasenotes/notes/add-restore-server-d8c73e0e83df17dd.yaml
releasenotes/notes/add-server-add-network-98ede8ff6079eb23.yaml
releasenotes/notes/add-server-backup-e63feaebb6140f83.yaml
@@ -1043,6 +1052,7 @@ releasenotes/notes/bug-2007513-ae39456aeb93bb98.yaml
releasenotes/notes/bug-27882-402ced7ffe930058.yaml
releasenotes/notes/bug-volume-list-with-project-2dc867c5e8346a66.yaml
releasenotes/notes/change-098377fd53cce7a0.yaml
+releasenotes/notes/check-limit-quota-cc7f291dd1b537c1.yaml
releasenotes/notes/cliff-2.3.0-7ead18fae9ceea80.yaml
releasenotes/notes/complete_image_switch-203e0b3105a54674.yaml
releasenotes/notes/compute-agent-deff48988e81b30e.yaml
@@ -1052,6 +1062,7 @@ releasenotes/notes/credential_list_user_type-c809e5b8014d6275.yaml
releasenotes/notes/deprecated-server-create-file-option-80246b13bd3c1b43.yaml
releasenotes/notes/drop-py2-421c90fbdf18dbc2.yaml
releasenotes/notes/entrypoint-3.8-0597d159889042f7.yaml
+releasenotes/notes/fix-flavor-in-server-list-microversion-2.47-af200e9bb4747e2d.yaml
releasenotes/notes/fix-flavor-props-formatting-d21e97745543caa7.yaml
releasenotes/notes/fix-network-rbac-create-d1f4de77ad2dd421.yaml
releasenotes/notes/fix-openstak-image-save-sdk-port-eb160e8ffc92e514.yaml
@@ -1076,10 +1087,18 @@ releasenotes/notes/keypair-user-id-db694210695a0ee0.yaml
releasenotes/notes/keystone-endpoint-filter-e930a7b72276fa2c.yaml
releasenotes/notes/keystone-endpoint-group-0c55debbb66844f2.yaml
releasenotes/notes/list-detailed-quota-informations-1755129e1c68a252.yaml
+releasenotes/notes/list-subnet-by-pool-id-a642efc13d04fa08.yaml
releasenotes/notes/list_role_assignment_names-0db89f50259d4be2.yaml
releasenotes/notes/list_volume_type_access-f7d9aa6159f757ea.yaml
releasenotes/notes/make-snapshot-and-backup-name-optional-01971d33640ef1c8.yaml
+releasenotes/notes/migrate-add-fixed-ip-to-sdk-3d932d77633bc765.yaml
+releasenotes/notes/migrate-create-server-image-to-sdk-e3d8077ffe05bb3d.yaml
+releasenotes/notes/migrate-server-add-network-add-port-to-sdk-7d81b25f59cfbec9.yaml
+releasenotes/notes/migrate-server-add-volume-to-sdk-685e036a88839651.yaml
releasenotes/notes/migrate-server-backup-to-sdk-0f170baf38e98b40.yaml
+releasenotes/notes/migrate-server-pause-unpause-to-sdk-d74ec8536b764af6.yaml
+releasenotes/notes/migrate-server-suspend-resume-to-sdk-fd1709336607b496.yaml
+releasenotes/notes/migrate-service-list-delete-set-to-sdk-920cbe0d210af565.yaml
releasenotes/notes/modify-compute-agent-set-77ff894ef62ebbc7.yaml
releasenotes/notes/name-lookup-one-by-one-e0f15f4eab329b19.yaml
releasenotes/notes/network-add-qos-policy-a25e868e67142f90.yaml
@@ -1090,13 +1109,16 @@ releasenotes/notes/neutron-client-flavors-81387171f67a3c82.yaml
releasenotes/notes/neutron_mtu-d87e53e2d76f8612.yaml
releasenotes/notes/no-project-usage-list-e88eb49aa2e96cf7.yaml
releasenotes/notes/object-stdout-db76cc500948b0e8.yaml
+releasenotes/notes/options-create-router-97910a882b604652.yaml
releasenotes/notes/osc-included-image-signing-a7021a4dbdcf6336.yaml
releasenotes/notes/osc4-compute-09246008eff260cb.yaml
releasenotes/notes/osc4-identity-6564257c67d43106.yaml
releasenotes/notes/osc4-image-e922ee6f8e028648.yaml
releasenotes/notes/osc4-network-db2aed696d964ca6.yaml
releasenotes/notes/osc4-volume-470422e5a453310e.yaml
+releasenotes/notes/pass_ssh_args-cf26a2ce26ccddaf.yaml
releasenotes/notes/port-device-profile-4a3bf800da21c778.yaml
+releasenotes/notes/port-list-security-group-4af5d2e789174ff9.yaml
releasenotes/notes/properties-with-image-property-field.yaml-c51bf37c3106d6ff.yaml
releasenotes/notes/rbac-add-address-group-f9bb83238b5a7c1f.yaml
releasenotes/notes/rbac-add-address-scope-7f6409ab70d36306.yaml
@@ -1152,6 +1174,8 @@ releasenotes/notes/switch-aggregate-to-sdk-ced451a0f28bf6ea.yaml
releasenotes/notes/switch-console-log-to-sdk-6ee92b7833364d3d.yaml
releasenotes/notes/switch-flavor-to-sdk-b874a3c39559815e.yaml
releasenotes/notes/switch-keypair-to-sdk-81e28380e66a7f9c.yaml
+releasenotes/notes/switch-server-remove-network-port-to-sdk-829ba711e0e198d5.yaml
+releasenotes/notes/switch-server-remove-volume-to-sdk-47e9befd2672dcdf.yaml
releasenotes/notes/task-40279-eb0d718ac1959c50.yaml
releasenotes/notes/unlock-volume-a6990fc3bf1f5f67.yaml
releasenotes/notes/unset-router-7b0cbd9518bb1de6.yaml
diff --git a/python_openstackclient.egg-info/entry_points.txt b/python_openstackclient.egg-info/entry_points.txt
index 0715a79..28d1638 100644
--- a/python_openstackclient.egg-info/entry_points.txt
+++ b/python_openstackclient.egg-info/entry_points.txt
@@ -334,6 +334,14 @@ floating_ip_show = openstackclient.network.v2.floating_ip:ShowFloatingIP
floating_ip_unset = openstackclient.network.v2.floating_ip:UnsetFloatingIP
ip_availability_list = openstackclient.network.v2.ip_availability:ListIPAvailability
ip_availability_show = openstackclient.network.v2.ip_availability:ShowIPAvailability
+local_ip_association_create = openstackclient.network.v2.local_ip_association:CreateLocalIPAssociation
+local_ip_association_delete = openstackclient.network.v2.local_ip_association:DeleteLocalIPAssociation
+local_ip_association_list = openstackclient.network.v2.local_ip_association:ListLocalIPAssociation
+local_ip_create = openstackclient.network.v2.local_ip:CreateLocalIP
+local_ip_delete = openstackclient.network.v2.local_ip:DeleteLocalIP
+local_ip_list = openstackclient.network.v2.local_ip:ListLocalIP
+local_ip_set = openstackclient.network.v2.local_ip:SetLocalIP
+local_ip_show = openstackclient.network.v2.local_ip:ShowLocalIP
network_agent_add_network = openstackclient.network.v2.network_agent:AddNetworkToAgent
network_agent_add_router = openstackclient.network.v2.network_agent:AddRouterToAgent
network_agent_delete = openstackclient.network.v2.network_agent:DeleteNetworkAgent
diff --git a/python_openstackclient.egg-info/pbr.json b/python_openstackclient.egg-info/pbr.json
index 743394d..b97b200 100644
--- a/python_openstackclient.egg-info/pbr.json
+++ b/python_openstackclient.egg-info/pbr.json
@@ -1 +1 @@
-{"git_version": "163cb01e", "is_release": true} \ No newline at end of file
+{"git_version": "63452f36", "is_release": true} \ No newline at end of file
diff --git a/python_openstackclient.egg-info/requires.txt b/python_openstackclient.egg-info/requires.txt
index 2436826..0e3fadd 100644
--- a/python_openstackclient.egg-info/requires.txt
+++ b/python_openstackclient.egg-info/requires.txt
@@ -1,6 +1,6 @@
cliff>=3.5.0
iso8601>=0.1.11
-openstacksdk>=0.56.0
+openstacksdk>=0.61.0
osc-lib>=2.3.0
oslo.i18n>=3.15.3
oslo.utils>=3.33.0
diff --git a/releasenotes/notes/add-network-local-ip-df3a9ce7610d8b90.yaml b/releasenotes/notes/add-network-local-ip-df3a9ce7610d8b90.yaml
new file mode 100644
index 0000000..dbbd302
--- /dev/null
+++ b/releasenotes/notes/add-network-local-ip-df3a9ce7610d8b90.yaml
@@ -0,0 +1,8 @@
+---
+features:
+ - Add ``local ip create``, ``local ip delete``,
+ ``local ip list``, ``local ip set``, ``local ip show``,
+ ``local ip association create``, ``local ip association delete``
+ and ``local ip association list`` commands to support Neutron Local IP
+ CRUD operations.
+ [`bug 1930200 <https://bugs.launchpad.net/neutron/+bug/1930200>`_]
diff --git a/releasenotes/notes/add-option-to-unset-port-host-c76de9b1d2addf9a.yaml b/releasenotes/notes/add-option-to-unset-port-host-c76de9b1d2addf9a.yaml
new file mode 100644
index 0000000..0aa0476
--- /dev/null
+++ b/releasenotes/notes/add-option-to-unset-port-host-c76de9b1d2addf9a.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ Add possibility to unbind Neutron's port from the host by unsetting its
+ host_id.
diff --git a/releasenotes/notes/add-remote-managed-vnic-type-4fc540b47427c37f.yaml b/releasenotes/notes/add-remote-managed-vnic-type-4fc540b47427c37f.yaml
new file mode 100644
index 0000000..79c4f7b
--- /dev/null
+++ b/releasenotes/notes/add-remote-managed-vnic-type-4fc540b47427c37f.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Support for the ``remote-managed`` VNIC type has been added and can now be
+ passed to the ``--vnic-type`` option when used in conjunction with the
+ ``port create`` and ``port set`` commands.
diff --git a/releasenotes/notes/check-limit-quota-cc7f291dd1b537c1.yaml b/releasenotes/notes/check-limit-quota-cc7f291dd1b537c1.yaml
new file mode 100644
index 0000000..171b4a5
--- /dev/null
+++ b/releasenotes/notes/check-limit-quota-cc7f291dd1b537c1.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - Add ``--check-limit`` option to the ``openstack quota set`` command (only
+ for network commands). The network quota engine will check the resource
+ usage before setting the new quota limit.
diff --git a/releasenotes/notes/fix-flavor-in-server-list-microversion-2.47-af200e9bb4747e2d.yaml b/releasenotes/notes/fix-flavor-in-server-list-microversion-2.47-af200e9bb4747e2d.yaml
new file mode 100644
index 0000000..fdb37bb
--- /dev/null
+++ b/releasenotes/notes/fix-flavor-in-server-list-microversion-2.47-af200e9bb4747e2d.yaml
@@ -0,0 +1,8 @@
+---
+features:
+ - |
+ Add support for compute API microversion 2.47, which changes how flavor
+ details are included in server detail responses. In 2.46 and below,
+ only the flavor ID was shown in the server detail response. Starting in
+ 2.47, flavor information is embedded in the server response. The newer
+ behavior is now supported.
diff --git a/releasenotes/notes/list-subnet-by-pool-id-a642efc13d04fa08.yaml b/releasenotes/notes/list-subnet-by-pool-id-a642efc13d04fa08.yaml
new file mode 100644
index 0000000..d784a9a
--- /dev/null
+++ b/releasenotes/notes/list-subnet-by-pool-id-a642efc13d04fa08.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ Add ``--subnet-pool`` option to ``subnet list`` to filter
+ by subnets by subnet pool.
diff --git a/releasenotes/notes/migrate-add-fixed-ip-to-sdk-3d932d77633bc765.yaml b/releasenotes/notes/migrate-add-fixed-ip-to-sdk-3d932d77633bc765.yaml
new file mode 100644
index 0000000..79899b3
--- /dev/null
+++ b/releasenotes/notes/migrate-add-fixed-ip-to-sdk-3d932d77633bc765.yaml
@@ -0,0 +1,3 @@
+features:
+ - |
+ Switch the add fixed IP command from novaclient to SDK.
diff --git a/releasenotes/notes/migrate-create-server-image-to-sdk-e3d8077ffe05bb3d.yaml b/releasenotes/notes/migrate-create-server-image-to-sdk-e3d8077ffe05bb3d.yaml
new file mode 100644
index 0000000..20f8d55
--- /dev/null
+++ b/releasenotes/notes/migrate-create-server-image-to-sdk-e3d8077ffe05bb3d.yaml
@@ -0,0 +1,4 @@
+---
+features:
+ - |
+ Migrate openstack server image create from novaclient to sdk.
diff --git a/releasenotes/notes/migrate-server-add-network-add-port-to-sdk-7d81b25f59cfbec9.yaml b/releasenotes/notes/migrate-server-add-network-add-port-to-sdk-7d81b25f59cfbec9.yaml
new file mode 100644
index 0000000..930d6bc
--- /dev/null
+++ b/releasenotes/notes/migrate-server-add-network-add-port-to-sdk-7d81b25f59cfbec9.yaml
@@ -0,0 +1,4 @@
+---
+features:
+ - |
+ Migrate server add network/port from novaclient to openstacksdk.
diff --git a/releasenotes/notes/migrate-server-add-volume-to-sdk-685e036a88839651.yaml b/releasenotes/notes/migrate-server-add-volume-to-sdk-685e036a88839651.yaml
new file mode 100644
index 0000000..54abdac
--- /dev/null
+++ b/releasenotes/notes/migrate-server-add-volume-to-sdk-685e036a88839651.yaml
@@ -0,0 +1,4 @@
+---
+features:
+ - |
+ Migrate openstack server add volume to using sdk.
diff --git a/releasenotes/notes/migrate-server-pause-unpause-to-sdk-d74ec8536b764af6.yaml b/releasenotes/notes/migrate-server-pause-unpause-to-sdk-d74ec8536b764af6.yaml
new file mode 100644
index 0000000..e2d4003
--- /dev/null
+++ b/releasenotes/notes/migrate-server-pause-unpause-to-sdk-d74ec8536b764af6.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ Migrate ``server pause`` and ``server unpause`` commands from novaclient
+ to sdk.
diff --git a/releasenotes/notes/migrate-server-suspend-resume-to-sdk-fd1709336607b496.yaml b/releasenotes/notes/migrate-server-suspend-resume-to-sdk-fd1709336607b496.yaml
new file mode 100644
index 0000000..7d3781b
--- /dev/null
+++ b/releasenotes/notes/migrate-server-suspend-resume-to-sdk-fd1709336607b496.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ Migrate ``server suspend`` and ``server resume`` commands from novaclient
+ to sdk.
diff --git a/releasenotes/notes/migrate-service-list-delete-set-to-sdk-920cbe0d210af565.yaml b/releasenotes/notes/migrate-service-list-delete-set-to-sdk-920cbe0d210af565.yaml
new file mode 100644
index 0000000..55dcb43
--- /dev/null
+++ b/releasenotes/notes/migrate-service-list-delete-set-to-sdk-920cbe0d210af565.yaml
@@ -0,0 +1,3 @@
+features:
+ - |
+ Switch the compute service commands from novaclient to SDK.
diff --git a/releasenotes/notes/options-create-router-97910a882b604652.yaml b/releasenotes/notes/options-create-router-97910a882b604652.yaml
new file mode 100644
index 0000000..f7d90b7
--- /dev/null
+++ b/releasenotes/notes/options-create-router-97910a882b604652.yaml
@@ -0,0 +1,8 @@
+---
+features:
+ - |
+ It is now possible to add an external gateway to a router
+ immediately on creation. Previously it could only be done by
+ modifying the router after it had been created. This includes
+ the options to en- or disable SNAT and to specify a fixed-ip
+ on the external network.
diff --git a/releasenotes/notes/pass_ssh_args-cf26a2ce26ccddaf.yaml b/releasenotes/notes/pass_ssh_args-cf26a2ce26ccddaf.yaml
new file mode 100644
index 0000000..fe81de9
--- /dev/null
+++ b/releasenotes/notes/pass_ssh_args-cf26a2ce26ccddaf.yaml
@@ -0,0 +1,14 @@
+---
+features:
+ - |
+ Added the ability to pass arguments through to the ``ssh`` command When
+ using ``openstack server ssh``. This allows the user to use any ``ssh``
+ option without needing to add that option to the openstack client.
+ Existing openstackclient options that mirror SSH options are now
+ deprecated.
+deprecations:
+ - |
+ ``openstack server ssh`` options that mirror ``ssh`` options are now
+ deprecated (``--login, -l, --port, --identity, --option, -o, -vz``).
+ The ``ssh`` equivalent of each deprecated option should be used instead.
+ For example ``openstack server ssh instance -- -l user -i key``
diff --git a/releasenotes/notes/port-list-security-group-4af5d2e789174ff9.yaml b/releasenotes/notes/port-list-security-group-4af5d2e789174ff9.yaml
new file mode 100644
index 0000000..c68eeaf
--- /dev/null
+++ b/releasenotes/notes/port-list-security-group-4af5d2e789174ff9.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ Added ``--security-group`` option to the ``os port list`` command. This
+ option is appendable and multiple security group IDs can be provided.
diff --git a/releasenotes/notes/switch-server-remove-network-port-to-sdk-829ba711e0e198d5.yaml b/releasenotes/notes/switch-server-remove-network-port-to-sdk-829ba711e0e198d5.yaml
new file mode 100644
index 0000000..6b47b1b
--- /dev/null
+++ b/releasenotes/notes/switch-server-remove-network-port-to-sdk-829ba711e0e198d5.yaml
@@ -0,0 +1,4 @@
+---
+features:
+ - |
+ Switch server remove volume/port to using sdk.
diff --git a/releasenotes/notes/switch-server-remove-volume-to-sdk-47e9befd2672dcdf.yaml b/releasenotes/notes/switch-server-remove-volume-to-sdk-47e9befd2672dcdf.yaml
new file mode 100644
index 0000000..3e0397d
--- /dev/null
+++ b/releasenotes/notes/switch-server-remove-volume-to-sdk-47e9befd2672dcdf.yaml
@@ -0,0 +1,4 @@
+---
+features:
+ - |
+ Switch command server remove volume to using sdk.
diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py
index 206c0ce..179f8f2 100644
--- a/releasenotes/source/conf.py
+++ b/releasenotes/source/conf.py
@@ -37,6 +37,14 @@
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
+from sphinx.util import logging
+
+# According to the discussion in
+# https://github.com/sphinx-doc/sphinx/issues/10112 this may be applied as a
+# dirty hack until the issue with replacing extlinks is resolved
+linklogger = logging.getLogger('sphinx.ext.extlinks')
+linklogger.setLevel(40) # Ignore messages less severe than ERROR
+
extensions = [
'openstackdocstheme',
'reno.sphinxext',
diff --git a/requirements.txt b/requirements.txt
index 0ac991d..cb414eb 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -5,7 +5,7 @@ pbr!=2.1.0,>=2.0.0 # Apache-2.0
cliff>=3.5.0 # Apache-2.0
iso8601>=0.1.11 # MIT
-openstacksdk>=0.56.0 # Apache-2.0
+openstacksdk>=0.61.0 # Apache-2.0
osc-lib>=2.3.0 # Apache-2.0
oslo.i18n>=3.15.3 # Apache-2.0
oslo.utils>=3.33.0 # Apache-2.0
diff --git a/setup.cfg b/setup.cfg
index 1211462..8c0163f 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -406,6 +406,16 @@ openstack.network.v2 =
ip_availability_list = openstackclient.network.v2.ip_availability:ListIPAvailability
ip_availability_show = openstackclient.network.v2.ip_availability:ShowIPAvailability
+ local_ip_create = openstackclient.network.v2.local_ip:CreateLocalIP
+ local_ip_delete = openstackclient.network.v2.local_ip:DeleteLocalIP
+ local_ip_list = openstackclient.network.v2.local_ip:ListLocalIP
+ local_ip_set = openstackclient.network.v2.local_ip:SetLocalIP
+ local_ip_show = openstackclient.network.v2.local_ip:ShowLocalIP
+
+ local_ip_association_create = openstackclient.network.v2.local_ip_association:CreateLocalIPAssociation
+ local_ip_association_delete = openstackclient.network.v2.local_ip_association:DeleteLocalIPAssociation
+ local_ip_association_list = openstackclient.network.v2.local_ip_association:ListLocalIPAssociation
+
network_agent_add_network = openstackclient.network.v2.network_agent:AddNetworkToAgent
network_agent_add_router = openstackclient.network.v2.network_agent:AddRouterToAgent
network_agent_delete = openstackclient.network.v2.network_agent:DeleteNetworkAgent